Files
superset2/tests/unit_tests/views/test_utils.py
T

137 lines
5.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.
"""Tests for superset.views.utils module"""
from unittest.mock import patch
from flask import current_app
from sqlalchemy.orm.session import Session
from superset import db
from superset.connectors.sqla.models import Database, SqlaTable
from superset.models.dashboard import Dashboard
from superset.models.slice import Slice
from superset.utils import json
from superset.views.utils import get_dashboard_extra_filters, get_form_data
def test_get_form_data_handles_non_json_body_with_json_content_type() -> None:
"""get_form_data returns gracefully when Content-Type claims JSON but the
body isn't parseable JSON, instead of letting Werkzeug's BadRequest escape.
This is the shape of the request context an MCP tool call runs in when a
chart/dataset SQL template calls the ``filter_values()`` Jinja macro: the
Content-Type header says ``application/json`` but the body is not a JSON
chart-data payload.
"""
with current_app.test_request_context(
data="not-json-at-all", content_type="application/json"
):
form_data, slc = get_form_data()
assert form_data == {}
assert slc is None
def test_get_form_data_handles_non_dict_json_body() -> None:
"""get_form_data coerces a well-formed but non-object JSON body to {}.
``request.get_json()`` happily returns a scalar or list for valid JSON
that isn't a JSON object (e.g. ``null`` or ``42``). Downstream code treats
the parsed body as a mapping, so a non-dict result must not leak through.
"""
with current_app.test_request_context(data="42", content_type="application/json"):
form_data, slc = get_form_data()
assert form_data == {}
assert slc is None
def test_get_dashboard_extra_filters_includes_native_filter_defaults(
session: Session,
) -> None:
"""Native filter defaults are included in dashboard cache warming."""
Dashboard.metadata.create_all(session.get_bind())
dataset = SqlaTable(
table_name="extra_filters_table",
database=Database(database_name="extra_filters_db", sqlalchemy_uri="sqlite://"),
)
db.session.add(dataset)
db.session.flush()
chart = Slice(
slice_name="chart_with_native_filter",
datasource_id=dataset.id,
datasource_type="table",
)
dashboard = Dashboard(
dashboard_title="native_filter_dash",
slices=[chart],
published=True,
json_metadata=json.dumps(
{
"native_filter_configuration": [
{
"id": "NATIVE_FILTER-1",
"name": "Region filter",
"type": "NATIVE_FILTER",
"scope": {"rootPath": ["ROOT_ID"], "excluded": []},
"targets": [{"column": {"name": "region"}}],
"defaultDataMask": {
"extraFormData": {
"filters": [
{"col": "region", "op": "IN", "val": ["APAC"]}
]
},
"filterState": {"value": ["APAC"]},
},
"controlValues": {},
}
]
}
),
position_json="{}",
)
db.session.add_all([chart, dashboard])
db.session.flush()
with patch("superset.charts.data.dashboard_filter_context._check_dashboard_access"):
extra_filters = get_dashboard_extra_filters(chart.id, dashboard.id)
assert extra_filters == [{"col": "region", "op": "IN", "val": ["APAC"]}]
legacy_filter = {"col": "country", "op": "in", "val": ["Brazil"]}
metadata = json.loads(dashboard.json_metadata)
metadata["default_filters"] = json.dumps({"legacy-filter": {"country": ["Brazil"]}})
metadata["filter_scopes"] = {}
dashboard.json_metadata = json.dumps(metadata)
with (
patch("superset.charts.data.dashboard_filter_context._check_dashboard_access"),
patch(
"superset.views.utils.build_extra_filters",
return_value=[legacy_filter],
),
):
extra_filters = get_dashboard_extra_filters(chart.id, dashboard.id)
assert extra_filters == [
legacy_filter,
{"col": "region", "op": "IN", "val": ["APAC"]},
]