def test_split_groups_read_on_specific_group(self, group_b_fixture): with application.test_request_context('/v2/groups/group-b', method='GET') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups//dev/group-b', body=json.dumps(group_b_fixture), status=200) apps = list(request_parser.split()) self.assertEqual(2, len(apps)) original_app_one = MarathonApp.from_json( {"id": "/dev/group-b/appb0"}) original_app_two = MarathonApp.from_json( {"id": "/dev/group-b/group-b0/app0"}) expected_apps = [ (request_parser.merge_marathon_apps( MarathonApp(), original_app_one), original_app_one), (request_parser.merge_marathon_apps( MarathonApp(), original_app_two), original_app_two), ] self.assertEqual(expected_apps, apps)
def test_a_request_with_n_apps_returns_n_marathonapps(self, fixture): with application.test_request_context("/v2/apps/", method="GET") as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/", body=json.dumps(fixture), status=200, ) apps = list(request_parser.split()) self.assertEqual( [request_app for request_app, _ in apps], [ request_parser.merge_marathon_apps( request_app, original_app) for request_app, original_app in apps ], ) self.assertEqual( [app.id for app, _ in apps], [app["id"] for app in fixture["apps"]], )
def test_change_request_path_if_is_write_on_one_app(self, fixture): """ Quando fazemos WRITE em cima de uma app específica, devemos ajustar o request.path para que o `upstream_request` seja feito no endpoint correto. """ user = User(tx_name="User One", tx_email="*****@*****.**") user.current_account = Account(name="Dev", namespace="dev", owner="company") full_app_with_name_space = deepcopy(fixture) full_app_with_name_space['id'] = "/dev/foo" with application.test_request_context('/v2/apps//foo', method='PUT', data=json.dumps(fixture)) as ctx: with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'app': full_app_with_name_space}), status=200) ctx.request.user = user request_parser = Request(ctx.request) apps = list(request_parser.split()) request = request_parser.join(apps) self.assertIsInstance(request, HollowmanRequest) self.assertEqual("/v2/apps/dev/foo", request.path)
def test_can_read_app_if_already_migrated(self, single_full_app_fixture): """ Conferimos que é possível fazer um GET em /v2/apps/<app-id> para uma app que já está migrada. O <app-id> usado é sempre *sem* namespace """ request_data = deepcopy(single_full_app_fixture) single_full_app_fixture["id"] = "/dev/foo" with application.test_request_context("/v2/apps/foo", method="GET") as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/apps//dev/foo", body=json.dumps({"app": single_full_app_fixture}), status=200, ) apps = list(request_parser.split()) original_app = MarathonApp.from_json(single_full_app_fixture) expected_app = ( request_parser.merge_marathon_apps(MarathonApp(), original_app), original_app, ) self.assertEqual(apps, [expected_app])
def test_split_queue_should_return_empty_iterator(self): with application.test_request_context('/v2/queue', method='GET') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) apps = list(request_parser.split()) self.assertEqual(0, len(apps)) self.assertEqual([], apps)
def test_join_apps_read_empty_list(self): with application.test_request_context('/v2/apps', method='GET') as ctx: ctx.request.user = self.user request = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps', status=200, body='''{"apps":[]}''') apps = list(request.split()) joined_request = request.join(apps) self.assertEqual("/v2/apps", joined_request.path) self.assertEqual(b"", joined_request.data)
def test_it_recreates_a_post_request_for_a_single_app(self, fixture): with application.test_request_context('/v2/apps//foo', method='POST', data=json.dumps(fixture)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with patch.object(request_parser, 'marathon_client') as client: client.get_app.return_value = MarathonApp.from_json(fixture) apps = list(request_parser.split()) request = request_parser.join(apps) self.assertIsInstance(request, HollowmanRequest) self.assertEqual(request.get_json()['id'], '/foo')
def test_split_tasks_GET(self): """ Quadno recebemos um GET em /v2/tasks/delete, não temos o que fazer, entãoo request pode passar direto. Isso significa que o spit retorna [] """ with application.test_request_context('/v2/tasks/delete', method='GET') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) tasks = list(request_parser.split()) self.assertEqual(0, len(tasks))
def test_it_recreates_a_get_request_for_a_single_app(self, fixture): with application.test_request_context("/v2/apps//foo", method="GET", data=b"") as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with patch.object(request_parser, "marathon_client") as client: client.get_app.return_value = MarathonApp.from_json(fixture) apps = list(request_parser.split()) request = request_parser.join(apps) self.assertIsInstance(request, HollowmanRequest) self.assertEqual(request, ctx.request) self.assertEqual(request.data, b"")
def test_split_groups_write_PUT_on_group(self): """ Atualmente, o único body que chega em um PUT em /v2/groups é: {"scaleBy": <N>} onde `<N>` é o fator que será multiplicado pelo atual número de TASK_RUNNING de cada app. O problema é que o Request.split() retorna uma lista de apps, e o Request.join() potencialmente vai reconstruir um body com essa lista de apps. O problema é que isso gera um request body *diferente* do orignal, já que agora temos um body contendo um APP_GROUP com todas suas apps (e sub apps). E se fazemos apenas isso, a informação do "scaleBy" se perdeu, pois se mandamos um request com o TASK_GROUP inteiro para o upstream, nada vai mudar já que as apps não foram modificadas. Uma ideia é o Core do hollowman decobrir essa ação de scaleBy e chamar o métoro "scale_by" dos filtros, já com a request_app tendo seu atributo "instances" multiplicado pelo fator. Opcionalmente o fator poderia ser passado como parametro para o filtro. Isso nos daria a possibilidade de "corrigir" um problema atual do scaleby que é: Quando damos scale_by = 2 em um app que está suspended, ela continua suspended já que 2 * 0 = 0. A ideia é que suspended apps também sejam ligadas considerando esse fator. O que faríamos no filtro seria, para toda app que instances = 0, consideramos instances = 1 e multiplicamos pelo fator. Enfim, apenas uma ideia. Temos que ver o que fazemos com esse teste aqui. """ with application.test_request_context("/v2/groups/group-b", method="PUT") as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/group-b", body=json.dumps(group_b_fixture), status=200, ) apps = list(request_parser.split()) self.assertEqual(2, len(apps)) expected_apps = [ ( MarathonApp(), MarathonApp.from_json({"id": "/dev/group-b/appb0"}), ), ( MarathonApp(), MarathonApp.from_json( {"id": "/dev/group-b/group-b0/app0"}), ), ] self.assertEqual(expected_apps, apps)
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)
def test_a_read_single_app_request_returns_a_single_marathonapp_if_app_exists( self, fixture): with application.test_request_context('/v2/apps//foo', method='GET', data=b'') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with patch.object(request_parser, 'marathon_client') as client: original_app = MarathonApp.from_json(fixture) client.get_app.return_value = original_app apps = list(request_parser.split()) self.assertEqual(apps, [(request_parser.merge_marathon_apps( MarathonApp(), original_app), client.get_app.return_value)])
def test_join_apps_read_empty_list(self): with application.test_request_context("/v2/apps", method="GET") as ctx: ctx.request.user = self.user request = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/", status=200, body=json.dumps({"apps": []}), ) apps = list(request.split()) joined_request = request.join(apps) self.assertEqual("/v2/apps", joined_request.path) self.assertEqual(b"", joined_request.data)
def test_join_group_read_root_group(self, group_dev_namespace_fixture): with application.test_request_context('/v2/groups', method='GET') as ctx: ctx.request.user = self.user request = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups//dev/', body=json.dumps(group_dev_namespace_fixture), status=200) apps = list(request.split()) joined_request = request.join(apps) self.assertEqual("/v2/groups/dev", joined_request.path) self.assertEqual(b"", joined_request.data)
def test_a_request_for_a_new_app_will_return_a_tuple_with_an_empty_marathonapp( self, fixture): with application.test_request_context('/v2/apps//foo', method='PUT', data=json.dumps(fixture)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with patch.object(request_parser, 'marathon_client') as client: response_mock = Mock() response_mock.headers.get.return_value = 'application/json' client.get_app.side_effect = NotFoundError( response=response_mock) apps = list(request_parser.split()) self.assertEqual(apps, [(AsgardApp.from_json(fixture), MarathonApp.from_json({"id": "/dev/foo"}))])
def test_split_group_nonroot_empty_group(self, non_root_group_empty_fixture): with application.test_request_context('/v2/groups/group-c', method='GET') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/groups//dev/group-c', body=json.dumps(non_root_group_empty_fixture), status=200) apps = list(request_parser.split()) self.assertEqual(0, len(apps)) self.assertEqual([], apps)
def test_join_tasks_POST(self, tasks_post_fixture): """ O join deve juntar apenas o id das tasks. O body do request é apenas: {"ids": ["...", "...", ...]} """ with application.test_request_context( '/v2/tasks/delete', method='POST', data=json.dumps(tasks_post_fixture)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) joined_request = request_parser.join(list(request_parser.split())) joined_request_data = json.loads(joined_request.data) self.assertEqual( [task_id for task_id in joined_request_data['ids']], [task_id for task_id in tasks_post_fixture['ids']])
def test_join_group_read_non_root_empty_group( self, non_root_group_empty_fixture): with application.test_request_context("/v2/groups/group-c", method="GET") as ctx: ctx.request.user = self.user request = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/group-c", body=json.dumps(non_root_group_empty_fixture), status=200, ) apps = list(request.split()) joined_request = request.join(apps) self.assertEqual("/v2/groups/dev/group-c", joined_request.path) self.assertEqual(b"", joined_request.data)
def test_a_request_for_write_operation_with_appid_in_url_path_returns_a_tuple_of_marathonapp( self, fixture): scale_up = {'instances': 10} with application.test_request_context( '/v2/apps/foo', method='PUT', data=json.dumps(scale_up)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'app': fixture}), status=200) apps = list(request_parser.split()) original_app = MarathonApp.from_json(fixture) expected_apps = (request_parser.merge_marathon_apps( MarathonApp.from_json(scale_up), original_app), original_app) self.assertEqual(apps, [expected_apps])
def test_a_request_for_restart_operation_with_appid_in_url_path_returns_a_tuple_of_marathonapp( self, fixture): with application.test_request_context('/v2/apps/xablau/restart', method='PUT', data=b'{"force": true}') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/xablau', body=json.dumps({'app': fixture}), status=200) apps = list(request_parser.split()) original_app = MarathonApp.from_json(fixture) expected_app = (request_parser.merge_marathon_apps( MarathonApp(), original_app), original_app) self.assertEqual(apps, [expected_app])
def test_split_tasks_POST(self, tasks_post_fixture): """ Quadno recebemos um POST em /v2/tasks/delete, devemos fazer o split da lista e tasks e passar para os filtros """ with application.test_request_context( '/v2/tasks/delete', method='POST', data=json.dumps(tasks_post_fixture)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) tasks = list(request_parser.split()) self.assertEqual(3, len(tasks)) # Confere os ids olhando o "request_task" self.assertEqual( [task[0].id for task in tasks], [task_id for task_id in tasks_post_fixture['ids']])
def test_a_request_with_n_apps_returns_n_marathonapps(self, fixture): with application.test_request_context('/v2/apps/', method='GET') as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps', body=json.dumps(fixture), status=200) apps = list(request_parser.split()) self.assertEqual([request_app for request_app, _ in apps], [ request_parser.merge_marathon_apps(request_app, original_app) for request_app, original_app in apps ]) self.assertEqual([app.id for app, _ in apps], [app['id'] for app in fixture['apps']])
def test_split_does_not_break_when_removing_force_parameter_if_request_is_a_list( self, fixture): request_data = {"id": "/foo", "instances": 2} with application.test_request_context( '/v2/apps/', method='PUT', data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add(method='GET', url=conf.MARATHON_ADDRESSES[0] + '/v2/apps//dev/foo', body=json.dumps({'app': fixture}), status=200) apps = list(request_parser.split()) original_app = MarathonApp.from_json(fixture) expected_app = (request_parser.merge_marathon_apps( MarathonApp.from_json(request_data), original_app), original_app) self.assertEqual(apps, [expected_app])
def test_split_groups_read_on_root_group(self, group_dev_namespace_fixture): with application.test_request_context("/v2/groups", method="GET") as ctx: ctx.request.user = self.user request_parser = Request(ctx.request) with RequestsMock() as rsps: rsps.add( method="GET", url=conf.MARATHON_ADDRESSES[0] + "/v2/groups//dev/", body=json.dumps(group_dev_namespace_fixture), status=200, ) apps = list(request_parser.split()) self.assertEqual(3, len(apps)) original_app_one = MarathonApp.from_json({"id": "/dev/a/app0"}) original_app_two = MarathonApp.from_json( {"id": "/dev/group-b/appb0"}) original_app_three = MarathonApp.from_json( {"id": "/dev/group-b/group-b0/app0"}) expected_apps = [ ( request_parser.merge_marathon_apps( MarathonApp(), original_app_one), original_app_one, ), ( request_parser.merge_marathon_apps( MarathonApp(), original_app_two), original_app_two, ), ( request_parser.merge_marathon_apps( MarathonApp(), original_app_three), original_app_three, ), ] self.assertEqual(apps, expected_apps)