def test_update_version(self, *mocks): """ Ensures that version in env is updated when the publish command is run """ version = '1.2.3' new_version = '0.9.999' docker_image = 'foo:bar' docker_mock = mocks[0] docker_mock.get_config.return_value = ( f"FOO=1\nBAR=2\nVERSION={version}\nDOCKER_IMAGE={docker_image}") utils_mock = mocks[1] utils_mock.get_tag_version.return_value = new_version utils_mock.render = utils.render command = shlex.split('-e dev publish') flow = Workflow(argv=command) publish = flow.subcommand publish.get_built_docker_images = mock.Mock() publish.get_built_docker_images.return_value = [] flow.run() env = flow.environment self.assertEqual(utils_mock.get_tag_version.return_value, env.data['VERSION']) self.assertEqual(f'foo:{new_version}', env.data['DOCKER_IMAGE'])
def test_load_runtime(self, *mocks): """ Ensures that runtime variables are able to be viewed/edited without being set """ version = "1.2.3" docker_image = "foo:bar" bar_env_val = "bar" os.environ["BAR"] = bar_env_val get_backend_mock = mocks[0] get_backend_mock.return_value.read.return_value = ( f"FOO={RUNTIME_PLACEHOLDER}\nBAR={RUNTIME_PLACEHOLDER}\n" f"VERSION={version}\nDOCKER_IMAGE={docker_image}" ) command = shlex.split("-e dev env cat") flow = Workflow(argv=command) flow.run() env = flow.subcommand self.assertEqual(RUNTIME_PLACEHOLDER, env.data["FOO"]) self.assertEqual(bar_env_val, env.data["BAR"])
def test_version_written(self, *mocks): """ Ensures that version in env is written to the docker config """ docker_mock = mocks[-1] docker_mock.get_config.return_value = ( "FOO=1\nBAR=2\nVERSION=1.0\nDOCKER_IMAGE=foo:dev") utils_mock = mocks[0] utils_mock.get_tag_version.return_value = "0.0.1-test" utils_mock.render.side_effect = lambda x, **kwargs: x command = shlex.split("-e dev deploy") workflow = Workflow(argv=command) workflow.environment.write = mock.Mock() workflow.profile.check = mock.Mock() workflow.run() # make sure the environment write call is made workflow.environment.write.assert_called() # make sure the profile is checked workflow.profile.check.assert_called()
def test_load_ro(self, *mocks): """ Ensures that env.load does not reset the VERSION var The DOCKER_IMAGE and VERSION vars should only be modified when publishing an image In all other commands, the environment should be read-only """ version = "1.2.3" docker_image = "foo:bar" get_backend_mock = mocks[0] get_backend_mock.return_value.read.return_value = ( f"FOO=1\nBAR=2\nVERSION={version}\nDOCKER_IMAGE={docker_image}" ) command = shlex.split("-e dev env cat") flow = Workflow(argv=command) flow.run() env = flow.subcommand self.assertEqual(version, env.data["VERSION"]) self.assertEqual(docker_image, env.data["DOCKER_IMAGE"]) self.assertEqual( ["BAR", "DOCKER_IMAGE", "FOO", "VERSION"], sorted(env._persistable_keys) )
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_update_version(self, *mocks): """ Ensures that version in env is updated when the publish command is run """ settings_mock = mocks[2] settings_mock.DOCKER_IMAGE_PREFIX = "test.registry" settings_mock.LOGGING = {"version": 1, "loggers": {"compose_flow": {}}} version = "1.2.3" new_version = "0.9.999" docker_image = "foo:bar" utils_mock = mocks[1] utils_mock.get_tag_version.return_value = new_version utils_mock.render = utils.render command = shlex.split("-e dev publish") flow = Workflow(argv=command) publish = flow.subcommand publish.get_built_docker_images = mock.Mock() publish.get_built_docker_images.return_value = [] flow.run() env = flow.environment self.assertEqual(utils_mock.get_tag_version.return_value, env.data["VERSION"]) self.assertEqual(f"test.registry/testdirname:{new_version}", env.data["DOCKER_IMAGE"])
def test_load_ro(self, *mocks): """ Ensures that env.load does not reset the VERSION var The DOCKER_IMAGE and VERSION vars should only be modified when publishing an image In all other commands, the environment should be read-only """ version = '1.2.3' docker_image = 'foo:bar' docker_mock = mocks[0] docker_mock.get_config.return_value = ( f"FOO=1\nBAR=2\nVERSION={version}\nDOCKER_IMAGE={docker_image}" ) command = shlex.split('-e dev env cat') flow = Workflow(argv=command) flow.run() env = flow.subcommand self.assertEqual(version, env.data['VERSION']) self.assertEqual(docker_image, env.data['DOCKER_IMAGE']) self.assertEqual( ['BAR', 'DOCKER_IMAGE', 'FOO', 'VERSION'], sorted(env._persistable_keys) )
def test_setup_environment_flag(self, *mocks): """ Ensures the environment cache is set to an empty dictionary when a workflow environment should not be setup """ subcommand_mock = mocks[0] subcommand_mock.return_value.setup_environment = False command = shlex.split("-e dev env cat") workflow = Workflow(argv=command) workflow._setup_environment() self.assertEqual({}, workflow.environment._data)
def test_rancher_no_namespaces_defined(self, *mocks): """ Ensures that Rancher namespaces are not created when none are defined """ command = shlex.split("-e dev deploy rancher") workflow = Workflow(argv=command) workflow.environment.write = mock.Mock() workflow.profile.check = mock.Mock() workflow.run() # make sure the new namespace is created mock_create_ns = mocks[0] mock_create_ns.assert_not_called()
def test_rancher_namespace_created(self, *mocks): """ Ensures that Rancher namespaces are created when they do not exist """ command = shlex.split("-e dev deploy rancher") workflow = Workflow(argv=command) workflow.environment.write = mock.Mock() workflow.profile.check = mock.Mock() workflow.run() # make sure the new namespace is created mock_create_ns = mocks[0] mock_create_ns.assert_called_once_with("my-namespace", False)
def test_version(self, *mocks): """ Ensure the --version arg just returns the version """ version = "0.0.0-test" pkg_resources_mock = mocks[0] pkg_resources_mock.require.return_value = [mock.Mock(version=version)] command = shlex.split("--version") workflow = Workflow(argv=command) workflow.run() print_mock = mocks[1] print_mock.assert_called_with(version)
def test_rancher_url_manifest(self, *mocks): """ Ensure that manifests can be deployed to Rancher from external URLs """ command = shlex.split("-e dev deploy rancher") workflow = Workflow(argv=command) workflow.environment.write = mock.Mock() workflow.profile.check = mock.Mock() workflow.run() command = mocks[0].call_args[0][0] # make sure the command contains the manifest URL self.assertTrue(MANIFEST_URL in command)
def test_e2e_happy_path_publish_with_auto_tags(self, *mocks): new_version = "3.5.9" utils_mock = mocks[1] utils_mock.get_tag_version.return_value = new_version utils_mock.render = utils.render command = shlex.split("-e prod publish --tag-major-minor") flow = Workflow(argv=command) publish = flow.subcommand execute_mock = mock.MagicMock() publish.execute = execute_mock flow.run() target_executions = [ ("docker push localhost.localdomain/testdirname:3.5.9", { "_fg": True }), ( "docker tag localhost.localdomain/testdirname:3.5.9 localhost.localdomain/testdirname:3", {}, ), ("docker push localhost.localdomain/testdirname:3", { "_fg": True }), ( "docker tag localhost.localdomain/testdirname:3.5.9 localhost.localdomain/testdirname:3.5", {}, ), ("docker push localhost.localdomain/testdirname:3.5", { "_fg": True }), ] call_target_tuples = list( zip(execute_mock.call_args_list, target_executions)) self.assertEqual(len(target_executions), len(call_target_tuples)) for call, target_call in zip(execute_mock.call_args_list, target_executions): args, kwargs = call target_args, target_kwargs = target_call self.assertEqual((target_args, ), args) self.assertEqual(target_kwargs, kwargs)
def test_exec_pod_without_specified_container(self, *mocks): """ Test that the command works when no container is specified """ argv = shlex.split("-e test pod exec generic-workers /bin/bash") workflow = Workflow(argv=argv) pod = workflow.subcommand pod.list_pods = mock.MagicMock() pod.list_pods.return_value = self._get_mock_pod_list_raw() workflow.run() target_command = f"rancher kubectl -n {workflow.project_name} exec -it generic-workers-6c744b8fb8-7sjb8 -- /bin/bash" self.assertEqual(target_command, mocks[1].call_args[0][0])
def test_exec_pod_with_specified_namespace(self, *mocks): """ Test that we can override the namespace with --namespace. """ argv = shlex.split( "-e test pod exec --namespace foobar generic-workers /bin/bash") workflow = Workflow(argv=argv) pod = workflow.subcommand pod.list_pods = mock.MagicMock() pod.list_pods.return_value = self._get_mock_pod_list_raw() workflow.run() target_command = "rancher kubectl -n foobar exec -it generic-workers-6c744b8fb8-7sjb8 -- /bin/bash" self.assertEqual(target_command, mocks[1].call_args[0][0])
def test_docker_image_prefix_from_os_settings(self, *mocks): os_mock = mocks[0] os_mock.path.exists.return_value = False settings_mock = mocks[1] settings_mock.DOCKER_IMAGE_PREFIX = "foo" workflow = Workflow(argv=[]) self.assertEqual(workflow.docker_image_prefix, "foo")
def test_default_env_when_no_env_specified(self, *mocks): self._setup_docker_config_mock(*mocks) self._setup_utils_mock(*mocks) command = shlex.split("env cat") workflow = Workflow(argv=command) env = workflow.environment self.assertEqual([], sorted(env.data.keys()))
def test_config_name_with_different_env(self, *mocks): """Ensure the config can have a different env prefix than the current env This allows storage of environments other than the current one, for example, storing a default local config in the dev remote so that multiple devs can access it to seed their environment """ command = shlex.split("-e dev -c local-test-project env cat") workflow = Workflow(argv=command) self.assertEquals("local-test-project", workflow.config_name)
def test_profile_env(self, *mocks): """ Ensure the VERSION is updated """ utils_mock = mocks[1] utils_mock.get_tag_version.return_value = "0.0.1" utils_mock.render = utils.render command = shlex.split("-e dev publish") flow = Workflow(argv=command) flow.subcommand.build = mock.Mock() flow.subcommand.push = mock.Mock() flow.run() env_data = flow.environment.data self.assertEqual(True, "VERSION" in env_data)
def test_empty_env_value(self, *mocks): """Ensure that a value can be empty if the line ends with an equals """ get_backend_mock = mocks[0] get_backend_mock.return_value.read.return_value = "FOO=" command = shlex.split("-e dev env cat") flow = Workflow(argv=command) self.assertEquals("", flow.environment.data["FOO"])
def test_docker_image_prefix_default(self, *mocks): """ Ensure the default image name will not accidentally push the image to a remote registry """ os_mock = mocks[0] os_mock.environ = {} os_mock.path.exists.return_value = False workflow = Workflow(argv=[]) self.assertEqual(workflow.docker_image_prefix, "localhost.localdomain")
def test_config_name_arg(self, *mocks): """ Ensure the config arg updates the config name TODO: this should move to test_workflow """ command = shlex.split('-e dev --config-name=test env cat') flow = Workflow(argv=command) env = Env(flow) self.assertEqual(flow.config_name, 'test')
def test_publish_with_missing_env_vars(self, *mocks): command = shlex.split('publish') flow = Workflow(argv=command) flow.subcommand.build = mock.Mock() flow.subcommand.check = mock.Mock() flow.subcommand.push = mock.Mock() with mock.patch( 'compose_flow.commands.workflow.Workflow.profile', new_callable=mock.PropertyMock, ) as profile_mock: flow.run() profile_mock.return_value.write.assert_called_with() flow.subcommand.push.assert_called() # make sure check is not called flow.subcommand.check.assert_not_called()
def test_default_config_name(self, *mocks): """ Ensure the default config is given TODO: this should move to test_workflow """ command = shlex.split('-e dev env cat') flow = Workflow(argv=command) env = Env(flow) self.assertEqual(flow.config_name, 'dev-testdirname')
def test_sensible_defaults_no_env(self, *mocks): """ Test sensible defaults when no environment is defined """ command = shlex.split("publish") workflow = Workflow(argv=command) self.assertEqual(None, workflow.args.environment) self.assertEqual(None, workflow.args.remote) self.assertEqual(TEST_PROJECT_NAME, workflow.config_name) self.assertEqual(TEST_PROJECT_NAME, workflow.project_name)
def test_sensible_defaults_with_env_and_project(self, *mocks): """ Test sensible defaults when an environment and project name is defined """ env = "dev" command = shlex.split(f"-e {env} --project-name foo publish") workflow = Workflow(argv=command) self.assertEqual(env, workflow.args.environment) self.assertEqual(env, workflow.args.remote) self.assertEqual(f"{env}-foo", workflow.config_name) self.assertEqual("foo", workflow.project_name)
def test_exec_pod_with_specified_container_and_index(self, *mocks): """ Basic test to ensure the command runs as expected """ argv = shlex.split( "-e test pod exec generic-workers --container generic-workers -i 2 /bin/bash" ) workflow = Workflow(argv=argv) pod = workflow.subcommand pod.list_pods = mock.MagicMock() pod.list_pods.return_value = self._get_mock_pod_list_raw() workflow.run() target_command = ( f"rancher kubectl -n {workflow.project_name} exec -it generic-workers-6c744b8fb8-c66gl " "--container generic-workers -- /bin/bash") self.assertEqual(target_command, mocks[1].call_args[0][0])
def test_load_env_when_env_specified(self, *mocks): self._setup_docker_config_mock(*mocks) self._setup_utils_mock(*mocks) command = shlex.split("-e dev env cat") workflow = Workflow(argv=command) env = workflow.environment self.assertEqual(["BAR", "FOO"], sorted(env.data.keys())) self.assertEqual("1", env.data["FOO"]) self.assertEqual("2", env.data["BAR"])
def test_sensible_defaults_with_env(self, *mocks): """ Test sensible defaults when an environment is defined """ env = "dev" command = shlex.split(f"-e {env} publish") workflow = Workflow(argv=command) self.assertEqual(env, workflow.args.environment) self.assertEqual(env, workflow.args.remote) self.assertEqual(f"{env}-{TEST_PROJECT_NAME}", workflow.config_name) self.assertEqual(TEST_PROJECT_NAME, workflow.project_name)
def test_config_updated(self, *mocks): """ Ensures that the config is updated in order to run tasks on the latest locally built image """ utils_mock = mocks[0] utils_mock.get_tag_version.return_value = "0.0.1-test" utils_mock.render.side_effect = lambda x, **kwargs: x command = shlex.split("-e test task foo") workflow = Workflow(argv=command) self.assertEqual(True, "DOCKER_IMAGE" in workflow.environment.data)