sadpandajoe commented on code in PR #45395:
URL: https://github.com/apache/superset/pull/45395#discussion_r4343053527
##########
superset-core/src/superset_core/semantic_layers/testing.py:
##########
@@ -59,3 +79,313 @@ def semantic_layer_registration(monkeypatch:
pytest.MonkeyPatch) -> None:
integration lane. Use in isolated provider test processes, not a live host.
"""
monkeypatch.setattr(decorators, "semantic_layer", _registration)
+
+
+# Keep test data and provider construction in the provider's own fixtures. This
+# suite consumes the real SDK types rather than a copy of a factory signature.
+class SemanticProviderConformance:
+ """Subclass in a ``Test...`` class and supply the documented provider
fixtures.
+
+ Query fixtures seed discriminating data and provide independent expected
+ Arrow tables for identity, grain, NULL, grouped OR, and order-before-limit.
+ Error fixtures call real provider methods against controlled backend
outcomes.
+ See the provider author guide for every fixture and the limits of this
suite.
+ """
+
+ def test_catalog_identity(
+ self, semantic_view: SemanticView, semantic_reloaded_view: SemanticView
+ ) -> None:
+ """Stable selections survive reloads without ambiguous catalog
members."""
+ assert semantic_view.uid()
+ assert semantic_view.uid() == semantic_reloaded_view.uid()
+ assert _catalog(semantic_view) == _catalog(semantic_reloaded_view)
+
+ @pytest.mark.parametrize(
+ "case", ["identity", "grain", "null", "not_null", "or", "order_limit"]
+ )
+ def test_query_outputs(
+ self,
+ case: str,
+ semantic_view: SemanticView,
+ semantic_query_cases: Mapping[str, tuple[SemanticQuery, pa.Table]],
+ ) -> None:
+ """Compare executed results, including column names and row order."""
+ query: SemanticQuery
+ expected: pa.Table
+ query, expected = semantic_query_cases[case]
+ assert expected.num_rows > 0, (
+ f"{case} must distinguish a correct result from no data"
+ )
+ assert query.order or expected.num_rows == 1, (
+ f"{case}: multi-row fixtures need explicit order"
+ )
+ assert set(query.dimensions) <= semantic_view.get_dimensions()
+ assert set(query.metrics) <= semantic_view.get_metrics()
+ if case == "grain":
+ assert any(dimension.grain is not None for dimension in
query.dimensions)
Review Comment:
The `grain` case requires a grain-bearing dimension, so a provider whose
views only expose categorical dimensions (every `grain` is `None`, which the
SDK allows) fails this assertion on every legal query, and can only conform by
inventing a temporal dimension. Should this case skip with a clear reason when
the catalog has no grain-bearing dimension, like the unadvertised capability
lanes do?
##########
superset-core/tests/semantic_layers/conformance_provider.py:
##########
@@ -0,0 +1,237 @@
+# 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.
+
+"""Test-only SQLite adapter for the conformance examples; no external
service."""
+
+import sqlite3
+from contextlib import closing
+from datetime import date
+from typing import Any
+
+import pyarrow as pa
+from example_provider import ExampleView
+from superset_core.semantic_layers.errors import (
+ SemanticQueryErrorCode,
+ SemanticQueryRejectedError,
+ SemanticResultCompletenessError,
+ SemanticResultCompletenessReason,
+)
+from superset_core.semantic_layers.types import (
+ Dimension,
+ Filter,
+ FilterExpression,
+ Grains,
+ Metric,
+ Operator,
+ OrFilter,
+ SemanticQuery,
+ SemanticResult,
+)
+from superset_core.semantic_layers.view import SemanticViewFeature
+
+
+class Backend:
+ """Controlled backend responses and a changing metadata catalog."""
+
+ def __init__(self) -> None:
+ self.revision: int = 0
+ self.fault: bool = False
+ self.completeness: SemanticResultCompletenessReason | None = None
+
+ def execute(self, sql: str, parameters: list[object]) -> list[tuple[Any,
...]]:
+ """Execute against deliberately unsorted data, including a NULL
group."""
+ if self.fault:
+ raise ConnectionError("test backend unavailable")
+ connection: sqlite3.Connection
+ with closing(sqlite3.connect(":memory:")) as connection:
+ connection.execute(
+ "CREATE TABLE records(category TEXT, occurred TEXT, amount
INT)"
+ )
+ connection.executemany(
+ "INSERT INTO records VALUES (?, ?, ?)",
+ [
+ ("B", "2026-02-04", 8),
Review Comment:
The seed only has categories A, B and NULL, and the `or` case selects all
three, so a provider that ignores the grouped filter entirely (keeping just the
outer February bound) still returns `[(None, 1), ('A', 5), ('B', 8)]` and
passes. The current mutations only drop the parentheses, the outer comparison,
or one IN value. Could a February row in an excluded category (say `"C"`) be
seeded, with a mutation that drops the whole OR group added, so that case fails?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]