| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| """Unit tests for Superset with caching""" |
| |
| import pytest |
| from flask import current_app as app |
| |
| from superset.common.db_query_status import QueryStatus |
| from superset.extensions import cache_manager |
| from superset.utils import json |
| from tests.integration_tests.base_tests import SupersetTestCase |
| from tests.integration_tests.constants import ADMIN_USERNAME |
| from tests.integration_tests.fixtures.birth_names_dashboard import ( |
| load_birth_names_dashboard_with_slices, # noqa: F401 |
| load_birth_names_data, # noqa: F401 |
| ) |
| |
| |
| class TestCache(SupersetTestCase): |
| def setUp(self): |
| self.login(ADMIN_USERNAME) |
| cache_manager.cache.clear() |
| cache_manager.data_cache.clear() |
| |
| def tearDown(self): |
| cache_manager.cache.clear() |
| cache_manager.data_cache.clear() |
| super().tearDown() |
| |
| @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") |
| def test_no_data_cache(self): |
| data_cache_config = app.config["DATA_CACHE_CONFIG"] |
| app.config["DATA_CACHE_CONFIG"] = {"CACHE_TYPE": "NullCache"} |
| cache_manager.init_app(app) |
| |
| slc = self.get_slice("Pivot Table v2") |
| |
| # Get chart metadata |
| metadata = self.get_json_resp(f"api/v1/chart/{slc.id}") |
| query_context = json.loads(metadata.get("result").get("query_context")) |
| query_context["form_data"] = slc.form_data |
| |
| # Request chart for the first time |
| resp = self.get_json_resp( |
| "api/v1/chart/data", |
| json_=query_context, |
| ) |
| |
| # Request chart for the second time |
| resp_from_cache = self.get_json_resp( |
| "api/v1/chart/data", |
| json_=query_context, |
| ) |
| |
| # restore DATA_CACHE_CONFIG |
| app.config["DATA_CACHE_CONFIG"] = data_cache_config |
| assert resp.get("result")[0].get("cached_dttm") is None |
| assert resp_from_cache.get("result")[0].get("cached_dttm") is None |
| |
| @pytest.mark.usefixtures("load_birth_names_dashboard_with_slices") |
| def test_slice_data_cache(self): |
| # Override cache config |
| data_cache_config = app.config["DATA_CACHE_CONFIG"] |
| cache_default_timeout = app.config["CACHE_DEFAULT_TIMEOUT"] |
| app.config["CACHE_DEFAULT_TIMEOUT"] = 100 |
| app.config["DATA_CACHE_CONFIG"] = { |
| "CACHE_TYPE": "SimpleCache", |
| "CACHE_DEFAULT_TIMEOUT": 10, |
| } |
| cache_manager.init_app(app) |
| |
| slc = self.get_slice("Pivot Table v2") |
| |
| # Get chart metadata |
| metadata = self.get_json_resp(f"api/v1/chart/{slc.id}") |
| query_context = json.loads(metadata.get("result").get("query_context")) |
| query_context["form_data"] = slc.form_data |
| |
| # Request chart for the first time |
| resp = self.get_json_resp( |
| "api/v1/chart/data", |
| json_=query_context, |
| ) |
| |
| # Request chart for the second time |
| resp_from_cache = self.get_json_resp( |
| "api/v1/chart/data", |
| json_=query_context, |
| ) |
| |
| result = resp.get("result")[0] |
| cached_result = resp_from_cache.get("result")[0] |
| |
| assert result.get("cached_dttm") is None |
| assert cached_result.get("cached_dttm") is not None |
| |
| # should fallback to default cache timeout |
| assert cached_result["cache_timeout"] == 10 |
| assert cached_result["status"] == QueryStatus.SUCCESS |
| assert result["data"] == cached_result["data"] |
| assert result["query"] == cached_result["query"] |
| |
| # should exists in `data_cache` |
| assert ( |
| cache_manager.data_cache.get(cached_result["cache_key"])["query"] |
| == cached_result["query"] |
| ) |
| |
| # should not exists in `cache` |
| assert cache_manager.cache.get(cached_result["cache_key"]) is None |
| |
| # reset cache config |
| app.config["DATA_CACHE_CONFIG"] = data_cache_config |
| app.config["CACHE_DEFAULT_TIMEOUT"] = cache_default_timeout |
| cache_manager.init_app(app) |