Exemple #1
0
def test_tool_info_set():
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)

    # Unable to change name
    with pytest.raises(AttributeError):
        tool_obj.name = "new_name"

    with pytest.raises(ValueError):
        tool_obj.updated = "16062006"

    tool_obj.updated = datetime(2020, 3, 11, 11, 37)
    assert tool_obj.updated == datetime(2020, 3, 11, 11, 37)
Exemple #2
0
def test_tool_info_from_dict():
    t_info = ToolInfo(**FAKE_TOOL_INFO)
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER))
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER))
    t_info_dict = dict(t_info)
    t_info_from_dict = ToolInfo.from_dict(t_info_dict)
    assert t_info.name == t_info_from_dict.name
    assert t_info.updated == t_info_from_dict.updated
    assert t_info.location == t_info_from_dict.location
    assert t_info.versions[1].version == t_info_from_dict.versions[1].version
    assert t_info.versions[1].version == "1.1"

    with pytest.raises(TypeError):
        ToolInfo.from_dict("not_dict")

    assert json.dumps(t_info, cls=ToolInfoEncoder)
Exemple #3
0
def test_failed_constraints_meta_data(caplog, base_db):
    caplog.set_level(logging.DEBUG)
    # Null tool data
    tmp_conf = deepcopy(FAKE_CHECKER_CONF)
    tmp_conf["tool"] = None
    tmp_checker = {
        "version": "1.9",
        "version_type": VersionType.REMOTE,
        "source": "no_checker_case",
        "tags": {"latest", "latest-stable"},
        "updated": datetime(
            2021,
            3,
            3,
            13,
            37,
        ),
        "size": 89529754,
    }
    with pytest.raises(sqlite3.IntegrityError):
        with base_db.transaction():
            base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                        VersionInfo(**tmp_checker))
            base_db.insert_meta_info(FAKE_TOOL_INFO.get("name"),
                                     FAKE_TOOL_INFO.get("location"), tmp_conf)
        # Rollback should happen, inserted version not found
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version != "1.9"
        tools = base_db.get_tools()
        assert len(tools[0].versions) == 2
Exemple #4
0
def test_db_tool_data_insert_with_versions(config, caplog):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        n_tools = test_db.get_tools()
        assert len(n_tools) == 1
        assert len(n_tools[0].versions) == 2
        n_versions = n_tools[0].versions
        assert n_versions[0].version == FAKE_VERSION_INFO_NO_CHECKER.get(
            "version")
        assert n_versions[0].version_type == FAKE_VERSION_INFO_NO_CHECKER.get(
            "version_type")
        assert n_versions[0].source == FAKE_VERSION_INFO_NO_CHECKER.get(
            "source")
        assert n_versions[0].tags == FAKE_VERSION_INFO_NO_CHECKER.get("tags")
        # DB insert should not update time - should tell information of origin update time
        assert n_versions[0].updated == FAKE_VERSION_INFO_NO_CHECKER.get(
            "updated")
        assert n_versions[0].raw_size() == FAKE_VERSION_INFO_NO_CHECKER.get(
            "size")
        # Duplicate insert, should be handled gracefully
        test_db.insert_tool_info(tool_obj)
        n_tools = test_db.get_tools()
        # Still two versions
        assert len(n_tools[0].versions) == 2
Exemple #5
0
def test_insert_meta_data(caplog, config):
    """Insert metadata of checker"""
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    assert isinstance(ver2.source, UpstreamChecker)

    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        test_db.insert_meta_info(tool_obj.name, tool_obj.location,
                                 FAKE_CHECKER_CONF)
        meta_data = test_db.get_meta_information(
            tool_obj.name, FAKE_CHECKER_CONF.get("provider"))[0]
        assert meta_data.get("uri") == FAKE_CHECKER_CONF.get("uri")
        assert meta_data.get("repository") == FAKE_CHECKER_CONF.get(
            "repository")
        assert meta_data.get("tool") == FAKE_CHECKER_CONF.get("tool")
        assert meta_data.get("provider") == FAKE_CHECKER_CONF.get("provider")
        assert meta_data.get("method") == FAKE_CHECKER_CONF.get("method")
        assert meta_data.get("suite") == FAKE_CHECKER_CONF.get("suite")
        assert meta_data.get("origin") == FAKE_CHECKER_CONF.get("origin")
        assert meta_data.get("docker_origin") == FAKE_CHECKER_CONF.get(
            "docker_origin")
Exemple #6
0
def base_db(caplog, config):
    caplog.set_level(logging.DEBUG)
    # Make sample database for other tests
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        tool_obj2 = ToolInfo(**FAKE_TOOL_INFO2)
        tool_obj2.versions.append(ver1)
        tool_obj2.versions.append(ver2)
        test_db.insert_tool_info(tool_obj2)
    yield test_db
Exemple #7
0
def test_insert_tool_list(config, caplog):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    tools = [ToolInfo(**FAKE_TOOL_INFO), ToolInfo(**FAKE_TOOL_INFO2)]
    with test_db.transaction():
        test_db.insert_tool_info(tools)
    # Read values
    with test_db.transaction():
        tools_from_db = test_db.get_tools()
    assert len(tools_from_db) == 2
    assert tools[0].description == FAKE_TOOL_INFO.get("description")
    assert tools[0].name == FAKE_TOOL_INFO.get("name")
    assert tools[0].updated == FAKE_TOOL_INFO.get("updated")
    assert tools[0].location == FAKE_TOOL_INFO.get("location")
    assert tools[1].description == FAKE_TOOL_INFO2.get("description")
    assert tools[1].name == FAKE_TOOL_INFO2.get("name")
    assert tools[1].updated == FAKE_TOOL_INFO2.get("updated")
    assert tools[1].location == FAKE_TOOL_INFO2.get("location")
Exemple #8
0
def test_get_latest_version_by_provider(base_db):
    tmp_checker = {
        "version": "1.9",
        "version_type": VersionType.REMOTE,
        "source": "no_checker_case",
        "tags": {"latest", "latest-stable"},
        "updated": datetime(
            2021,
            3,
            3,
            13,
            37,
        ),
        "size": 89529754,
    }
    with base_db.transaction():
        base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                    VersionInfo(**tmp_checker))
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version == "1.9"
        versions = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=False)
        assert len(versions) == 2
        # Replace existing record with identical data but different date
        tmp_checker["updated"] = datetime(
            2018,
            3,
            3,
            13,
            37,
        )
        base_db.insert_version_info(ToolInfo(**FAKE_TOOL_INFO),
                                    VersionInfo(**tmp_checker))
        version = base_db.get_versions_by_tool(
            FAKE_TOOL_INFO.get("name"),
            provider=tmp_checker.get("source"),
            latest=True)
        assert version.version == "0.9"
    def fetch_tags(self, tool: ToolInfo, update_cache: bool = False):
        """
        Fetches available tags for single tool from quay.io HTTP API
        See: https://docs.quay.io/api/swagger/#!/repository/getRepo
        """
        if not self.auth_url:
            self._set_auth_and_service_location()
        # In case name includes tag, separate it
        self.logger.info("fetch %s...", tool.name)
        tool_name, tool_tag = split_tool_tag(tool.name)
        # Use name without registry prefix e.g. quay.io
        # name_without_prefix = "/".join(tool_name.split("/")[-2:])
        name_without_prefix = f"{self.cincan_namespace}/{tool_name}"
        endpoint = f"{self.registry_root}/api/v1/repository/{name_without_prefix}"
        params = {
            "includeTags": True,
            "includeStats": False
        }
        resp = None
        try:
            resp = self.session.get(endpoint, params=params)
        except requests.exceptions.ConnectionError as e:
            self.logger.error(e)
        if resp and resp.status_code == 200:
            resp_cont = resp.json()
            tags = resp_cont.get("tags")
            tag_names = tags.keys()
            if tag_names:
                available_versions = self.update_versions_from_manifest_by_tags(name_without_prefix, tag_names)
            else:
                self.logger.error(f"No tags found for tool {tool_name}.")
                return
            tool.versions = available_versions
            tool.updated = datetime.datetime.now()
            if update_cache:
                self.update_cache_by_tool(tool)

        else:
            self.logger.error(f"Failed to fetch tags for image {tool.name} - not updated")
            if resp:
                self._quay_api_error(resp)
            return
Exemple #10
0
def test_create_tool_info():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)

    assert tool_obj.name == "test_tool"
    assert tool_obj.updated == datetime(2020, 3, 13, 13, 37)
    assert tool_obj.location == "test_location"
    assert tool_obj.description == "test_description"

    assert tool_obj.versions[0].version == "0.9"
    assert tool_obj.versions[1].version == "1.1"

    assert len(tool_obj.versions) == 2

    with pytest.raises(ValueError):
        ToolInfo("", datetime.now(), "test-location")

    with pytest.raises(ValueError):
        ToolInfo(1234, datetime.now(), "test-location")
Exemple #11
0
def test_tool_info_eq():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj2 = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj2.versions.append(ver2)

    # Same name and version
    assert tool_obj == tool_obj2
    # Different version
    tool_obj.versions[0].version = "NOT_SAME"
    assert tool_obj != tool_obj2

    # Test different names
    tool_obj = ToolInfo(**FAKE_TOOL_INFO2)
    tool_obj.versions.append(ver1)
    assert tool_obj != tool_obj2

    # Invalid type comparison
    with pytest.raises(ValueError):
        assert tool_obj == "Heheehe"
Exemple #12
0
def test_tool_info_latest_version():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)

    assert tool_obj.get_latest() == "0.9"
    assert tool_obj.get_latest(in_upstream=True) == "1.1"

    # No versions at all
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    assert tool_obj.get_latest() == VersionInfo("undefined", VersionType.UNDEFINED, "", set(), datetime.min)
Exemple #13
0
def test_db_tool_data_insert(config, caplog):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        # Duplicate insert, should be handled gracefully
        test_db.insert_tool_info(tool_obj)
    # Read data
    with test_db.transaction():
        tools = test_db.get_tools()
    assert len(tools) == 1
    assert tools[0].description == FAKE_TOOL_INFO.get("description")
    assert tools[0].name == FAKE_TOOL_INFO.get("name")
    assert tools[0].updated == FAKE_TOOL_INFO.get("updated")
    assert tools[0].location == FAKE_TOOL_INFO.get("location")
Exemple #14
0
def test_db_insert_duplicate_version(caplog, config):
    caplog.set_level(logging.DEBUG)
    test_db = ToolDatabase(config)
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    cp_FAKE_VERSION_INFO_NO_CHECKER = deepcopy(FAKE_VERSION_INFO_NO_CHECKER)
    cp_FAKE_VERSION_INFO_NO_CHECKER["version"] = "1.1"
    ver3 = VersionInfo(**cp_FAKE_VERSION_INFO_NO_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)
    tool_obj.versions.append(ver2)
    tool_obj.versions.append(ver3)
    with test_db.transaction():
        test_db.insert_tool_info(tool_obj)
        tools_db = test_db.get_tools()
        assert len(tools_db[0].versions) == 2
Exemple #15
0
def test_tool_info_iter():
    t_info = ToolInfo(**FAKE_TOOL_INFO)
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER))
    t_info.versions.append(VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER))
    t_info_dict = dict(t_info)

    assert t_info_dict.get("name") == "test_tool"
    assert t_info_dict.get("updated") == "2020-03-13T13:37:00"
    assert t_info_dict.get("location") == "test_location"
    assert t_info_dict.get("description") == "test_description"
    assert t_info_dict.get("versions")[0] == {
        "version": "0.9",
        "version_type": VersionType.REMOTE.value,
        "source": "no_checker_case",
        "tags": ["latest", "latest-stable"],
        "updated": format_time(datetime(2020, 3, 3, 13, 37,)),
        "size": "39.53 MB",
        "origin": False,
    }
Exemple #16
0
 async def get_tools(self, defined_tag: str = "", force_update: bool = False) -> Dict[str, ToolInfo]:
     """Get tools from remote registry. Name set without repository prefixes"""
     self._set_auth_and_service_location()
     available_tools = self.__fetch_available_tools()
     tool_list = {}
     for t in available_tools:
         # name = f"{self.image_prefix}/{t.get('namespace')}/{t.get('name')}"
         name = t.get('name')
         timestamp = t.get("last_modified")
         description = t.get("description")
         tool_list[name] = ToolInfo(name, datetime.datetime.fromtimestamp(timestamp),
                                    self.registry_name, description=description)
     tools = await self.update_tools_in_parallel(tool_list, self.fetch_tags, force_update)
     if defined_tag:
         keep = []
         for t in tools.keys():
             for v in tools[t].versions:
                 if defined_tag in v.tags:
                     keep.append(t)
                     break
         tools = {k: tools[k] for k in keep}
     return tools
Exemple #17
0
def test_get_tool_by_remote(base_db, caplog):
    caplog.set_level(logging.DEBUG)
    tmp_tool = {
        "name": "test_tool_temp",
        "updated": datetime(2021, 3, 13, 13, 37),
        "location": "test_location",
        "description": "test_description",
    }
    with base_db.transaction():
        base_db.insert_tool_info(ToolInfo(**tmp_tool))
    tool = base_db.get_single_tool(tool_name=FAKE_TOOL_INFO.get("name"),
                                   remote_name=FAKE_TOOL_INFO.get("location"))
    assert tool.name == FAKE_TOOL_INFO.get("name")
    tool = base_db.get_single_tool(tool_name=FAKE_TOOL_INFO.get("name"),
                                   remote_name=FAKE_TOOL_INFO.get("location"),
                                   filter_by=[VersionType.UPSTREAM])
    assert len(tool.versions) == 1
    assert tool.versions[0].version_type == VersionType.UPSTREAM
    tool = base_db.get_single_tool(tool_name=FAKE_TOOL_INFO.get("name"),
                                   remote_name=FAKE_TOOL_INFO.get("location"),
                                   filter_by=[VersionType.REMOTE])
    assert len(tool.versions) == 1
    assert tool.versions[0].version_type == VersionType.REMOTE
    tmp_version = deepcopy(FAKE_VERSION_INFO_NO_CHECKER)
    tmp_version["version_type"] = VersionType.LOCAL
    with base_db.transaction():
        base_db.insert_version_info(tool, tmp_version)
    tool = base_db.get_single_tool(
        tool_name=FAKE_TOOL_INFO.get("name"),
        remote_name=FAKE_TOOL_INFO.get("location"),
        filter_by=[VersionType.REMOTE, VersionType.UPSTREAM])
    assert len(tool.versions) == 2
    assert VersionType.LOCAL not in [i.version_type for i in tool.versions]

    tools = base_db.get_tools(remote_name=FAKE_TOOL_INFO.get("location"))
    assert len(tools) == 2
Exemple #18
0
def test_tool_info_origin_version():
    ver1 = VersionInfo(**FAKE_VERSION_INFO_NO_CHECKER)
    ver2 = VersionInfo(**FAKE_VERSION_INFO_WITH_CHECKER)
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    tool_obj.versions.append(ver1)

    assert tool_obj.get_origin_version() == VersionInfo(
        "Not implemented", VersionType.UNDEFINED, "", set(), datetime.min
    )
    assert tool_obj.get_docker_origin_version() == VersionInfo(
        "Not implemented", VersionType.UNDEFINED, "", set(), datetime.min
    )

    tool_obj.versions.append(ver2)

    assert tool_obj.get_origin_version() == "1.1"
    # Above fetch updated timestamp when getting 1.2 version with 'get_version' method, because
    # timestamp was older than 1 hour
    # However, this is mock object, and does not update original object as real UpstreamCheck
    # Object would do - therefore we are getting version 1.1 in next fetch, because VersionInfo
    # has timestamp updated
    assert tool_obj.get_docker_origin_version() == "1.1"
Exemple #19
0
    async def list_versions(
        self,
        tool: str = "",
        to_json: bool = False,
        only_updates: bool = False,
        force_refresh: bool = False,
    ):
        maintainer = VersionMaintainer(
            self.config,
            db=self.db,
            force_refresh=force_refresh,
        )
        versions = {}
        if tool:
            if "/" in tool:
                self.logger.error(
                    "Give only name of the tool, without prefixes or namespaces related to tool image."
                    f" Tool must be in default registry: {self.default_remote}."
                )
                sys.exit(1)
            tool_name = basename(tool)
            # tool_with_namespace = f"{self.remote_registry.full_prefix}/{tool_name}"
            l_tool = self.local_registry.create_local_tool_info_by_name(
                tool_name)
            r_tool = self.remote_registry.read_remote_versions_from_db(
                tool_name) if not force_refresh else {}

            now = datetime.now()
            if not r_tool:
                r_tool = ToolInfo(tool_name, datetime.min,
                                  self.remote_registry.registry_name)
            if not r_tool.updated or not (
                    now - timedelta(hours=self.config.cache_lifetime) <=
                    r_tool.updated <= now):
                self.remote_registry.fetch_tags(r_tool, update_cache=True)
            if l_tool or (r_tool and not r_tool.updated == datetime.min):
                l_tool, r_tool = maintainer.get_versions_single_tool(
                    tool_name, l_tool, r_tool)
                versions = await maintainer.list_versions_single(
                    l_tool, r_tool, only_updates)
            else:
                raise FileNotFoundError(
                    f"Given tool {tool} not found locally or remotely. Please, give only the basename of the tool,"
                    f"without prefixes.")
        else:
            remote_tools = await self.remote_registry.get_tools(
                force_update=force_refresh)
            # Remote tools, with included upstream version information
            remote_tools_with_origin_version = await maintainer.check_upstream_versions(
                remote_tools)
            # Local tools, without checking and corresponding the configured registry
            local_tools = await self.local_registry.get_tools(
                prefix=self.remote_registry.full_prefix)
            for t in remote_tools_with_origin_version:
                r_tool = remote_tools_with_origin_version.get(
                    t)  # Contains also upstream version info
                l_tool = local_tools.get(t, "")
                t_info = await maintainer.list_versions_single(
                    l_tool, r_tool, only_updates)
                if t_info:
                    versions[t] = t_info

        if to_json:
            return json.dumps(versions)
        else:
            return versions
Exemple #20
0
def test_tool_info_to_str():
    tool_obj = ToolInfo(**FAKE_TOOL_INFO)
    assert str(tool_obj) == "test_tool test_description"