diff --git a/.gitignore b/.gitignore index 51a36a2..8a04419 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,6 @@ venv MANIFEST reports **/RCS/** -.venv \ No newline at end of file +.venv +**.mypy_cache** +uv.lock diff --git a/Dockerfile.skipper-build b/Dockerfile.skipper-build index 6fb8b36..6d5b7b9 100644 --- a/Dockerfile.skipper-build +++ b/Dockerfile.skipper-build @@ -1,9 +1,18 @@ -FROM python:3.11 +FROM python:3.12 -COPY requirements.txt /tmp/requirements.txt -RUN pip install -r /tmp/requirements.txt +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ -COPY dev-requirements.txt /tmp/dev-requirements.txt -RUN pip install -r /tmp/dev-requirements.txt +ENV VIRTUAL_ENV=/opt/venv +# Add virtual environment bin directory to PATH and link to /usr/local/bin +RUN rm -rf /usr/local/sbin && ln -sf ${VIRTUAL_ENV}/bin /usr/local/sbin -RUN rm /tmp/*requirements.txt +ENV PYTHONPATH=${VIRTUAL_ENV}/lib/python3.12/site-packages +ENV UV_LINK_MODE=copy + +WORKDIR /tmp + +RUN uv venv ${VIRTUAL_ENV} --system --system-site-packages + +COPY pyproject.toml pyproject.toml + +RUN uv pip install -r pyproject.toml --all-extras diff --git a/MANIFEST.in b/MANIFEST.in index e69de29..60ab70e 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include skipper/data/* +recursive-include skipper/data * diff --git a/Makefile b/Makefile index cd68f01..68ce4de 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,30 @@ -all: pep8 pylint tests build +PACKAGE_NAME := strato_skipper + +all: lint tests build build: - python setup.py sdist + rm -rf build/$(PACKAGE_NAME)-*.whl + uv build --wheel --out-dir $(PWD)/build/ . + rm -rf dist *.egg-info build/lib build/bdist* -pep8: - pep8 skipper tests +lint: + ruff check --preview skipper tests -pylint: - mkdir -p reports - PYLINTHOME=reports/ pylint skipper +lint-fix: + ruff check --preview skipper tests --fix tests: - py.test --cov=skipper --cov-report=term-missing + pytest --cov=skipper --cov-report=term-missing -v tests install: - pip install -U . + uv pip install -U . + rm -rf dist *.egg-info build/lib build/bdist* uninstall: - pip uninstall -y strato-skipper + uv pip uninstall -y strato-skipper clean: rm -rf build dist *egg-info .tox tests/__pycache__ reports find -name *.pyc -delete -.PHONY: build pep8 pylint tests install uninstall clean +.PHONY: build lint lint-fix tests install uninstall clean diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index 23cd8fd..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -mock -pep8 -pylint -pytest -pytest-cov diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..73cfc74 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[build-system] +requires = [ + "setuptools", + "setuptools-git-versioning", +] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +include = ["skipper*"] + +[tool.setuptools-git-versioning] +enabled = true + +[tool.distutils.bdist_wheel] +universal = true + +[project] +name = "strato-skipper" +dynamic = ["version"] +description = "Easily dockerize your Git repository" +readme = "README.md" +requires-python = ">=3" +license = {text = "Apache-2"} +authors = [ + {name = "Adir Gabai", email = "adir@stratoscale.com"} +] +dependencies = [ + "PyYAML>=3.11", + "click>=6.7", + "requests>=2.6.0", + "tabulate>=0.7.5", + "six>=1.10.0", + "urllib3>=1.22", + "requests-bearer==0.5.1", + "retry", + "setuptools", + "pbr" +] + +[project.optional-dependencies] +dev = [ + "pytest", + "pytest-cov", + "ruff", +] + +[project.scripts] +skipper = "skipper.main:main" + +[tool.pep8] +max-line-length = 145 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 25d34b4..0000000 --- a/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -PyYAML>=3.11 -click>=6.7 -requests>=2.6.0 -tabulate>=0.7.5 -six>=1.10.0 -urllib3>=1.22 -pbr>=5.4 -requests-bearer==0.5.1 -retry diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..99dbf05 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,43 @@ +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", +] + +# Assume Python 3.11. +target-version = "py311" + +# Same as Black. +line-length = 120 + +[lint] +# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default. +select = ["E", "F", "W"] +ignore = [] + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["A", "B", "C", "D", "E", "F"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +pycodestyle.max-line-length = 145 \ No newline at end of file diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1ef6f87..0000000 --- a/setup.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[metadata] -name = strato-skipper -author = Adir Gabai -author_email = adir@stratoscale.com -home_page = http://github.com/Stratoscale/skipper -summary = Easily dockerize your Git repository -license = Apache-2 -long_description = file: README.md -long_description_content_type = text/markdown - -requires_dist = setuptools -requires_python = >=3 - -[files] -packages = - skipper - -[entry_points] -console_scripts = - skipper = skipper.main:main - -[pep8] -max_line_length=145 diff --git a/setup.py b/setup.py deleted file mode 100644 index c424934..0000000 --- a/setup.py +++ /dev/null @@ -1,9 +0,0 @@ -from setuptools import setup - -setup( - setup_requires=[ - 'pbr >= 1.9', - 'setuptools >= 17.1' - ], - pbr=True, -) diff --git a/skipper/builder.py b/skipper/builder.py index 0773287..a9d0436 100644 --- a/skipper/builder.py +++ b/skipper/builder.py @@ -67,9 +67,7 @@ def fqdn(self): :return: image Fully Qualified Domain Name """ if not self.__fqdn: - self.__fqdn = utils.generate_fqdn_image( - self.registry, self.namespace, self.name, self.tag - ) + self.__fqdn = utils.generate_fqdn_image(self.registry, self.namespace, self.name, self.tag) return self.__fqdn @property diff --git a/skipper/cli.py b/skipper/cli.py index 42b2553..0fe4fe0 100644 --- a/skipper/cli.py +++ b/skipper/cli.py @@ -4,24 +4,22 @@ import os import os.path import sys - from re import compile as compile_expression + import click import six import tabulate -from pkg_resources import get_distribution from pbr import packaging +from pkg_resources import get_distribution -from skipper import git, builder -from skipper import runner -from skipper import utils +from skipper import builder, git, runner, utils from skipper.builder import BuildOptions, Image def _validate_publish(ctx, param, value): # pylint: disable=unused-argument if value: - matcher = compile_expression(r'^((\d+)(-(\d+))?):((\d+)(-(\d+))?)$') + matcher = compile_expression(r"^((\d+)(-(\d+))?):((\d+)(-(\d+))?)$") for port_mapping in value: _validate_port(matcher, port_mapping) @@ -34,7 +32,9 @@ def _validate_port(matcher, port_forwarding): if not match: raise click.BadParameter("Publish need to be in format port:port or port-port:port-port") - host_port_start_range, host_port_end_range, container_port_start_range, container_port_end_range = match.group(2, 4, 6, 8) + host_port_start_range, host_port_end_range, container_port_start_range, container_port_end_range = match.group( + 2, 4, 6, 8 + ) _validate_port_out_of_range(host_port_start_range) _validate_port_out_of_range(host_port_end_range) _validate_port_out_of_range(container_port_start_range) @@ -55,52 +55,54 @@ def _validate_port_out_of_range(port): # pylint: disable=too-many-arguments @click.group() -@click.option('-v', '--verbose', help='Increase verbosity', is_flag=True, default=False) -@click.option('--registry', help='URL of the docker registry') -@click.option('--build-container-image', help='Image to use as build container') -@click.option('--build-container-tag', help='Tag of the build container') -@click.option('--build-container-net', help='Network to connect the build container') -@click.option('--env-file', multiple=True, help='Environment variable file(s) to load') -@click.option('--build-arg', multiple=True, help='Build arguments to pass to the container build', envvar='SKIPPER_BUILD_ARGS') -@click.option('--build-context', multiple=True, help='Build contexts to pass to the container build') +@click.option("-v", "--verbose", help="Increase verbosity", is_flag=True, default=False) +@click.option("--registry", help="URL of the docker registry") +@click.option("--build-container-image", help="Image to use as build container") +@click.option("--build-container-tag", help="Tag of the build container") +@click.option("--build-container-net", help="Network to connect the build container") +@click.option("--env-file", multiple=True, help="Environment variable file(s) to load") +@click.option( + "--build-arg", multiple=True, help="Build arguments to pass to the container build", envvar="SKIPPER_BUILD_ARGS" +) +@click.option("--build-context", multiple=True, help="Build contexts to pass to the container build") @click.pass_context def cli( - ctx, - registry, - build_container_image, - build_container_tag, - build_container_net, - verbose, - env_file, - build_arg, - build_context, + ctx, + registry, + build_container_image, + build_container_tag, + build_container_net, + verbose, + env_file, + build_arg, + build_context, ): """ Easily dockerize your Git repository """ logging_level = logging.DEBUG if verbose else logging.INFO - utils.configure_logging(name='skipper', level=logging_level) - ctx.obj['registry'] = registry - ctx.obj['env_file'] = env_file - ctx.obj['build_container_image'] = build_container_image - ctx.obj['build_container_net'] = build_container_net - ctx.obj['git_revision'] = build_container_tag == 'git:revision' - ctx.obj['build_container_tag'] = (git.get_hash() if ctx.obj['git_revision'] else build_container_tag) - ctx.obj['env'] = ctx.default_map.get('env', {}) - ctx.obj['containers'] = ctx.default_map.get('containers') - ctx.obj['volumes'] = ctx.default_map.get('volumes') - ctx.obj['workdir'] = ctx.default_map.get('workdir') - ctx.obj['workspace'] = ctx.default_map.get('workspace', None) - ctx.obj['container_context'] = ctx.default_map.get('container_context') - ctx.obj['build_args'] = build_arg - ctx.obj['build_contexts'] = build_context + utils.configure_logging(name="skipper", level=logging_level) + ctx.obj["registry"] = registry + ctx.obj["env_file"] = env_file + ctx.obj["build_container_image"] = build_container_image + ctx.obj["build_container_net"] = build_container_net + ctx.obj["git_revision"] = build_container_tag == "git:revision" + ctx.obj["build_container_tag"] = git.get_hash() if ctx.obj["git_revision"] else build_container_tag + ctx.obj["env"] = ctx.default_map.get("env", {}) + ctx.obj["containers"] = ctx.default_map.get("containers") + ctx.obj["volumes"] = ctx.default_map.get("volumes") + ctx.obj["workdir"] = ctx.default_map.get("workdir") + ctx.obj["workspace"] = ctx.default_map.get("workspace", None) + ctx.obj["container_context"] = ctx.default_map.get("container_context") + ctx.obj["build_args"] = build_arg + ctx.obj["build_contexts"] = build_context utils.set_remote_registry_login_info(registry, ctx.obj) @cli.command() -@click.argument('images_to_build', nargs=-1, metavar='[IMAGE...]') -@click.option('--container-context', help='Container context path', default=None) -@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE') +@click.argument("images_to_build", nargs=-1, metavar="[IMAGE...]") +@click.option("--container-context", help="Container context path", default=None) +@click.option("-c", "--cache", help="Use cache image", is_flag=True, default=False, envvar="SKIPPER_USE_CACHE_IMAGE") @click.pass_context def build(ctx, images_to_build, container_context, cache): """ @@ -110,13 +112,13 @@ def build(ctx, images_to_build, container_context, cache): valid_images_to_build = _get_images_to_build(ctx, images_to_build) tag = git.get_hash() - build_args = (ctx.obj.get('build_args', ()) + (f'TAG={tag}',)) - build_contexts = ctx.obj.get('build_contexts', ()) + build_args = ctx.obj.get("build_args", ()) + (f"TAG={tag}",) + build_contexts = ctx.obj.get("build_contexts", ()) for image, dockerfile in valid_images_to_build.items(): utils.logger.info("Building image: %s", image) - main_context = container_context or ctx.obj.get('container_context') or os.path.dirname(dockerfile) + main_context = container_context or ctx.obj.get("container_context") or os.path.dirname(dockerfile) options = BuildOptions( Image(name=image, tag=tag, dockerfile=dockerfile), main_context, @@ -134,18 +136,18 @@ def build(ctx, images_to_build, container_context, cache): @cli.command() -@click.option('--namespace', help='Namespace to push into') -@click.option('--force', help="Push image even if it's already in the registry", is_flag=True, default=False) -@click.option('--pbr', help="Use PBR to tag the image", is_flag=True, default=False) -@click.option('--tag', help="Tag to push", default=None) -@click.argument('image') +@click.option("--namespace", help="Namespace to push into") +@click.option("--force", help="Push image even if it's already in the registry", is_flag=True, default=False) +@click.option("--pbr", help="Use PBR to tag the image", is_flag=True, default=False) +@click.option("--tag", help="Tag to push", default=None) +@click.argument("image") @click.pass_context def push(ctx, namespace, force, pbr, tag, image): """ Push a container """ utils.logger.debug("Executing push command") - _validate_global_params(ctx, 'registry') + _validate_global_params(ctx, "registry") image_tag = git.get_hash() tag_to_push = tag or image_tag if not tag and pbr: @@ -153,7 +155,7 @@ def push(ctx, namespace, force, pbr, tag, image): # pylint: disable=protected-access tag_to_push = f"{packaging._get_version_from_git().replace('dev', '')}.{tag[:8]}" - image_name = image + ':' + image_tag + image_name = image + ":" + image_tag ret = _push(ctx, force, image, image_name, namespace, tag_to_push) if ret != 0: @@ -162,37 +164,36 @@ def push(ctx, namespace, force, pbr, tag, image): def _push(ctx, force, image, image_name, namespace, tag): - fqdn_image = utils.generate_fqdn_image(ctx.obj['registry'], namespace, image, tag) + fqdn_image = utils.generate_fqdn_image(ctx.obj["registry"], namespace, image, tag) utils.logger.debug("Adding tag %s", fqdn_image) - command = ['tag', image_name, fqdn_image] + command = ["tag", image_name, fqdn_image] ret = runner.run(command) if ret != 0: - utils.logger.error('Failed to tag image: %s as fqdn: %s', image_name, fqdn_image) + utils.logger.error("Failed to tag image: %s as fqdn: %s", image_name, fqdn_image) sys.exit(ret) repo_name = utils.generate_fqdn_image(None, namespace, image, tag=None) - images_info = utils.get_remote_images_info([repo_name], ctx.obj['registry'], - ctx.obj.get('username'), ctx.obj.get('password')) + images_info = utils.get_remote_images_info( + [repo_name], ctx.obj["registry"], ctx.obj.get("username"), ctx.obj.get("password") + ) tags = [info[-1] for info in images_info] if tag in tags: if not force: - utils.logger.info("Image %s is already in registry %s, not pushing", - fqdn_image, ctx.obj['registry']) + utils.logger.info("Image %s is already in registry %s, not pushing", fqdn_image, ctx.obj["registry"]) else: - utils.logger.warning("Image %s is already in registry %s, pushing anyway", - fqdn_image, ctx.obj['registry']) - _push_to_registry(ctx.obj['registry'], fqdn_image) + utils.logger.warning("Image %s is already in registry %s, pushing anyway", fqdn_image, ctx.obj["registry"]) + _push_to_registry(ctx.obj["registry"], fqdn_image) else: - _push_to_registry(ctx.obj['registry'], fqdn_image) + _push_to_registry(ctx.obj["registry"], fqdn_image) utils.logger.debug("Removing tag %s", fqdn_image) - command = ['rmi', fqdn_image] + command = ["rmi", fqdn_image] ret = runner.run(command) if ret != 0: - utils.logger.warning('Failed to remove image tag: %s', fqdn_image) + utils.logger.warning("Failed to remove image tag: %s", fqdn_image) return ret @cli.command() -@click.option('-r', '--remote', help='List also remote images', is_flag=True, default=False) +@click.option("-r", "--remote", help="List also remote images", is_flag=True, default=False) @click.pass_context def images(ctx, remote): """ @@ -200,25 +201,26 @@ def images(ctx, remote): """ utils.logger.debug("Executing images command") - valid_images = ctx.obj.get('containers') or utils.get_images_from_dockerfiles() + valid_images = ctx.obj.get("containers") or utils.get_images_from_dockerfiles() images_names = valid_images.keys() utils.logger.info("Expected images: %s\n", ", ".join(images_names)) images_info = utils.get_local_images_info(images_names) if remote: - _validate_global_params(ctx, 'registry') + _validate_global_params(ctx, "registry") try: - images_info += utils.get_remote_images_info(images_names, ctx.obj['registry'], - ctx.obj.get('username'), ctx.obj.get('password')) + images_info += utils.get_remote_images_info( + images_names, ctx.obj["registry"], ctx.obj.get("username"), ctx.obj.get("password") + ) except Exception as exp: - raise click.exceptions.ClickException(f'Got unknown error from remote registry {exp}') + raise click.exceptions.ClickException(f"Got unknown error from remote registry {exp}") - print(tabulate.tabulate(images_info, headers=['REGISTRY', 'IMAGE', 'TAG'], tablefmt='grid')) + print(tabulate.tabulate(images_info, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid")) @cli.command() -@click.option('-r', '--remote', help='Delete image from registry', is_flag=True, default=False) -@click.argument('image') -@click.argument('tag') +@click.option("-r", "--remote", help="Delete image from registry", is_flag=True, default=False) +@click.argument("image") +@click.argument("tag") @click.pass_context def rmi(ctx, remote, image, tag): """ @@ -227,34 +229,35 @@ def rmi(ctx, remote, image, tag): utils.logger.debug("Executing rmi command") _validate_project_image(image) if remote: - _validate_global_params(ctx, 'registry') - utils.delete_image_from_registry(ctx.obj['registry'], image, tag, - ctx.obj.get('username'), ctx.obj.get('password')) + _validate_global_params(ctx, "registry") + utils.delete_image_from_registry( + ctx.obj["registry"], image, tag, ctx.obj.get("username"), ctx.obj.get("password") + ) else: utils.delete_local_image(image, tag) @cli.command(context_settings={"ignore_unknown_options": True}) -@click.option('-i', '--interactive', help='Interactive mode', is_flag=True, default=False, envvar='SKIPPER_INTERACTIVE') -@click.option('-n', '--name', help='Container name', default=None) -@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container') -@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE') -@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish) -@click.argument('command', nargs=-1, type=click.UNPROCESSED, required=True) +@click.option("-i", "--interactive", help="Interactive mode", is_flag=True, default=False, envvar="SKIPPER_INTERACTIVE") +@click.option("-n", "--name", help="Container name", default=None) +@click.option("-e", "--env", multiple=True, help="Environment variables to pass the container") +@click.option("-c", "--cache", help="Use cache image", is_flag=True, default=False, envvar="SKIPPER_USE_CACHE_IMAGE") +@click.option("-p", "--publish", multiple=True, help="Publish a port", callback=_validate_publish) +@click.argument("command", nargs=-1, type=click.UNPROCESSED, required=True) @click.pass_context def run(ctx, interactive, name, env, publish, cache, command): """ Run arbitrary commands """ utils.logger.debug("Executing run command") - _validate_global_params(ctx, 'build_container_image') - ctx.obj['use_cache'] = cache + _validate_global_params(ctx, "build_container_image") + ctx.obj["use_cache"] = cache build_container = _prepare_build_container( BuildOptions.from_context_obj(ctx.obj), - ctx.obj.get('git_revision'), - ctx.obj.get('username'), - ctx.obj.get('password'), + ctx.obj.get("git_revision"), + ctx.obj.get("username"), + ctx.obj.get("password"), ) return runner.run( @@ -263,91 +266,91 @@ def run(ctx, interactive, name, env, publish, cache, command): environment=_expend_env(ctx, env), interactive=interactive, name=name, - net=ctx.obj['build_container_net'], + net=ctx.obj["build_container_net"], publish=publish, - volumes=ctx.obj.get('volumes'), - workdir=ctx.obj.get('workdir'), + volumes=ctx.obj.get("volumes"), + workdir=ctx.obj.get("workdir"), use_cache=cache, - workspace=ctx.obj.get('workspace'), - env_file=ctx.obj.get('env_file'), + workspace=ctx.obj.get("workspace"), + env_file=ctx.obj.get("env_file"), ) @cli.command(context_settings={"ignore_unknown_options": True}) -@click.option('-i', '--interactive', help='Interactive mode', is_flag=True, default=False, envvar='SKIPPER_INTERACTIVE') -@click.option('-n', '--name', help='Container name', default=None) -@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container') -@click.option('-f', 'makefile', help='Makefile to use', default='Makefile') -@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE') -@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish) -@click.argument('make_params', nargs=-1, type=click.UNPROCESSED, required=False) +@click.option("-i", "--interactive", help="Interactive mode", is_flag=True, default=False, envvar="SKIPPER_INTERACTIVE") +@click.option("-n", "--name", help="Container name", default=None) +@click.option("-e", "--env", multiple=True, help="Environment variables to pass the container") +@click.option("-f", "makefile", help="Makefile to use", default="Makefile") +@click.option("-c", "--cache", help="Use cache image", is_flag=True, default=False, envvar="SKIPPER_USE_CACHE_IMAGE") +@click.option("-p", "--publish", multiple=True, help="Publish a port", callback=_validate_publish) +@click.argument("make_params", nargs=-1, type=click.UNPROCESSED, required=False) @click.pass_context def make(ctx, interactive, name, env, makefile, cache, publish, make_params): """ Execute makefile target(s) """ utils.logger.debug("Executing make command") - _validate_global_params(ctx, 'build_container_image') - ctx.obj['use_cache'] = cache + _validate_global_params(ctx, "build_container_image") + ctx.obj["use_cache"] = cache build_container = _prepare_build_container( BuildOptions.from_context_obj(ctx.obj), - ctx.obj.get('git_revision'), - ctx.obj.get('username'), - ctx.obj.get('password'), + ctx.obj.get("git_revision"), + ctx.obj.get("username"), + ctx.obj.get("password"), ) - command = ['make', '-f', makefile] + list(make_params) + command = ["make", "-f", makefile] + list(make_params) return runner.run( command, fqdn_image=build_container, environment=_expend_env(ctx, env), interactive=interactive, name=name, - net=ctx.obj['build_container_net'], + net=ctx.obj["build_container_net"], publish=publish, - volumes=ctx.obj.get('volumes'), - workdir=ctx.obj.get('workdir'), + volumes=ctx.obj.get("volumes"), + workdir=ctx.obj.get("workdir"), use_cache=cache, - workspace=ctx.obj.get('workspace'), - env_file=ctx.obj.get('env_file'), + workspace=ctx.obj.get("workspace"), + env_file=ctx.obj.get("env_file"), ) @cli.command() -@click.option('-e', '--env', multiple=True, help='Environment variables to pass the container') -@click.option('-n', '--name', help='Container name', default=None) -@click.option('-c', '--cache', help='Use cache image', is_flag=True, default=False, envvar='SKIPPER_USE_CACHE_IMAGE') -@click.option('-p', '--publish', multiple=True, help="Publish a port", callback=_validate_publish) +@click.option("-e", "--env", multiple=True, help="Environment variables to pass the container") +@click.option("-n", "--name", help="Container name", default=None) +@click.option("-c", "--cache", help="Use cache image", is_flag=True, default=False, envvar="SKIPPER_USE_CACHE_IMAGE") +@click.option("-p", "--publish", multiple=True, help="Publish a port", callback=_validate_publish) @click.pass_context def shell(ctx, env, name, cache, publish): """ Start a shell """ utils.logger.debug("Starting a shell") - _validate_global_params(ctx, 'build_container_image') - ctx.obj['use_cache'] = cache + _validate_global_params(ctx, "build_container_image") + ctx.obj["use_cache"] = cache build_container = _prepare_build_container( BuildOptions.from_context_obj(ctx.obj), - ctx.obj.get('git_revision'), - ctx.obj.get('username'), - ctx.obj.get('password'), + ctx.obj.get("git_revision"), + ctx.obj.get("username"), + ctx.obj.get("password"), ) return runner.run( - ['bash'], + ["bash"], fqdn_image=build_container, environment=_expend_env(ctx, env), interactive=True, name=name, - net=ctx.obj['build_container_net'], + net=ctx.obj["build_container_net"], publish=publish, - volumes=ctx.obj.get('volumes'), - workdir=ctx.obj.get('workdir'), + volumes=ctx.obj.get("volumes"), + workdir=ctx.obj.get("workdir"), use_cache=cache, - workspace=ctx.obj.get('workspace'), - env_file=ctx.obj.get('env_file'), + workspace=ctx.obj.get("workspace"), + env_file=ctx.obj.get("env_file"), ) @@ -367,24 +370,24 @@ def completion(): """ completion_file_path = utils.get_extra_file("skipper-complete.sh") - with open(completion_file_path, 'r') as fin: + with open(completion_file_path, "r") as fin: print(fin.read(), end="") def _push_to_registry(registry, fqdn_image): utils.logger.debug("Pushing to registry %s", registry) - command = ['push', fqdn_image] + command = ["push", fqdn_image] ret = runner.run(command) if ret != 0: - utils.logger.error('Failed to push image: %s', fqdn_image) + utils.logger.error("Failed to push image: %s", fqdn_image) sys.exit(ret) def _prepare_build_container( - options: BuildOptions, - git_revision: bool, - username: str, - password: str, + options: BuildOptions, + git_revision: bool, + username: str, + password: str, ): def runner_run(command): """ @@ -407,25 +410,25 @@ def runner_run(command): if image.tag: if utils.local_image_exist(image.name, image.tag): - utils.logger.info('Using build container: %s', image.name) + utils.logger.info("Using build container: %s", image.name) return image.local if image.registry and utils.remote_image_exist(image.registry, image.name, image.tag, username, password): - utils.logger.info('Using build container: %s', image.fqdn) + utils.logger.info("Using build container: %s", image.fqdn) return image.fqdn if not git_revision: raise click.exceptions.ClickException(f"Couldn't find build image {image.name} with tag {image.tag}") else: - utils.logger.info('No build container tag was provided') + utils.logger.info("No build container tag was provided") if not image.dockerfile: - sys.exit(f'Could not find any dockerfile for {image.name}') + sys.exit(f"Could not find any dockerfile for {image.name}") - utils.logger.info('Building image using docker file: %s', image.dockerfile) + utils.logger.info("Building image using docker file: %s", image.dockerfile) if builder.build(options, runner_run, utils.logger) != 0: - sys.exit(f'Failed to build image: {image}') + sys.exit(f"Failed to build image: {image}") return image.local @@ -439,12 +442,12 @@ def _validate_global_params(ctx, *params): def _validate_project_image(image): project_images = utils.get_images_from_dockerfiles() if image not in project_images: - raise click.BadParameter(f"'{image}' is not an image of this project, try {project_images}", param_hint='image') + raise click.BadParameter(f"'{image}' is not an image of this project, try {project_images}", param_hint="image") def _expend_env(ctx, extra_env): environment = [] - env = ctx.obj['env'] + env = ctx.obj["env"] # env is allowed to be of type list and of type dict if isinstance(env, dict): for key, value in six.iteritems(env): @@ -452,25 +455,23 @@ def _expend_env(ctx, extra_env): environment.append(f"{key}={value}") elif isinstance(env, list): for item in env: - if '=' in item: + if "=" in item: # if the items is of the form 'a=b', add it to the environment list environment.append(item) else: # if the items is just a name of environment variable, try to get it # from the host's environment variables if item in os.environ: - environment.append(f'{item}={os.environ[item]}') + environment.append(f"{item}={os.environ[item]}") else: - raise TypeError(f'Type {type(env)} not supported for key env, use dict or list instead') + raise TypeError(f"Type {type(env)} not supported for key env, use dict or list instead") return environment + list(extra_env) def _get_images_to_build(ctx, images_to_build): - valid_images = ctx.obj.get('containers') or utils.get_images_from_dockerfiles() - valid_images = { - image: os.path.abspath(dockerfile) for image, dockerfile in valid_images.items() - } + valid_images = ctx.obj.get("containers") or utils.get_images_from_dockerfiles() + valid_images = {image: os.path.abspath(dockerfile) for image, dockerfile in valid_images.items()} valid_images_to_build = {} if not images_to_build: valid_images_to_build = valid_images diff --git a/skipper/runner.py b/skipper/runner.py index 94861ff..9dca49d 100644 --- a/skipper/runner.py +++ b/skipper/runner.py @@ -57,6 +57,7 @@ def _run_nested(fqdn_image, environment, command, interactive, name, net, publis homedir = os.path.expanduser('~') cmd = ['run'] if interactive: + utils.logger.info("Running in interactive mode") cmd += ['-i'] cmd += ['-e', 'SKIPPER_INTERACTIVE=True'] if name: diff --git a/tests/test_builder.py b/tests/test_builder.py index 849a3e7..b06a5c3 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -116,26 +116,27 @@ def test_build_with_use_cache(self): use_cache=True, ) expected_cmds = [ + mock.call(["pull", options.image.cache_fqdn]), mock.call( [ "build", "--network=host", - "--cache-from", - options.image.cache_fqdn, "-f", options.image.dockerfile, "-t", options.image.local, ".", + "--cache-from", + options.image.cache_fqdn, ] ), - mock.call(["pull", options.image.cache_fqdn]), mock.call(["tag", options.image.name, options.image.cache_fqdn]), + mock.call(["push", options.image.cache_fqdn]), ] result = builder.build(options, runner.run, logging.getLogger()) self.assertEqual(0, result) - runner.run.has_calls(expected_cmds) + runner.run.assert_has_calls(expected_cmds) def test_build_with_options_from_context(self): """Testing the 'build' function with options from context.""" @@ -151,13 +152,13 @@ def test_build_with_options_from_context(self): "build_args": ["test1", "test2"], "use_cache": True, } + options = BuildOptions.from_context_obj(ctx_obj) expected_cmds = [ + mock.call(["pull", "test:cache"]), mock.call( [ "build", "--network=host", - "--cache-from", - "test:test", "--build-arg", "test1", "--build-arg", @@ -167,21 +168,21 @@ def test_build_with_options_from_context(self): "--build-context", "test2", "-f", - "test", + options.image.dockerfile, "-t", "test:test", ".", + "--cache-from", + "test:cache", ] ), - mock.call(["pull", "test:test"]), - mock.call(["tag", "test", "test:test"]), + mock.call(["tag", "test", "test:cache"]), + mock.call(["push", "test:cache"]), ] - result = builder.build( - BuildOptions.from_context_obj(ctx_obj), runner.run, logging.getLogger() - ) + result = builder.build(options, runner.run, logging.getLogger()) self.assertEqual(0, result) - runner.run.has_calls(expected_cmds) + runner.run.assert_has_calls(expected_cmds) def test_build_fail(self): """Testing the 'build' function when the build fails.""" diff --git a/tests/test_cli.py b/tests/test_cli.py index b416c3a..85bf0fa 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,154 +1,163 @@ import os import unittest -import mock -from six.moves import http_client +from unittest import mock + import click import six from click import testing from requests import HTTPError +from six.moves import http_client -from skipper import cli -from skipper import config, utils -from tests.consts import REGISTRY, SKIPPER_CONF_BUILD_CONTAINER_TAG, SKIPPER_CONF_MAKEFILE, SKIPPER_CONF_BUILD_CONTAINER_IMAGE, IMAGE, TAG +from skipper import cli, config, utils +from tests.consts import ( + IMAGE, + REGISTRY, + SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + SKIPPER_CONF_BUILD_CONTAINER_TAG, + SKIPPER_CONF_MAKEFILE, + TAG, +) -BUILD_CONTAINER_IMAGE = 'build-container-image' -BUILD_CONTAINER_TAG = 'build-container-tag' -BUILD_CONTAINER_FQDN_IMAGE = REGISTRY + '/' + BUILD_CONTAINER_IMAGE + ':' + BUILD_CONTAINER_TAG +BUILD_CONTAINER_IMAGE = "build-container-image" +BUILD_CONTAINER_TAG = "build-container-tag" +BUILD_CONTAINER_FQDN_IMAGE = REGISTRY + "/" + BUILD_CONTAINER_IMAGE + ":" + BUILD_CONTAINER_TAG ENV = ["KEY1=VAL1", "KEY2=VAL2"] -ENV_FILE_PATH = '/home/envfile.env' -ENV_FILES = ['/home/envfile1.env', '/home/envfile2.env'] +ENV_FILE_PATH = "/home/envfile.env" +ENV_FILES = ["/home/envfile1.env", "/home/envfile2.env"] -SKIPPER_CONF_CONTAINER_CONTEXT = '/some/context' -SKIPPER_CONF_BUILD_CONTAINER_FQDN_IMAGE = REGISTRY + '/' + SKIPPER_CONF_BUILD_CONTAINER_IMAGE + ':' + SKIPPER_CONF_BUILD_CONTAINER_TAG +SKIPPER_CONF_CONTAINER_CONTEXT = "/some/context" +SKIPPER_CONF_BUILD_CONTAINER_FQDN_IMAGE = ( + REGISTRY + "/" + SKIPPER_CONF_BUILD_CONTAINER_IMAGE + ":" + SKIPPER_CONF_BUILD_CONTAINER_TAG +) SKIPPER_CONF = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, - } + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, + }, } SKIPPER_CONF_WITH_ENV_FILE = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'env_file': [ENV_FILE_PATH] + "env_file": [ENV_FILE_PATH], } SKIPPER_CONF_ENV = { "KEY2": "NOT_VAL2", "KEY3": "VAL3", } SKIPPER_CONF_WITH_ENV = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'env': SKIPPER_CONF_ENV + "env": SKIPPER_CONF_ENV, } SKIPPER_CONF_WITH_MULTIPLE_ENV_FILES = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'env_file': ENV_FILES + "env_file": ENV_FILES, } SKIPPER_CONF_WITH_ENV_LIST = { - 'registry': REGISTRY, - 'build-container-image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build-container-tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build-container-image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build-container-tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'env': ['key1=value1', 'key2'] + "env": ["key1=value1", "key2"], } SKIPPER_CONF_WITH_ENV_WRONG_TYPE = { - 'registry': REGISTRY, - 'build-container-image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build-container-tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build-container-image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build-container-tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'env': 'wrong-env-type', + "env": "wrong-env-type", } SKIPPER_CONF_WITH_CONTAINERS = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, + }, + "containers": { + "image1": "app1/Dockerfile", + "image2": "app2/Dockerfile", }, - 'containers': { - 'image1': 'app1/Dockerfile', - 'image2': 'app2/Dockerfile', - } } SKIPPER_CONF_WITH_VOLUMES = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'volumes': [ - 'volume1', - 'volume2', - ] + "volumes": [ + "volume1", + "volume2", + ], } SKIPPER_CONF_WITH_WORKDIR = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'workdir': 'test-workdir' + "workdir": "test-workdir", } SKIPPER_CONF_WITH_WORKSPACE = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'workspace': '/test/workspace' + "workspace": "/test/workspace", } SKIPPER_CONF_WITH_GIT_REV = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': 'git:revision', - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": "git:revision", + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, } SKIPPER_CONF_WITH_CONTEXT = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'build_container_tag': SKIPPER_CONF_BUILD_CONTAINER_TAG, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "build_container_tag": SKIPPER_CONF_BUILD_CONTAINER_TAG, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'container_context': SKIPPER_CONF_CONTAINER_CONTEXT + "container_context": SKIPPER_CONF_CONTAINER_CONTEXT, } SKIPPER_CONF_WITH_CONTEXT_NO_TAG = { - 'registry': REGISTRY, - 'build_container_image': SKIPPER_CONF_BUILD_CONTAINER_IMAGE, - 'make': { - 'makefile': SKIPPER_CONF_MAKEFILE, + "registry": REGISTRY, + "build_container_image": SKIPPER_CONF_BUILD_CONTAINER_IMAGE, + "make": { + "makefile": SKIPPER_CONF_MAKEFILE, }, - 'container_context': SKIPPER_CONF_CONTAINER_CONTEXT + "container_context": SKIPPER_CONF_CONTAINER_CONTEXT, } @@ -158,33 +167,32 @@ def setUp(self): utils.CONTAINER_RUNTIME_COMMAND = self.runtime self._runner = testing.CliRunner() self.global_params = [ - '--registry', REGISTRY, - '--build-container-image', BUILD_CONTAINER_IMAGE, - '--build-container-tag', BUILD_CONTAINER_TAG + "--registry", + REGISTRY, + "--build-container-image", + BUILD_CONTAINER_IMAGE, + "--build-container-tag", + BUILD_CONTAINER_TAG, ] def test_cli_without_params(self): result = self._invoke_cli() - self.assertEqual(result.exit_code, 0) + self.assertEqual(result.exit_code, 1) def test_cli_help(self): - result = self._invoke_cli(global_params=['--help']) + result = self._invoke_cli(global_params=["--help"]) self.assertEqual(result.exit_code, 0) def test_subcommand_help(self): - for subcmd in ('build', 'push', 'make', 'run'): - result = self._invoke_cli( - global_params=None, - subcmd=subcmd, - subcmd_params=['--help'] - ) + for subcmd in ("build", "push", "make", "run"): + result = self._invoke_cli(global_params=None, subcmd=subcmd, subcmd_params=["--help"]) self.assertEqual(result.exit_code, 0) def test_subcommand_without_global_params(self): subcmd_params_map = { - 'push': [IMAGE], - 'run': ['ls' '-l'], - 'make': ['-f', 'Makefile', 'all'], + "push": [IMAGE], + "run": ["ls-l"], + "make": ["-f", "Makefile", "all"], } for subcmd, subcmd_params in six.iteritems(subcmd_params_map): @@ -198,269 +206,348 @@ def test_subcommand_without_global_params(self): # we just verify if the exit code is not 0 self.assertNotEqual(0, result.exit_code) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_subcommand_without_subcommand_params(self, skipper_runner_run_mock): - for subcmd in ('build', 'push', 'run', 'make'): + for subcmd in ("build", "push", "run", "make"): result = self._invoke_cli(self.global_params, subcmd) self.assertNotEqual(result.exit_code, 0) self.assertFalse(skipper_runner_run_mock.called) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_existing_image(self, skipper_runner_run_mock): - build_params = ['image1'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', - '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - '/home/user/work/project' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock(autospec=True, return_value={"image1": "/home/user/work/project/Dockerfile.image1"}), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_existing_image_with_context(self, skipper_runner_run_mock): - build_params = ['image1', - '--container-context', - '/home/user/work/project'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1", "--container-context", "/home/user/work/project"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', - '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - '/home/user/work/project' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTEXT)) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTEXT)) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_with_context_from_config_file(self, skipper_runner_run_mock): - build_params = ['image1'] - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1"] + self._invoke_cli(defaults=config.load_defaults(), subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', - '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - SKIPPER_CONF_CONTAINER_CONTEXT + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + SKIPPER_CONF_CONTAINER_CONTEXT, ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTEXT_NO_TAG)) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch( + "skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTEXT_NO_TAG) + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_make_without_build_container_tag_with_context(self, skipper_runner_run_mock): global_params = self.global_params[:-2] - makefile = 'Makefile' - target = 'all' - make_params = ['-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-f", makefile, target] self._invoke_cli( - defaults=config.load_defaults(), - global_params=global_params, - subcmd='make', - subcmd_params=make_params + defaults=config.load_defaults(), global_params=global_params, subcmd="make", subcmd_params=make_params ) expected_commands = [ - mock.call(['build', '--network=host', - '-f', 'Dockerfile.build-container-image', - '-t', 'build-container-image', - SKIPPER_CONF_CONTAINER_CONTEXT], - stdout_to_stderr=True), - mock.call(['make'] + make_params, fqdn_image='build-container-image', environment=[], - interactive=False, name=None, net=None, publish=(), volumes=None, workdir=None, - use_cache=False, workspace=None, env_file=()), + mock.call( + [ + "build", + "--network=host", + "-f", + "Dockerfile.build-container-image", + "-t", + "build-container-image", + SKIPPER_CONF_CONTAINER_CONTEXT, + ], + stdout_to_stderr=True, + ), + mock.call( + ["make"] + make_params, + fqdn_image="build-container-image", + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + use_cache=False, + workspace=None, + env_file=(), + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=False)) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=False)) + @mock.patch("skipper.runner.run", autospec=True) def test_build_non_existing_image(self, skipper_runner_run_mock): - build_params = ['my_image'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + build_params = ["my_image"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) self.assertFalse(skipper_runner_run_mock.called) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_multiple_images(self, skipper_runner_run_mock): skipper_runner_run_mock.return_value = 0 - build_params = ['image1', 'image2'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1", "image2"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) expected_commands = [ - mock.call(['build', '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', '-t', - 'image1:1234567', - '/home/user/work/project']), - mock.call(['build', '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image2', '-t', - 'image2:1234567', - '/home/user/work/project']), + mock.call( + [ + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", + ] + ), + mock.call( + [ + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image2", + "-t", + "image2:1234567", + "/home/user/work/project", + ] + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands, any_order=True) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.runner.run', autospec=True, return_value=1) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock(autospec=True, return_value={"image1": "/home/user/work/project/Dockerfile.image1"}), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.runner.run", autospec=True, return_value=1) def test_build_multiple_images_with_invalid_image(self, skipper_runner_run_mock): - build_params = ['image1', 'image2'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1", "image2"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', - '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - '/home/user/work/project' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', autospec=True) - @mock.patch('skipper.runner.run', autospec=True, return_value=1) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", autospec=True) + @mock.patch("skipper.runner.run", autospec=True, return_value=1) def test_build_multiple_images_with_non_existing_dockerfile(self, skipper_runner_run_mock, os_path_exists_mock): - os_path_exists_mock.side_effect = lambda dockerfile: 'image1' in dockerfile - build_params = ['image1', 'image2'] - self._invoke_cli( - global_params=self.global_params, - subcmd='build', - subcmd_params=build_params - ) + os_path_exists_mock.side_effect = lambda dockerfile: "image1" in dockerfile + build_params = ["image1", "image2"] + self._invoke_cli(global_params=self.global_params, subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', - '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - '/home/user/work/project' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_all_images(self, skipper_runner_run_mock): self._invoke_cli( global_params=self.global_params, - subcmd='build', + subcmd="build", ) expected_commands = [ - mock.call(['build', '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', '-t', - 'image1:1234567', - '/home/user/work/project']), - mock.call(['build', '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image2', '-t', - 'image2:1234567', - '/home/user/work/project']), + mock.call( + [ + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", + ] + ), + mock.call( + [ + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image2", + "-t", + "image2:1234567", + "/home/user/work/project", + ] + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands, any_order=True) - @mock.patch('skipper.utils.get_images_from_dockerfiles', mock.MagicMock(autospec=True, - return_value={ - 'image1': '/home/user/work/project/Dockerfile.image1', - 'image2': '/home/user/work/project/Dockerfile.image2'})) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "skipper.utils.get_images_from_dockerfiles", + mock.MagicMock( + autospec=True, + return_value={ + "image1": "/home/user/work/project/Dockerfile.image1", + "image2": "/home/user/work/project/Dockerfile.image2", + }, + ), + ) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_with_defaults_from_config_file(self, skipper_runner_run_mock): - build_params = ['image1'] - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1"] + self._invoke_cli(defaults=config.load_defaults(), subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/Dockerfile.image1', - '-t', 'image1:1234567', - '/home/user/work/project' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", + "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_command) - @mock.patch('os.path.abspath', - mock.MagicMock(autospec=True, return_value='/home/user/work/project/app1/Dockerfile')) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTAINERS)) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch( + "os.path.abspath", mock.MagicMock(autospec=True, return_value="/home/user/work/project/app1/Dockerfile") + ) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch( + "skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_CONTAINERS) + ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_with_defaults_from_config_file_including_containers(self, skipper_runner_run_mock): - build_params = ['image1'] - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='build', - subcmd_params=build_params - ) + build_params = ["image1"] + self._invoke_cli(defaults=config.load_defaults(), subcmd="build", subcmd_params=build_params) expected_command = [ - 'build', - '--network=host', '--build-arg', 'TAG=1234567', - '-f', '/home/user/work/project/app1/Dockerfile', - '-t', 'image1:1234567', - '/home/user/work/project/app1' + "build", + "--network=host", + "--build-arg", + "TAG=1234567", + "-f", + "/home/user/work/project/app1/Dockerfile", + "-t", + "image1:1234567", + "/home/user/work/project/app1", ] skipper_runner_run_mock.assert_called_once_with(expected_command) @@ -472,9 +559,7 @@ def test_build_with_defaults_from_config_file_including_containers(self, skipper ), ) @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) - @mock.patch( - "skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567") - ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_with_build_args(self, skipper_runner_run_mock): build_params = ["image1"] @@ -508,9 +593,7 @@ def test_build_with_build_args(self, skipper_runner_run_mock): ), ) @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) - @mock.patch( - "skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567") - ) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_build_with_build_contexts(self, skipper_runner_run_mock): build_params = ["image1"] @@ -522,1010 +605,1001 @@ def test_build_with_build_contexts(self, skipper_runner_run_mock): expected_commands = [ "build", "--network=host", - "--build-arg", "TAG=1234567", - "--build-context", "context1=/path/to/context", - "-f", "/home/user/work/project/Dockerfile.image1", - "-t", "image1:1234567", + "--build-arg", + "TAG=1234567", + "--build-context", + "context1=/path/to/context", + "-f", + "/home/user/work/project/Dockerfile.image1", + "-t", + "image1:1234567", "/home/user/work/project", ] skipper_runner_run_mock.assert_called_once_with(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0] - push_params = ['my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_already_in_registry(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0] - push_params = ['my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb', "1234567"] + "name": "my_image", + "tags": ["latest", "aaaaaaa", "bbbbbbb", "1234567"], } requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_already_in_registry_with_force(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0] - push_params = ['my_image', "--force"] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image", "--force"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_fail(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 1] - push_params = ['my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - result = self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + result = self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) self.assertEqual(result.exit_code, 1) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True) def test_push_tag_fail(self, skipper_runner_run_mock): skipper_runner_run_mock.side_effect = [1] - push_params = ['my_image'] - result = self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + push_params = ["my_image"] + result = self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) self.assertEqual(result.exit_code, 1) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_rmi_fail(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0, 1] - push_params = ['my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - result = self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + result = self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) self.assertEqual(result.exit_code, 0) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_to_namespace(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0] - push_params = ['--namespace', 'my_namespace', 'my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["--namespace", "my_namespace", "my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='push', - subcmd_params=push_params - ) + self._invoke_cli(global_params=self.global_params, subcmd="push", subcmd_params=push_params) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_namespace/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_namespace/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_namespace/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_namespace/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_namespace/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_namespace/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) - @mock.patch('skipper.git.get_hash', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) + @mock.patch("skipper.git.get_hash", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_push_with_defaults_from_config_file(self, skipper_runner_run_mock, requests_get_mock): skipper_runner_run_mock.side_effect = [0, 0] - push_params = ['my_image'] - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + push_params = ["my_image"] + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='push', - subcmd_params=push_params - ) + self._invoke_cli(defaults=config.load_defaults(), subcmd="push", subcmd_params=push_params) expected_commands = [ - mock.call(['tag', 'my_image:1234567', 'registry.io:5000/my_image:1234567']), - mock.call(['push', 'registry.io:5000/my_image:1234567']), - mock.call(['rmi', 'registry.io:5000/my_image:1234567']), + mock.call(["tag", "my_image:1234567", "registry.io:5000/my_image:1234567"]), + mock.call(["push", "registry.io:5000/my_image:1234567"]), + mock.call(["rmi", "registry.io:5000/my_image:1234567"]), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('subprocess.check_output', autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("subprocess.check_output", autospec=True) def test_images_with_single_local_results(self, subprocess_check_output_mock, tabulate_mock): subprocess_check_output_mock.return_value = '{"name": "my_image", "tag": "1234567"}' - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=[] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=[]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image' + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - tabulate_mock.assert_called_once_with([['none', 'my_image', '1234567']], headers=['REGISTRY', 'IMAGE', 'TAG'], - tablefmt='grid') + tabulate_mock.assert_called_once_with( + [["none", "my_image", "1234567"]], headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid" + ) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.image1', 'Dockerfile.image2'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('subprocess.check_output', autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.image1", "Dockerfile.image2"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("subprocess.check_output", autospec=True) def test_images_with_multiple_local_results(self, subprocess_check_output_mock, tabulate_mock): subprocess_check_output_mock.side_effect = [ '{"name": "image1", "tag": "aaaaaaa"}\n', '{"name": "image2", "tag": "bbbbbbb"}\n{"name": "image2", "tag": "ccccccc"}\n', ] - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=[] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=[]) command_prefix = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', ] expected_check_output_calls = [ - mock.call(command_prefix + ['image1']), - mock.call(command_prefix + ['image2']), + mock.call(command_prefix + ["image1"]), + mock.call(command_prefix + ["image2"]), ] subprocess_check_output_mock.assert_has_calls(expected_check_output_calls, any_order=True) expected_table = [ - ['none', 'image1', 'aaaaaaa'], - ['none', 'image2', 'bbbbbbb'], - ['none', 'image2', 'ccccccc'], + ["none", "image1", "aaaaaaa"], + ["none", "image2", "bbbbbbb"], + ["none", "image2", "ccccccc"], ] - tabulate_mock.assert_called_once_with(expected_table, headers=['REGISTRY', 'IMAGE', 'TAG'], tablefmt='grid') - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('requests.get', autospec=True) - @mock.patch('subprocess.check_output', autospec=True) - def test_images_with_all_results(self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, - requests_bearer_auth_mock): + tabulate_mock.assert_called_once_with(expected_table, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid") + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("requests.get", autospec=True) + @mock.patch("subprocess.check_output", autospec=True) + def test_images_with_all_results( + self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, requests_bearer_auth_mock + ): subprocess_check_output_mock.return_value = '{"name": "my_image", "tag": "aaaaaaa"}' - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=['-r'] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=["-r"]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - expected_url = 'https://%(registry)s/v2/my_image/tags/list' % dict(registry=REGISTRY) - requests_get_mock.assert_called_once_with( - url=expected_url, - auth=requests_bearer_auth_mock(), - verify=False - ) + expected_url = "https://%(registry)s/v2/my_image/tags/list" % dict(registry=REGISTRY) + requests_get_mock.assert_called_once_with(url=expected_url, auth=requests_bearer_auth_mock(), verify=False) expected_images_results = [ - ['none', 'my_image', 'aaaaaaa'], - ['registry.io:5000', 'my_image', 'latest'], - ['registry.io:5000', 'my_image', 'aaaaaaa'], - ['registry.io:5000', 'my_image', 'bbbbbbb'] + ["none", "my_image", "aaaaaaa"], + ["registry.io:5000", "my_image", "latest"], + ["registry.io:5000", "my_image", "aaaaaaa"], + ["registry.io:5000", "my_image", "bbbbbbb"], ] - tabulate_mock.assert_called_once_with(expected_images_results, headers=['REGISTRY', 'IMAGE', 'TAG'], - tablefmt='grid') - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('requests.get', autospec=True) - @mock.patch('subprocess.check_output', autospec=True, return_value='') - def test_images_with_remote_results_only(self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, - requests_bearer_auth_mock): - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + tabulate_mock.assert_called_once_with( + expected_images_results, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid" + ) + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("requests.get", autospec=True) + @mock.patch("subprocess.check_output", autospec=True, return_value="") + def test_images_with_remote_results_only( + self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, requests_bearer_auth_mock + ): + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=['-r'] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=["-r"]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - expected_url = 'https://%(registry)s/v2/my_image/tags/list' % dict(registry=REGISTRY) - requests_get_mock.assert_called_once_with( - url=expected_url, - verify=False, - auth=requests_bearer_auth_mock() - ) + expected_url = "https://%(registry)s/v2/my_image/tags/list" % dict(registry=REGISTRY) + requests_get_mock.assert_called_once_with(url=expected_url, verify=False, auth=requests_bearer_auth_mock()) expected_images_results = [ - ['registry.io:5000', 'my_image', 'latest'], - ['registry.io:5000', 'my_image', 'aaaaaaa'], - ['registry.io:5000', 'my_image', 'bbbbbbb'] + ["registry.io:5000", "my_image", "latest"], + ["registry.io:5000", "my_image", "aaaaaaa"], + ["registry.io:5000", "my_image", "bbbbbbb"], ] - tabulate_mock.assert_called_once_with(expected_images_results, headers=['REGISTRY', 'IMAGE', 'TAG'], - tablefmt='grid') - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('requests.get', autospec=True) - @mock.patch('subprocess.check_output', autospec=True, return_value='') - def test_images_with_missing_remote_results(self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, - requests_bearer_auth_mock): - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + tabulate_mock.assert_called_once_with( + expected_images_results, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid" + ) + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("requests.get", autospec=True) + @mock.patch("subprocess.check_output", autospec=True, return_value="") + def test_images_with_missing_remote_results( + self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, requests_bearer_auth_mock + ): + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value requests_response_mock.ok = False requests_response_mock.json.return_value = { - u'errors': [{u'message': u'repository name not known to registry', u'code': u'NAME_UNKNOWN', - u'detail': {u'name': u'my_image'}}] + "errors": [ + { + "message": "repository name not known to registry", + "code": "NAME_UNKNOWN", + "detail": {"name": "my_image"}, + } + ] } requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=['-r'] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=["-r"]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - expected_url = 'https://%(registry)s/v2/my_image/tags/list' % dict(registry=REGISTRY) - requests_get_mock.assert_called_once_with( - url=expected_url, - verify=False, - auth=requests_bearer_auth_mock() - ) + expected_url = "https://%(registry)s/v2/my_image/tags/list" % dict(registry=REGISTRY) + requests_get_mock.assert_called_once_with(url=expected_url, verify=False, auth=requests_bearer_auth_mock()) expected_images_results = [] - tabulate_mock.assert_called_once_with(expected_images_results, headers=['REGISTRY', 'IMAGE', 'TAG'], - tablefmt='grid') - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('requests.get', autospec=True) - @mock.patch('subprocess.check_output', autospec=True) - def test_images_with_local_result_and_missing_remote_results(self, subprocess_check_output_mock, requests_get_mock, - tabulate_mock, requests_bearer_auth_mock): + tabulate_mock.assert_called_once_with( + expected_images_results, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid" + ) + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("requests.get", autospec=True) + @mock.patch("subprocess.check_output", autospec=True) + def test_images_with_local_result_and_missing_remote_results( + self, subprocess_check_output_mock, requests_get_mock, tabulate_mock, requests_bearer_auth_mock + ): subprocess_check_output_mock.return_value = '{"name": "my_image", "tag": "aaaaaaa"}' - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value requests_response_mock.ok = False requests_response_mock.json.return_value = { - u'errors': [{u'message': u'repository name not known to registry', u'code': u'NAME_UNKNOWN', - u'detail': {u'name': u'my_image'}}] + "errors": [ + { + "message": "repository name not known to registry", + "code": "NAME_UNKNOWN", + "detail": {"name": "my_image"}, + } + ] } requests_get_mock.return_value = requests_response_mock - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=['-r'] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=["-r"]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - expected_url = 'https://%(registry)s/v2/my_image/tags/list' % dict(registry=REGISTRY) - requests_get_mock.assert_called_once_with( - url=expected_url, - verify=False, - auth=requests_bearer_auth_mock() - ) + expected_url = "https://%(registry)s/v2/my_image/tags/list" % dict(registry=REGISTRY) + requests_get_mock.assert_called_once_with(url=expected_url, verify=False, auth=requests_bearer_auth_mock()) expected_images_results = [ - ['none', 'my_image', 'aaaaaaa'], + ["none", "my_image", "aaaaaaa"], ] - tabulate_mock.assert_called_once_with(expected_images_results, headers=['REGISTRY', 'IMAGE', 'TAG'], - tablefmt='grid') - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', mock.MagicMock(autospec=True)) - @mock.patch('requests.get', autospec=True) - @mock.patch('subprocess.check_output', autospec=True, return_value='') - def test_images_with_with_remote_error(self, subprocess_check_output_mock, requests_get_mock, - requests_bearer_auth_mock): - with mock.patch('requests.Response', autospec=True) as requests_response_class_mock: + tabulate_mock.assert_called_once_with( + expected_images_results, headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid" + ) + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", mock.MagicMock(autospec=True)) + @mock.patch("requests.get", autospec=True) + @mock.patch("subprocess.check_output", autospec=True, return_value="") + def test_images_with_with_remote_error( + self, subprocess_check_output_mock, requests_get_mock, requests_bearer_auth_mock + ): + with mock.patch("requests.Response", autospec=True) as requests_response_class_mock: requests_response_mock = requests_response_class_mock.return_value requests_response_mock.ok = False requests_response_mock.json.return_value = { - u'errors': [{u'message': u'repository name not known to registry', u'code': u'UNKNOWN_ERROR', - u'detail': {u'name': u'my_image'}}] + "errors": [ + { + "message": "repository name not known to registry", + "code": "UNKNOWN_ERROR", + "detail": {"name": "my_image"}, + } + ] } requests_get_mock.return_value = requests_response_mock - result = self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=['-r'] - ) + result = self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=["-r"]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - expected_url = 'https://%(registry)s/v2/my_image/tags/list' % dict(registry=REGISTRY) - requests_get_mock.assert_called_once_with( - url=expected_url, - verify=False, - auth=requests_bearer_auth_mock() - ) + expected_url = "https://%(registry)s/v2/my_image/tags/list" % dict(registry=REGISTRY) + requests_get_mock.assert_called_once_with(url=expected_url, verify=False, auth=requests_bearer_auth_mock()) self.assertIsInstance(result.exception, click.exceptions.ClickException) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('tabulate.tabulate', autospec=True) - @mock.patch('subprocess.check_output', autospec=True, return_value='') + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("tabulate.tabulate", autospec=True) + @mock.patch("subprocess.check_output", autospec=True, return_value="") def test_images_without_local_results(self, subprocess_check_output_mock, tabulate_mock): - self._invoke_cli( - global_params=self.global_params, - subcmd='images', - subcmd_params=[] - ) + self._invoke_cli(global_params=self.global_params, subcmd="images", subcmd_params=[]) expected_command = [ - 'docker', - 'images', - '--format', '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', - 'my_image', + "docker", + "images", + "--format", + '{"name": "{{.Repository}}", "tag": "{{.Tag}}"}', + "my_image", ] subprocess_check_output_mock.assert_called_once_with(expected_command) - tabulate_mock.assert_called_once_with([], headers=['REGISTRY', 'IMAGE', 'TAG'], tablefmt='grid') + tabulate_mock.assert_called_once_with([], headers=["REGISTRY", "IMAGE", "TAG"], tablefmt="grid") - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.my_image'])) - @mock.patch('subprocess.check_output', autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile.my_image"])) + @mock.patch("subprocess.check_output", autospec=True) def test_rmi_local(self, subprocess_check_output_mock): - self._invoke_cli( - global_params=self.global_params, - subcmd='rmi', - subcmd_params=['my_image', '1234567'] - ) + self._invoke_cli(global_params=self.global_params, subcmd="rmi", subcmd_params=["my_image", "1234567"]) - expected_command = [ - 'docker', - 'rmi', - u'my_image:1234567' - ] + expected_command = ["docker", "rmi", "my_image:1234567"] subprocess_check_output_mock.assert_called_once_with(expected_command) - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.' + IMAGE])) - @mock.patch('requests.delete', autospec=True) - @mock.patch('requests.get', autospec=True) + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile." + IMAGE])) + @mock.patch("requests.delete", autospec=True) + @mock.patch("requests.get", autospec=True) def test_rmi_remote(self, requests_get_mock, requests_delete_mock, requests_bearer_auth_mock): - requests_get_mock.side_effect = [mock.Mock(headers={'Docker-Content-Digest': 'digest'})] + requests_get_mock.side_effect = [mock.Mock(headers={"Docker-Content-Digest": "digest"})] requests_delete_mock.side_effect = [mock.Mock(ok=True)] - self._invoke_cli( - global_params=self.global_params, - subcmd='rmi', - subcmd_params=['-r', IMAGE, TAG] - ) + self._invoke_cli(global_params=self.global_params, subcmd="rmi", subcmd_params=["-r", IMAGE, TAG]) - url = 'https://%(registry)s/v2/%(image)s/manifests/%(reference)s' % dict(registry=REGISTRY, image=IMAGE, - reference=TAG) + url = "https://%(registry)s/v2/%(image)s/manifests/%(reference)s" % dict( + registry=REGISTRY, image=IMAGE, reference=TAG + ) headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"} - requests_get_mock.assert_called_once_with(url=url, headers=headers, verify=False, - auth=requests_bearer_auth_mock()) - url = 'https://%(registry)s/v2/%(image)s/manifests/%(reference)s' % dict(registry=REGISTRY, image=IMAGE, - reference='digest') - requests_delete_mock.assert_called_once_with(url=url, verify=False, - auth=requests_bearer_auth_mock()) - - @mock.patch('skipper.utils.HttpBearerAuth', autospec=True) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.' + IMAGE])) - @mock.patch('requests.delete', autospec=True) - @mock.patch('requests.get', autospec=True) + requests_get_mock.assert_called_once_with( + url=url, headers=headers, verify=False, auth=requests_bearer_auth_mock() + ) + url = "https://%(registry)s/v2/%(image)s/manifests/%(reference)s" % dict( + registry=REGISTRY, image=IMAGE, reference="digest" + ) + requests_delete_mock.assert_called_once_with(url=url, verify=False, auth=requests_bearer_auth_mock()) + + @mock.patch("skipper.utils.HttpBearerAuth", autospec=True) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile." + IMAGE])) + @mock.patch("requests.delete", autospec=True) + @mock.patch("requests.get", autospec=True) def test_rmi_remote_fail(self, requests_get_mock, requests_delete_mock, requests_bearer_auth_mock): - requests_get_mock.side_effect = [mock.Mock(headers={'Docker-Content-Digest': 'digest'})] + requests_get_mock.side_effect = [mock.Mock(headers={"Docker-Content-Digest": "digest"})] requests_delete_mock.side_effect = HTTPError() - result = self._invoke_cli( - global_params=self.global_params, - subcmd='rmi', - subcmd_params=['-r', IMAGE, TAG] - ) + result = self._invoke_cli(global_params=self.global_params, subcmd="rmi", subcmd_params=["-r", IMAGE, TAG]) self.assertIsInstance(result.exception, Exception) - url = 'https://%(registry)s/v2/%(image)s/manifests/%(reference)s' % dict(registry=REGISTRY, image=IMAGE, - reference=TAG) + url = "https://%(registry)s/v2/%(image)s/manifests/%(reference)s" % dict( + registry=REGISTRY, image=IMAGE, reference=TAG + ) headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"} - requests_get_mock.assert_called_once_with(url=url, headers=headers, verify=False, - auth=requests_bearer_auth_mock()) - url = 'https://%(registry)s/v2/%(image)s/manifests/%(reference)s' % dict(registry=REGISTRY, image=IMAGE, - reference='digest') + requests_get_mock.assert_called_once_with( + url=url, headers=headers, verify=False, auth=requests_bearer_auth_mock() + ) + url = "https://%(registry)s/v2/%(image)s/manifests/%(reference)s" % dict( + registry=REGISTRY, image=IMAGE, reference="digest" + ) requests_delete_mock.assert_called_once_with(url=url, verify=False, auth=requests_bearer_auth_mock()) - @mock.patch('glob.glob', mock.MagicMock(autospec=True, return_value=['Dockerfile.' + IMAGE])) + @mock.patch("glob.glob", mock.MagicMock(autospec=True, return_value=["Dockerfile." + IMAGE])) def test_validate_project_image(self): result = self._invoke_cli( - global_params=self.global_params, - subcmd='rmi', - subcmd_params=['-r', 'non-project-image', TAG] + global_params=self.global_params, subcmd="rmi", subcmd_params=["-r", "non-project-image", TAG] ) self.assertIsInstance(result.exception, click.BadParameter) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_existing_local_build_container(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_image_name = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_image_name, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('requests.get', autospec=True) - @mock.patch('skipper.runner.run', autospec=True) + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_image_name = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_image_name, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch("requests.get", autospec=True) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_existing_remote_build_container(self, skipper_runner_run_mock, requests_get_mock): - requests_response_class_mock = mock.MagicMock(spec='requests.Response') + requests_response_class_mock = mock.MagicMock(spec="requests.Response") requests_response_mock = requests_response_class_mock.return_value requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb', 'build-container-tag'] + "name": "my_image", + "tags": ["latest", "aaaaaaa", "bbbbbbb", "build-container-tag"], } requests_response_mock.status_code = http_client.OK requests_get_mock.return_value = requests_response_mock - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_image_name = 'registry.io:5000/build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_image_name, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('skipper.runner.run', mock.MagicMock(autospec=True)) - @mock.patch('requests.get', autospec=True) + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_image_name = "registry.io:5000/build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_image_name, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch("skipper.runner.run", mock.MagicMock(autospec=True)) + @mock.patch("requests.get", autospec=True) def test_run_with_non_existing_build_container(self, requests_get_mock): - requests_response_class_mock = mock.MagicMock(spec='requests.Response') + requests_response_class_mock = mock.MagicMock(spec="requests.Response") requests_response_mock = requests_response_class_mock.return_value - requests_response_mock.json.return_value = { - 'name': 'my_image', - 'tags': ['latest', 'aaaaaaa', 'bbbbbbb'] - } + requests_response_mock.json.return_value = {"name": "my_image", "tags": ["latest", "aaaaaaa", "bbbbbbb"]} requests_get_mock.return_value = requests_response_mock - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - ret = self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) + ret = self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) self.assertIsInstance(ret.exception, click.exceptions.ClickException) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_defaults_from_config_file(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) - def test_run_with_defaults_and_env_from_env_file( - self, - skipper_runner_run_mock - ): - command = ['ls', '-l'] + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) + def test_run_with_defaults_and_env_from_env_file(self, skipper_runner_run_mock): + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=SKIPPER_CONF_WITH_ENV_FILE, - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=SKIPPER_CONF_WITH_ENV_FILE, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(ENV_FILE_PATH,), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, - fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, - name=None, net=None, publish=(), - volumes=None, - workdir=None, - workspace=None, - use_cache=False, - env_file=(ENV_FILE_PATH,)) - - @mock.patch('os.path.exists', - mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('subprocess.check_output', - mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) - def test_run_with_defaults_and_env_from_multiple_env_file( - self, - skipper_runner_run_mock - ): - command = ['ls', '-l'] + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) + def test_run_with_defaults_and_env_from_multiple_env_file(self, skipper_runner_run_mock): + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=SKIPPER_CONF_WITH_MULTIPLE_ENV_FILES, - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=SKIPPER_CONF_WITH_MULTIPLE_ENV_FILES, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=tuple(ENV_FILES), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, - fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, - name=None, net=None, publish=(), - volumes=None, - workdir=None, - workspace=None, - use_cache=False, - env_file=tuple(ENV_FILES)) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_env_overriding_config_file(self, skipper_runner_run_mock): - command = ['ls', '-l'] - run_params = ['-e', ENV[0], '-e', ENV[1]] + command - self._invoke_cli( - defaults=SKIPPER_CONF_WITH_ENV, - subcmd='run', - subcmd_params=run_params - ) - env = [f'{key}={value}' for key, value in six.iteritems(SKIPPER_CONF_ENV)] + ENV - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=env, - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('builtins.open', mock.MagicMock(create=True)) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('os.environ', {}) - @mock.patch('yaml.safe_load', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_LIST)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + command = ["ls", "-l"] + run_params = ["-e", ENV[0], "-e", ENV[1]] + command + self._invoke_cli(defaults=SKIPPER_CONF_WITH_ENV, subcmd="run", subcmd_params=run_params) + env = [f"{key}={value}" for key, value in six.iteritems(SKIPPER_CONF_ENV)] + ENV + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=env, + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("builtins.open", mock.MagicMock(create=True)) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("os.environ", {}) + @mock.patch("yaml.safe_load", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_LIST)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_env_list(self, skipper_runner_run_mock): - os.environ['VAL4'] = "val4-evaluation" - command = ['ls', '-l'] - run_params = ['-e', ENV[0], '-e', ENV[1]] + command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params - ) - env = ['key1=value1'] + ENV - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=env, - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('builtins.open', mock.MagicMock(create=True)) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('os.environ', {'key2': 'value2'}) - @mock.patch('yaml.safe_load', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_LIST)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + os.environ["VAL4"] = "val4-evaluation" + command = ["ls", "-l"] + run_params = ["-e", ENV[0], "-e", ENV[1]] + command + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + env = ["key1=value1"] + ENV + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=env, + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("builtins.open", mock.MagicMock(create=True)) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("os.environ", {"key2": "value2"}) + @mock.patch("yaml.safe_load", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_LIST)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_env_list_get_from_env(self, skipper_runner_run_mock): - os.environ['VAL4'] = "val4-evaluation" - command = ['ls', '-l'] - run_params = ['-e', ENV[0], '-e', ENV[1]] + command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params - ) - env = ['key1=value1', 'key2=value2'] + ENV - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=env, - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('builtins.open', mock.MagicMock(create=True)) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('yaml.safe_load', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_WRONG_TYPE)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + os.environ["VAL4"] = "val4-evaluation" + command = ["ls", "-l"] + run_params = ["-e", ENV[0], "-e", ENV[1]] + command + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + env = ["key1=value1", "key2=value2"] + ENV + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=env, + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("builtins.open", mock.MagicMock(create=True)) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("yaml.safe_load", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_ENV_WRONG_TYPE)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_env_wrong_type(self, skipper_runner_run_mock): - os.environ['VAL4'] = "val4-evaluation" - command = ['ls', '-l'] - run_params = ['-e', ENV[0], '-e', ENV[1]] + command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params - ) + os.environ["VAL4"] = "val4-evaluation" + command = ["ls", "-l"] + run_params = ["-e", ENV[0], "-e", ENV[1]] + command + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) self.assertEqual(len(skipper_runner_run_mock.mock_calls), 0) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_env(self, skipper_runner_run_mock): - command = ['ls', '-l'] - os.environ['VAL4'] = "val4-evaluation" - run_params = ['-e', ENV[0], '-e', ENV[1]] + command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=ENV, - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + command = ["ls", "-l"] + os.environ["VAL4"] = "val4-evaluation" + run_params = ["-e", ENV[0], "-e", ENV[1]] + command + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=ENV, + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_interactive_from_environment(self, skipper_runner_run_mock): - os.environ['SKIPPER_INTERACTIVE'] = 'True' - command = ['ls', '-l'] + os.environ["SKIPPER_INTERACTIVE"] = "True" + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=True, name=None, net=None, publish=(), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - del os.environ['SKIPPER_INTERACTIVE'] - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=True, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + del os.environ["SKIPPER_INTERACTIVE"] + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_non_interactive_from_environment(self, skipper_runner_run_mock): - os.environ['SKIPPER_INTERACTIVE'] = 'False' - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - del os.environ['SKIPPER_INTERACTIVE'] - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_non_interactive(self, skipper_runner_run_mock): - command = ['ls', '-l'] - run_params = ['--interactive'] + command - self._invoke_cli( - global_params=self.global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=True, name=None, net=None, publish=(), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('skipper.utils.image_to_dockerfile', mock.MagicMock(autospec=True, side_effect=lambda x: 'Dockerfile.'+x)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + command = ["ls", "-l"] + run_params = ["--interactive"] + command + self._invoke_cli(global_params=self.global_params, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=True, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch( + "skipper.utils.image_to_dockerfile", mock.MagicMock(autospec=True, side_effect=lambda x: "Dockerfile." + x) + ) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_run_without_build_container_tag(self, skipper_runner_run_mock): global_params = self.global_params[:-2] - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=global_params, - subcmd='run', - subcmd_params=run_params - ) + self._invoke_cli(global_params=global_params, subcmd="run", subcmd_params=run_params) expected_commands = [ - mock.call(['build', '--network=host', - '-f', 'Dockerfile.build-container-image', - '-t', 'build-container-image', '.'], - stdout_to_stderr=True), - mock.call(command, fqdn_image='build-container-image', environment=[], - interactive=False, name=None, net=None, publish=(), volumes=None, workdir=None, workspace=None, - use_cache=False, env_file=()), + mock.call( + [ + "build", + "--network=host", + "-f", + "Dockerfile.build-container-image", + "-t", + "build-container-image", + ".", + ], + stdout_to_stderr=True, + ), + mock.call( + command, + fqdn_image="build-container-image", + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('skipper.utils.image_to_dockerfile', mock.MagicMock(autospec=True, side_effect=lambda x: 'Dockerfile.'+x)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch( + "skipper.utils.image_to_dockerfile", mock.MagicMock(autospec=True, side_effect=lambda x: "Dockerfile." + x) + ) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_run_without_build_container_tag_cached(self, skipper_runner_run_mock): global_params = self.global_params[:-2] - command = ['ls', '-l'] - run_params = ['--cache'] + command - self._invoke_cli( - global_params=global_params, - subcmd='run', - subcmd_params=run_params - ) + command = ["ls", "-l"] + run_params = ["--cache"] + command + self._invoke_cli(global_params=global_params, subcmd="run", subcmd_params=run_params) expected_commands = [ - mock.call(command, fqdn_image='build-container-image', environment=[], - interactive=False, name=None, net=None, publish=(), volumes=None, workdir=None, workspace=None, - use_cache=True, env_file=()), + mock.call( + command, + fqdn_image="build-container-image", + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=True, + env_file=(), + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_non_default_net(self, skipper_runner_run_mock): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] - command = ['ls', '-l'] + global_params += ["--build-container-net", "non-default-net"] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - global_params=global_params, - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net='non-default-net', - publish=(), volumes=None, workdir=None, workspace=None, - use_cache=False, env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True) + self._invoke_cli(global_params=global_params, subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net="non-default-net", + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_publish_single_port(self, skipper_runner_run_mock): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] - - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123:123', '-f', makefile, target] - - self._invoke_cli( - global_params=global_params, - subcmd='make', - subcmd_params=make_params - ) - - expected_command = ['make', '-f', makefile, target] - - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=u'non-default-net', - publish=(u'123:123',), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True) + global_params += ["--build-container-net", "non-default-net"] + + makefile = "Makefile" + target = "all" + make_params = ["-p", "123:123", "-f", makefile, target] + + self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) + + expected_command = ["make", "-f", makefile, target] + + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net="non-default-net", + publish=("123:123",), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_publish_multiple_ports(self, skipper_runner_run_mock): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] - - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123:123', '-p', '12:12', '-f', makefile, target] - - self._invoke_cli( - global_params=global_params, - subcmd='make', - subcmd_params=make_params - ) - - expected_command = ['make', '-f', makefile, target] - - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=u'non-default-net', - publish=('123:123', '12:12'), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567')) - @mock.patch('skipper.runner.run', autospec=True) + global_params += ["--build-container-net", "non-default-net"] + + makefile = "Makefile" + target = "all" + make_params = ["-p", "123:123", "-p", "12:12", "-f", makefile, target] + + self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) + + expected_command = ["make", "-f", makefile, target] + + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net="non-default-net", + publish=("123:123", "12:12"), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_publish_port_range(self, skipper_runner_run_mock): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] + global_params += ["--build-container-net", "non-default-net"] - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123:123', '-p', '12-13:12-13', '-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-p", "123:123", "-p", "12-13:12-13", "-f", makefile, target] - self._invoke_cli( - global_params=global_params, - subcmd='make', - subcmd_params=make_params - ) + self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) - expected_command = ['make', '-f', makefile, target] + expected_command = ["make", "-f", makefile, target] - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=u'non-default-net', - publish=('123:123', '12-13:12-13'), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net="non-default-net", + publish=("123:123", "12-13:12-13"), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) def test_run_with_publish_textual_port(self): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] + global_params += ["--build-container-net", "non-default-net"] - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123:a1', '-p', '12:12', '-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-p", "123:a1", "-p", "12:12", "-f", makefile, target] - result = self._invoke_cli(global_params=global_params, subcmd='make', subcmd_params=make_params) + result = self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) self.assertIsInstance(result.exception, click.BadParameter) self.assertEqual("Publish need to be in format port:port or port-port:port-port", result.exception.message) # since click testing module messes up exit code @@ -1534,13 +1608,13 @@ def test_run_with_publish_textual_port(self): def test_run_with_publish_textual_port_range(self): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] + global_params += ["--build-container-net", "non-default-net"] - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123-1:1-a1', '-p', '12:12', '-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-p", "123-1:1-a1", "-p", "12:12", "-f", makefile, target] - result = self._invoke_cli(global_params=global_params, subcmd='make', subcmd_params=make_params) + result = self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) self.assertIsInstance(result.exception, click.BadParameter) self.assertEqual("Publish need to be in format port:port or port-port:port-port", result.exception.message) # since click testing module messes up exit code @@ -1549,21 +1623,21 @@ def test_run_with_publish_textual_port_range(self): def test_run_with_invalid_port_range(self): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] + global_params += ["--build-container-net", "non-default-net"] - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '15-25:25-15', '-p', '12:12', '-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-p", "15-25:25-15", "-p", "12:12", "-f", makefile, target] - result = self._invoke_cli(global_params=global_params, subcmd='make', subcmd_params=make_params) + result = self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) self.assertIsInstance(result.exception, click.BadParameter) self.assertEqual("Invalid port range: 25 should be bigger than 15", result.exception.message) # since click testing module messes up exit code # we just verify if the exit code is not 0 self.assertNotEqual(0, result.exit_code) - make_params = ['-p', '25-15:15-25', '-p', '12:12', '-f', makefile, target] - result = self._invoke_cli(global_params=global_params, subcmd='make', subcmd_params=make_params) + make_params = ["-p", "25-15:15-25", "-p", "12:12", "-f", makefile, target] + result = self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) self.assertIsInstance(result.exception, click.BadParameter) self.assertEqual("Invalid port range: 25 should be bigger than 15", result.exception.message) # since click testing module messes up exit code @@ -1572,242 +1646,317 @@ def test_run_with_invalid_port_range(self): def test_run_with_publish_out_of_range_port(self): global_params = self.global_params - global_params += ['--build-container-net', 'non-default-net'] + global_params += ["--build-container-net", "non-default-net"] - makefile = 'Makefile' - target = 'all' - make_params = ['-p', '123:1', '-p', '12:121111111', '-f', makefile, target] + makefile = "Makefile" + target = "all" + make_params = ["-p", "123:1", "-p", "12:121111111", "-f", makefile, target] - result = self._invoke_cli(global_params=global_params, subcmd='make', subcmd_params=make_params) + result = self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) self.assertIsInstance(result.exception, click.BadParameter) self.assertEqual("Invalid port number: port 121111111 is out of range", result.exception.message) # since click testing module messes up exit code # we just verify if the exit code is not 0 self.assertNotEqual(0, result.exit_code) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_VOLUMES)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_VOLUMES)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_defaults_from_config_file_including_volumes(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=["volume1", "volume2"], + workspace=None, + workdir=None, + use_cache=False, + env_file=(), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=['volume1', 'volume2'], workspace=None, - workdir=None, use_cache=False, env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_WORKDIR)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_WORKDIR)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_defaults_from_config_file_including_workdir(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir="test-workdir", + workspace=None, + use_cache=False, + env_file=(), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir='test-workdir', workspace=None, use_cache=False, - env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_WORKSPACE)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_WORKSPACE)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_defaults_from_config_file_including_workspace(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace="/test/workspace", + use_cache=False, + env_file=(), ) - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace="/test/workspace", use_cache=False, - env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_GIT_REV)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value=b'1234567\n')) - @mock.patch('skipper.git.uncommitted_changes', mock.MagicMock(return_value=True)) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_GIT_REV)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value=b"1234567\n")) + @mock.patch("skipper.git.uncommitted_changes", mock.MagicMock(return_value=True)) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_config_including_git_revision_with_uncommitted_changes(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:1234567" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + use_cache=False, + workspace=None, + env_file=(), ) - expected_fqdn_image = 'skipper-conf-build-container-image:1234567' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, use_cache=False, workspace=None, - env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_GIT_REV)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value=b'1234567\n')) - @mock.patch('skipper.git.uncommitted_changes', mock.MagicMock(return_value=False)) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF_WITH_GIT_REV)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value=b"1234567\n")) + @mock.patch("skipper.git.uncommitted_changes", mock.MagicMock(return_value=False)) + @mock.patch("skipper.runner.run", autospec=True) def test_run_with_config_including_git_revision_without_uncommitted_changes(self, skipper_runner_run_mock): - command = ['ls', '-l'] + command = ["ls", "-l"] run_params = command - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='run', - subcmd_params=run_params - ) - expected_fqdn_image = 'skipper-conf-build-container-image:1234567' - skipper_runner_run_mock.assert_called_once_with(command, fqdn_image=expected_fqdn_image, environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + self._invoke_cli(defaults=config.load_defaults(), subcmd="run", subcmd_params=run_params) + expected_fqdn_image = "skipper-conf-build-container-image:1234567" + skipper_runner_run_mock.assert_called_once_with( + command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_make(self, skipper_runner_run_mock): - makefile = 'Makefile' - target = 'all' - make_params = ['-f', makefile, target] - self._invoke_cli( - global_params=self.global_params, - subcmd='make', - subcmd_params=make_params - ) - expected_command = ['make', '-f', makefile, target] - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + makefile = "Makefile" + target = "all" + make_params = ["-f", makefile, target] + self._invoke_cli(global_params=self.global_params, subcmd="make", subcmd_params=make_params) + expected_command = ["make", "-f", makefile, target] + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_make_with_default_params(self, skipper_runner_run_mock): self._invoke_cli( global_params=self.global_params, - subcmd='make', - ) - expected_command = ['make', '-f', "Makefile"] - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + subcmd="make", + ) + expected_command = ["make", "-f", "Makefile"] + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_make_with_additional_make_params(self, skipper_runner_run_mock): - target = 'all' - make_params = ['-j', '4', target, 'OS=linux'] - self._invoke_cli( - global_params=self.global_params, - subcmd='make', - subcmd_params=make_params + target = "all" + make_params = ["-j", "4", target, "OS=linux"] + res = self._invoke_cli(global_params=self.global_params, subcmd="make", subcmd_params=make_params) + self.assertEqual(res.exit_code, 0, res.exc_info) + expected_command = ["make", "-f", "Makefile"] + make_params + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), ) - expected_command = ['make', '-f', 'Makefile', '-j', '4', target, 'OS=linux'] - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('skipper.config.load_defaults', mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("skipper.config.load_defaults", mock.MagicMock(autospec=True, return_value=SKIPPER_CONF)) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_make_with_defaults_from_config_file(self, skipper_runner_run_mock): - makefile = 'Makefile' - target = 'all' - make_params = ['-f', makefile, target] - self._invoke_cli( - defaults=config.load_defaults(), - subcmd='make', - subcmd_params=make_params - ) - expected_command = ['make', '-f', makefile, target] - expected_fqdn_image = 'skipper-conf-build-container-image:skipper-conf-build-container-tag' - skipper_runner_run_mock.assert_called_once_with(expected_command, fqdn_image=expected_fqdn_image, - environment=[], - interactive=False, name=None, net=None, publish=(), - volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='')) - @mock.patch('skipper.utils.image_to_dockerfile', mock.MagicMock(autospec=True, side_effect=lambda x: 'Dockerfile.'+x)) - @mock.patch('skipper.runner.run', autospec=True, return_value=0) + makefile = "Makefile" + target = "all" + make_params = ["-f", makefile, target] + self._invoke_cli(defaults=config.load_defaults(), subcmd="make", subcmd_params=make_params) + expected_command = ["make", "-f", makefile, target] + expected_fqdn_image = "skipper-conf-build-container-image:skipper-conf-build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + expected_command, + fqdn_image=expected_fqdn_image, + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="")) + @mock.patch( + "skipper.utils.image_to_dockerfile", mock.MagicMock(autospec=True, side_effect=lambda x: "Dockerfile." + x) + ) + @mock.patch("skipper.runner.run", autospec=True, return_value=0) def test_make_without_build_container_tag(self, skipper_runner_run_mock): global_params = self.global_params[:-2] - makefile = 'Makefile' - target = 'all' - make_params = ['-f', makefile, target] - self._invoke_cli( - global_params=global_params, - subcmd='make', - subcmd_params=make_params - ) + makefile = "Makefile" + target = "all" + make_params = ["-f", makefile, target] + self._invoke_cli(global_params=global_params, subcmd="make", subcmd_params=make_params) expected_commands = [ - mock.call(['build', '--network=host', '-f', 'Dockerfile.build-container-image', - '-t', 'build-container-image', '.'], - stdout_to_stderr=True), - mock.call(['make'] + make_params, fqdn_image='build-container-image', environment=[], - interactive=False, name=None, net=None, publish=(), volumes=None, workdir=None, workspace=None, - use_cache=False, env_file=()), + mock.call( + [ + "build", + "--network=host", + "-f", + "Dockerfile.build-container-image", + "-t", + "build-container-image", + ".", + ], + stdout_to_stderr=True, + ), + mock.call( + ["make"] + make_params, + fqdn_image="build-container-image", + environment=[], + interactive=False, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ), ] skipper_runner_run_mock.assert_has_calls(expected_commands) - @mock.patch('subprocess.check_output', mock.MagicMock(autospec=True, return_value='1234567\n')) - @mock.patch('skipper.runner.run', autospec=True) + @mock.patch("subprocess.check_output", mock.MagicMock(autospec=True, return_value="1234567\n")) + @mock.patch("skipper.runner.run", autospec=True) def test_shell(self, skipper_runner_run_mock): self._invoke_cli( global_params=self.global_params, - subcmd='shell', - ) - expected_fqdn_image = 'build-container-image:build-container-tag' - skipper_runner_run_mock.assert_called_once_with(['bash'], fqdn_image=expected_fqdn_image, environment=[], - interactive=True, name=None, net=None, publish=(), volumes=None, - workdir=None, workspace=None, use_cache=False, - env_file=()) - - @mock.patch('click.echo', autospec=True) - @mock.patch('skipper.cli.get_distribution', autospec=True) + subcmd="shell", + ) + expected_fqdn_image = "build-container-image:build-container-tag" + skipper_runner_run_mock.assert_called_once_with( + ["bash"], + fqdn_image=expected_fqdn_image, + environment=[], + interactive=True, + name=None, + net=None, + publish=(), + volumes=None, + workdir=None, + workspace=None, + use_cache=False, + env_file=(), + ) + + @mock.patch("click.echo", autospec=True) + @mock.patch("skipper.cli.get_distribution", autospec=True) def test_version(self, get_dist_mock, echo_mock): - expected_version = '1.2.3' + expected_version = "1.2.3" get_dist_mock.return_value = mock.MagicMock() get_dist_mock.return_value.version = expected_version self._invoke_cli( - subcmd='version', + subcmd="version", ) echo_mock.assert_called_once_with(expected_version) def _invoke_cli(self, defaults=None, global_params=None, subcmd=None, subcmd_params=None): - self.assertFalse(subcmd is None and subcmd_params is not None, 'No sub-command was provided!') + self.assertFalse(subcmd is None and subcmd_params is not None, "No sub-command was provided!") defaults = defaults or {} diff --git a/tests/test_git.py b/tests/test_git.py index 1f3a40a..5005fed 100644 --- a/tests/test_git.py +++ b/tests/test_git.py @@ -1,58 +1,62 @@ import subprocess import unittest -import mock -from skipper import git +from unittest import mock +from skipper import git -GIT_HASH_FULL = b'00efe974e3cf18c3493f110f5aeda04ff78b125f' -GIT_HASH_SHORT = b'00efe97' +GIT_HASH_FULL = b"00efe974e3cf18c3493f110f5aeda04ff78b125f" +GIT_HASH_SHORT = b"00efe97" class TestGit(unittest.TestCase): - @mock.patch('subprocess.check_output', return_value=GIT_HASH_FULL) - @mock.patch('skipper.git.is_git_repository', return_value=True) + @mock.patch("subprocess.check_output", return_value=GIT_HASH_FULL) + @mock.patch("skipper.git.is_git_repository", return_value=True) def test_get_hash_with_default_argument(self, is_git_repository_mock, check_output_mock): git_hash = git.get_hash() is_git_repository_mock.assert_called_once() - check_output_mock.assert_called_once_with(['git', 'rev-parse', 'HEAD']) - self.assertEqual(git_hash, GIT_HASH_FULL.decode('utf-8')) + check_output_mock.assert_called_once_with(["git", "rev-parse", "HEAD"]) + self.assertEqual(git_hash, GIT_HASH_FULL.decode("utf-8")) - @mock.patch('subprocess.check_output', return_value=GIT_HASH_FULL) - @mock.patch('skipper.git.is_git_repository', return_value=True) + @mock.patch("subprocess.check_output", return_value=GIT_HASH_FULL) + @mock.patch("skipper.git.is_git_repository", return_value=True) def test_get_full_hash(self, is_git_repository_mock, check_output_mock): git_hash = git.get_hash(short=False) is_git_repository_mock.assert_called_once() - check_output_mock.assert_called_once_with(['git', 'rev-parse', 'HEAD']) - self.assertEqual(git_hash, GIT_HASH_FULL.decode('utf-8')) + check_output_mock.assert_called_once_with(["git", "rev-parse", "HEAD"]) + self.assertEqual(git_hash, GIT_HASH_FULL.decode("utf-8")) - @mock.patch('subprocess.check_output', return_value=GIT_HASH_SHORT) - @mock.patch('skipper.git.is_git_repository', return_value=True) + @mock.patch("subprocess.check_output", return_value=GIT_HASH_SHORT) + @mock.patch("skipper.git.is_git_repository", return_value=True) def test_get_short_hash(self, is_git_repository_mock, check_output_mock): git_hash = git.get_hash(short=True) is_git_repository_mock.assert_called_once() - check_output_mock.assert_called_once_with(['git', 'rev-parse', '--short', 'HEAD']) - self.assertEqual(git_hash, GIT_HASH_SHORT.decode('utf-8')) + check_output_mock.assert_called_once_with(["git", "rev-parse", "--short", "HEAD"]) + self.assertEqual(git_hash, GIT_HASH_SHORT.decode("utf-8")) - @mock.patch('skipper.git.is_git_repository', return_value=False) + @mock.patch("skipper.git.is_git_repository", return_value=False) def test_not_in_git_project(self, is_git_repository_mock): - self.assertEqual(git.get_hash(), 'none') + self.assertEqual(git.get_hash(), "none") is_git_repository_mock.assert_called_once() - @mock.patch('os.path.exists', return_value=True) + @mock.patch("os.path.exists", return_value=True) def test_should_be_in_git_project_os_path(self, exists_mock): self.assertTrue(git.is_git_repository()) - exists_mock.assert_called_once_with('.git') + exists_mock.assert_called_once_with(".git") - @mock.patch('subprocess.call', return_value=0) - @mock.patch('os.path.exists', return_value=False) + @mock.patch("subprocess.call", return_value=0) + @mock.patch("os.path.exists", return_value=False) def test_should_be_in_git_project_git(self, exists_mock, call_mock): self.assertTrue(git.is_git_repository()) - exists_mock.assert_called_once_with('.git') - call_mock.assert_called_once_with(['git', 'rev-parse', '--is-inside-work-tree'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + exists_mock.assert_called_once_with(".git") + call_mock.assert_called_once_with( + ["git", "rev-parse", "--is-inside-work-tree"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL + ) - @mock.patch('subprocess.call', return_value=1) - @mock.patch('os.path.exists', return_value=False) + @mock.patch("subprocess.call", return_value=1) + @mock.patch("os.path.exists", return_value=False) def test_should_not_be_in_git_project(self, exists_mock, call_mock): self.assertFalse(git.is_git_repository()) - exists_mock.assert_called_once_with('.git') - call_mock.assert_called_once_with(['git', 'rev-parse', '--is-inside-work-tree'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + exists_mock.assert_called_once_with(".git") + call_mock.assert_called_once_with( + ["git", "rev-parse", "--is-inside-work-tree"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL + ) diff --git a/tests/test_runner.py b/tests/test_runner.py index 5f83fcc..707d101 100644 --- a/tests/test_runner.py +++ b/tests/test_runner.py @@ -1,544 +1,739 @@ -import sys import os +import sys import unittest -import mock -from skipper import utils -from skipper import runner +from unittest import mock + +from skipper import runner, utils from skipper.runner import get_default_net from skipper.utils import DOCKER_CONFIG USER_ID = 1000 GROUP_ID = 2000 -REGISTRY = 'registry.io:5000' -IMAGE = 'image' -TAG = '1234567' -FQDN_IMAGE = REGISTRY + '/' + IMAGE + ':' + TAG +REGISTRY = "registry.io:5000" +IMAGE = "image" +TAG = "1234567" +FQDN_IMAGE = REGISTRY + "/" + IMAGE + ":" + TAG -WORKDIR = '/home/adir/work' -HOME_DIR = '/home/adir' -PROJECT = 'proj' +WORKDIR = "/home/adir/work" +HOME_DIR = "/home/adir" +PROJECT = "proj" PROJECT_DIR = os.path.join(WORKDIR, PROJECT) ENV = ["KEY1=VAL1", "KEY2=VAL2"] -ENV_FILE_PATH = '/home/envfile.env' +ENV_FILE_PATH = "/home/envfile.env" ENV_FILES = [ENV_FILE_PATH, ENV_FILE_PATH] def get_volume_mapping(volume_mapping): - if sys.platform == 'darwin': - if volume_mapping.startswith('/etc/') or volume_mapping.startswith('/var/lib/'): - return '/private' + volume_mapping + if sys.platform == "darwin": + if volume_mapping.startswith("/etc/") or volume_mapping.startswith("/var/lib/"): + return "/private" + volume_mapping return volume_mapping def get_docker_config_volume(): suffix = runner.get_docker_config_volume_suffix() - return get_volume_mapping( - f'{HOME_DIR}{suffix}:{DOCKER_CONFIG}{suffix}:rw' - ) + return get_volume_mapping(f"{HOME_DIR}{suffix}:{DOCKER_CONFIG}{suffix}:rw") -@mock.patch('skipper.runner._network_exists', mock.MagicMock(autospec=True, return_value=True)) +@mock.patch("skipper.runner._network_exists", mock.MagicMock(autospec=True, return_value=True)) class TestRunner(unittest.TestCase): - - NET_LS = 'NETWORK ID NAME DRIVER SCOPE\n' \ - '8c954c27cf41 host host local\n' - NET_NOT_EXISTS = 'NETWORK ID NAME DRIVER SCOPE\n' + NET_LS = ( + "NETWORK ID NAME DRIVER SCOPE\n" + "8c954c27cf41 host host local\n" + ) + NET_NOT_EXISTS = "NETWORK ID NAME DRIVER SCOPE\n" def setUp(self): self.runtime = "docker" utils.CONTAINER_RUNTIME_COMMAND = self.runtime - os.environ['KEEP_CONTAINERS'] = 'True' + os.environ["KEEP_CONTAINERS"] = "True" - @mock.patch('subprocess.Popen', autospec=False) + @mock.patch("subprocess.Popen", autospec=False) def test_run_simple_command_not_nested(self, popen_mock): - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 - command = ['pwd'] + command = ["pwd"] runner.run(command) popen_mock.assert_called_once_with([self.runtime] + command) - @mock.patch('subprocess.Popen', autospec=False) + @mock.patch("subprocess.Popen", autospec=False) def test_run_complex_command_not_nested(self, popen_mock): - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 - command = ['ls -l'] + command = ["ls -l"] runner.run(command) popen_mock.assert_called_once_with([self.runtime] + command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_simple_command_nested_network_exist(self, resource_filename_mock, check_output_mock, - popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_simple_command_nested_network_exist( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_simple_command_nested_network_not_exist(self, resource_filename_mock, - check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_simple_command_nested_network_not_exist( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_NOT_EXISTS, 'new-net-hash', ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_NOT_EXISTS, "new-net-hash", ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_simple_command_nested_with_env(self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_simple_command_nested_with_env( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE, ENV) expected_docker_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'KEY1=VAL1', - '-e', 'KEY2=VAL2', - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "KEY1=VAL1", + "-e", + "KEY2=VAL2", + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_docker_command) - @mock.patch('os.path.exists', - mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', - mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', - mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', - mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) def test_run_simple_command_nested_with_env_file( - self, resource_filename_mock, check_output_mock, popen_mock, - grp_getgrnam_mock, os_getuid_mock + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', - 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE, env_file=[ENV_FILE_PATH]) expected_docker_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '--env-file', ENV_FILE_PATH, - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict( - homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict( - homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "--env-file", + ENV_FILE_PATH, + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_docker_command) - @mock.patch('os.path.exists', - mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', - mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', - mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', - mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) def test_run_simple_command_nested_with_multiple_env_files( - self, resource_filename_mock, check_output_mock, popen_mock, - grp_getgrnam_mock, os_getuid_mock + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', - 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE, env_file=ENV_FILES) expected_docker_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', 'host', - '--env-file', ENV_FILE_PATH, - '--env-file', ENV_FILE_PATH, - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', '%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict( - homedir=HOME_DIR), - '-v', '%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict( - homedir=HOME_DIR), - '-v', get_docker_config_volume(), - '-v', '/etc/docker:/etc/docker:ro', - '-v', '%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR), - '-v', '/var/run/docker.sock:/var/run/docker.sock:rw', - '-v', 'entrypoint.sh:/opt/skipper/skipper-entrypoint.sh', - '-v', '/var/lib/osmosis:/var/lib/osmosis:rw', - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + "host", + "--env-file", + ENV_FILE_PATH, + "--env-file", + ENV_FILE_PATH, + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + "%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR), + "-v", + "%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR), + "-v", + get_docker_config_volume(), + "-v", + "/etc/docker:/etc/docker:ro", + "-v", + "%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR), + "-v", + "/var/run/docker.sock:/var/run/docker.sock:rw", + "-v", + "entrypoint.sh:/opt/skipper/skipper-entrypoint.sh", + "-v", + "/var/lib/osmosis:/var/lib/osmosis:rw", + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_docker_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_simple_command_nested_interactive(self, resource_filename_mock, - check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_simple_command_nested_interactive( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE, interactive=True) expected_nested_command = [ - 'docker', 'run', - '-i', - '-e', 'SKIPPER_INTERACTIVE=True', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-i", + "-e", + "SKIPPER_INTERACTIVE=True", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True,) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_complex_command_nested(self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch( + "grp.getgrnam", + autospec=True, + ) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_complex_command_nested( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - 'docker', 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) + " ".join(command), ] popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('os.path.exists', mock.MagicMock(autospec=True, return_value=True)) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_complex_command_nested_with_env(self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock): + @mock.patch("os.path.exists", mock.MagicMock(autospec=True, return_value=True)) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_complex_command_nested_with_env( + self, resource_filename_mock, check_output_mock, popen_mock, grp_getgrnam_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] runner.run(command, FQDN_IMAGE, ENV, name="test") expected_nested_command = [ - 'docker', 'run', - '--name', - 'test', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'KEY1=VAL1', - '-e', 'KEY2=VAL2', - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "--name", + "test", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "KEY1=VAL1", + "-e", + "KEY2=VAL2", + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) + " ".join(command), ] popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('skipper.runner.utils.create_path_and_add_data', autospec=True) - @mock.patch('os.path.exists', autospec=True) - @mock.patch('os.getuid', autospec=True) - @mock.patch('grp.getgrnam', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_complex_command_nested_with_special_case_verification(self, resource_filename_mock, check_output_mock, - popen_mock, grp_getgrnam_mock, os_getuid_mock, - path_exists_mock, create_path_and_add_data_mock): - + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("skipper.runner.utils.create_path_and_add_data", autospec=True) + @mock.patch("os.path.exists", autospec=True) + @mock.patch("os.getuid", autospec=True) + @mock.patch("grp.getgrnam", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_complex_command_nested_with_special_case_verification( + self, + resource_filename_mock, + check_output_mock, + popen_mock, + grp_getgrnam_mock, + os_getuid_mock, + path_exists_mock, + create_path_and_add_data_mock, + ): path_exists_mock.return_value = False resource_filename_mock.return_value = "entrypoint.sh" - check_output_mock.side_effect = [self.NET_LS, ''] - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + check_output_mock.side_effect = [self.NET_LS, ""] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 grp_getgrnam_mock.return_value.gr_gid = 978 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] volumes = [] runner.run(command, FQDN_IMAGE, ENV, name="test", volumes=volumes) expected_nested_command = [ - 'docker', 'run', - '--name', - 'test', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'KEY1=VAL1', - '-e', 'KEY2=VAL2', - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '-e', 'DOCKER_CONFIG=/opt/.docker', - '-e', 'DOCKER_CONTEXT=default', - '-e', 'SKIPPER_DOCKER_GID=978', - '-v', '%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR), - '-v', '%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR), - '-v', '%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR), - '-v', '/var/run/docker.sock:/var/run/docker.sock:rw', - '-v', 'entrypoint.sh:/opt/skipper/skipper-entrypoint.sh', - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + "docker", + "run", + "--name", + "test", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "KEY1=VAL1", + "-e", + "KEY2=VAL2", + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "-e", + "DOCKER_CONFIG=/opt/.docker", + "-e", + "DOCKER_CONTEXT=default", + "-e", + "SKIPPER_DOCKER_GID=978", + "-v", + "%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR), + "-v", + "%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR), + "-v", + "%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR), + "-v", + "/var/run/docker.sock:/var/run/docker.sock:rw", + "-v", + "entrypoint.sh:/opt/skipper/skipper-entrypoint.sh", + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) - ] - calls = [ - mock.call(full_path="/home/adir/.gitconfig", data="", is_file=True) + " ".join(command), ] + calls = [mock.call(full_path="/home/adir/.gitconfig", data="", is_file=True)] create_path_and_add_data_mock.assert_has_calls(calls, any_order=True) popen_mock.assert_called_once_with(expected_nested_command) def test_handle_volumes_bind_mount_with_bad_volume_mount(self): - docker_cmd = ['docker', 'run'] - volumes = ['bad volume mount'] + docker_cmd = ["docker", "run"] + volumes = ["bad volume mount"] with self.assertRaises(ValueError): runner.handle_volumes_bind_mount(docker_cmd, HOME_DIR, volumes, WORKDIR) diff --git a/tests/test_runner_podman.py b/tests/test_runner_podman.py index 8432cb1..e93e0cc 100644 --- a/tests/test_runner_podman.py +++ b/tests/test_runner_podman.py @@ -1,274 +1,377 @@ import os import unittest -import mock -from skipper import utils -from skipper import runner +from unittest import mock + +from skipper import runner, utils from skipper.runner import get_default_net -from tests.test_runner import get_volume_mapping, get_docker_config_volume +from tests.test_runner import get_docker_config_volume, get_volume_mapping USER_ID = 1000 GROUP_ID = 2000 -REGISTRY = 'registry.io:5000' -IMAGE = 'image' -TAG = '1234567' -FQDN_IMAGE = REGISTRY + '/' + IMAGE + ':' + TAG +REGISTRY = "registry.io:5000" +IMAGE = "image" +TAG = "1234567" +FQDN_IMAGE = REGISTRY + "/" + IMAGE + ":" + TAG -WORKDIR = '/home/adir/work' -HOME_DIR = '/home/adir' -PROJECT = 'proj' +WORKDIR = "/home/adir/work" +HOME_DIR = "/home/adir" +PROJECT = "proj" PROJECT_DIR = os.path.join(WORKDIR, PROJECT) ENV = ["KEY1=VAL1", "KEY2=VAL2"] def mock_makedirs(param): - if param == '/usr/bin/nonexistentbinary': - raise OSError('Permission denied') + if param == "/usr/bin/nonexistentbinary": + raise OSError("Permission denied") return True def mock_path_exists(param): - return param != '/usr/bin/nonexistentbinary' + return param != "/usr/bin/nonexistentbinary" -@mock.patch('os.path.exists', mock.MagicMock(autospec=True, side_effect=mock_path_exists)) +@mock.patch("os.path.exists", mock.MagicMock(autospec=True, side_effect=mock_path_exists)) class TestRunnerPodman(unittest.TestCase): - def setUp(self): self.runtime = "podman" utils.CONTAINER_RUNTIME_COMMAND = self.runtime - os.environ['KEEP_CONTAINERS'] = 'True' + os.environ["KEEP_CONTAINERS"] = "True" - @mock.patch('subprocess.Popen', autospec=False) + @mock.patch("subprocess.Popen", autospec=False) def test_run_simple_command_not_nested(self, popen_mock): - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 - command = ['pwd'] + command = ["pwd"] runner.run(command) popen_mock.assert_called_once_with([self.runtime] + command) - @mock.patch('subprocess.Popen', autospec=False) + @mock.patch("subprocess.Popen", autospec=False) def test_run_complex_command_not_nested(self, popen_mock): - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 - command = ['ls -l'] + command = ["ls -l"] runner.run(command) popen_mock.assert_called_once_with([self.runtime] + command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_simple_command_nested_network_exist(self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock): + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_simple_command_nested_network_exist( + self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - self.runtime, 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '--group-add', 'keep-groups', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw'), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + self.runtime, + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "--group-add", + "keep-groups", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw"), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] assert not check_output_mock.called popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=True) - def test_run_simple_command_nested_network_not_exist(self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock): + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=True) + def test_run_simple_command_nested_network_not_exist( + self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 os_getuid_mock.return_value = USER_ID - command = ['pwd'] + command = ["pwd"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - self.runtime, 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '--group-add', 'keep-groups', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw'), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + self.runtime, + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "--group-add", + "keep-groups", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw"), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - command[0] + command[0], ] assert not check_output_mock.called popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) def test_run_complex_command_nested(self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock): resource_filename_mock.return_value = "entrypoint.sh" - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] runner.run(command, FQDN_IMAGE) expected_nested_command = [ - self.runtime, 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '--group-add', 'keep-groups', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw'), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + self.runtime, + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "--group-add", + "keep-groups", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw"), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) + " ".join(command), ] assert not check_output_mock.called popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - @mock.patch('os.makedirs', mock.MagicMock(autospec=True, side_effect=mock_makedirs)) - def test_run_non_existent_unauthorized_volume(self, resource_filename_mock, - check_output_mock, popen_mock, os_getuid_mock): + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + @mock.patch("os.makedirs", mock.MagicMock(autospec=True, side_effect=mock_makedirs)) + def test_run_non_existent_unauthorized_volume( + self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] runner.run(command, FQDN_IMAGE, volumes=["/usr/bin/nonexistentbinary:/usr/bin/nonexistentbinary"]) expected_nested_command = [ - self.runtime, 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '--group-add', 'keep-groups', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw'), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + self.runtime, + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "--group-add", + "keep-groups", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw"), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) + " ".join(command), ] assert not check_output_mock.called popen_mock.assert_called_once_with(expected_nested_command) - @mock.patch('getpass.getuser', mock.MagicMock(autospec=True, return_value='testuser')) - @mock.patch('os.getcwd', mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) - @mock.patch('os.path.expanduser', mock.MagicMock(autospec=True, return_value=HOME_DIR)) - @mock.patch('os.getuid', autospec=True) - @mock.patch('subprocess.Popen', autospec=False) - @mock.patch('subprocess.check_output', autospec=False) - @mock.patch('pkg_resources.resource_filename', autospec=False) - def test_run_complex_command_nested_with_env(self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock): + @mock.patch("getpass.getuser", mock.MagicMock(autospec=True, return_value="testuser")) + @mock.patch("os.getcwd", mock.MagicMock(autospec=True, return_value=PROJECT_DIR)) + @mock.patch("os.path.expanduser", mock.MagicMock(autospec=True, return_value=HOME_DIR)) + @mock.patch("os.getuid", autospec=True) + @mock.patch("subprocess.Popen", autospec=False) + @mock.patch("subprocess.check_output", autospec=False) + @mock.patch("pkg_resources.resource_filename", autospec=False) + def test_run_complex_command_nested_with_env( + self, resource_filename_mock, check_output_mock, popen_mock, os_getuid_mock + ): resource_filename_mock.return_value = "entrypoint.sh" - popen_mock.return_value.stdout.readline.side_effect = ['aaa', 'bbb', 'ccc', ''] + popen_mock.return_value.stdout.readline.side_effect = ["aaa", "bbb", "ccc", ""] popen_mock.return_value.poll.return_value = -1 os_getuid_mock.return_value = USER_ID - command = ['ls', '-l'] + command = ["ls", "-l"] runner.run(command, FQDN_IMAGE, ENV) expected_nested_command = [ - self.runtime, 'run', - '-t', - '-e', 'KEEP_CONTAINERS=True', - '--ulimit', 'nofile=65536:65536', - '--privileged', - '--net', get_default_net(), - '-e', 'KEY1=VAL1', - '-e', 'KEY2=VAL2', - '-e', 'SKIPPER_USERNAME=testuser', - '-e', 'SKIPPER_UID=%(user_uid)s' % dict(user_uid=USER_ID), - '-e', 'HOME=%(homedir)s' % dict(homedir=HOME_DIR), - '-e', 'CONTAINER_RUNTIME_COMMAND=%(runtime_command)s' % dict(runtime_command=utils.get_runtime_command()), - '--group-add', 'keep-groups', - '-v', get_volume_mapping('%(homedir)s/.netrc:%(homedir)s/.netrc:ro' % dict(homedir=HOME_DIR)), - '-v', get_volume_mapping('%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro' % dict(homedir=HOME_DIR)), - '-v', get_docker_config_volume(), - '-v', get_volume_mapping('/etc/docker:/etc/docker:ro'), - '-v', get_volume_mapping('%(workdir)s:%(workdir)s:rw' % dict(workdir=WORKDIR)), - '-v', get_volume_mapping('entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw'), - '-v', get_volume_mapping('/var/run/docker.sock:/var/run/docker.sock:rw'), - '-v', get_volume_mapping('/var/lib/osmosis:/var/lib/osmosis:rw'), - '-w', PROJECT_DIR, - '--entrypoint', '/opt/skipper/skipper-entrypoint.sh', + self.runtime, + "run", + "-t", + "-e", + "KEEP_CONTAINERS=True", + "--ulimit", + "nofile=65536:65536", + "--privileged", + "--net", + get_default_net(), + "-e", + "KEY1=VAL1", + "-e", + "KEY2=VAL2", + "-e", + "SKIPPER_USERNAME=testuser", + "-e", + "SKIPPER_UID=%(user_uid)s" % dict(user_uid=USER_ID), + "-e", + "HOME=%(homedir)s" % dict(homedir=HOME_DIR), + "-e", + "CONTAINER_RUNTIME_COMMAND=%(runtime_command)s" % dict(runtime_command=utils.get_runtime_command()), + "--group-add", + "keep-groups", + "-v", + get_volume_mapping("%(homedir)s/.netrc:%(homedir)s/.netrc:ro" % dict(homedir=HOME_DIR)), + "-v", + get_volume_mapping("%(homedir)s/.gitconfig:%(homedir)s/.gitconfig:ro" % dict(homedir=HOME_DIR)), + "-v", + get_docker_config_volume(), + "-v", + get_volume_mapping("/etc/docker:/etc/docker:ro"), + "-v", + get_volume_mapping("%(workdir)s:%(workdir)s:rw" % dict(workdir=WORKDIR)), + "-v", + get_volume_mapping("entrypoint.sh:/opt/skipper/skipper-entrypoint.sh:rw"), + "-v", + get_volume_mapping("/var/run/docker.sock:/var/run/docker.sock:rw"), + "-v", + get_volume_mapping("/var/lib/osmosis:/var/lib/osmosis:rw"), + "-w", + PROJECT_DIR, + "--entrypoint", + "/opt/skipper/skipper-entrypoint.sh", FQDN_IMAGE, - ' '.join(command) + " ".join(command), ] assert not check_output_mock.called popen_mock.assert_called_once_with(expected_nested_command) diff --git a/tests/test_utils.py b/tests/test_utils.py index c990d4b..b002f5f 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,14 +1,12 @@ import os import unittest - -import mock +from unittest import mock from skipper import utils class TestUtils(unittest.TestCase): - - @mock.patch('skipper.utils.which', autospec=False) + @mock.patch("skipper.utils.which", autospec=False) def test_get_runtime_command(self, find_executable_mock): utils.CONTAINER_RUNTIME_COMMAND = None find_executable_mock.side_effect = "done" @@ -26,9 +24,9 @@ def test_get_runtime_command(self, find_executable_mock): res = utils.get_runtime_command() self.assertEqual(res, utils.DOCKER) - @mock.patch('skipper.utils.open', autospec=False) - @mock.patch('skipper.utils.os.makedirs', autospec=True) - @mock.patch('skipper.utils.os.path.exists', autospec=True) + @mock.patch("skipper.utils.open", autospec=False) + @mock.patch("skipper.utils.os.makedirs", autospec=True) + @mock.patch("skipper.utils.os.path.exists", autospec=True) def test_create_path_and_add_data(self, path_exists_mock, makedir_mock, open_mock): test_dir = "/home/test" test_file = os.path.join(test_dir, "test_file.txt")