diff --git a/doc/source/admin/galaxy_options.rst b/doc/source/admin/galaxy_options.rst index 63a83293b9d6..3ce3c4ce53c7 100644 --- a/doc/source/admin/galaxy_options.rst +++ b/doc/source/admin/galaxy_options.rst @@ -773,7 +773,7 @@ container resolvers to use when discovering containers for Galaxy. If this is set to None, the default container resolvers loaded is determined by enable_mulled_containers. For available options see - config/container_resolvers_conf.xml.sample. + https://docs.galaxyproject.org/en/master/admin/container_resolvers.html :Default: ``None`` :Type: str @@ -1255,6 +1255,43 @@ :Type: str +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``biotools_service_cache_url`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When biotools_service_cache_type = ext:database, this is the url + of the database used by beaker for bio.tools web service request + related caching. The application config code will set it to the + value of database_connection if this is not set. +:Default: ``None`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``biotools_service_cache_table_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When biotools_service_cache_type = ext:database, this is the + database table name used by beaker for bio.tools web service + request related caching. +:Default: ``beaker_cache`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``biotools_service_cache_schema_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When biotools_service_cache_type = ext:database, this is the + database table name used by beaker for bio.tools web service + request related caching. +:Default: ``None`` +:Type: str + + ~~~~~~~~~~~~~~~~~~~~~~~ ``citation_cache_type`` ~~~~~~~~~~~~~~~~~~~~~~~ @@ -1298,6 +1335,42 @@ :Type: str +~~~~~~~~~~~~~~~~~~~~~~ +``citation_cache_url`` +~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When citation_cache_type = ext:database, this is the url of the + database used by beaker for citation caching. The application + config code will set it to the value of database_connection if + this is not set. +:Default: ``None`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``citation_cache_table_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When citation_cache_type = ext:database, this is the database + table name used by beaker for citation related caching. +:Default: ``beaker_cache`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``citation_cache_schema_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When citation_cache_type = ext:database, this is the database + schema name of the table used by beaker for citation related + caching. +:Default: ``None`` +:Type: str + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``mulled_resolution_cache_type`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1347,6 +1420,43 @@ :Type: int +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``mulled_resolution_cache_url`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When mulled_resolution_cache_type = ext:database, this is the url + of the database used by beaker for caching mulled resolution + requests. The application config code will set it to the value of + database_connection if this is not set. +:Default: ``None`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``mulled_resolution_cache_table_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When mulled_resolution_cache_type = ext:database, this is the + database table name used by beaker for caching mulled resolution + requests. +:Default: ``beaker_cache`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``mulled_resolution_cache_schema_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + When mulled_resolution_cache_type = ext:database, this is the + database schema name of the table used by beaker for caching + mulled resolution requests. +:Default: ``None`` +:Type: str + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``object_store_config_file`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1360,6 +1470,67 @@ :Type: str +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``object_store_cache_monitor_driver`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + Specify where cache monitoring is driven for caching object stores + such as S3, Azure, and iRODS. This option has no affect on disk + object stores. For production instances, the cache should be + monitored by external tools such as tmpwatch and this value should + be set to 'external'. This will disable all cache monitoring in + Galaxy. Alternatively, 'celery' can monitor caches using a + periodic task or an 'inprocess' thread can be used - but this last + option seriously limits Galaxy's ability to scale. The default of + 'auto' will use 'celery' if 'enable_celery_tasks' is set to true + or 'inprocess' otherwise. This option serves as the default for + all object stores and can be overridden on a per object store + basis (but don't - just setup tmpwatch for all relevant cache + paths). +:Default: ``auto`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``object_store_cache_monitor_interval`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + For object store cache monitoring done by Galaxy, this is the + interval between cache checking steps. This is used by both + inprocess cache monitors (which we recommend you do not use) and + by the celery task if it is configured (by setting + enable_celery_tasks to true and not setting + object_store_cache_monitor_driver to external). +:Default: ``600`` +:Type: int + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``object_store_cache_path`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + Default cache path for caching object stores if cache not + configured for that object store entry. + The value of this option will be resolved with respect to + . +:Default: ``object_store_cache`` +:Type: str + + +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``object_store_cache_size`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:Description: + Default cache size for caching object stores if cache not + configured for that object store entry. +:Default: ``-1`` +:Type: int + + ~~~~~~~~~~~~~~~~~~~~~~~~~ ``object_store_store_by`` ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/lib/galaxy/app.py b/lib/galaxy/app.py index 3b1796ac0951..767cc27bbd07 100644 --- a/lib/galaxy/app.py +++ b/lib/galaxy/app.py @@ -323,6 +323,9 @@ def _configure_toolbox(self): "cache.data_dir": self.config.mulled_resolution_cache_data_dir, "cache.lock_dir": self.config.mulled_resolution_cache_lock_dir, "cache.expire": self.config.mulled_resolution_cache_expire, + "cache.url": self.config.mulled_resolution_cache_url, + "cache.table_name": self.config.mulled_resolution_cache_table_name, + "cache.schema_name": self.config.mulled_resolution_cache_schema_name, } mulled_resolution_cache = CacheManager(**parse_cache_config_options(cache_opts)).get_cache( "mulled_resolution" diff --git a/lib/galaxy/config/__init__.py b/lib/galaxy/config/__init__.py index a70fb9e3acf2..9bc573842d66 100644 --- a/lib/galaxy/config/__init__.py +++ b/lib/galaxy/config/__init__.py @@ -139,6 +139,15 @@ } """Default value for logging configuration, passed to :func:`logging.config.dictConfig`""" +DEPENDENT_CONFIG_DEFAULTS: Dict[str, str] = { + "mulled_resolution_cache_url": "database_connection", + "citation_cache_url": "database_connection", + "biotools_service_cache_url": "database_connection", +} +"""Config parameters whose default is the value of another config parameter +This should be moved to a .yml config file. +""" + VERSION_JSON_FILE = "version.json" DEFAULT_EMAIL_FROM_LOCAL_PART = "galaxy-no-reply" DISABLED_FLAG = "disabled" # Used to mark a config option as disabled @@ -731,6 +740,20 @@ def __init__(self, **kwargs): self._override_tempdir(kwargs) self._configure_sqlalchemy20_warnings(kwargs) self._process_config(kwargs) + self._set_dependent_defaults() + + def _set_dependent_defaults(self): + """Set values of unset parameters which take their default values from other parameters""" + for dependent_config_param, config_param in DEPENDENT_CONFIG_DEFAULTS.items(): + try: + if getattr(self, dependent_config_param) is None: + setattr(self, dependent_config_param, getattr(self, config_param)) + except AttributeError: + raise Exception( + "One or more invalid config parameter names specified in " + "DEPENDENT_CONFIG_DEFAULTS, " + f"{dependent_config_param}, {config_param}" + ) def _configure_sqlalchemy20_warnings(self, kwargs): """ diff --git a/lib/galaxy/config/sample/galaxy.yml.sample b/lib/galaxy/config/sample/galaxy.yml.sample index 927736e0f4eb..506300418a4f 100644 --- a/lib/galaxy/config/sample/galaxy.yml.sample +++ b/lib/galaxy/config/sample/galaxy.yml.sample @@ -938,6 +938,22 @@ galaxy: # . #biotools_service_cache_lock_dir: biotools/locks + # When biotools_service_cache_type = ext:database, this is the url of + # the database used by beaker for bio.tools web service request + # related caching. The application config code will set it to the + # value of database_connection if this is not set. + #biotools_service_cache_url: null + + # When biotools_service_cache_type = ext:database, this is the + # database table name used by beaker for bio.tools web service request + # related caching. + #biotools_service_cache_table_name: beaker_cache + + # When biotools_service_cache_type = ext:database, this is the + # database table name used by beaker for bio.tools web service request + # related caching. + #biotools_service_cache_schema_name: null + # Citation related caching. Tool citations information maybe fetched # from external sources such as https://doi.org/ by Galaxy - the # following parameters can be used to control the caching used to @@ -960,6 +976,20 @@ galaxy: # . #citation_cache_lock_dir: citations/locks + # When citation_cache_type = ext:database, this is the url of the + # database used by beaker for citation caching. The application config + # code will set it to the value of database_connection if this is not + # set. + #citation_cache_url: null + + # When citation_cache_type = ext:database, this is the database table + # name used by beaker for citation related caching. + #citation_cache_table_name: beaker_cache + + # When citation_cache_type = ext:database, this is the database schema + # name of the table used by beaker for citation related caching. + #citation_cache_schema_name: null + # Mulled resolution caching. Mulled resolution uses external APIs of # quay.io, these requests are caching using this and the following # parameters @@ -981,12 +1011,60 @@ galaxy: # created. #mulled_resolution_cache_expire: 3600 + # When mulled_resolution_cache_type = ext:database, this is the url of + # the database used by beaker for caching mulled resolution requests. + # The application config code will set it to the value of + # database_connection if this is not set. + #mulled_resolution_cache_url: null + + # When mulled_resolution_cache_type = ext:database, this is the + # database table name used by beaker for caching mulled resolution + # requests. + #mulled_resolution_cache_table_name: beaker_cache + + # When mulled_resolution_cache_type = ext:database, this is the + # database schema name of the table used by beaker for caching mulled + # resolution requests. + #mulled_resolution_cache_schema_name: null + # Configuration file for the object store If this is set and exists, # it overrides any other objectstore settings. # The value of this option will be resolved with respect to # . #object_store_config_file: object_store_conf.xml + # Specify where cache monitoring is driven for caching object stores + # such as S3, Azure, and iRODS. This option has no affect on disk + # object stores. For production instances, the cache should be + # monitored by external tools such as tmpwatch and this value should + # be set to 'external'. This will disable all cache monitoring in + # Galaxy. Alternatively, 'celery' can monitor caches using a periodic + # task or an 'inprocess' thread can be used - but this last option + # seriously limits Galaxy's ability to scale. The default of 'auto' + # will use 'celery' if 'enable_celery_tasks' is set to true or + # 'inprocess' otherwise. This option serves as the default for all + # object stores and can be overridden on a per object store basis (but + # don't - just setup tmpwatch for all relevant cache paths). + #object_store_cache_monitor_driver: auto + + # For object store cache monitoring done by Galaxy, this is the + # interval between cache checking steps. This is used by both + # inprocess cache monitors (which we recommend you do not use) and by + # the celery task if it is configured (by setting enable_celery_tasks + # to true and not setting object_store_cache_monitor_driver to + # external). + #object_store_cache_monitor_interval: 600 + + # Default cache path for caching object stores if cache not configured + # for that object store entry. + # The value of this option will be resolved with respect to + # . + #object_store_cache_path: object_store_cache + + # Default cache size for caching object stores if cache not configured + # for that object store entry. + #object_store_cache_size: -1 + # What Dataset attribute is used to reference files in an ObjectStore # implementation, this can be 'uuid' or 'id'. The default will depend # on how the object store is configured, starting with 20.05 Galaxy diff --git a/lib/galaxy/config/sample/tool_shed.yml.sample b/lib/galaxy/config/sample/tool_shed.yml.sample index 9744f777c9d5..3b04d57f94a7 100644 --- a/lib/galaxy/config/sample/tool_shed.yml.sample +++ b/lib/galaxy/config/sample/tool_shed.yml.sample @@ -288,6 +288,16 @@ tool_shed: # store this information. #citation_cache_lock_dir: database/citations/lock + # Url to database used by beaker for citation related caching. + #citation_cache_url: null + + # Database table used by beaker for citation related caching. + #citation_cache_table_name: beaker_cache + + # Schema of database table used by beaker for citation related + # caching. + #citation_cache_schema_name: null + # Turn on logging of user actions to the database. Actions currently # logged are grid views, tool searches, and use of "recently" used # tools menu. The log_events and log_actions functionality will diff --git a/lib/galaxy/config/schemas/config_schema.yml b/lib/galaxy/config/schemas/config_schema.yml index e8b75067f90c..175e792996d8 100644 --- a/lib/galaxy/config/schemas/config_schema.yml +++ b/lib/galaxy/config/schemas/config_schema.yml @@ -905,6 +905,33 @@ mapping: bio.tools web service request related caching. The lock directory to point beaker cache at. + biotools_service_cache_url: + type: str + required: false + desc: | + When biotools_service_cache_type = ext:database, this is + the url of the database used by beaker for + bio.tools web service request related caching. + The application config code will set it to the + value of database_connection if this is not set. + + biotools_service_cache_table_name: + type: str + default: beaker_cache + required: false + desc: | + When biotools_service_cache_type = ext:database, this is + the database table name used by beaker for + bio.tools web service request related caching. + + biotools_service_cache_schema_name: + type: str + required: false + desc: | + When biotools_service_cache_type = ext:database, this is + the database table name used by beaker for + bio.tools web service request related caching. + citation_cache_type: type: str default: file @@ -934,6 +961,32 @@ mapping: external sources such as https://doi.org/ by Galaxy - the following parameters can be used to control the caching used to store this information. + citation_cache_url: + type: str + required: false + desc: | + When citation_cache_type = ext:database, this is + the url of the database used by beaker for citation + caching. The application config code will set it to the + value of database_connection if this is not set. + + citation_cache_table_name: + type: str + default: beaker_cache + required: false + desc: | + When citation_cache_type = ext:database, this is + the database table name used by beaker for + citation related caching. + + citation_cache_schema_name: + type: str + required: false + desc: | + When citation_cache_type = ext:database, this is + the database schema name of the table used by beaker for + citation related caching. + mulled_resolution_cache_type: type: str default: file @@ -965,6 +1018,32 @@ mapping: desc: | Seconds until the beaker cache is considered old and a new value is created. + mulled_resolution_cache_url: + type: str + required: false + desc: | + When mulled_resolution_cache_type = ext:database, this is + the url of the database used by beaker for caching mulled resolution + requests. The application config code will set it to the + value of database_connection if this is not set. + + mulled_resolution_cache_table_name: + type: str + default: beaker_cache + required: false + desc: | + When mulled_resolution_cache_type = ext:database, this is + the database table name used by beaker for + caching mulled resolution requests. + + mulled_resolution_cache_schema_name: + type: str + required: false + desc: | + When mulled_resolution_cache_type = ext:database, this is + the database schema name of the table used by beaker for + caching mulled resolution requests. + object_store_config_file: type: str default: object_store_conf.xml diff --git a/lib/galaxy/config/schemas/tool_shed_config_schema.yml b/lib/galaxy/config/schemas/tool_shed_config_schema.yml index 37612b580713..116f0521f483 100644 --- a/lib/galaxy/config/schemas/tool_shed_config_schema.yml +++ b/lib/galaxy/config/schemas/tool_shed_config_schema.yml @@ -520,6 +520,25 @@ mapping: external sources such as https://doi.org/ by Galaxy - the following parameters can be used to control the caching used to store this information. + citation_cache_url: + type: str + required: false + desc: | + Url to database used by beaker for citation related caching. + + citation_cache_table_name: + type: str + default: beaker_cache + required: false + desc: | + Database table used by beaker for citation related caching. + + citation_cache_schema_name: + type: str + required: false + desc: | + Schema of database table used by beaker for citation related caching. + log_actions: type: bool default: false diff --git a/lib/galaxy/managers/citations.py b/lib/galaxy/managers/citations.py index d8f2264b1b1e..64e8ca91754d 100644 --- a/lib/galaxy/managers/citations.py +++ b/lib/galaxy/managers/citations.py @@ -38,9 +38,12 @@ def _get_tool(self, tool_id): class DoiCache: def __init__(self, config): cache_opts = { - "cache.type": getattr(config, "citation_cache_type", "file"), - "cache.data_dir": getattr(config, "citation_cache_data_dir", None), - "cache.lock_dir": getattr(config, "citation_cache_lock_dir", None), + "cache.type": config.citation_cache_type, + "cache.data_dir": config.citation_cache_data_dir, + "cache.lock_dir": config.citation_cache_lock_dir, + "cache.url": config.citation_cache_url, + "cache.table_name": config.citation_cache_table_name, + "cache.schema_name": config.citation_cache_schema_name, } self._cache = CacheManager(**parse_cache_config_options(cache_opts)).get_cache("doi") diff --git a/lib/galaxy/model/unittest_utils/beaker_testing_utils.py b/lib/galaxy/model/unittest_utils/beaker_testing_utils.py new file mode 100644 index 000000000000..d2480aa4f969 --- /dev/null +++ b/lib/galaxy/model/unittest_utils/beaker_testing_utils.py @@ -0,0 +1,17 @@ +from sqlalchemy import ( + MetaData, + select, + Table, +) + +from galaxy.model.unittest_utils.model_testing_utils import disposing_engine + + +def is_cache_empty(url: str, namespace: str, beaker_table: str = "beaker_cache") -> bool: + """Check if there are any entries for a given namespace in a beaker cache db table""" + with disposing_engine(url) as eng: # type: ignore[arg-type] + metadata_obj = MetaData() + table = Table(beaker_table, metadata_obj, autoload_with=eng) + with eng.connect() as conn: + result = conn.execute(select(table).where(table.c.namespace == namespace)) + return result.fetchone() is None diff --git a/lib/galaxy/tools/biotools.py b/lib/galaxy/tools/biotools.py index d396037b1381..a27fe7afef34 100644 --- a/lib/galaxy/tools/biotools.py +++ b/lib/galaxy/tools/biotools.py @@ -16,9 +16,12 @@ def get_galaxy_biotools_metadata_source(config) -> BiotoolsMetadataSource: biotools_metadata_source_config.content_directory = config.biotools_content_directory biotools_metadata_source_config.use_api = config.biotools_use_api cache_opts = { - "cache.type": getattr(config, "biotools_service_cache_type", "file"), - "cache.data_dir": getattr(config, "biotools_service_cache_data_dir", None), - "cache.lock_dir": getattr(config, "biotools_service_cache_lock_dir", None), + "cache.type": config.biotools_service_cache_type, + "cache.data_dir": config.biotools_service_cache_data_dir, + "cache.lock_dir": config.biotools_service_cache_lock_dir, + "cache.url": config.biotools_service_cache_url, + "cache.table_name": config.biotools_service_cache_table_name, + "cache.schema_name": config.biotools_service_cache_schema_name, } cache = CacheManager(**parse_cache_config_options(cache_opts)).get_cache("doi") biotools_metadata_source_config.cache = cache diff --git a/lib/tool_shed/webapp/config.py b/lib/tool_shed/webapp/config.py index ec22c7ff514f..4511b54e1cd7 100644 --- a/lib/tool_shed/webapp/config.py +++ b/lib/tool_shed/webapp/config.py @@ -130,6 +130,9 @@ def _process_config(self, kwargs): self.citation_cache_lock_dir = self._in_root_dir( kwargs.get("citation_cache_lock_dir", "database/tool_shed_citations/locks") ) + self.citation_cache_url = kwargs.get("citation_cache_lock_dir", None) + self.citation_cache_schema_name = kwargs.get("citation_cache_schema_name", None) + self.citation_cache_table_name = kwargs.get("citation_cache_table_name", None) self.password_expiration_period = timedelta(days=int(self.password_expiration_period)) # Security/Policy Compliance diff --git a/test/unit/app/managers/test_CitationsManager.py b/test/unit/app/managers/test_CitationsManager.py index 9a739c86d86b..027ab0530380 100644 --- a/test/unit/app/managers/test_CitationsManager.py +++ b/test/unit/app/managers/test_CitationsManager.py @@ -8,8 +8,12 @@ def test_DoiCache(): with tempfile.TemporaryDirectory() as tmp_database_dir: config = Bunch( + citation_cache_type="file", citation_cache_data_dir=os.path.join(tmp_database_dir, "data"), citation_cache_lock_dir=os.path.join(tmp_database_dir, "locks"), + citation_cache_url=None, + citation_cache_table_name=None, + citation_cache_schema_name=None, ) doi_cache = DoiCache(config) assert "Jörg" in doi_cache.get_bibtex("10.1093/bioinformatics/bts252") diff --git a/test/unit/app/managers/test_CitationsManager_db.py b/test/unit/app/managers/test_CitationsManager_db.py new file mode 100644 index 000000000000..8c7b8f8eb29c --- /dev/null +++ b/test/unit/app/managers/test_CitationsManager_db.py @@ -0,0 +1,36 @@ +from beaker.cache import CacheManager +from beaker.util import parse_cache_config_options + +import galaxy.config +from galaxy.managers.citations import DoiCache +from galaxy.model.unittest_utils.beaker_testing_utils import is_cache_empty +from galaxy.model.unittest_utils.migration_scripts_testing_utils import tmp_directory # noqa: F401 +from galaxy.model.unittest_utils.model_testing_utils import ( # noqa: F401 (url_factory is a fixture we have to import explicitly) + create_and_drop_database, + url_factory, +) + + +class MockDoiCache(DoiCache): + def __init__(self, config, db_url): + cache_opts = { + "cache.type": "ext:database", + "cache.data_dir": config.citation_cache_data_dir, + "cache.url": db_url, + "cache.table_name": config.citation_cache_table_name, + "cache.schema_name": config.citation_cache_schema_name, + } + self._cache = CacheManager(**parse_cache_config_options(cache_opts)).get_cache("doi") + self._cache.clear() + + +def test_DoiCache(url_factory): # noqa: F811 + db_url = url_factory() + with create_and_drop_database(db_url): + doi_cache = MockDoiCache(galaxy.config.GalaxyAppConfiguration(override_tempdir=False), db_url) + assert is_cache_empty(db_url, "doi") + assert "Jörg" in doi_cache.get_bibtex("10.1093/bioinformatics/bts252") + assert "Özkurt" in doi_cache.get_bibtex("10.1101/2021.12.24.474111") + assert not is_cache_empty(db_url, "doi") + doi_cache._cache.clear() + assert is_cache_empty(db_url, "doi") diff --git a/test/unit/app/tools/test_resolution_cache_db.py b/test/unit/app/tools/test_resolution_cache_db.py new file mode 100644 index 000000000000..156fbbc7c8a7 --- /dev/null +++ b/test/unit/app/tools/test_resolution_cache_db.py @@ -0,0 +1,68 @@ +import time + +import pytest +from beaker.cache import CacheManager +from beaker.util import parse_cache_config_options + +import galaxy.config +from galaxy.model.unittest_utils.beaker_testing_utils import is_cache_empty +from galaxy.model.unittest_utils.migration_scripts_testing_utils import tmp_directory # noqa: F401 +from galaxy.model.unittest_utils.model_testing_utils import ( # noqa: F401 (url_factory is a fixture we have to import explicitly) + create_and_drop_database, + url_factory, +) +from galaxy.tool_util.deps.container_resolvers import ResolutionCache +from galaxy.tool_util.deps.mulled.util import ( + _namespace_has_repo_name, + mulled_tags_for, + NAMESPACE_HAS_REPO_NAME_KEY, + TAG_CACHE_KEY, +) + +cache_namespace = "mulled_resolution" + + +@pytest.fixture(scope="module") +def appconfig(): + return galaxy.config.GalaxyAppConfiguration(override_tempdir=False) + + +@pytest.fixture() +def resolution_cache(url_factory, appconfig): # noqa: F811 + db_url = url_factory() + with create_and_drop_database(db_url): + resolution_cache = ResolutionCache() + cache_opts = { + "cache.type": "ext:database", + "cache.expire": "1", + "cache.url": db_url, + "cache.schema_name": appconfig.mulled_resolution_cache_schema_name, + "cache.table_name": appconfig.mulled_resolution_cache_table_name, + } + cm = CacheManager(**parse_cache_config_options(cache_opts)).get_cache(cache_namespace) + cm.clear() + resolution_cache.mulled_resolution_cache = cm + yield resolution_cache + assert not is_cache_empty(db_url, cache_namespace) + cm.clear() + assert is_cache_empty(db_url, cache_namespace) + + +def test_resolution_cache_namepace_has_repo_name(resolution_cache): + resolution_cache.mulled_resolution_cache[NAMESPACE_HAS_REPO_NAME_KEY] = ["mytool3000"] + assert _namespace_has_repo_name("bioconda", "mytool3000", resolution_cache=resolution_cache) + + +def test_resolution_cache_expires(resolution_cache): + resolution_cache.mulled_resolution_cache[NAMESPACE_HAS_REPO_NAME_KEY] = ["mytool3000"] + assert NAMESPACE_HAS_REPO_NAME_KEY in resolution_cache.mulled_resolution_cache + time.sleep(1.2) + assert NAMESPACE_HAS_REPO_NAME_KEY not in resolution_cache.mulled_resolution_cache + + +def test_targets_to_mulled_name(resolution_cache): + resolution_cache.mulled_resolution_cache[NAMESPACE_HAS_REPO_NAME_KEY] = ["mytool3000"] + cache = resolution_cache.mulled_resolution_cache._get_cache("mulled_tag_cache", {"expire": 1}) + cache[TAG_CACHE_KEY] = {"bioconda": {"mytool3000": ["1.0", "1.1"]}} + tags = mulled_tags_for(namespace="bioconda", image="mytool3000", resolution_cache=resolution_cache) + assert tags == ["1.1", "1.0"]