text: import unittest
  
  from enum import Enum
  from unittest.mock import patch, call, MagicMock
  
  import requests
  
  from conjur.wrapper.http_wrapper import HttpVerb, invoke_endpoint
  
  
  class HttpVerbTest(unittest.TestCase):
      def test_http_verb_has_all_the_verbs_expected(self):
          self.assertTrue(HttpVerb.GET)
          self.assertTrue(HttpVerb.PUT)
          self.assertTrue(HttpVerb.POST)
          self.assertTrue(HttpVerb.DELETE)
          self.assertTrue(HttpVerb.PATCH)
  
  
  class HttpInvokeEndpointTest(unittest.TestCase):
      UNESCAPED_PARAMS = {
          'url': 'https://foo.bar',
          'one': 'abc/$!@#$%^&*() \\[]{}',
          'two': ')(*&^%$#@![]{} <>?',
      }
  
      ESCAPED_PARAMS = [
          'abc%2F%24%21%40%23%24%25%5E%26%2A%28%29%20%5C%5B%5D%7B%7D',
          '%29%28%2A%26%5E%25%24%23%40%21%5B%5D%7B%7D%20%3C%3E%3F',
      ]
  
      class MockEndpoint(Enum):
          NO_PARAMS = "no/params"
          WITH_URL = "{url}/no/params"
          PARAMETER_ESCAPING = "{url}/{one}/{two}"
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_can_invoke_http_client(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, {})
  
          mock_get.assert_called_once_with('no/params', auth=None, headers={}, verify=True, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_can_handle_unset_params(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None)
  
          mock_get.assert_called_once_with('no/params', auth=None, headers={}, verify=True, params=None)
  
      @patch.object(requests, 'get')
      @patch.object(requests, 'post')
      @patch.object(requests, 'delete')
      def test_invoke_endpoint_uses_http_verb_for_method_name(self, mock_delete, mock_post, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, {})
          mock_get.assert_called_once_with('no/params', auth=None, headers={}, verify=True, params=None)
  
          invoke_endpoint(HttpVerb.POST, self.MockEndpoint.NO_PARAMS, {})
          mock_post.assert_called_once_with('no/params', auth=None, headers={}, verify=True, params=None)
  
          invoke_endpoint(HttpVerb.DELETE, self.MockEndpoint.NO_PARAMS, {})
          mock_delete.assert_called_once_with('no/params', auth=None, headers={}, verify=True, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_generates_url_from_endpoint_object(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.WITH_URL, {'url': 'http://host'})
  
          mock_get.assert_called_once_with('http://host/no/params', auth=None, headers={}, verify=True, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_attaches_api_token_header_if_present_in_params(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, api_token='token')
  
          mock_get.assert_called_once_with('no/params', auth=None, verify=True,
                                           headers={'Authorization': 'Token token="dG9rZW4="'}, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_verifies_ssl_by_default(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None)
  
          mock_get.assert_called_once_with('no/params', auth=None, verify=True, headers={}, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_ssl_verify_param_defaults_to_true_to_http_client(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, ssl_verify='foo')
  
          mock_get.assert_called_once_with('no/params', auth=None, verify=True, headers={}, params=None)
  
      @patch.object(requests, 'get', side_effect=[requests.exceptions.SSLError(), None])
      def test_invoke_endpoint_passes_ssl_verify_param_and_tries_verify_true_first_to_http_client(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, ssl_verify='foo', check_errors=False)
          calls = [call('no/params', auth=None, verify=True, headers={}, params=None), call('no/params', auth=None, verify='foo', headers={}, params=None)]
          mock_get.assert_has_calls(calls)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_raises_hostname_mismatch_error(self, mock_get):
          mock = MagicMock()
          mock.response="hostname"
          mock_get.side_effect=requests.exceptions.SSLError(response=mock.response)
          with self.assertRaises(requests.exceptions.SSLError):
              invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, ssl_verify='foo', check_errors=False)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_passes_auth_param_to_hettp_client_if_provided(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, auth='bar')
  
          mock_get.assert_called_once_with('no/params', auth='bar', verify=True, headers={}, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_passes_extra_args_to_http_client(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, 'a', 'b')
  
          mock_get.assert_called_once_with('no/params', 'a', 'b', auth=None, verify=True, headers={}, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_passes_query_param(self, mock_get):
          query = {
              'foo!@#$': 'a',
              'bar)(*&^%': 'b',
          }
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, 'a', 'b', query=query)
  
          mock_get.assert_called_once_with('no/params', 'a', 'b', auth=None, verify=True, headers={}, params=query)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_quotes_all_params_except_url(self, mock_get):
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.PARAMETER_ESCAPING,
                  self.UNESCAPED_PARAMS, '$#\\% ^%')
  
          quoted_endpoint = '/'.join([self.UNESCAPED_PARAMS['url']] + self.ESCAPED_PARAMS)
          mock_get.assert_called_once_with(quoted_endpoint, '$#\\% ^%', auth=None, verify=True, headers={}, params=None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_raises_error_if_bad_status_code_is_returned(self, mock_get):
          class MockResponse(object):
              def raise_for_status(self):
                  raise Exception('bad status code!')
          mock_get.return_value = MockResponse()
  
          with self.assertRaises(Exception) as context:
              invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_does_not_raise_error_if_bad_status_but_check_errors_is_false(self, mock_get):
          class MockResponse(object):
              def raise_for_status(self):
                  # This line should not be hit but if it is, it's a test failure
                  raise Exception('bad status code!') # pragma: no cover
          mock_get.return_value = MockResponse()
  
          invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None, check_errors=False)
  
      @patch.object(requests, 'get')
      def test_invoke_endpoint_returns_http_client_response(self, mock_get):
          class MockResponse(object):
              def raise_for_status(self):
                  pass
          mock_get.return_value = MockResponse()
  
          response = invoke_endpoint(HttpVerb.GET, self.MockEndpoint.NO_PARAMS, None)
  
          self.assertEquals(response, mock_get.return_value)
  