mirror of
https://github.com/apache/superset.git
synced 2026-04-19 16:14:52 +00:00
test: birth names (#12226)
* add birth names fixture * fix birth names related tests * fix test_import_v0_dataset_cli_export columns order * fix celery tests drop table * fix mysql datetime type * fix mysql typo in charts/api_tests * refactor * add licence * fix use fixture for presto * fix presto, hive query * fix flaky metadata * fix mysql bigint type * fix run query * fix hive datatype in metadata * fix slice owner for cypress * refactor num_boys num_girls * fix is_dttm column * debug logging * fix query offset * fix presto ds type in metadata * fix presto ds type * clean up debug logging
This commit is contained in:
@@ -18,16 +18,19 @@
|
||||
"""Unit tests for Superset"""
|
||||
import json
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from io import BytesIO
|
||||
from unittest import mock
|
||||
from zipfile import is_zipfile, ZipFile
|
||||
|
||||
from superset.models.sql_lab import Query
|
||||
from tests.fixtures.birth_names_dashboard import load_birth_names_dashboard_with_slices
|
||||
|
||||
import humanize
|
||||
import prison
|
||||
import pytest
|
||||
import yaml
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import and_, or_
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
from tests.test_app import app
|
||||
@@ -41,7 +44,7 @@ from superset.models.dashboard import Dashboard
|
||||
from superset.models.reports import ReportSchedule, ReportScheduleType
|
||||
from superset.models.slice import Slice
|
||||
from superset.utils import core as utils
|
||||
from superset.utils.core import AnnotationType, get_example_database
|
||||
from superset.utils.core import AnnotationType, get_example_database, get_main_database
|
||||
|
||||
from tests.base_api_tests import ApiOwnersTestCaseMixin
|
||||
from tests.base_tests import SupersetTestCase, post_assert_metric, test_client
|
||||
@@ -57,6 +60,7 @@ from tests.fixtures.energy_dashboard import load_energy_table_with_slice
|
||||
from tests.fixtures.query_context import get_query_context, ANNOTATION_LAYERS
|
||||
from tests.fixtures.unicode_dashboard import load_unicode_dashboard_with_slice
|
||||
from tests.annotation_layers.fixtures import create_annotation_layers
|
||||
from tests.utils.get_dashboards import get_dashboards_ids
|
||||
|
||||
CHART_DATA_URI = "api/v1/chart/data"
|
||||
CHARTS_FIXTURE_COUNT = 10
|
||||
@@ -431,10 +435,12 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
db.session.delete(user_alpha2)
|
||||
db.session.commit()
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_create_chart(self):
|
||||
"""
|
||||
Chart API: Test create chart
|
||||
"""
|
||||
dashboards_ids = get_dashboards_ids(db, ["world_health", "births"])
|
||||
admin_id = self.get_user("admin").id
|
||||
chart_data = {
|
||||
"slice_name": "name1",
|
||||
@@ -445,7 +451,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
"cache_timeout": 1000,
|
||||
"datasource_id": 1,
|
||||
"datasource_type": "table",
|
||||
"dashboards": [1, 2],
|
||||
"dashboards": dashboards_ids,
|
||||
}
|
||||
self.login(username="admin")
|
||||
uri = f"api/v1/chart/"
|
||||
@@ -733,6 +739,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.get_assert_metric(uri, "get")
|
||||
self.assertEqual(rv.status_code, 404)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_get_chart_no_data_access(self):
|
||||
"""
|
||||
Chart API: Test get chart without data access
|
||||
@@ -747,8 +754,11 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.client.get(uri)
|
||||
self.assertEqual(rv.status_code, 404)
|
||||
|
||||
@pytest.mark.usefixtures("load_unicode_dashboard_with_slice")
|
||||
@pytest.mark.usefixtures("load_energy_table_with_slice")
|
||||
@pytest.mark.usefixtures(
|
||||
"load_energy_table_with_slice",
|
||||
"load_birth_names_dashboard_with_slices",
|
||||
"load_unicode_dashboard_with_slice",
|
||||
)
|
||||
def test_get_charts(self):
|
||||
"""
|
||||
Chart API: Test get charts
|
||||
@@ -788,6 +798,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
db.session.delete(chart)
|
||||
db.session.commit()
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_get_charts_filter(self):
|
||||
"""
|
||||
Chart API: Test get charts filter
|
||||
@@ -995,7 +1006,9 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
self.assertEqual(len(data["result"]), 3)
|
||||
|
||||
@pytest.mark.usefixtures(
|
||||
"load_unicode_dashboard_with_slice", "load_energy_table_with_slice"
|
||||
"load_unicode_dashboard_with_slice",
|
||||
"load_energy_table_with_slice",
|
||||
"load_birth_names_dashboard_with_slices",
|
||||
)
|
||||
def test_get_charts_page(self):
|
||||
"""
|
||||
@@ -1028,6 +1041,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["count"], 0)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_simple(self):
|
||||
"""
|
||||
Chart data API: Test chart data query
|
||||
@@ -1037,8 +1051,10 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
self.assertEqual(data["result"][0]["rowcount"], 45)
|
||||
expected_row_count = self.get_expected_row_count("client_id_1")
|
||||
self.assertEqual(data["result"][0]["rowcount"], expected_row_count)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_applied_time_extras(self):
|
||||
"""
|
||||
Chart data API: Test chart data query with applied time extras
|
||||
@@ -1060,8 +1076,10 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
data["result"][0]["rejected_filters"],
|
||||
[{"column": "__time_origin", "reason": "not_druid_datasource"},],
|
||||
)
|
||||
self.assertEqual(data["result"][0]["rowcount"], 45)
|
||||
expected_row_count = self.get_expected_row_count("client_id_2")
|
||||
self.assertEqual(data["result"][0]["rowcount"], expected_row_count)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_limit_offset(self):
|
||||
"""
|
||||
Chart data API: Test chart data query with limit and offset
|
||||
@@ -1090,6 +1108,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
self.assertEqual(result["rowcount"], 5)
|
||||
self.assertEqual(result["data"][0]["name"], expected_name)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
@mock.patch(
|
||||
"superset.common.query_object.config", {**app.config, "ROW_LIMIT": 7},
|
||||
)
|
||||
@@ -1105,6 +1124,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
result = response_payload["result"][0]
|
||||
self.assertEqual(result["rowcount"], 7)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
@mock.patch(
|
||||
"superset.common.query_context.config", {**app.config, "SAMPLES_ROW_LIMIT": 5},
|
||||
)
|
||||
@@ -1131,6 +1151,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 400)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_incorrect_result_format(self):
|
||||
"""
|
||||
Chart data API: Test chart data with unsupported result format
|
||||
@@ -1141,6 +1162,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 400)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_query_result_type(self):
|
||||
"""
|
||||
Chart data API: Test chart data with query result format
|
||||
@@ -1151,6 +1173,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_csv_result_format(self):
|
||||
"""
|
||||
Chart data API: Test chart data with CSV result format
|
||||
@@ -1161,6 +1184,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_mixed_case_filter_op(self):
|
||||
"""
|
||||
Chart data API: Ensure mixed case filter operator generates valid result
|
||||
@@ -1208,6 +1232,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
self.assertIn("sum__num__yhat_lower", row)
|
||||
self.assertEqual(result["rowcount"], 47)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_query_missing_filter(self):
|
||||
"""
|
||||
Chart data API: Ensure filter referencing missing column is ignored
|
||||
@@ -1223,6 +1248,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
response_payload = json.loads(rv.data.decode("utf-8"))
|
||||
assert "non_existent_filter" not in response_payload["result"][0]["query"]
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_no_data(self):
|
||||
"""
|
||||
Chart data API: Test chart data with empty result
|
||||
@@ -1283,6 +1309,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = self.post_assert_metric(CHART_DATA_URI, payload, "data")
|
||||
self.assertEqual(rv.status_code, 401)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_jinja_filter_request(self):
|
||||
"""
|
||||
Chart data API: Ensure request referencing filters via jinja renders a correct query
|
||||
@@ -1325,6 +1352,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
"superset.extensions.feature_flag_manager._feature_flags",
|
||||
GLOBAL_ASYNC_QUERIES=True,
|
||||
)
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
def test_chart_data_async_results_type(self):
|
||||
"""
|
||||
Chart data API: Test chart data query non-JSON format (async)
|
||||
@@ -1353,6 +1381,7 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
rv = post_assert_metric(test_client, CHART_DATA_URI, request_payload, "data")
|
||||
self.assertEqual(rv.status_code, 401)
|
||||
|
||||
@pytest.mark.usefixtures("load_birth_names_dashboard_with_slices")
|
||||
@mock.patch.dict(
|
||||
"superset.extensions.feature_flag_manager._feature_flags",
|
||||
GLOBAL_ASYNC_QUERIES=True,
|
||||
@@ -1379,8 +1408,9 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
)
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
|
||||
expected_row_count = self.get_expected_row_count("client_id_3")
|
||||
self.assertEqual(rv.status_code, 200)
|
||||
self.assertEqual(data["result"][0]["rowcount"], 45)
|
||||
self.assertEqual(data["result"][0]["rowcount"], expected_row_count)
|
||||
|
||||
@mock.patch.dict(
|
||||
"superset.extensions.feature_flag_manager._feature_flags",
|
||||
@@ -1609,7 +1639,9 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
"message": {"metadata.yaml": {"type": ["Must be equal to Slice."]}}
|
||||
}
|
||||
|
||||
@pytest.mark.usefixtures("create_annotation_layers")
|
||||
@pytest.mark.usefixtures(
|
||||
"create_annotation_layers", "load_birth_names_dashboard_with_slices"
|
||||
)
|
||||
def test_chart_data_annotations(self):
|
||||
"""
|
||||
Chart data API: Test chart data query
|
||||
@@ -1648,3 +1680,32 @@ class TestChartApi(SupersetTestCase, ApiOwnersTestCaseMixin):
|
||||
data = json.loads(rv.data.decode("utf-8"))
|
||||
# response should only contain interval and event data, not formula
|
||||
self.assertEqual(len(data["result"][0]["annotation_data"]), 2)
|
||||
|
||||
def get_expected_row_count(self, client_id: str) -> int:
|
||||
start_date = datetime.now()
|
||||
start_date = start_date.replace(
|
||||
year=start_date.year - 100, hour=0, minute=0, second=0
|
||||
)
|
||||
|
||||
quoted_table_name = self.quote_name("birth_names")
|
||||
sql = f"""
|
||||
SELECT COUNT(*) AS rows_count FROM (
|
||||
SELECT name AS name, SUM(num) AS sum__num
|
||||
FROM {quoted_table_name}
|
||||
WHERE ds >= '{start_date.strftime("%Y-%m-%d %H:%M:%S")}'
|
||||
AND gender = 'boy'
|
||||
GROUP BY name
|
||||
ORDER BY sum__num DESC
|
||||
LIMIT 100) AS inner__query
|
||||
"""
|
||||
resp = self.run_sql(sql, client_id, raise_on_error=True)
|
||||
db.session.query(Query).delete()
|
||||
db.session.commit()
|
||||
return resp["data"][0]["rows_count"]
|
||||
|
||||
def quote_name(self, name: str):
|
||||
if get_main_database().backend in {"presto", "hive"}:
|
||||
return get_example_database().inspector.engine.dialect.identifier_preparer.quote_identifier(
|
||||
name
|
||||
)
|
||||
return name
|
||||
|
||||
Reference in New Issue
Block a user