def setUp(self, single_full_app_fixture): self.filter = NameSpaceFilter() self.request_app = SieveMarathonApp.from_json(single_full_app_fixture) self.original_app = SieveMarathonApp.from_json(single_full_app_fixture) self.account = Account(name="Dev Account", namespace="dev", owner="company") self.user = User(tx_email="*****@*****.**") self.user.current_account = self.account
def test_dispatch_should_pass_an_instance_if_SieveMarathonApp_to_filters( self): """ Certifica que quando um request remove todas as constraints e algum filtro adiciona novas constraints, essas constraints adicionadas pelo filtro são preservadas """ class AddNewConstraintFilter: def write(self, user, request_app, original_app): assert isinstance(request_app, SieveMarathonApp) return request_app pipeline = { OperationType.WRITE: [ AddNewConstraintFilter(), ] } request_data = {"constraints": []} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", headers={"Content-type": "application/json"}, data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline)
def test_update_app_remove_all_constraints(self): """ Certifica que um request que remove todas as constraints, remove essas constraints na app original """ class DummyFilter: def write(self, user, request_app, original_app): return request_app pipeline = { OperationType.WRITE: [ DummyFilter(), ] } request_data = {"constraints": []} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", data=json.dumps(request_data), headers={"Content-type": "application/json"}) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual(0, len(filtered_app.constraints)) self._check_other_fields("constraints", filtered_app)
def test_preserve_envs_added_by_filter(self): class AddNewEnvFilter: def write(self, user, request_app, original_app): request_app.env["env1"] = "env-value1" return request_app pipeline = { OperationType.WRITE: [ AddNewEnvFilter(), ] } request_data = {"env": []} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", headers={"Content-type": "application/json"}, data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual(1, len(filtered_app.env.keys())) self.assertEqual({"env1": "env-value1"}, filtered_app.env) self._check_other_fields("env", filtered_app)
def test_multiapp_response_returns_multiple_marathonapp_instances( self, fixture): modified_app = fixture.copy() modified_app['id'] = '/xablau' apps = [fixture, modified_app] with application.test_request_context('/v2/apps/', method='GET', data=b'') as ctx: response = FlaskResponse(response=json.dumps({"apps": apps}), status=HTTPStatus.OK, headers={}) response = Response(ctx.request, response) with patch.object(response, 'marathon_client') as client: original_apps = [MarathonApp.from_json(app) for app in apps] client.get_app.side_effect = original_apps apps = list(response.split()) self.assertEqual([call("/foo"), call("/xablau")], client.get_app.call_args_list) self.assertEqual( apps, [(SieveMarathonApp.from_json(fixture), original_apps[0]), (SieveMarathonApp.from_json(modified_app), original_apps[1])])
def split(self) -> Apps: if self.is_read_request(): response_content = json.loads(self.response.data) if self.is_list_apps_request(): for app in response_content['apps']: response_app = SieveMarathonApp.from_json(app) app = self.marathon_client.get_app(self.object_id or response_app.id) yield response_app, app return elif self.is_group_request(): response_group = SieveAppGroup( MarathonGroup.from_json(response_content)) for current_group in response_group.iterate_groups(): group_id = current_group.id group_id_without_namespace = self._remove_namespace_if_exists( self.request.user.current_account.namespace, group_id) original_group = self._get_original_group( self.request.user, group_id_without_namespace) yield current_group, original_group return elif self.is_tasks_request(): for task in response_content['tasks']: response_task = MarathonTask.from_json(task) yield response_task, response_task return elif self.is_deployment(): content = response_content deployments = (MarathonDeployment.from_json(deploy) for deploy in content) for deployment in deployments: yield deployment, deployment return elif self.is_queue_request(): queue_data = response_content queued_apps = (MarathonQueueItem.from_json(queue_item) for queue_item in queue_data['queue']) for queued_app in queued_apps: yield queued_app, queued_app return else: response_app = SieveMarathonApp.from_json( response_content.get('app') or response_content) app = self.marathon_client.get_app(self.object_id) yield response_app, app return if self.is_write_request(): response_content = json.loads(self.response.data) if 'tasks' in response_content: for task in response_content['tasks']: response_task = MarathonTask.from_json(task) yield response_task, response_task return return yield SieveMarathonApp(), self.marathon_client.get_app(self.app_id)
def setUp(self, single_full_app_fixture): self.request = Request(None) self.single_full_app_fixture = single_full_app_fixture self.filter = IncompatibleFieldsFilter() self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) self.original_app = SieveMarathonApp.from_json( self.single_full_app_fixture)
def setUp(self, single_full_app_fixture): self.docker_auth_uri = "file:///etc/docker.tar.bz2" self.base_uris = ["http://google.com", "file://etc/file.txt"] self.single_full_app_fixture = single_full_app_fixture self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) self.original_app = SieveMarathonApp.from_json( self.single_full_app_fixture) self.filter = AddURIFilter()
def setUp(self): self.single_full_app_fixture = get_fixture("single_full_app.json") self.filter = BasicConstraintFilter() self.request_app = SieveMarathonApp.from_json(self.single_full_app_fixture) self.original_app = Mock() self.user = Mock() self.constraints = (BasicConstraintFilter.mesos_constraint, BasicConstraintFilter.workload_constraint)
def test_it_recreates_a_get_response_for_multiple_apps(self, fixture): modified_app = deepcopy(fixture) modified_app['id'] = '/xablau' fixtures = [fixture, modified_app] expected_response = deepcopy(fixtures) with application.test_request_context('/v2/apps/', method='GET', data=b'') as ctx: response = FlaskResponse(response=json.dumps({"apps": fixtures}), status=HTTPStatus.OK, headers={}) response = Response(ctx.request, response) with patch.object(response, 'marathon_client') as client: original_apps = [ SieveMarathonApp.from_json(app) for app in fixtures ] client.get_app.side_effect = original_apps apps = list(response.split()) joined_response = response.join(apps) self.assertIsInstance(joined_response, FlaskResponse) self.assertDictEqual(json.loads(joined_response.data), {'apps': expected_response})
def merge_marathon_apps(self, modified_app, base_app): """ A junção das duas apps (request_app (aqui modified_app) e original_app (aqui base_app)) é sempre feita pegando todos os dados da original_app e jogando os dados da requst_app "em cima". Não podemos usar o `minimal=Fase` na request_app pois para requests que estão *incompletos*, ou seja, sem alguns vampos (já veremos exemplo) se esássemos minimal=False, iríramos apagar esses "campos faltantes" da original_app. Exemplos: request_app = {"instances": 10} original_app está completa, com envs, constraints e tudo mais. se usamos `minimal=False` na request_app, teremos um JSON com *todos* os campos em branco, menos o "instances". Então quando fizermos `merged.update(modified_app.json_repr(minimal=False))`, vamos no final ter um JSON apenas com o campo "instances" perrnchido e todo o restante vazio. """ merged = base_app.json_repr(minimal=False) merged.update(modified_app.json_repr(minimal=True)) try: raw_request_data = json.loads(self.request.data) for key in REMOVABLE_KEYS: if key in raw_request_data: merged[key] = raw_request_data[key] except Exception as e: pass if isinstance(base_app, MarathonTask): return MarathonTask.from_json(merged) return SieveMarathonApp.from_json(merged)
def test_create_app_add_uri_if_not_exist(self): self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) filtered_app = self.filter.write(None, self.request_app, SieveMarathonApp()) self.assertEqual(1, len(filtered_app.uris)) self.assertEqual([self.docker_auth_uri], filtered_app.uris)
def test_preserve_healthchecks_added_by_filter(self): class AddNewHealthCheckFilter: def write(self, user, request_app, original_app): hc_data = { "command": None, "gracePeriodSeconds": 30, "intervalSeconds": 10, "maxConsecutiveFailures": 3, "path": "/marathon/healthcheck", "portIndex": 0, "protocol": "HTTP", "timeoutSeconds": 5, "ignoreHttp1xx": False } request_app.health_checks.append( MarathonHealthCheck.from_json(hc_data)) return request_app pipeline = { OperationType.WRITE: [ AddNewHealthCheckFilter(), ] } request_data = {"healthChecks": []} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", headers={"Content-type": "application/json"}, data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual(1, len(filtered_app.health_checks)) self.assertEqual("/marathon/healthcheck", filtered_app.health_checks[0].json_repr()['path']) self._check_other_fields("healthChecks", filtered_app)
def test_response_apps_remove_namespace_from_app_id_containig_namespace_in_its_name(self, single_full_app_with_tasks_fixture): """ Uma app com id = "/<namespace>/some/other/path/<namespace>/other/app" deve ter apenas a primeira ocorrência de "/<namespace>" removida. """ response_app = original_app = SieveMarathonApp.from_json(single_full_app_with_tasks_fixture) response_app.id = "/dev/some/other/path/dev/other/app" modified_app = self.filter.response(self.user, response_app, original_app) self.assertEqual("/some/other/path/dev/other/app", modified_app.id)
def test_a_single_app_response_returns_a_single_marathonapp(self, fixture): with application.test_request_context('/v2/apps//foo', method='GET', data=b'') as ctx: flask_response = FlaskResponse(response=json.dumps( {"app": fixture}), status=HTTPStatus.OK, headers={}) response = Response(ctx.request, flask_response) with patch.object(response, 'marathon_client') as client: client.get_app.return_value = SieveMarathonApp.from_json( fixture) apps = list(response.split()) self.assertEqual([call("/foo")], client.get_app.call_args_list) self.assertEqual(apps, [(SieveMarathonApp.from_json(fixture), client.get_app.return_value)])
def test_update_app_do_not_add_uri_if_exist(self): self.single_full_app_fixture['uris'] = copy( self.base_uris) + [self.docker_auth_uri] self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) filtered_app = self.filter.write(None, self.request_app, self.original_app) self.assertEqual(3, len(filtered_app.uris)) self.assertEqual(self.base_uris + [self.docker_auth_uri], filtered_app.uris)
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_response_apps_remove_namespace_from_all_tasks_empty_task_list(self, single_full_app_with_tasks_fixture): request_app = original_app = SieveMarathonApp.from_json(single_full_app_with_tasks_fixture) request_app.id = "/dev/foo" request_app.tasks = [] original_app.id = "/dev/foo" original_app.tasks = [] self.assertEqual(0, len(request_app.tasks)) modified_app = self.filter.response(self.user, request_app, original_app) self.assertEqual(0, len(self.request_app.tasks))
def test_preserve_upgrade_strategy_added_by_filter(self): class AddNewUpgradeStrategyFilter: def write(self, user, request_app, original_app): us_data = { "maximumOverCapacity": 1, "minimumHealthCapacity": 0.75 } request_app.upgrade_strategy = MarathonUpgradeStrategy.from_json( us_data) return request_app pipeline = { OperationType.WRITE: [ AddNewUpgradeStrategyFilter(), ] } # Simulando uma app que veio sem o campo "upgradeStrategy" request_data = {} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", headers={"Content-type": "application/json"}, data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual( 1, filtered_app.upgrade_strategy.maximum_over_capacity) self.assertEqual( 0.75, filtered_app.upgrade_strategy.minimum_health_capacity) self._check_other_fields("upgradeStrategy", filtered_app)
def test_create_app_add_uri_with_other_existing_uris(self): """ Mesmo se a app já tiver utras uris, temos que adicionar a nossa """ self.single_full_app_fixture['uris'] = copy(self.base_uris) self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) filtered_app = self.filter.write(None, self.request_app, SieveMarathonApp()) self.assertEqual(3, len(filtered_app.uris)) self.assertEqual(self.base_uris + [self.docker_auth_uri], filtered_app.uris)
def test_response_apps_remove_namespace_from_all_tasks(self, single_full_app_with_tasks_fixture): request_app = original_app = SieveMarathonApp.from_json(single_full_app_with_tasks_fixture) self.assertEqual(3, len(request_app.tasks)) modified_app = self.filter.response(self.user, request_app, original_app) self.assertEqual("foo.a29b3666-be63-11e7-8ef1-0242a8c1e33e", modified_app.tasks[0].id) self.assertEqual("/foo", modified_app.tasks[0].app_id) self.assertEqual("foo.a31e220e-be63-11e7-8ef1-0242a8c1e33e", modified_app.tasks[1].id) self.assertEqual("/foo", modified_app.tasks[1].app_id) self.assertEqual("foo.a31dfafb-be63-11e7-8ef1-0242a8c1e33e", modified_app.tasks[2].id) self.assertEqual("/foo", modified_app.tasks[2].app_id)
def test_update_app_do_not_add_uri_if_exist_with_spaces(self): """ Não precisamos fazer o strip nos valores originais pois o Marathon já faz isso pra nós. """ self.single_full_app_fixture['uris'] = copy( self.base_uris) + [" " + self.docker_auth_uri] self.request_app = SieveMarathonApp.from_json( self.single_full_app_fixture) filtered_app = self.filter.write(None, self.request_app, self.original_app) self.assertEqual(3, len(filtered_app.uris)) self.assertEqual(self.base_uris + [" " + self.docker_auth_uri], filtered_app.uris)
def test_update_app_change_all_constraints(self): """ Devemos respeitar as constraints quem estão da request, elas devem substituir as constrains da app original """ class DummyFilter: def write(self, user, request_app, original_app): return request_app pipeline = { OperationType.WRITE: [ DummyFilter(), ] } request_data = {"constraints": [["hostname", "LIKE", "myhost"]]} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", data=json.dumps(request_data), headers={"Content-type": "application/json"}) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual(1, len(filtered_app.constraints)) self.assertEqual(["hostname", "LIKE", "myhost"], filtered_app.constraints[0].json_repr()) self._check_other_fields("constraints", filtered_app)
def test_preserve_constraints_added_by_filter(self): """ Certifica que quando um request remove todas as constraints e algum filtro adiciona novas constraints, essas constraints adicionadas pelo filtro são preservadas """ class AddNewConstraintFilter: def write(self, user, request_app, original_app): request_app.constraints.append( MarathonConstraint.from_json("key:LIKE:value".split(":"))) return request_app pipeline = { OperationType.WRITE: [ AddNewConstraintFilter(), ] } request_data = {"constraints": []} request_app = SieveMarathonApp.from_json(request_data) original_app = SieveMarathonApp.from_json( deepcopy(self.single_full_app_fixture)) with application.test_request_context( "/v2/apps/foo", method="PUT", headers={"Content-type": "application/json"}, data=json.dumps(request_data)) as ctx: ctx.request.user = self.user request = Request(ctx.request) filtered_request = dispatch(self.user, request, filters_pipeline=pipeline) filtered_request_app = SieveMarathonApp.from_json( filtered_request.get_json()) self.assertEqual(1, len(filtered_request_app.constraints)) self._check_other_fields("constraints", filtered_request_app)
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, [(SieveMarathonApp.from_json(fixture), MarathonApp.from_json({"id": "/dev/foo"}))])
def test_it_recreates_a_get_response_for_a_single_app(self, fixture): self.maxDiff = None with application.test_request_context('/v2/apps//foo', method='GET', data=b'') as ctx: response = FlaskResponse(response=json.dumps({"app": fixture}), status=HTTPStatus.OK, headers={}) response = Response(ctx.request, response) with patch.object(response, 'marathon_client') as client: client.get_app.return_value = SieveMarathonApp.from_json( deepcopy(fixture)) apps = list(response.split()) joined_response = response.join(apps) self.assertIsInstance(joined_response, FlaskResponse) self.assertDictEqual(json.loads(joined_response.data), {'app': fixture})
def setUp(self, single_full_app_fixture): self.sieve_marathon_app = SieveMarathonApp.from_json( single_full_app_fixture)
def setUp(self, single_full_app_fixture): self.filter = LabelsFilter() self.single_full_app_fixture = single_full_app_fixture self.request_app = SieveMarathonApp.from_json(self.single_full_app_fixture) self.original_app = SieveMarathonApp.from_json(self.single_full_app_fixture)
def test_response_apps_returns_none_if_outside_current_namespace(self, single_full_app_with_tasks_fixture): request_app = original_app =SieveMarathonApp.from_json(single_full_app_with_tasks_fixture) request_app.id = original_app.id = "/othernamespace/foo" self.assertIsNone(self.filter.response(self.user, request_app, original_app))