def test_response_task_filter_modifies_task(self, tasks_get_fixture): class ModifyTaskFilter: def response_task(self, user, response_task, original_task): response_task.id = f"{response_task.id}_bla" return response_task with application.test_request_context("/v2/tasks/", method="GET") as ctx: original_response = FlaskResponse( response=json.dumps(tasks_get_fixture), status=200) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline={OperationType.READ: [ModifyTaskFilter()]}, filter_method_name_callback=lambda *args: "response_task", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(3, len(response_data["tasks"])) self.assertEqual( [ "dev_waiting.01339ffa-ce9c-11e7-8144-2a27410e5638_bla", "dev_waiting.0432fd4b-ce9c-11e7-8144-2a27410e5638_bla", "dev_waiting.75b2ed9c-ce9c-11e7-8144-2a27410e5638_bla", ], [task["id"] for task in response_data["tasks"]], )
def test_filters_can_modify_all_apps_from_group_and_subgroups( self, group_dev_namespace_fixture): """ Um fltro deve poder alterar todas as apps de todos os grupos de um response. """ with application.test_request_context("/v2/groups/group-b", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture["groups"][1]), status=HTTPStatus.OK, headers={}, ) response_wrapper = Response(ctx.request, ok_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline={OperationType.READ: [DummyFilter()]}, filter_method_name_callback=lambda *args: "response_group", ) final_response_data = json.loads(final_response.data) returned_group = MarathonGroup.from_json(final_response_data) self.assertEqual("/dummy/dev/group-b/appb0", returned_group.apps[0].id) self.assertEqual( "/dummy/dev/group-b/group-b0/app0", returned_group.groups[0].apps[0].id, )
def test_response_task_remove_from_response_tasks_outside_same_prefix_namespace( self, tasks_multinamespace_fixure): """ Confirmamos que uma task do namespace "developers" *deve ser removida* quando o usuário faz parte do namespace "dev", mesmo esses dois namespaces começando pelo mesmo prefixo """ with application.test_request_context("/v2/tasks/", method="GET") as ctx: original_response = FlaskResponse( response=json.dumps(tasks_multinamespace_fixure), status=200) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response_task", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual( [ "waiting.01339ffa-ce9c-11e7-8144-2a27410e5638", "waiting.0432fd4b-ce9c-11e7-8144-2a27410e5638", ], [task["id"] for task in response_data["tasks"]], ) self.assertEqual(2, len(response_data["tasks"]))
def test_response_task_do_not_dispatch_pipeline_if_response_is_deployment( self, tasks_post_fixture): """ Se o request for de escrita em /v2/tasks e foi passado `?scale=true`, não devemos rodar o pipeline, já que nesse response tem apenas um DeploymentId """ with application.test_request_context("/v2/tasks/delete?scale=true", method="POST") as ctx: original_response = FlaskResponse( response=json.dumps(tasks_post_fixture), status=200) response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=[], filter_method_name_callback=lambda *args: "response_task", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual( "5ed4c0c5-9ff8-4a6f-a0cd-f57f59a34b43", response_data["deploymentId"], )
def test_response_apps_remove_outside_current_namespace(self): with application.test_request_context("/v2/apps/", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one['id'] = '/dev/foo' single_full_app_two = deepcopy(self.single_full_app_fixture) single_full_app_two['id'] = '/dev/other-app' single_full_app_three = deepcopy(self.single_full_app_fixture) single_full_app_three['id'] = '/othernamespace/other-app' with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'app': single_full_app_one}), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/other-app', body=json.dumps({'app': single_full_app_two}), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//othernamespace/other-app', body=json.dumps({'app': single_full_app_three}), status=200) original_response = FlaskResponse(response=json.dumps({'apps': [single_full_app_one, single_full_app_two, single_full_app_three]}), status=200, headers={}) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch(user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response" ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data['apps'])) self.assertEqual("/foo", response_data['apps'][0]['id']) self.assertEqual("/other-app", response_data['apps'][1]['id'])
def test_response_task_remove_from_response_tasks_outside_namespace( self, tasks_multinamespace_fixure): class ModifyTaskFilter: def response_task(self, user, response_task): response_task.id = response_task.id.replace( f"{user.current_account.namespace}_", "") return response_task with application.test_request_context("/v2/tasks/", method="GET") as ctx: original_response = FlaskResponse( response=json.dumps(tasks_multinamespace_fixure), status=200) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response_task", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data["tasks"])) self.assertEqual( [ "waiting.01339ffa-ce9c-11e7-8144-2a27410e5638", "waiting.0432fd4b-ce9c-11e7-8144-2a27410e5638", ], [task["id"] for task in response_data["tasks"]], )
def test_changes_from_all_filters_are_persisted_after_response_join( self, group_dev_namespace_fixture): """ Certificamos que uma modificação de um filtro não é perdida durante a execução do pipeline. No response final, todas as modificações devem estar disponíveis. """ with application.test_request_context("/v2/groups/group-b", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture["groups"][1]), status=HTTPStatus.OK, headers={}, ) ctx.request.user = self.user response_wrapper = Response(ctx.request, ok_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline={ OperationType.READ: [DummyFilter(), FooFilter()] }, filter_method_name_callback=lambda *args: "response_group", ) final_response_data = json.loads(final_response.data) returned_group = MarathonGroup.from_json(final_response_data) self.assertEqual("/foo/dummy/dev/group-b/appb0", returned_group.apps[0].id) self.assertEqual( "/foo/dummy/dev/group-b/group-b0/app0", returned_group.groups[0].apps[0].id, )
def test_do_not_call_filter_if_it_doesnt_implement_response_method(self): class DummyRequestFilter: def write(self, user, request_app): return request_app with application.test_request_context("/v2/apps/foo", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one['id'] = "/dev/foo" with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//foo', json={"app": single_full_app_one}, status=200) original_response = FlaskResponse(response=json.dumps({"app": single_full_app_one}), status=200, headers={}) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch(user=self.user, request=response_wrapper, filters_pipeline={OperationType.READ: [DummyRequestFilter()]}, filter_method_name_callback=lambda *args: "response" ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual("/dev/foo", response_data['app']['id'])
def test_call_filter_method_passing_each_group( self, group_dev_namespace_fixture): """ Todos os grupos de um response devem ser passados para os filtros, um de cada vez """ with application.test_request_context("/v2/groups/group-b", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture["groups"][1]), status=HTTPStatus.OK, headers={}, ) response_wrapper = Response(ctx.request, ok_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline={OperationType.READ: [DummyFilter()]}, filter_method_name_callback=lambda *args: "response_group", ) final_response_data = json.loads(final_response.data) returned_group = MarathonGroup.from_json(final_response_data) self.assertEqual("/dummy/dev/group-b", returned_group.id) self.assertEqual("/dummy/dev/group-b/group-b0", returned_group.groups[0].id)
def test_filters_can_modify_all_apps_from_group_and_subgroups(self, group_dev_namespace_fixture): """ Um fltro deve poder alterar todas as apps de todos os grupos de um response. """ with application.test_request_context("/v2/groups/group-b", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture['groups'][1]), status=HTTPStatus.OK, headers={} ) 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/group-b0', body=json.dumps(deepcopy(group_dev_namespace_fixture['groups'][1]['groups'][0])), status=200) response_wrapper = Response(ctx.request, ok_response) final_response = dispatch(user=self.user, request=response_wrapper, filters_pipeline={OperationType.READ: [DummyFilter()]}, filter_method_name_callback=lambda *args: "response_group") final_response_data = json.loads(final_response.data) returned_group = MarathonGroup.from_json(final_response_data) self.assertEqual("/dummy/dev/group-b/appb0", returned_group.apps[0].id) self.assertEqual("/dummy/dev/group-b/group-b0/app0", returned_group.groups[0].apps[0].id)
def test_return_correct_request_resource(self): expected_request_resources = { "/v2/apps": RequestResource.APPS, "/v2/apps/": RequestResource.APPS, "/v2/groups": RequestResource.GROUPS, "/v2/groups/": RequestResource.GROUPS, "/v2/deployments": RequestResource.DEPLOYMENTS, "/v2/deployments/": RequestResource.DEPLOYMENTS, "/v2/tasks": RequestResource.TASKS, "/v2/tasks/": RequestResource.TASKS, "/v2/queue": RequestResource.QUEUE, "/v2/queue/": RequestResource.QUEUE, } for ( request_path, expected_request_resource, ) in expected_request_resources.items(): # noinspection PyTypeChecker request_mock = Mock(path=request_path) request_wrapper = Request(request_mock) response_wrapper = Response(request_mock, Mock()) self.assertEqual(request_wrapper.request_resource, expected_request_resource) self.assertEqual(response_wrapper.request_resource, expected_request_resource)
def test_response_has_list_of_apps_modified_by_filters(self): """ Certificamos que uma lista de apps pode ser modificada por algum filtro de response. """ with application.test_request_context("/v2/apps/", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one["id"] = "/dev/foo" single_full_app_two = deepcopy(self.single_full_app_fixture) single_full_app_two["id"] = "/dev/other-app" original_response = FlaskResponse( response=json.dumps( {"apps": [single_full_app_one, single_full_app_two]}), status=200, headers={}, ) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data["apps"])) self.assertEqual("/foo", response_data["apps"][0]["id"]) self.assertEqual("/other-app", response_data["apps"][1]["id"])
def test_response_has_app_modified_by_filter(self): """ Certificamos que um request em uma app, roda o pipeline e essa app pode ser modificada por algum filtro """ with application.test_request_context("/v2/apps/dev/foo", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one["id"] = "/dev/foo" _url = conf.MARATHON_ADDRESSES[0] + "/v2/apps//dev/foo" with RequestsMock() as rsps: rsps.add( method="GET", url=_url, json={"app": single_full_app_one}, status=200, ) original_response = FlaskResponse( response=json.dumps({"app": single_full_app_one}), status=200, headers={}, ) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response", ) self.assertEqual(200, final_response.status_code) self.assertEqual("/foo", json.loads(final_response.data)["app"]["id"])
def test_response_group_remove_namespace_from_all_tasks_of_all_apps_empty_task_list(self, group_dev_namespace_fixture): with application.test_request_context("/v2/groups/a", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture['groups'][0]), status=HTTPStatus.OK, headers={} ) response_group = original_group = MarathonGroup.from_json(group_dev_namespace_fixture['groups'][0]) response_group.apps[0].tasks = [] original_group.apps[0].tasks = [] response_wrapper = Response(ctx.request, ok_response) filtered_group = self.filter.response_group(self.user, response_group, original_group) self.assertEqual(1, len(filtered_group.apps))
def test_response_group_remove_namespace_from_group_name(self, group_dev_namespace_fixture): with application.test_request_context("/v2/groups/group-b", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture['groups'][1]), status=HTTPStatus.OK, headers={} ) response_group = original_group = MarathonGroup.from_json(group_dev_namespace_fixture['groups'][1]) original_group = original_group = MarathonGroup.from_json(group_dev_namespace_fixture['groups'][1]) response_wrapper = Response(ctx.request, ok_response) filtered_group = self.filter.response_group(self.user, response_group, original_group) self.assertEqual("/group-b", filtered_group.id) self.assertEqual(1, len(filtered_group.groups)) # Não removemos o namespace de subgrupos. self.assertEqual("/dev/group-b/group-b0", filtered_group.groups[0].id)
def test_response_task_returns_empty_response_when_all_tasks_are_from_other_namespace(self, tasks_namespace_infra_fixture): with application.test_request_context("/v2/tasks/", method="GET") as ctx: original_response = FlaskResponse(response=json.dumps(tasks_namespace_infra_fixture), status=200) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch(user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response" ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(0, len(response_data['tasks']))
def test_response_group_remove_namespace_from_all_tasks_of_all_apps(self, group_dev_namespace_fixture): with application.test_request_context("/v2/groups/a", method="GET") as ctx: ctx.request.user = self.user ok_response = FlaskResponse( response=json.dumps(group_dev_namespace_fixture['groups'][0]), status=HTTPStatus.OK, headers={} ) response_group = original_group = MarathonGroup.from_json(group_dev_namespace_fixture['groups'][0]) response_wrapper = Response(ctx.request, ok_response) filtered_group = self.filter.response_group(self.user, response_group, original_group) self.assertEqual(1, len(filtered_group.apps)) self.assertEqual("a_app0.a31dfafb-be63-11e7-8ef1-0242a8c1e33e", filtered_group.apps[0].tasks[0].id) self.assertEqual("/a/app0", filtered_group.apps[0].tasks[0].app_id) self.assertEqual("a_app0.a31dfafb-be63-11e7-8ef1-0242a8c1e44o", filtered_group.apps[0].tasks[1].id) self.assertEqual("/a/app0", filtered_group.apps[0].tasks[1].app_id)
def test_remove_from_response_apps_outside_same_prefix_namespace(self): """ Uma app com namespace `/developers/` deve ser removida quando o usuário faz parte do namespace ´/dev/`, mesmo os namespaces começando pelo mesmo prefixo """ with application.test_request_context("/v2/apps/", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one["id"] = "/dev/foo" single_full_app_two = deepcopy(self.single_full_app_fixture) single_full_app_two["id"] = "/dev/other-app" single_full_app_three = deepcopy(self.single_full_app_fixture) single_full_app_three["id"] = "/developers/other-app" original_response = FlaskResponse( response=json.dumps({ "apps": [ single_full_app_one, single_full_app_two, single_full_app_three, ] }), status=200, headers={}, ) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data["apps"])) self.assertEqual( ["/foo", "/other-app"], [app["id"] for app in response_data["apps"]], )
def test_remove_from_response_apps_outside_same_prefix_namespace(self): """ Uma app com namespace `/developers/` deve ser removida quando o usuário faz parte do namespace ´/dev/`, mesmo os namespaces começando pelo mesmo prefixo """ with application.test_request_context("/v2/apps/", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one['id'] = '/dev/foo' single_full_app_two = deepcopy(self.single_full_app_fixture) single_full_app_two['id'] = '/dev/other-app' single_full_app_three = deepcopy(self.single_full_app_fixture) single_full_app_three['id'] = '/developers/other-app' with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'app': single_full_app_one}), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/other-app', body=json.dumps({'app': single_full_app_two}), status=200) rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//developers/other-app', body=json.dumps({'app': single_full_app_three}), status=200) original_response = FlaskResponse(response=json.dumps({'apps': [single_full_app_one, single_full_app_two, single_full_app_three]}), status=200, headers={}) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch(user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response" ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data['apps'])) self.assertEqual(["/foo", "/other-app"], [app['id'] for app in response_data['apps']])
def test_response_apps_remove_outside_current_namespace(self): with application.test_request_context("/v2/apps/", method="GET") as ctx: single_full_app_one = deepcopy(self.single_full_app_fixture) single_full_app_one["id"] = "/dev/foo" single_full_app_two = deepcopy(self.single_full_app_fixture) single_full_app_two["id"] = "/dev/other-app" single_full_app_three = deepcopy(self.single_full_app_fixture) single_full_app_three["id"] = "/othernamespace/other-app" original_response = FlaskResponse( response=json.dumps({ "apps": [ single_full_app_one, single_full_app_two, single_full_app_three, ] }), status=200, headers={}, ) ctx.request.user = self.user response_wrapper = Response(ctx.request, original_response) final_response = dispatch( user=self.user, request=response_wrapper, filters_pipeline=FILTERS_PIPELINE[FilterType.RESPONSE], filter_method_name_callback=lambda *args: "response", ) response_data = json.loads(final_response.data) self.assertEqual(200, final_response.status_code) self.assertEqual(2, len(response_data["apps"])) self.assertEqual("/foo", response_data["apps"][0]["id"]) self.assertEqual("/other-app", response_data["apps"][1]["id"])