コード例 #1
0
class TestServiceClient(unittest.TestCase):
    def setUp(self):
        self._transport = MagicMock()
        self._response = APIResponse({}, {}, 200)
        self._transport.post.return_value = self._response
        self._transport.get.return_value = self._response
        self._transport.put.return_value = self._response
        self._transport.delete.return_value = self._response
        self._device_response = {
            "auth_request": str(uuid4()),
            "response": True,
            "device_id": str(uuid4()),
            "service_pins": ["1234", "3456", "5678"]
        }
        self._transport.loaded_issuer_private_key.decrypt.return_value = dumps(
            self._device_response)
        self._service_id = uuid4()
        self._issuer = "svc:{}".format(self._service_id)
        self._service_client = ServiceClient(self._service_id, self._transport)
        self._service_client._transport._verify_jwt_response = MagicMock()

    def test_authorize_calls_authorization_request(self):
        policy = AuthPolicy()
        auth_response = AuthorizationRequest(str(uuid4()), None)
        self._service_client.authorization_request = MagicMock(
            return_value=auth_response)
        self._service_client.authorize('user', 'context', policy, 'title', 30,
                                       'push_title', 'push_body')
        self._service_client.authorization_request.assert_called_once_with(
            'user', 'context', policy, 'title', 30, 'push_title', 'push_body')

    def test_authorize_returns_auth_request_id_from_authorization_request_response(
            self):
        expected = str(uuid4())
        self._response.data = {"auth_request": expected}
        actual = self._service_client.authorize('user', 'context',
                                                AuthPolicy())
        self.assertEqual(actual, expected)

    def test_authorization_request_success(self):
        self._response.data = {"auth_request": "value"}
        policy = MagicMock(spec=AuthPolicy)
        policy.get_policy.return_value = "policy"
        self._service_client.authorization_request("user", "context", policy)
        self._transport.post.assert_called_once_with('/service/v3/auths',
                                                     self._issuer,
                                                     username="******",
                                                     context="context",
                                                     policy="policy")

    def test_authorization_request_response_has_auth_request(self):
        self._response.data = {"auth_request": "expected value"}
        self.assertEqual(
            'expected value',
            self._service_client.authorization_request(ANY).auth_request)

    def test_authorization_request_response_has_push_package(self):
        self._response.data = {
            "auth_request": "auth",
            "push_package": "expected package"
        }
        self.assertEqual(
            'expected package',
            self._service_client.authorization_request(ANY).push_package)

    def test_authorization_request_invalid_policy_input(self):
        self._response.data = {"auth_request": ANY}
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(ANY, ANY, ANY)

    def test_authorization_request_unexpected_result(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_invalid_policy(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-002",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidPolicyInput):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_policy_failure(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-003",
                "error_detail": ""
            }, 400)
        with self.assertRaises(PolicyFailure):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_rate_limited(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 429)
        with self.assertRaises(RateLimited):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_default(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user")
        self._transport.post.assert_called_with(ANY, ANY, username="******")

    def test_authorization_request_context(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request(
            "my_user", context="Here's some context!")
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                context="Here's some context!")

    def test_authorization_request_title(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user",
                                                   title="Here's a title!")
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                title="Here's a title!")

    def test_authorization_request_push_title(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user",
                                                   push_title="A Push Title")
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                push_title="A Push Title")

    def test_authorization_request_push_body(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user",
                                                   push_body="Push Body")
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                push_body="Push Body")

    def test_authorization_request_ttl(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", ttl=336)
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                ttl=336)

    def test_authorization_request_denial_reasons_as_list(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request(
            "my_user",
            denial_reasons=[
                DenialReason('fraud', 'Fraud Reason', True),
                DenialReason('not', 'Not Fraud Reason', False)
            ])
        self._transport.post.assert_called_with(ANY,
                                                ANY,
                                                username="******",
                                                denial_reasons=[{
                                                    "id": 'fraud',
                                                    "reason": 'Fraud Reason',
                                                    "fraud": True
                                                }, {
                                                    "id": 'not',
                                                    "reason":
                                                    'Not Fraud Reason',
                                                    "fraud": False
                                                }])

    def test_authorization_request_denial_reasons_as_set(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request(
            "my_user",
            denial_reasons={
                DenialReason('fraud', 'Fraud Reason', True),
                DenialReason('not', 'Not Fraud Reason', False)
            })
        denial_reasons = self._transport.post.call_args[1]['denial_reasons']
        self.assertEqual(len(denial_reasons), 2)
        self.assertIn({
            "id": 'fraud',
            "reason": 'Fraud Reason',
            "fraud": True
        }, denial_reasons)
        self.assertIn(
            {
                "id": 'not',
                "reason": 'Not Fraud Reason',
                "fraud": False
            }, denial_reasons)

    @data("e6e809ab-9e83-47a2-924a-64ae3d424a45", True, False,
          {"Test": "Data"}, DenialReason(1, 2, 3))
    def test_authorization_request_denial_reasons_invalid_input(self, reasons):
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request("my_user",
                                                       denial_reasons=reasons)

    @data("e6e809ab-9e83-47a2-924a-64ae3d424a45", True, False,
          {"Test": "Data"})
    def test_authorization_request_denial_reasons_invalid_reason(self, reason):
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request("my_user",
                                                       denial_reasons=[reason])

    @patch("launchkey.entities.service.loads")
    @patch("launchkey.entities.service.AuthorizationResponsePackageValidator")
    def test_get_authorization_response_success(
            self, json_loads_patch, auth_response_package_validator_patch):
        json_loads_patch.return_value = MagicMock(spec=dict)
        auth_response_package_validator_patch.return_value = MagicMock(
            spec=dict)
        public_key_id = str(uuid4())
        self._service_client._transport.loaded_issuer_private_keys = {
            public_key_id: MagicMock()
        }
        self._response.data = {
            "auth": ANY,
            "service_user_hash": ANY,
            "user_push_id": ANY,
            "org_user_hash": ANY,
            "public_key_id": public_key_id
        }
        actual = self._service_client.get_authorization_response(
            "auth-request-id")
        self._transport.get.assert_called_once_with(
            "/service/v3/auths/auth-request-id", self._issuer)
        self.assertIsInstance(actual, AuthorizationResponse)

    def test_get_authorization_response_unexpected_response(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_no_response(self):
        self._response.status_code = 204
        self.assertIsNone(self._service_client.get_authorization_response(ANY))

    def test_get_authorization_response_invalid_params(self):
        self._transport.get.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_response_exists(self):
        self._transport.get.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-006",
                "error_detail": ""
            }, 400)
        with self.assertRaises(AuthorizationResponseExists):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_timeout(self):
        self._transport.get.side_effect = LaunchKeyAPIException({}, 408)
        with self.assertRaises(RequestTimedOut):
            self._service_client.get_authorization_response(ANY)

    def test_cancel_authorization_request_success(self):
        self._service_client.cancel_authorization_request("auth-request-id")
        self._transport.delete.assert_called_once_with(
            "/service/v3/auths/auth-request-id", self._issuer)

    def test_cancel_authorization_request_invalid_params(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.cancel_authorization_request(
                "auth-request-id")

    def test_cancel_authorization_request_authorization_response_exists(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-006",
                "error_detail": ""
            }, 400)
        with self.assertRaises(AuthorizationResponseExists):
            self._service_client.cancel_authorization_request(
                "auth-request-id")

    def test_cancel_authorization_request_authorization_request_canceled(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-007",
                "error_detail": ""
            }, 400)
        with self.assertRaises(AuthorizationRequestCanceled):
            self._service_client.cancel_authorization_request(
                "auth-request-id")

    def test_cancel_authorization_request_invalid_params(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.cancel_authorization_request(
                "auth-request-id")

    def test_session_start_success(self):
        self._service_client.session_start("user-id", "auth-request-id")
        self._transport.post.assert_called_once_with(
            "/service/v3/sessions",
            self._issuer,
            username="******",
            auth_request="auth-request-id")

    def test_session_start_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_start(ANY, ANY)

    def test_session_start_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_start(ANY, ANY)

    def test_session_end_success(self):
        self._service_client.session_end("user-id")
        self._transport.delete.assert_called_once_with("/service/v3/sessions",
                                                       self._issuer,
                                                       username="******")

    def test_session_end_invalid_params(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_end(ANY)

    def test_session_end_entity_not_found(self):
        self._transport.delete.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_end(ANY)
コード例 #2
0
class TestServiceClient(unittest.TestCase):
    def setUp(self):
        self._transport = MagicMock()
        self._response = APIResponse({}, {}, 200)
        self._transport.post.return_value = self._response
        self._transport.get.return_value = self._response
        self._transport.put.return_value = self._response
        self._transport.delete.return_value = self._response
        self._device_response = {
            "auth_request": str(uuid4()),
            "response": True,
            "device_id": str(uuid4()),
            "service_pins": ["1234", "3456", "5678"]
        }
        self._transport.loaded_issuer_private_key.decrypt.return_value = dumps(
            self._device_response)
        self._service_client = ServiceClient(uuid4(), self._transport)
        self._service_client._transport._verify_jwt_response = MagicMock()

    def test_authorize_success(self):
        self._response.data = {"auth_request": ANY}
        self._service_client.authorize(ANY, ANY, MagicMock(spec=AuthPolicy))

    def test_authorize_invalid_policy_input(self):
        self._response.data = {"auth_request": ANY}
        with self.assertRaises(InvalidParameters):
            self._service_client.authorize(ANY, ANY, ANY)

    def test_authorize_unexpected_result(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.authorize(ANY)

    def test_authorize_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.authorize(ANY)

    def test_authorize_invalid_policy(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-002",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidPolicyInput):
            self._service_client.authorize(ANY)

    def test_authorize_policy_failure(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "SVC-003",
                "error_detail": ""
            }, 400)
        with self.assertRaises(PolicyFailure):
            self._service_client.authorize(ANY)

    def test_authorize_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.authorize(ANY)

    def test_authorize_rate_limited(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 429)
        with self.assertRaises(RateLimited):
            self._service_client.authorize(ANY)

    @patch("launchkey.entities.service.b64decode")
    @patch("launchkey.entities.service.loads")
    @patch("launchkey.entities.service.AuthorizationResponsePackageValidator")
    def test_get_authorization_response_success(
            self, b64decode_patch, json_loads_patch,
            auth_response_package_validator_patch):
        b64decode_patch.return_value = MagicMock(spec=str)
        json_loads_patch.return_value = MagicMock(spec=dict)
        auth_response_package_validator_patch.return_value = MagicMock(
            spec=dict)
        public_key_id = str(uuid4())
        self._service_client._transport.loaded_issuer_private_keys = {
            public_key_id: MagicMock()
        }
        self._response.data = {
            "auth": ANY,
            "service_user_hash": ANY,
            "user_push_id": ANY,
            "org_user_hash": ANY,
            "public_key_id": public_key_id
        }
        self.assertIsInstance(
            self._service_client.get_authorization_response(ANY),
            AuthorizationResponse)

    def test_get_authorization_response_unexpected_response(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_no_response(self):
        self._response.status_code = 204
        self.assertIsNone(self._service_client.get_authorization_response(ANY))

    def test_get_authorization_response_invalid_params(self):
        self._transport.get.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_timeout(self):
        self._transport.get.side_effect = LaunchKeyAPIException({}, 408)
        with self.assertRaises(RequestTimedOut):
            self._service_client.get_authorization_response(ANY)

    def test_session_start_success(self):
        self.assertIsNone(self._service_client.session_start(ANY, ANY))

    def test_session_start_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_start(ANY, ANY)

    def test_session_start_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_start(ANY, ANY)

    def test_session_end_success(self):
        self.assertIsNone(self._service_client.session_end(ANY))

    def test_session_end_invalid_params(self):
        self._transport.delete.side_effect = LaunchKeyAPIException(
            {
                "error_code": "ARG-001",
                "error_detail": ""
            }, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_end(ANY)

    def test_session_end_entity_not_found(self):
        self._transport.delete.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_end(ANY)

    def test_webhook_session_end(self):
        request = dumps({
            "service_user_hash":
            str(uuid4()),
            "api_time":
            str(datetime.utcnow())[:19].replace(" ", "T") + "Z"
        })
        self.assertIsInstance(
            self._service_client.handle_webhook(request, ANY),
            SessionEndRequest)

    def test_webhook_session_end_invalid_input(self):
        request = dumps({"service_user_hash": str(uuid4())})
        with self.assertRaises(UnexpectedAPIResponse):
            self.assertIsInstance(
                self._service_client.handle_webhook(request, ANY),
                SessionEndRequest)

    @patch("launchkey.entities.service.b64decode")
    @patch("launchkey.clients.service.loads")
    @patch("launchkey.entities.service.loads")
    @patch("launchkey.entities.validation.AuthorizeSSEValidator")
    @patch("launchkey.entities.service.AuthorizationResponsePackageValidator")
    def test_webhook_authorization_response(
            self, auth_response_package_validator_patch,
            auth_sse_validator_patch, json_loads_patch, json_loads_patch_2,
            b64decode_patch):
        b64decode_patch.return_value = MagicMock(spec=str)
        json_loads_patch.return_value = MagicMock(spec=dict)
        json_loads_patch_2.return_value = MagicMock(spec=dict)
        auth_sse_validator_patch.return_value = MagicMock(spec=dict)
        auth_response_package_validator_patch.return_value = MagicMock(
            spec=dict)
        self._transport.loaded_issuer_private_keys = {
            json_loads_patch_2().get(): MagicMock()
        }
        self.assertIsInstance(
            self._service_client.handle_webhook(MagicMock(), ANY),
            AuthorizationResponse)
コード例 #3
0
class TestServiceClient(unittest.TestCase):

    def setUp(self):
        self._transport = MagicMock()
        self._response = APIResponse({}, {}, 200)
        self._transport.post.return_value = self._response
        self._transport.get.return_value = self._response
        self._transport.put.return_value = self._response
        self._transport.delete.return_value = self._response
        self._device_response = {"auth_request": str(uuid4()), "response": True, "device_id": str(uuid4()),
                                 "service_pins": ["1234", "3456", "5678"]}
        self._transport.loaded_issuer_private_key.decrypt.return_value = dumps(self._device_response)
        self._service_id = uuid4()
        self._issuer = "svc:{}".format(self._service_id)
        self._service_client = ServiceClient(self._service_id, self._transport)
        self._service_client._transport._verify_jwt_response = MagicMock()

    def test_authorize_calls_authorization_request(self):
        policy = AuthPolicy()
        auth_response = AuthorizationRequest(str(uuid4()), None)
        self._service_client.authorization_request = MagicMock(return_value=auth_response)
        self._service_client.authorize('user', 'context', policy, 'title', 30,
                                       'push_title', 'push_body')
        self._service_client.authorization_request.assert_called_once_with(
            'user', 'context', policy, 'title', 30, 'push_title', 'push_body')

    def test_authorize_returns_auth_request_id_from_authorization_request_response(self):
        expected = str(uuid4())
        self._response.data = {"auth_request": expected}
        actual = self._service_client.authorize('user', 'context', AuthPolicy())
        self.assertEqual(actual, expected)

    def test_authorization_request_success(self):
        self._response.data = {"auth_request": "value"}
        policy = MagicMock(spec=AuthPolicy)
        policy.get_policy.return_value = "policy"
        self._service_client.authorization_request("user", "context", policy)
        self._transport.post.assert_called_once_with(
            '/service/v3/auths', self._issuer, username="******",
            context="context", policy="policy"
        )

    def test_authorization_request_response_has_auth_request(self):
        self._response.data = {"auth_request": "expected value"}
        self.assertEqual('expected value', self._service_client.authorization_request(ANY).auth_request)

    def test_authorization_request_response_has_push_package(self):
        self._response.data = {"auth_request": "auth", "push_package": "expected package"}
        self.assertEqual('expected package', self._service_client.authorization_request(ANY).push_package)

    def test_authorization_request_invalid_policy_input(self):
        self._response.data = {"auth_request": ANY}
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(ANY, ANY, ANY)

    def test_authorization_request_unexpected_result(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException({"error_code": "ARG-001", "error_detail": ""}, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_invalid_policy(self):
        self._transport.post.side_effect = LaunchKeyAPIException({"error_code": "SVC-002", "error_detail": ""}, 400)
        with self.assertRaises(InvalidPolicyInput):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_policy_failure(self):
        self._transport.post.side_effect = LaunchKeyAPIException({"error_code": "SVC-003", "error_detail": ""}, 400)
        with self.assertRaises(PolicyFailure):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_rate_limited(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 429)
        with self.assertRaises(RateLimited):
            self._service_client.authorization_request(ANY)

    def test_authorization_request_default(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user")
        self._transport.post.assert_called_with(ANY, ANY, username="******")

    def test_authorization_request_context(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", context="Here's some context!")
        self._transport.post.assert_called_with(ANY, ANY, username="******", context="Here's some context!")

    def test_authorization_request_title(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", title="Here's a title!")
        self._transport.post.assert_called_with(ANY, ANY, username="******", title="Here's a title!")

    def test_authorization_request_push_title(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user",
                                                   push_title="A Push Title")
        self._transport.post.assert_called_with(ANY, ANY, username="******",
                                                push_title="A Push Title")

    def test_authorization_request_push_body(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user",
                                                   push_body="Push Body")
        self._transport.post.assert_called_with(ANY, ANY, username="******",
                                                push_body="Push Body")

    def test_authorization_request_ttl(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", ttl=336)
        self._transport.post.assert_called_with(ANY, ANY, username="******", ttl=336)

    def test_authorization_request_denial_reasons_as_list(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", denial_reasons=[
            DenialReason('fraud', 'Fraud Reason', True),
            DenialReason('not', 'Not Fraud Reason', False)
        ])
        self._transport.post.assert_called_with(
            ANY, ANY, username="******",
            denial_reasons=[
                {"id": 'fraud', "reason": 'Fraud Reason', "fraud": True},
                {"id": 'not', "reason": 'Not Fraud Reason', "fraud": False}
            ]
        )

    def test_authorization_request_denial_reasons_as_set(self):
        self._response.data = {"auth_request": "expected value"}
        self._service_client.authorization_request("my_user", denial_reasons={
            DenialReason('fraud', 'Fraud Reason', True),
            DenialReason('not', 'Not Fraud Reason', False)
        })
        denial_reasons = self._transport.post.call_args[1]['denial_reasons']
        self.assertEqual(len(denial_reasons), 2)
        self.assertIn(
            {"id": 'fraud', "reason": 'Fraud Reason', "fraud": True},
            denial_reasons
        )
        self.assertIn(
            {"id": 'not', "reason": 'Not Fraud Reason', "fraud": False},
            denial_reasons
        )

    @data(
        "e6e809ab-9e83-47a2-924a-64ae3d424a45",
        True,
        False,
        {"Test": "Data"},
        DenialReason(1, 2, 3)
    )
    def test_authorization_request_denial_reasons_invalid_input(self, reasons):
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(
                "my_user",
                denial_reasons=reasons
            )

    @data(
        "e6e809ab-9e83-47a2-924a-64ae3d424a45",
        True,
        False,
        {"Test": "Data"}
    )
    def test_authorization_request_denial_reasons_invalid_reason(self,
                                                                 reason):
        with self.assertRaises(InvalidParameters):
            self._service_client.authorization_request(
                "my_user",
                denial_reasons=[reason]
            )

    @patch("launchkey.entities.service.loads")
    @patch("launchkey.entities.service.AuthorizationResponsePackageValidator")
    def test_get_authorization_response_success(
            self, json_loads_patch,
            auth_response_package_validator_patch):
        json_loads_patch.return_value = MagicMock(spec=dict)
        auth_response_package_validator_patch.return_value = MagicMock(spec=dict)
        public_key_id = str(uuid4())
        self._service_client._transport.loaded_issuer_private_keys = {public_key_id: MagicMock()}
        self._response.data = {
            "auth": ANY,
            "service_user_hash": ANY,
            "user_push_id": ANY,
            "org_user_hash": ANY,
            "public_key_id": public_key_id
        }
        actual = self._service_client.get_authorization_response(
            "auth-request-id")
        self._transport.get.assert_called_once_with(
            "/service/v3/auths/auth-request-id", self._issuer)
        self.assertIsInstance(actual, AuthorizationResponse)

    def test_get_authorization_response_unexpected_response(self):
        self._response.data = {MagicMock(spec=str): ANY}
        with self.assertRaises(UnexpectedAPIResponse):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_no_response(self):
        self._response.status_code = 204
        self.assertIsNone(self._service_client.get_authorization_response(ANY))

    def test_get_authorization_response_invalid_params(self):
        self._transport.get.side_effect = LaunchKeyAPIException({"error_code": "ARG-001", "error_detail": ""}, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.get_authorization_response(ANY)

    def test_get_authorization_response_timeout(self):
        self._transport.get.side_effect = LaunchKeyAPIException({}, 408)
        with self.assertRaises(RequestTimedOut):
            self._service_client.get_authorization_response(ANY)

    def test_session_start_success(self):
        self._service_client.session_start("user-id", "auth-request-id")
        self._transport.post.assert_called_once_with(
            "/service/v3/sessions", self._issuer, username="******",
            auth_request="auth-request-id")

    def test_session_start_invalid_params(self):
        self._transport.post.side_effect = LaunchKeyAPIException({"error_code": "ARG-001", "error_detail": ""}, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_start(ANY, ANY)

    def test_session_start_entity_not_found(self):
        self._transport.post.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_start(ANY, ANY)

    def test_session_end_success(self):
        self._service_client.session_end("user-id")
        self._transport.delete.assert_called_once_with(
            "/service/v3/sessions", self._issuer, username="******")

    def test_session_end_invalid_params(self):
        self._transport.delete.side_effect = LaunchKeyAPIException({"error_code": "ARG-001", "error_detail": ""}, 400)
        with self.assertRaises(InvalidParameters):
            self._service_client.session_end(ANY)

    def test_session_end_entity_not_found(self):
        self._transport.delete.side_effect = LaunchKeyAPIException({}, 404)
        with self.assertRaises(EntityNotFound):
            self._service_client.session_end(ANY)