Files
superset2/tests/unit_tests/common/test_query_actions_drill_detail.py
T

82 lines
3.0 KiB
Python

# 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.
from types import SimpleNamespace
from typing import cast, TYPE_CHECKING
from unittest.mock import MagicMock
import pytest
from superset.common.query_actions import _prepare_drill_detail_query
from superset.exceptions import QueryObjectValidationError
if TYPE_CHECKING:
from superset.common.query_object import QueryObject
def test_prepare_drill_detail_query_refuses_datasource_that_opts_out() -> None:
"""
A datasource with ``supports_drill_to_detail = False`` (e.g. semantic
views) must be hard-blocked on the server. Without this gate the request
would fall through to dataframe acquisition and fail with an opaque error, and
the flag would only be enforced by the frontend menu — leaving the
chart-data API endpoint accepting drill-detail requests it shouldn't.
"""
datasource = MagicMock()
datasource.supports_drill_to_detail = False
query_obj = MagicMock()
query_obj.datasource = datasource
query_context = MagicMock()
with pytest.raises(
QueryObjectValidationError,
match="Drill to detail is not available",
):
_prepare_drill_detail_query(query_context, query_obj)
def test_prepare_drill_detail_query_allows_datasource_without_flag() -> None:
"""
Datasources that don't declare the flag (e.g. legacy ``SqlaTable``
subclasses via ``getattr`` default) must continue to work — the gate
only fires when the flag is explicitly ``False``.
"""
datasource = SimpleNamespace(columns=[SimpleNamespace(column_name="id")])
query_obj = SimpleNamespace(
columns=[],
datasource=datasource,
is_timeseries=True,
metrics=["count"],
orderby=[("name", False)],
post_processing=[{"operation": "pivot"}],
)
query_context = MagicMock()
prepared_query = _prepare_drill_detail_query(
query_context,
cast("QueryObject", query_obj),
)
assert prepared_query is not query_obj
assert prepared_query.is_timeseries is False
assert prepared_query.metrics is None
assert prepared_query.post_processing == []
assert prepared_query.columns == ["id"]
assert prepared_query.orderby == [("id", True)]
assert query_obj.columns == []