from subprocess import CalledProcessError import pytest from galaxy.tool_util.deps.container_classes import DOCKER_CONTAINER_TYPE from galaxy.tool_util.deps.container_resolvers.mulled import ( CachedMulledDockerContainerResolver, CachedMulledSingularityContainerResolver, MulledDockerContainerResolver, ) from galaxy.tool_util.deps.containers import ContainerRegistry from galaxy.tool_util.deps.dependencies import ( AppInfo, ToolInfo, ) from galaxy.tool_util.deps.requirements import ToolRequirement SINGULARITY_IMAGES = ( "foo:1.0--bar", "baz:2.22", "mulled-v2-fe8a3b846bc50d24e5df78fa0b562c43477fe9ce:9f946d13f673ab2903cb0da849ad42916d619d18-0", ) @pytest.fixture def appinfo() -> AppInfo: return AppInfo( involucro_auto_init=True, enable_mulled_containers=True, container_image_cache_path=".", ) @pytest.fixture def container_registry(): app_info = AppInfo( involucro_auto_init=True, enable_mulled_containers=True, container_image_cache_path=".", ) return ContainerRegistry(app_info) def test_container_registry(container_registry, mocker): mocker.patch("galaxy.tool_util.deps.mulled.util._get_namespace", return_value=["samtools"]) tool_info = ToolInfo(requirements=[ToolRequirement(name="samtools", version="1.10", type="package")]) container_description = container_registry.find_best_container_description( [DOCKER_CONTAINER_TYPE], tool_info, install=False, ) assert container_description.type == "docker" assert "samtools:1.10" in container_description.identifier def test_docker_container_resolver_detects_docker_cli_absent(appinfo, mocker): mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.which", return_value=None) resolver = CachedMulledDockerContainerResolver(appinfo) assert resolver._cli_available is False def test_docker_container_resolver_detects_docker_cli(appinfo, mocker): """ - CachedMulledDockerContainerResolver properly detects present docker binary """ mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled", return_value="/bin/docker") resolver = CachedMulledDockerContainerResolver(appinfo) assert resolver.cli_available def test_cached_docker_container_docker_cli_absent_resolve(appinfo, mocker) -> None: mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.which", return_value=None) resolver = CachedMulledDockerContainerResolver(appinfo) assert resolver.cli_available is False assert resolver.resolve(enabled_container_types=[], tool_info=ToolInfo()) is None def test_docker_container_docker_cli_absent_resolve(appinfo, mocker): mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.which", return_value=None) resolver = MulledDockerContainerResolver(appinfo) assert resolver.cli_available is False requirement = ToolRequirement(name="samtools", version="1.10", type="package") tool_info = ToolInfo(requirements=[requirement]) mocker.patch( "galaxy.tool_util.deps.container_resolvers.mulled.targets_to_mulled_name", return_value="samtools:1.10--h2e538c0_3", ) container_description = resolver.resolve(enabled_container_types=["docker"], tool_info=tool_info) assert container_description assert container_description.type == "docker" assert container_description.identifier == "quay.io/biocontainers/samtools:1.10--h2e538c0_3" def test_docker_container_docker_cli_exception_resolve(appinfo, mocker): mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.which", return_value="/bin/docker") resolver = MulledDockerContainerResolver(appinfo) assert resolver.cli_available is True requirement = ToolRequirement(name="samtools", version="1.10", type="package") tool_info = ToolInfo(requirements=[requirement]) mocker.patch( "galaxy.tool_util.deps.container_resolvers.mulled.targets_to_mulled_name", return_value="samtools:1.10--h2e538c0_3", ) mocker.patch( "galaxy.tool_util.deps.container_resolvers.mulled.docker_cached_container_description", side_effect=CalledProcessError(1, "bla"), ) container_description = resolver.resolve(enabled_container_types=["docker"], tool_info=tool_info, install=True) assert resolver.cli_available is True assert container_description assert container_description.type == "docker" assert container_description.identifier == "quay.io/biocontainers/samtools:1.10--h2e538c0_3" def test_cached_singularity_container_resolver_uncached(mocker): mocker.patch("os.listdir", return_value=SINGULARITY_IMAGES) mocker.patch("os.path.exists", return_value=True) mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.safe_makedirs") resolver = CachedMulledSingularityContainerResolver(app_info=mocker.Mock(container_image_cache_path="/")) requirement = ToolRequirement(name="foo", version="1.0", type="package") tool_info = ToolInfo(requirements=[requirement]) container_description = resolver.resolve(enabled_container_types=["singularity"], tool_info=tool_info) assert container_description assert container_description.type == "singularity" assert container_description.identifier == "/singularity/mulled/foo:1.0--bar" def test_cached_singularity_container_resolver_dir_mtime_cached(mocker): mocker.patch("os.listdir", return_value=SINGULARITY_IMAGES) mocker.patch("os.path.exists", return_value=True) mocker.patch("galaxy.tool_util.deps.container_resolvers.mulled.safe_makedirs") mocker.patch("os.stat", return_value=mocker.Mock(st_mtime=42)) resolver = CachedMulledSingularityContainerResolver( app_info=mocker.Mock(container_image_cache_path="/"), cache_directory_cacher_type="dir_mtime" ) requirement = ToolRequirement(name="baz", version="2.22", type="package") tool_info = ToolInfo(requirements=[requirement]) container_description = resolver.resolve(enabled_container_types=["singularity"], tool_info=tool_info) assert container_description assert container_description.type == "singularity" assert container_description.identifier == "/singularity/mulled/baz:2.22" requirement = ToolRequirement(name="foo", version="1.0", type="package") tool_info.requirements.append(requirement) container_description = resolver.resolve(enabled_container_types=["singularity"], tool_info=tool_info) assert container_description assert container_description.type == "singularity" assert ( container_description.identifier == "/singularity/mulled/mulled-v2-fe8a3b846bc50d24e5df78fa0b562c43477fe9ce:9f946d13f673ab2903cb0da849ad42916d619d18-0" )