def test_check_no_resources(self, *mocks): """ Ensures the profile check fails when no resource constraints are found """ profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = get_content('profiles/no_constraints.yml') errors = profile._check_services(profile.check_resources, profile.data) self.assertRegex(' '.join(errors), r'resource constraints not found')
def test_check_with_node_constraints(self, *mocks): """ Ensures the profile check passes when no constraints are found """ profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = get_content("profiles/with_node_constraints.yml") errors = profile._check_services(profile.check_constraints, profile.data) self.assertEqual(0, len(errors))
def test_check_resources_empty(self, *mocks): """ Ensures the profile check fails when resources constraints are empty """ profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = get_content("profiles/resources_nothing_set.yml") errors = profile._check_services(profile.check_resources, profile.data) self.assertRegex(" ".join(errors), r"resource constraints not found")
def test_check_no_node_constraints(self, *mocks): """ Ensures the profile check fails when `node.` constraints are not found """ profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = get_content("profiles/no_node_constraints.yml") errors = profile._check_services(profile.check_constraints, profile.data) self.assertRegex(" ".join(errors), r"node constraints not found")
def test_check_global_mode(self, *mocks): """ Ensures the profile check does not fail when there is no constraint on a global service """ profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = get_content("profiles/global_no_constraints.yml") errors = profile._check_services(profile.check_constraints, profile.data) self.assertEqual(0, len(errors), errors)
def test_set_resources_empty_resources_left_alone(self, *mocks): """ Ensures when services.x.deploy doesn't exist it is not added """ content = get_content("profiles/no_constraints.yml") data = yaml_load(content) service_name, data = list(data["services"].items())[0] profile = Profile(self.workflow) profile.set_resources(service_name, data) self.assertEqual("deploy" not in data, True)
def test_checks_called(self, *mocks): """ Ensure constraint checks are called on deploy """ profile_data_mock = mocks[0] profile_data_mock.return_value = { "services": { "app": { "image": "foo:test" } } } command = shlex.split("-e dev deploy") workflow = Workflow(argv=command) workflow.environment.write = mock.Mock() # mock out all check methods all_checks = Profile.get_all_checks() self.assertEqual(3, len(all_checks), all_checks) for name in all_checks: _check_mock = mock.Mock() _check_mock.return_value = [] setattr(workflow.profile, name, _check_mock) workflow.run() for name in all_checks: _check_mock = getattr(workflow.profile, name) self.assertGreater(_check_mock.call_count, 0, f"{name} not called")
def test_expand_services(self, *mocks): data = { "services": { "foo": { "build": "..", "image": "${DOCKER_IMAGE}", "environment": [ "FOO=1", "SPARK_WORKER_PORT=8888", "SPARK_WORKER_WEBUI_PORT=8080", ], "ports": ["8000:8000"], "deploy": {"replicas": 3}, } }, "compose_flow": { "expand": { "foo": { "increment": { "env": ["SPARK_WORKER_PORT", "SPARK_WORKER_WEBUI_PORT"], "ports": {"source_port": True, "destination_port": True}, } } } }, } profile = Profile(self.workflow) new_data = profile._check_cf_config(data) self.assertEqual(len(new_data["services"]), 3) self.assertEqual(sorted(new_data["services"].keys()), ["foo1", "foo2", "foo3"]) self.assertEqual( [x["ports"] for x in new_data["services"].values()], [["8000:8000"], ["8001:8001"], ["8002:8002"]], ) self.assertEqual( [x["environment"] for x in new_data["services"].values()], [ ["FOO=1", "SPARK_WORKER_PORT=8888", "SPARK_WORKER_WEBUI_PORT=8080"], ["FOO=1", "SPARK_WORKER_PORT=8889", "SPARK_WORKER_WEBUI_PORT=8081"], ["FOO=1", "SPARK_WORKER_PORT=8890", "SPARK_WORKER_WEBUI_PORT=8082"], ], )
def test_set_resources_memory_reservation_no_limit(self, *mocks): """ Ensures memory limit is matched to reservation when no limit is given """ merge_profile_mock = mocks[0] merge_profile_mock.return_value = get_content( 'profiles/reservation_no_limit.yml') profile = Profile(self.workflow) param = {} content = profile._compile( param) # the param is ignored because it's using the mock merge_profile_mock.assert_called_with(param) data = yaml_load(content) resources = data['services']['app']['deploy']['resources'] self.assertEqual(resources['limits']['memory'], resources['reservations']['memory'])
def test_set_resources_memory_limit_and_reservation(self, *mocks): """ Ensures memory reservation and limit are left alone when they are both defined """ merge_profile_mock = mocks[0] merge_profile_mock.return_value = get_content( 'profiles/limit_and_reservation.yml') profile = Profile(self.workflow) param = {} content = profile._compile( param) # the param is ignored because it's using the mock merge_profile_mock.assert_called_with(param) data = yaml_load(content) resources = data['services']['app']['deploy']['resources'] self.assertEqual('10M', resources['reservations']['memory']) self.assertEqual('100M', resources['limits']['memory'])
def test_profile_writes_once(self, *mocks): open_mock = mocks[0] profile = Profile(self.workflow) profile.load = mock.Mock() profile.load.return_value = 'services:' profile.write() profile.write() profile.write() self.assertEqual(1, open_mock.call_count)
def test_set_resources_memory_limit_no_reservation(self, *mocks): """ Ensures memory reservation is matched to limit when no reservation is given """ merge_profile_mock = mocks[0] merge_profile_mock.return_value = get_content( "profiles/limit_no_reservation.yml" ) profile = Profile(self.workflow) param = {} content = profile._compile( param ) # the param is ignored because it's using the mock merge_profile_mock.assert_called_with(param) data = yaml_load(content) resources = data["services"]["app"]["deploy"]["resources"] self.assertEqual( resources["reservations"]["memory"], resources["limits"]["memory"] )
def test_expand_services(self, *mocks): data = { 'services': { 'foo': { 'build': '..', 'image': '${DOCKER_IMAGE}', 'environment': [ 'FOO=1', 'SPARK_WORKER_PORT=8888', 'SPARK_WORKER_WEBUI_PORT=8080', ], 'ports': ['8000:8000'], 'deploy': { 'replicas': 3 }, } }, 'compose_flow': { 'expand': { 'foo': { 'increment': { 'env': ['SPARK_WORKER_PORT', 'SPARK_WORKER_WEBUI_PORT'], 'ports': { 'source_port': True, 'destination_port': True }, } } } }, } profile = Profile(self.workflow) new_data = profile._check_cf_config(data) self.assertEqual(len(new_data['services']), 3) self.assertEqual(sorted(new_data['services'].keys()), ['foo1', 'foo2', 'foo3']) self.assertEqual( [x['ports'] for x in new_data['services'].values()], [['8000:8000'], ['8001:8001'], ['8002:8002']], ) self.assertEqual( [x['environment'] for x in new_data['services'].values()], [ [ 'FOO=1', 'SPARK_WORKER_PORT=8888', 'SPARK_WORKER_WEBUI_PORT=8080' ], [ 'FOO=1', 'SPARK_WORKER_PORT=8889', 'SPARK_WORKER_WEBUI_PORT=8081' ], [ 'FOO=1', 'SPARK_WORKER_PORT=8890', 'SPARK_WORKER_WEBUI_PORT=8082' ], ], )
def test_profile_no_compose_dir(self, *mocks): """ when there is no compose directory, do not attempt to render a profile """ profile = Profile(self.workflow)