Compare commits

...
Author SHA1 Message Date
rusackasandClaude Opus 4.8 ac1d89e52e test(warm_up_cache): pin exact native filter predicate, not just non-emptiness
Per review from @sadpandajoe: a fix could return any non-empty
native-filter object and still pass. Assert the actual col/op/val
predicate the native filter's extraFormData carries, so a fix that
doesn't extract the right value still fails this test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-12 18:13:43 -07:00
rusackasandClaude Opus 4.8 88b5c24151 test(warm_up_cache): rename test to reflect expected behavior
Test name read like it asserted the current buggy behavior; the
assertion actually expects native filter defaults to be included.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 18:37:18 -07:00
rusackas 1e37e79b61 test(warm_up_cache): pin native filter defaults dropped from cache warming
get_dashboard_extra_filters() in superset/views/utils.py only reads the
legacy Filter Box default_filters/filter_scopes metadata; it never looks
at native_filter_configuration. ChartWarmUpCacheCommand relies on this
function to reconstruct a dashboard's applied filters for cache warming,
so for any dashboard built with native filters (the standard mechanism
today, not the deprecated Filter Box) warming silently applies none of
the dashboard's actual default filters -- the warmed cache key never
matches what the browser requests, and warm_up_cache is effectively a
no-op for such dashboards.

A correct native-filter extractor already exists and is wired into the
real /api/v1/chart/data endpoint
(superset.charts.data.dashboard_filter_context.get_dashboard_filter_context
/ apply_dashboard_filter_context, see superset/charts/data/api.py) --
ChartWarmUpCacheCommand just isn't using it. That's the natural fix to
reach for, but this PR is test-only: it pins the reproduction so the fix
can be reviewed and merged separately with the failing test as its
acceptance criterion.

Verified independently against current master (both the missing
native-filter read and the affected code paths), not just the original
report.

Fixes #43024
2026-08-10 15:14:39 -07:00
+87 -1
View File
@@ -17,8 +17,14 @@
"""Tests for superset.views.utils module"""
from flask import current_app
from sqlalchemy.orm.session import Session
from superset.views.utils import get_form_data
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:
@@ -51,3 +57,83 @@ def test_get_form_data_handles_non_dict_json_body() -> None:
assert form_data == {}
assert slc is None
def test_get_dashboard_extra_filters_includes_native_filter_defaults(
session: Session,
) -> None:
"""
get_dashboard_extra_filters must surface native filter defaults, not just
the legacy Filter Box ``default_filters``/``filter_scopes`` metadata.
Reported in apache/superset#43024 (originally raised in discussion #42382):
``ChartWarmUpCacheCommand`` relies on this function to reconstruct a
dashboard's applied filters for cache warming. Because it only reads the
legacy fields, warming a
dashboard that uses native filters (the standard mechanism today, not the
deprecated Filter Box) silently drops every native filter's default
value, so the warmed cache key never matches what the browser actually
requests and warm_up_cache is effectively a no-op for such dashboards.
A working native-filter extractor already exists and is wired into the
real ``/api/v1/chart/data`` endpoint (see
``superset.charts.data.dashboard_filter_context.get_dashboard_filter_context``)
-- this function just isn't using it.
"""
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",
)
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": {},
}
]
dashboard = Dashboard(
dashboard_title="native_filter_dash",
slices=[chart],
published=True,
json_metadata=json.dumps(
{"native_filter_configuration": native_filter_configuration}
),
position_json="{}",
)
db.session.add_all([chart, dashboard])
db.session.flush()
extra_filters = get_dashboard_extra_filters(chart.id, dashboard.id)
# Pin the actual predicate, not just non-emptiness -- a fix that returns
# any placeholder/non-empty value without extracting the native filter's
# own col/op/val (from defaultDataMask.extraFormData.filters) would
# otherwise still pass this test while producing a cache key that
# diverges from what the browser actually requests.
assert {"col": "region", "op": "IN", "val": ["APAC"]} in extra_filters, (
"get_dashboard_extra_filters must surface the native filter's "
"region=APAC predicate from defaultDataMask.extraFormData.filters -- "
"it currently only reads the legacy default_filters/filter_scopes "
"metadata, so native filter defaults are silently dropped from "
f"cache warming. Got: {extra_filters!r}"
)