Repository navigation
Fixes #30361: Show failed rows sample when a test passes within its threshold - #35042
Conversation
… within its threshold A test case passing within its failure threshold still has failed rows, but ingestion, the server and the UI each kept or showed the failed rows sample only for a Failed result. Keep it for any run that found failed rows: a Failed result, or a Success with failedRows > 0. - ingestion: FailedSampleValidatorMixin samples under that rule - server: PUT /failedRowsSample accepts under that rule - UI: FailedTestCaseSampleData fetches under that rule Records the rule in ADR:2026-10-09-failed-rows-sample-follows-failed-rows-not-status.
…on-threshold-success
…on-threshold-success
…on-threshold-success
|
| Count | Rule |
|---|---|
| 2 | openmetadata-imports/no-lower-layer-page-imports |
| 1 | react-hooks/exhaustive-deps |
| 1 | openmetadata-ui-patterns/no-non-adaptive-palette |
All findings
| Location | Rule | Message | |
|---|---|---|---|
| 🟡 | src/components/DataQuality/IncidentManager/FailedTestCaseSampleData/FailedTestCaseSampleData.component.tsx:41:1 |
openmetadata-imports/no-lower-layer-page-imports |
Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here. |
| 🟡 | src/components/DataQuality/IncidentManager/FailedTestCaseSampleData/FailedTestCaseSampleData.component.tsx:264:6 |
react-hooks/exhaustive-deps |
React Hook useEffect has a missing dependency: 'fetchFailedTestCaseSampleData'. Either include it or remove the dependency array. |
| 🟡 | src/components/DataQuality/IncidentManager/FailedTestCaseSampleData/FailedTestCaseSampleData.component.tsx:366:27 |
openmetadata-ui-patterns/no-non-adaptive-palette |
Raw palette class "tw:border-r-gray-blue-100" is static — it does not flip in dark mode. Use the theme-adapting "utility-" variant (tw:border-r-utility-gray-blu |
| 🟡 | src/components/DataQuality/IncidentManager/FailedTestCaseSampleData/FailedTestCaseSampleData.test.tsx:20:1 |
openmetadata-imports/no-lower-layer-page-imports |
Pages are route-level composition modules. Move the shared implementation/type to a lower layer instead of importing a page from here. |
Fix locally (fast - only checks files changed in this branch):
make ui-checkstyle-changed…on-threshold-success # Conflicts: # openmetadata-ui/src/main/resources/ui/src/components/DataQuality/IncidentManager/FailedTestCaseSampleData/FailedTestCaseSampleData.component.tsx
🚦 Removed from the merge queue —
|
…on-threshold-success # Conflicts: # openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/TestCaseResourceIT.java
🚦 Removed from the merge queue —
|
…download retry When Central answers "not found", Maven writes a *.lastUpdated marker and won't ask again until the update interval passes, so attempts 2 and 3 failed instantly with the same error (the #35042 ejection's log shows Maven honouring those markers). Delete them before each retry. Also: retry only an attempt that failed within 10 minutes (a long attempt with no report was a hang, and must stay inside the job timeout), judge each attempt by its own output, and append every attempt to maven.log instead of overwriting the first failure.
🚦 Removed from the merge queue —
|
🚦 Removed from the merge queue —
|
Code Review ✅ Approved 1 closed / 1 findings🟡 Medium risk · Allowing threshold-passing tests to retain and display failed-row samples changes ingestion, API, and UI behavior; incorrect lifecycle gating could show stale rows or hide diagnostics. Extends failed-rows sample sampling, server acceptance, and UI fetching from Failed-only to any result with failed rows, so a test that passes within its threshold still shows its failing rows. Resolved a javadoc placement issue on toTestCaseStatus. No open issues found. ✅ 1 closed✅ Quality: New javadoc inserted under toTestCaseStatus's doc, orphaning it
VerificationRules No rules evaluated Functional validation Not enabledAuto-approval Not enabledFor more verification details, comment OptionsDisplay: compact → Showing compact verification results. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source |
| getattr(result.testCase, "computePassedFailedRowCount", False) | ||
| and result.testCaseResult.testCaseStatus == TestCaseStatus.Failed | ||
| ): | ||
| if not (getattr(result.testCase, "computePassedFailedRowCount", False) and self._has_failed_rows(result)): |
There was a problem hiding this comment.
Custom SQL samples stay missing
Changing the shared mixin does not cover tableCustomSQLQuery, whose SQLAlchemy validator overrides result_with_failed_samples and still requires Failed. With strategy=ROWS, operator="<=", threshold=7, and computePassedFailedRowCount=True, a query returning seven rows produces Success with failedRows=7. The override then skips both the sample and inspection query, so users still cannot inspect those rows.
Apply _has_failed_rows to that override too, keeping its ROWS check, and add a regression test.
|
|



Describe your changes:
Fixes #30361
A test case can pass while some rows still break its rule, as long as the failures stay under its failure threshold. For example, 7 failed rows with a threshold of 7 is a Success. Those rows are what a DQ team needs to see before the threshold is crossed, but three separate gates kept the failed rows sample for
Failedresults only:FailedSampleValidatorMixin)FailedFailed, orSuccesswithfailedRows > 0PUT /dataQuality/testCases/{id}/failedRowsSample)FailedFailedTestCaseSampleData)FailedWhat stays the same:
computePassedFailedRowCountis on.failedRows == 0or unknown) still costs no extra query.Successresult still deletes the stored sample on the server. The sink posts the result before the sample, so a Success within its threshold replaces the sample and a clean Success clears it.The rule and the write order it depends on are recorded in
docs/decisions/2026-10-09-failed-rows-sample-follows-failed-rows-not-status.mdand cited at each gate.Type of change:
High-level design:
Each layer applies the same check, "does the latest result have failed rows?", instead of "is the latest result Failed?". There is no schema change:
TestCaseResult.failedRowsalready exists and the threshold work already fills it.Alternative considered: dropping the server's delete-on-Success so that a sample outlives its run. I rejected it because the delete keeps the sample tied to the latest run, and the sink's write order already makes the delete correct for both kinds of Success.
Out of scope: the Warning status suggested in the issue thread. It needs a new
testCaseStatusenum value plus decisions on incidents and alerting, so it is better tracked separately.Tests:
Local Java test run: PASSED
eadd865c47aa(baseupstream/main) — uncommitted changes were presentTests run locally
CreateTestCaseToolTest(4 passed)AutoAssignIncidentIT(41 passed, 1 skipped),AutoCloseIncidentIT(95 passed, 12 skipped),BaseEntityIT$ListEntityHistoryByTimestampPaginationTest(27 passed, 2 skipped),ConfigResourceIT(12 passed),DataQualityDimensionMigrationIT(2 passed),DataQualityDimensionPropagationIT(10 passed),DataQualityLineageIT(24 passed),DatabaseSmokeIT(8 passed),EntityProfileResourceIT(11 passed),GlossaryTermResourceIT(82 passed, 2 skipped),IncidentGroupsIT(163 passed, 11 skipped),IncidentPaginationIT(19 passed, 1 skipped),IncidentTaskIntegrationIT(274 passed, 37 skipped),IncidentTaskNotificationIT(8 passed),LatestTestCaseResultListingIT(130 passed, 10 skipped),OrphanedTimeSeriesCleanupIT(44 passed, 2 skipped),SeedDataPresenceIT(1 passed),SqlTestDecoratorsIT(6 passed),StaleIncidentStatusIT(42 passed),TableResourceIT(5 passed),TestCaseCsvDomainIsolationIT(21 passed),TestCaseDeleteResilienceIT(25 passed),TestCaseLatestStatusIT(47 passed, 5 skipped),TestCaseRelationshipRetentionCleanupIT(27 passed),TestCaseResolutionStatusLegacyTestSuitesIT(1 passed),TestCaseResourceIT(358 passed, 11 skipped),TestCaseSoftDeleteSearchIT(1 passed),TestDefinitionResourceIT(31 passed, 4 skipped),TestSuiteResourceIT(31 passed, 2 skipped),UserResourceIT(62 passed, 7 skipped)TestSuiteReindexIT(1 passed)TestCaseStaleDefinitionReindexIT(1 passed)Per-class counts come from the test reports, which can credit a test to the wrong class when classes run concurrently, and keep only the last run of a nested class that several test classes inherit. The step totals above are Maven's own counts.
Why these tests
area data-quality←openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.javacalled from entity TestCase←openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.javachanged test←openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/TestCaseResourceIT.javaentity TestCase←openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.javasmoke←code other than a test class changedCommands
Use cases covered
Unit tests
ingestion/tests/unit/data_quality/validations/test_failed_sample_mixin.py: Success withfailedRows > 0is sampled; Success withfailedRows0 or None, the flag off, or Aborted is not. 16 passed.tests/unit/data_quality,tests/unit/observability/data_quality): 778 passed. 9 failed intest_clickzetta_data_diff.pywithModuleNotFoundError: clickzetta, an optional dependency missing from my local venv and unrelated to this change.FailedTestCaseSampleData.test.tsx: added "passed within its threshold → fetches". Both suites in the folder pass (12 tests). Checked that the new test fails when the Success branch is reverted.Backend integration tests
TestCaseResourceIT#test_failedRowsSampleAcceptedWhenPassingWithinThreshold(new)TestCaseResourceIT#test_failedRowsSampleRejectedWhenPassingWithoutFailedRows(new)Review fixes and verification (
5c66ebb717c; supersedes earlier local-test notes)clickzettapackage is absent from the local environment.git diff --checkpassed. Lint has pre-existing warnings. The full Playwright TypeScript check still reports errors in untouched helpers, not this changed spec.Ingestion integration tests
ingestion/tests/integration/data_quality/test_failed_row_samples.py::test_passing_within_threshold_publishes_failed_samples(new):columnValuesToBeNotNullonbad_data_customer.email(about 10% null) with a 50% threshold passes, and the sample holds only null-email rows.400 Failed rows can only be added to a failed test case. That is the guard this PR relaxes. The server side is covered by the ITs above; the end-to-end Python test has not yet been re-run against a server that includes this change.Playwright (UI) tests
failedRows > 0and checks that the sample table renders.Manual testing performed
UI screen recording / screenshots:
TODO: attach a recording of the sample table on a test case that passed within its threshold.
Checklist:
I have read the CONTRIBUTING document.
My PR title is
Fixes <issue-number>: <short explanation>My PR is linked to a GitHub issue via
Fixes #<issue-number>above.I have commented on my code, particularly in hard-to-understand areas.
For JSON Schema changes: I updated the migration scripts or explained why it is not needed. (N/A, no schema change)
For UI changes: I attached a screen recording and/or screenshots above.
I have added tests (unit / integration / Playwright as applicable) and listed them above.
Decision check: adds
docs/decisions/2026-10-09-failed-rows-sample-follows-failed-rows-not-status.md.I have added tests around the new logic.
🤖 Generated with Claude Code
Final CI monitoring result (
5c66ebb717c59a560d8cd706c6d0c7083591285b)All checks reached a terminal state: 42 successful, 27 skipped, 2 failed. Skipped jobs are not counted as executed tests. Collate, the Python 3.10/3.11/3.12 unit/static matrix and coverage aggregation, service unit tests, UI coverage/quality gates, Java/UI/Python formatting, and Maven/Sonar completed successfully.
The two failures occurred before their tests ran, while pulling unchanged Docker images:
eclipse-temurin:21-jdk. A single failed-job rerun also received HTTP 429 while building the existing PR-label action frompython:3.6.10-alpine3.10.alpine:3; browser assertions never ran.CI is not green. These infrastructure failures need a later successful rerun once registry pulls are available. No workflow, Dockerfile, credentials, or labels were changed to bypass the failures. No remaining blocking code defect was identified in the reviewed paths after the committed fixes; this is not a claim that the failed CI jobs passed.
Fix the custom SQL sampling override before merging so passing tests with failed rows receive the promised sample.
Findings
Summary
Allows failed-row samples for
Successresults withfailedRows > 0across the shared ingestion mixin, server, and UI.Diagram
Reviews (1) · Last reviewed commit: "Merge branch 'main' into failed-rows-sam..." · Reviewed by Greptile