class DispatchResponse404Test(TestCase): @with_json_fixture("single_full_app.json") def setUp(self, single_full_app_fixture): rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0") self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.user.accounts = [self.account_dev] self.session.add(self.user) self.session.add(self.account_dev) self.session.commit() def test_do_not_dispatch_response_pipeline_if_upstream_returns_404(self): auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } with application.test_client() as client: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'message': "App /foo not found"}), status=404) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps/dev/foo', body=json.dumps({'message': "App /foo not found"}), status=404) response = client.get("/v2/apps/foo", headers=auth_header) self.assertEqual(404, response.status_code)
class BaseApiTests: user_tx_authkey = "69ed620926be4067a36402c3f7e9ddf0" def setUp(self): rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey=self.user_tx_authkey) self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.user.accounts = [self.account_dev] self.user.current_account = self.account_dev self.session.add(self.account_dev) self.session.add(self.user) self.session.commit() self.proxy_mock_patcher = patch.object(hollowman.routes, 'raw_proxy') self.proxy_mock = self.proxy_mock_patcher.start() self.proxy_mock.return_value = Response(status=200) @property def auth_header(self): return {"Authorization": f"Token {self.user_tx_authkey}"} def tearDown(self): patch.stopall()
class TestAuthentication(TestCase): @with_json_fixture("single_full_app.json") def setUp(self, fixture): rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0") self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.account_infra = Account(name="Infra Team", namespace="infra", owner="company") self.account_sup = Account(name="Support Team", namespace="sup", owner="company") self.user.accounts = [self.account_dev, self.account_infra] self.session.add(self.user) self.session.add(self.account_dev) self.session.add(self.account_infra) self.session.add(self.account_sup) self.user_with_no_accounts = User( tx_email="*****@*****.**", tx_name="No Accounts", tx_authkey="7b4184bfe7d2349eb56bcfb9dc246cf8") self.session.add(self.user_with_no_accounts) self.account_with_no_user = Account(name="Team Nobody", namespace="nobody", owner="nobody") self.session.add(self.account_with_no_user) self.session.commit() self.response_http_200 = MagicMock(status_code=200) responses.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps', body=json.dumps({'apps': [fixture]}), status=200) responses.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//foo', body=json.dumps({'app': fixture}), status=200) responses.start() def tearDown(self): self.session.close() responses.stop() def test_populate_request_user_if_key_is_valid(self): """ Populates request.user if authentication is successful """ with application.test_client() as client: r = client.get("/v2/apps", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(200, r.status_code) self.assertEqual("*****@*****.**", request.user.tx_email) def test_token_populate_default_account_if_request_account_is_empty(self): with application.test_client() as client: r = client.get("/v2/apps", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(200, r.status_code) self.assertEqual("*****@*****.**", request.user.tx_email) self.assertEqual(self.account_dev.id, request.user.current_account.id) self.assertEqual(self.account_dev.namespace, request.user.current_account.namespace) self.assertEqual(self.account_dev.owner, request.user.current_account.owner) @unittest.skip("Pode não fazer sentido...") def test_jwt_populate_default_account_if_request_account_is_empty(self): """ Como quem gera o token JWT é o server e ele *sempre* coloca account_id (Um user sem nennhuma account associada não se loga), esse request nunca vai acontecer. Não acontece pois é impossivel gerar um JWT válido sem ter a SECRET_KEY que só o server tem. """ test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( {"email": "*****@*****.**"}) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code) self.assertEqual(3, r.user.current_account) def test_jwt_return_401_if_user_is_not_linked_to_account(self): """ If user tries to access account without being associated to this account """ test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_with_no_user)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Permission Denied to access this account", json.loads(r.data)['msg']) def test_return_200_if_key_found(self): with application.test_client() as client: r = client.get("/v2/apps", headers={ "Authorization": " Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(200, r.status_code) def test_return_401_if_key_not_found(self): with application.test_client() as client: r = client.get("/v2/apps", headers={"Authorization": "Token token-not-found"}) self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg']) def test_return_401_if_no_token_present(self): with application.test_client() as client: r = client.get("/v2/apps") self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg']) def test_jwt_do_not_trigger_token_auth_if_jwt_token_is_present(self): """ Both auth uses the same header: Authorization. Token Auth should *not* be called if current token is JWT """ with application.test_client() as test_client, \ application.app_context(), \ patch.object(decorators, "HollowmanSession") as session_mock: r = test_client.get("/v2/apps", headers={"Authorization": "JWT Token"}) self.assertEqual(0, session_mock.call_count) def test_token_return_401_if_user_is_not_associated_to_desired_account( self): """ Qualquer request com `?account_id` que o usuário nao esteja vinculado, retorna 401 """ account_id = self.account_with_no_user.id with application.test_client() as client: r = client.get("/v2/apps?account_id={}".format(account_id), headers={ "Authorization": " Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(401, r.status_code) def test_return_200_if_jwt_token_valid(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_dev)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code) def test_jwt_populate_request_user_if_token_is_valid(self): with application.app_context(), application.test_client( ) as test_client: jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_infra)) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(200, r.status_code) self.assertEqual("*****@*****.**", request.user.tx_email) self.assertEqual(5, request.user.current_account.id) def test_jwt_auth_with_token_from_session_if_headers_not_present(self): """ Se não encontrarmos o token JWT no header, olhamos na flask session procurando por ele. """ test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, self.account_dev)) with test_client.session_transaction() as flask_session: flask_session['jwt'] = jwt_token response = test_client.get("/v2/apps") self.assertEqual(200, response.status_code) @unittest.skip("Ainda nao temos usuarios validos/ativos/invalidos") def test_return_401_if_jwt_token_is_valid_but_user_is_invalid(self): """ User could be inactive or does not exist """ self.fail() def test_return_401_if_jwt_token_is_invalid(self): with application.app_context(), application.test_client( ) as test_client: jwt_token = jwt.encode({"email": "*****@*****.**"}, key="wrong key") auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg']) def test_return_401_if_jwt_token_not_present(self): test_client = application.test_client() with application.app_context(): r = test_client.get("/v2/apps") self.assertEqual(401, r.status_code) self.assertEqual("Authorization token is invalid", json.loads(r.data)['msg']) def test_redirect_with_jwt_url_is_formed_with_unicode_jwt(self): test_client = application.test_client() jwt = MagicMock() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": "*****@*****.**"}),\ patch.object(routes.jwt_auth, "jwt_encode_callback", return_value=jwt), \ patch.object(routes, 'redirect') as redirect: response = test_client.get("/authenticate/google") jwt.decode.assert_called_once_with('utf-8') redirect.assert_called_once_with("{}?jwt={}".format( conf.REDIRECT_AFTER_LOGIN, jwt.decode.return_value)) def test_login_failed_invalid_oauth2(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with("login-failed.html", reason="Invalid OAuth2 code") def test_login_failed_user_not_found(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": "*****@*****.**"}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with("login-failed.html", reason="User not found") def test_login_failed_user_does_not_have_any_account(self): test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user_with_no_accounts.tx_email}), \ patch.object(routes, "render_template") as render_mock: response = test_client.get("/authenticate/google") render_mock.assert_called_once_with( "login-failed.html", reason="No associated accounts") def test_return_401_user_has_no_associated_account(self): with application.test_client() as client: r = client.get("/v2/apps", headers={ "Authorization": "Token 7b4184bfe7d2349eb56bcfb9dc246cf8" }) self.assertEqual(401, r.status_code) self.assertEqual("No associated account", json.loads(r.data)['msg']) def test_jwt_add_redirect_with_account_id_on_token_after_login(self): """ Depois do processo de login, o token JWT conterá o account_id da conta padrão do usuário. """ test_client = application.test_client() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}),\ patch.object(routes, "redirect") as redirect_mock: response = test_client.get("/authenticate/google") jwt_token = redirect_mock.call_args_list[0][0][0].split("=")[1] token_content = jwt.decode(jwt_token, conf.SECRET_KEY) self.assertEqual(self.user.tx_email, token_content["user"]["email"]) self.assertEqual(self.user.tx_name, token_content["user"]["name"]) self.assertEqual(self.user.accounts[0].id, token_content["current_account"]["id"]) self.assertEqual(self.user.accounts[0].name, token_content["current_account"]["name"]) self.assertEqual(self.user.accounts[0].namespace, token_content["current_account"]["namespace"]) def test_add_default_account_on_first_jwt_token(self): """ Depois do processo de login, o token JWT conterá o account_id da conta padrão do usuário. """ test_client = application.test_client() jwt = MagicMock() with application.app_context(), \ patch.object(routes, "check_authentication_successful", return_value={"email": self.user.tx_email}),\ patch.object(routes.jwt_auth, "jwt_encode_callback") as jwt_auth_mock: response = test_client.get("/authenticate/google") jwt_auth_mock.assert_called_once_with( jwt_generate_user_info(self.user, self.user.accounts[0])) def test_token_return_401_if_user_has_no_associated_account(self): with application.test_client() as client: r = client.get("/v2/apps", headers={ "Authorization": " Token 7b4184bfe7d2349eb56bcfb9dc246cf8" }) self.assertEqual(401, r.status_code) self.assertEqual("No associated account", json.loads(r.data)['msg']) @unittest.skip( "Em teoria nunca vai existir um token JWT valido sem account_id. Mais detahes no teste test_jwt_populate_default_account_if_request_account_is_empty" ) def test_jwt_return_401_if_user_has_no_associated_account(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback({ "email": "*****@*****.**", "account_id": 2 }) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("No associated account", json.loads(r.data)['msg']) def test_jwt_return_401_if_when_account_does_not_exist(self): test_client = application.test_client() with application.app_context(): jwt_token = jwt_auth.jwt_encode_callback( jwt_generate_user_info(self.user, Account(id=1024))) auth_header = { "Authorization": "JWT {}".format(jwt_token.decode('utf-8')) } r = test_client.get("/v2/apps", headers=auth_header) self.assertEqual(401, r.status_code) self.assertEqual("Account does not exist", json.loads(r.data)['msg']) def test_token_return_401_if_when_account_does_not_exist(self): with application.test_client() as client: r = client.get("/v2/apps?account_id=1024", headers={ "Authorization": " Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(401, r.status_code) self.assertEqual("Account does not exist", json.loads(r.data)['msg'])
class RequestHandlersTests(TestCase): @with_json_fixture("single_full_app.json") def setUp(self, single_full_app_fixture): self.request_apps = [ (MarathonApp(id='/xablau'), MarathonApp(id='/xena')), (MarathonApp(id='/foo'), MarathonApp(id='/bar')), ] rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0") self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.user.accounts = [self.account_dev] self.session.add(self.user) self.session.add(self.account_dev) self.session.commit() def test_it_call_dispatch_using_user_from_request(self): """ Certificamos que o user preenchido no request é repassado para o dispatch """ with application.test_request_context('/v2/apps/foo', method='GET') as ctx: with patch('hollowman.request_handlers.upstream_request'), \ patch('hollowman.request_handlers.dispatch') as dispatch_mock: user = MagicMock() ctx.request.user = user request_parser = Request(ctx.request) request_parser.split = MagicMock( return_value=[self.request_apps[0]]) request_parser.join = MagicMock() response = new(request_parser) dispatch_mock.assert_called_once_with(user=user, request=ANY) @with_json_fixture("../fixtures/single_full_app.json") def test_versions_endpoint_returns_app_on_root_json( self, single_full_app_fixture): """ Apesar de um GET /v2/apps/<app-id> retornat a app em: {"app": <app-definition} um GET /v2/apps/<app-id>/versions/<version-id> retorna em: {<app-definition>} Aqui conferimos que nosso pipeline retorna um response consistente com essa regra """ auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } single_full_app_fixture['id'] = "/dev/foo" with application.test_client() as client: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps/dev/foo/versions/2017-10-31T13:01:07.768Z', body=json.dumps(single_full_app_fixture), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({"app": single_full_app_fixture}), status=200) response = client.get( "/v2/apps/foo/versions/2017-10-31T13:01:07.768Z", headers=auth_header) self.assertEqual(200, response.status_code) self.assertEqual("/foo", json.loads(response.data)['id']) @with_json_fixture("../fixtures/single_full_app.json") def test_apps_endpoint_accepts_app_with_versions_in_the_name( self, single_full_app_fixture): """ Regressão: Commit 0068801288b33a407676a6aa9b521881854de2f7 Devemos aceitar uma app que possui a string "versions" em um lugar no nome, especialmente no fim de uma parte do path, ex: "/workers/conversions/splitter" """ auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } single_full_app_fixture['id'] = "/dev/workers/conversions/splitter" with application.test_client() as client: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps/dev/workers/conversions/splitter', body=json.dumps({"app": single_full_app_fixture}), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/workers/conversions/splitter', body=json.dumps({"app": single_full_app_fixture}), status=200) response = client.get("/v2/apps/workers/conversions/splitter", headers=auth_header) self.assertEqual(200, response.status_code) self.assertTrue('app' in json.loads(response.data)) self.assertEqual("/workers/conversions/splitter", json.loads(response.data)['app']['id']) @with_json_fixture("../fixtures/group_dev_namespace_with_apps.json") def test_groups_endpoint_returns_group_on_root_json( self, group_dev_namespace_fixture): auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } with application.test_client() as client: with RequestsMock() as rsps: rsps.add( method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups//dev/group-b', body=json.dumps( deepcopy(group_dev_namespace_fixture['groups'][1])), status=200) rsps.add( method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups/dev/group-b', body=json.dumps( deepcopy(group_dev_namespace_fixture['groups'][1])), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups//dev/group-b/group-b0', body=json.dumps( deepcopy(group_dev_namespace_fixture['groups'][1] ['groups'][0])), status=200) response = client.get("/v2/groups/group-b", headers=auth_header) self.assertEqual(200, response.status_code) self.assertEqual("/group-b", json.loads(response.data)['id']) @with_json_fixture("../fixtures/queue/get.json") def test_queue_removes_queued_appps_from_other_namespaces( self, queue_get_fixture): """ Removemos todas as apps que não sejam do namespace atual. Esse teste tambéem confirma que o namespace é removido dos elementos que voltam no response. """ auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } with application.test_client() as client: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/queue', status=200, json=queue_get_fixture) response = client.get("/v2/queue", headers=auth_header) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(1, len(response_data['queue'])) self.assertEqual("/waiting", response_data['queue'][0]['app']['id']) def test_get_empty_apps_listing(self): auth_header = { "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" } with application.test_client() as client: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps', body=json.dumps({"apps": []}), status=200) response = client.get("/v2/apps", headers=auth_header) self.assertEqual(200, response.status_code) response_body = json.loads(response.data) self.assertEqual({"apps": []}, response_body)
class OwnerFilterTest(unittest.TestCase): @with_json_fixture("single_full_app.json") def setUp(self, single_full_app_fixture): self.filter = AddOwnerConstraintFilter() rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0") self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.user.accounts = [self.account_dev] self.session.add(self.user) self.session.add(self.account_dev) self.session.commit() self.request_app = SieveMarathonApp.from_json(single_full_app_fixture) self.original_app = SieveMarathonApp.from_json(single_full_app_fixture) self.user.current_account = self.account_dev def test_create_app_add_constraint_app_with_no_constraint(self): self.request_app.constraints = [] filtered_app = self.filter.write(self.user, self.request_app, SieveMarathonApp()) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(1, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_update_app_add_constraint_app_with_no_constraint(self): self.request_app.constraints = [] self.original_app.constraints = [] filtered_app = self.filter.write(self.user, self.request_app, self.original_app) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(1, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_create_app_constraint_exist_with_wrong_value(self): self.request_app.constraints.append( MarathonConstraint(field="owner", operator="LIKE", value="other-owner")) filtered_app = self.filter.write(self.user, self.request_app, SieveMarathonApp()) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(2, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_update_app_constraint_exist_with_wrong_value(self): self.request_app.constraints.append( MarathonConstraint(field="owner", operator="LIKE", value="other-owner")) filtered_app = self.filter.write(self.user, self.request_app, self.original_app) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(2, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_create_app_add_constraint_app_with_other_constraints(self): filtered_app = self.filter.write(self.user, self.request_app, SieveMarathonApp()) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(2, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_update_app_add_constraint_app_with_other_constraints(self): filtered_app = self.filter.write(self.user, self.request_app, self.original_app) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(2, len(filtered_app.constraints)) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value) def test_update_app_trying_to_remove_constraint(self): self.original_app.constraints.append( MarathonConstraint(field="owner", operator="LIKE", value=self.account_dev.owner)) filtered_app = self.filter.write(self.user, self.request_app, self.original_app) owner_constraint = filtered_app.get_constraints_by_name("owner") self.assertEqual(2, len(filtered_app.constraints)) self.assertEqual( "srv2.*", filtered_app.get_constraints_by_name("hostname")[0].value) self.assertEqual(1, len(owner_constraint)) self.assertEqual(self.account_dev.owner, owner_constraint[0].value)
class TestAccountEndpoints(unittest.TestCase): def setUp(self): rebuild_schema() self.session = HollowmanSession() self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.account_infra = Account(name="Infra Team", namespace="infra", owner="company") self.user = User(tx_email="*****@*****.**", tx_name="John Doe") self.user.accounts = [self.account_dev, self.account_infra] self.user_with_one_account = User( tx_email="*****@*****.**", tx_name="User One Account") self.user_with_one_account.accounts = [self.account_dev] self.session.add(self.account_dev) self.session.add(self.account_infra) self.session.add(self.user) self.session.add(self.user_with_one_account) self.session.commit() def tearDown(self): self.session.close() def generate_jwt_token_for_user(self, user, account): return jwt_auth.jwt_encode_callback( jwt_generate_user_info(user, account)) def test_get_current_user_info_valid_auth(self): with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.get("/hollow/account/me", headers={ "Authorization": "JWT {}".format(jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[0].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[0].name, response_data["current_account"]["name"]) def test_get_current_user_info_auth_invalid(self): with application.app_context(), \ application.test_client() as client: response = client.get("/hollow/account/me") self.assertEqual(401, response.status_code) def test_change_account_has_permmission(self): """ Troca para uma conta que o user atual está vinculado. """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post( "/hollow/account/change/{}".format(self.user.accounts[1].id), headers={ "Authorization": "JWT {}".format(jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[1].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, response_data["current_account"]["name"]) jwt_response_token = response_data["jwt_token"] self.assertTrue(jwt_response_token) returned_token = jwt.decode(jwt_response_token, key=SECRET_KEY) self.assertEqual(self.user.tx_email, returned_token["user"]["email"]) self.assertEqual(self.user.tx_name, returned_token["user"]["name"]) self.assertEqual(self.user.accounts[1].id, returned_token["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, returned_token["current_account"]["name"]) def test_change_account_user_is_not_associated(self): """ Retorna HTTP 401 se tentarmos trocar para uma conta que não estamos vinculados, ou seja, não existe registro na tabela `user_has_account` """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post("/hollow/account/change/42", headers={ "Authorization": "JWT {}".format( jwt_token.decode("utf8")) }) self.assertEqual(401, response.status_code) self.assertEquals("Not associated with account", json.loads(response.data)["msg"]) def test_change_to_next_account_one_account_left(self): """ User tem duas accounts, está usando a primeira e pede pra trocar para a proxima. Retornamos a segunda """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[0]) response = client.post("/hollow/account/next", headers={ "Authorization": "JWT {}".format( jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[1].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, response_data["current_account"]["name"]) jwt_response_header = response_data["jwt_token"] self.assertTrue(jwt_response_header) returned_token = jwt.decode(jwt_response_header, key=SECRET_KEY) self.assertEqual(self.user.tx_email, returned_token["user"]["email"]) self.assertEqual(self.user.tx_name, returned_token["user"]["name"]) self.assertEqual(self.user.accounts[1].id, returned_token["current_account"]["id"]) self.assertEqual(self.user.accounts[1].name, returned_token["current_account"]["name"]) def test_test_change_to_next_account_no_account_left(self): """ User tem duas accounts e já está usando a segunda, quando pedir a próxima retornamos a primeira account """ with application.app_context(), \ application.test_client() as client: jwt_token = self.generate_jwt_token_for_user( self.user, self.user.accounts[1]) response = client.post("/hollow/account/next", headers={ "Authorization": "JWT {}".format( jwt_token.decode("utf8")) }) self.assertEqual(200, response.status_code) response_data = json.loads(response.data) self.assertEqual(self.user.tx_email, response_data["user"]["email"]) self.assertEqual(self.user.tx_name, response_data["user"]["name"]) self.assertEqual(self.user.accounts[0].id, response_data["current_account"]["id"]) self.assertEqual(self.user.accounts[0].name, response_data["current_account"]["name"]) jwt_response_header = response_data["jwt_token"] self.assertTrue(jwt_response_header) returned_token = jwt.decode(jwt_response_header, key=SECRET_KEY) self.assertEqual(self.user.tx_email, returned_token["user"]["email"]) self.assertEqual(self.user.tx_name, returned_token["user"]["name"]) self.assertEqual(self.user.accounts[0].id, returned_token["current_account"]["id"]) self.assertEqual(self.user.accounts[0].name, returned_token["current_account"]["name"])
class RoutesTest(unittest.TestCase): def setUp(self): rebuild_schema() self.session = HollowmanSession() self.user = User(tx_email="*****@*****.**", tx_name="John Doe", tx_authkey="69ed620926be4067a36402c3f7e9ddf0") self.account_dev = Account(id=4, name="Dev Team", namespace="dev", owner="company") self.user.accounts = [self.account_dev] self.session.add(self.account_dev) self.session.add(self.user) self.session.commit() self.proxy_mock_patcher = patch.object(hollowman.routes, 'raw_proxy') self.proxy_mock = self.proxy_mock_patcher.start() self.proxy_mock.return_value = Response(status=200) def tearDown(self): self.session.close() self.proxy_mock_patcher.stop() def test_v2_artifacts(self): with application.test_client() as client: client.get("/v2/artifacts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.get("/v2/artifacts/etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.put("/v2/artifacts/etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.post("/v2/artifacts/etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.delete("/v2/artifacts/etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.get("/v2/artifacts//etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.put("/v2/artifacts//etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.post("/v2/artifacts//etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.delete("/v2/artifacts//etc/hosts", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(9, self.proxy_mock.call_count) def test_v2_info(self): with application.test_client() as client: client.get("/v2/info", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(1, self.proxy_mock.call_count) def test_v2_leader(self): with application.test_client() as client: client.get("/v2/leader", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) client.delete("/v2/leader", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(2, self.proxy_mock.call_count) def test_v2_info(self): with application.test_client() as client: client.get("/v2/info", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(1, self.proxy_mock.call_count) def test_ping(self): with application.test_client() as client: client.get("/ping", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(1, self.proxy_mock.call_count) def test_metrics(self): with application.test_client() as client: client.get("/metrics", headers={ "Authorization": "Token 69ed620926be4067a36402c3f7e9ddf0" }) self.assertEqual(1, self.proxy_mock.call_count)