Skip to content

Fixes 35274: Check test parameters against their definitions and fix open-window and boolean-set runs - #35629

Merged
Shreyansh100704 merged 14 commits into
mainfrom
fix/dq-generated-test-parameters
Oct 17, 2026
Merged

Shreyansh100704 merged 14 commits into
mainfrom
fix/dq-generated-test-parameters

Conversation

@Shreyansh100704

@Shreyansh100704 Shreyansh100704 commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Describe your changes:

Fixes #35274

Companion PR: open-metadata/ai-platform#1745 (test generation conforms to these definitions; it merges first). Related: open-metadata/ai-platform#1650, #35276 (2.0 line).

Main-line counterpart of #35276 (2.0, merged), with TeddyCr's review on it built in, plus the server-side half that 2.0 did not ship. Data quality tests could pass or fail for reasons unrelated to the data, and AI-generated tests hit every one of them (open-metadata/ai-platform#1650).

Runner (ingestion)

  • An open side of a between window excludes nothing: a dynamic test with no learned bounds now reports 0 failed rows instead of every row, and a window with one open side counts only the finite side (is_unbounded, SQAValidatorMixin._count_rows_outside shared by both SQL between validators and their failed-row filters).
  • Allowed and forbidden sets are parsed once, in the column's type (parse_set_values, get_set_param_value): on a column OpenMetadata records as BOOLEAN, "true"/"false" (any case) become booleans, so the comparison is boolean to boolean (Databricks aborted on the string mismatch, Data quality: open between bounds count every row as failed, and boolean sets compare as strings #35274). A datalake set keeps its values as written, because GenericDataFrameColumnParser types a column of "True"/"False" strings as BOOLEAN (TeddyCr's datalake regression on Fixes #35274: count no failed rows for an open between bound and compare boolean sets as booleans #35276).
  • A set written as JSON ([false], [null]) is read: literal_eval first, then JSON, so every value that parsed before parses the same. Found while reproducing on main: a generated forbiddenValues: [false] Aborted with "malformed node or string".
  • The set validators read their parameters inside the try, so a test on a missing column is Aborted by the validator's own handler.

Server

  • A new test case is rejected when a parameter value is none of its definition's optionValues (case-insensitive; blank is unset) or its column's type is outside a non-empty supportedDataTypes. The check runs in prepare() when update is false, so POST, createMany, the MCP tool and ODCS materialization get it now; PUT-create and the CSV import get it with Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667, which fixes how those callers reach prepare().
  • An update is checked only for what it changes: a changed parameter value must be one of its options, and a test moved to another column or definition is checked in full. A row stored before this rule, or on a column retyped since, stays editable.

Definitions

  • tableCustomSQLQuery.strategy says which option fits which query (the 2.0 text, verbatim). The 2.1.0 migration pushes it, and Fixes 31760: clarify MatchEnum behavior for column values #32123's columnValuesToBeInSet texts (matchEnum, allowedValues, the definition description, which never got a migration), to existing installs, since seeding only creates missing definitions.

Type of change:

  • Bug fix

High-level design:

  • Runner: one reading of "unbounded" (is_unbounded) is used by the checker, the row count and the failed-row filter; set parsing goes through one cooperative hook (get_set_values_type: the SQLAlchemy mixin returns the column type OpenMetadata records, mapped to SQLAlchemy; pandas returns none). Recorded in ADR:2026-10-16-a-set-parameter-is-read-in-its-column-type.
  • Server: prepare() checks a test case when update is false, after its other validations and before it creates the table's basic test suite, so a rejected create leaves no suite behind. That is the gate the disabled-definition check uses; PUT-create (createOrUpdate prepares with update true) and the CSV import (no prepare() call) miss it today, for both checks, and Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667 fixes those callers. createMany prepares every test before it stores any, so one rejected test fails the batch with no test case stored. Updates go through TestUpdater → validateUpdate, which loads the definition and table only when a parameter value or the target changed (an inspection query is stored by an update that changes neither). It does not check useDynamicAssertion against supportsDynamicAssertion, because the Collate UI sends it from a toggle left on. Recorded in ADR:2026-10-12-test-cases-are-checked-against-their-definition-at-create (v2).
  • Migration: appended to the unreleased 2.1.0 post-data scripts, both dialects, each statement guarded so it never writes NULL and idempotent. Main's 2.0.6 post-data scripts are empty (Fixes #35274: count no failed rows for an open between bound and compare boolean sets as booleans #35276's statements live only on 2.0), so a 2.0.5 or older install reaches the new text only through 2.1.0. On a 2.0.6 install the strategy statement is byte-identical to 2.0's and is skipped by the migration log, and the columnValuesToBeInSet statements replace 2.0's matchEnum wording with main's.
  • Merge order: after the ai-platform PR (open-metadata/ai-platform#1745), whose generator stops sending the option values and column types this server check rejects. It does not wait for Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667; PUT-create and the CSV import get the check when that lands.

Tests:

Use cases covered

  • A dynamic between test with no history reports 0 failed rows; one open side counts only the other.
  • ["true","false"] / ["true"] on a BOOLEAN column compares as booleans (InSet and NotInSet); a "True"/"False" string column on a datalake stays strings; a JSON [false] set runs.
  • A set test on a missing column is Aborted.
  • Creating a test with strategy=SUM, or a length test on an INT column, is rejected with 400 by POST and by createMany (which then stores no test case), and by PUT once Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667 lands; a rejected POST leaves no test suite behind; PATCHing a valid test to strategy=SUM is rejected; a valid row whose column is later retyped stays editable by PATCH and PUT.
  • dbt, Great Expectations and data diff definitions declare no supportedDataTypes or optionValues, so their test cases pass the check. A test library definition is held to the types and options its author declared.
  • An existing install on MySQL or Postgres gets the new descriptions, from 2.0.5, from 2.0.6, or from a 2.1.0 pre-release.

Unit tests

  • Added: TestCaseDefinitionConformanceTest (18, incl. what an update changes, and the seed invariant ai-platform relies on: every dynamic definition marks its two bounds with a validationRule), SeededTestDefinitions (helper moved out of TestCaseThresholdValidatorTest); ingestion test_utils.py (parse_set_values, JSON sets, is_boolean, is_unbounded), test_between_row_violations.py (open window, one open side, unfiltered sample), test_validations_databases.py (_no_bounds x2, _boolean_strings x2, _boolean_json, _missing_column, _lowercase_strategy, _blank_strategy), test_validations_datalake.py (string booleans), test_row_threshold.py (fixture declares the table, since a set is now parsed in its column's type).
  • Server: the 12 unit classes the impact map selects (incl. TestCaseDefinitionConformanceTest, TestCaseRepositoryTest, TestCaseThresholdValidatorTest): 377/377.
  • Ingestion: the 16 unit files that import a changed module: 594 passed. tests/unit/observability/data_quality: 813 passed. 6 Databend dialect errors in test_databend_profiler_sql.py are a missing local driver and fail identically on main.
  • Coverage on changed ingestion modules (whole-file, --cov per module): set validators 84 to 93%, between validators 83 to 86%, pandas_validator_mixin 90%, sqa_validator_mixin 66%, utils 59%, base_test_handler 55% (a 1,300-line module; every function this PR adds has a test).
  • Static: ruff clean, basedpyright 0 errors on the changed files, mvn spotless:apply no diff, Java impact map complete.

Backend integration tests

  • Added to TestCaseResourceIT: post_testWithUnofferedOptionValue_4xx, post_testOnUnsupportedColumnType_4xx, patch_toUnofferedOptionValue_4xx, createMany_withOneUnofferedOptionValue_createsNone, patch_keepsATestOnARetypedColumnEditable (creates a valid length test on VARCHAR name, retypes the column to INT, then PATCHes), post_rejectedForConformance_leavesNoTestSuite. The PUT-create ITs belong with Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667, which makes PUT-create reach the check. OrphanedTimeSeriesCleanupIT and DomainIsolationIT took the first listed definition for their fixture and put it on an integer column; both now use columnValuesToBeNotNull. ThresholdParameterMigrationIT executes every UPDATE test_definition in 2.1.0 twice on both engines, including the four new statements.

Local Java tests (make java_affected_run, on d6215060c012, 97 min): unit 371/371 passed; integration 4,456 run, 6 failed (MySQL + Elasticsearch: parallel 2,929, isolated 374, rdf 48, cache 1; Postgres + OpenSearch: parallel 1,034, isolated 6, search-it 64).

Each failure rerun alone on d03d713f738 (production code unchanged since):

  • OrphanedTimeSeriesCleanupIT: the new create check rejected its fixture (a length test on a BIGINT column). Fixture fixed in d03d713f738; rerun 6/6 passed.
  • SearchAggregateRbacIT (4 tests): a 60s wait for indexing timed out under load; rerun 4/4 passed.
  • DbToEsCountReconciliationIT: not caused by this PR, fails on rerun too. user has es=25, db=22: the 3 users SearchAggregateRbacIT soft-deletes, which the ES count includes and the DB count does not.

Not run locally: 10 *UIIT classes, which run in the nightly k8s Java IT job.

After the review change (every create path, changed-only updates), the tests it can affect, on ca1427dc7d3 + that change: unit 377/377 (the plan's 12 classes); every IT class that creates or updates test cases (38; 11 more than the plan selects), 2,607 run: MySQL + Elasticsearch 2,250 with 2 failures, Postgres + OpenSearch 352 and search-it 5, all passed.

  • DomainIsolationIT.test_incidents_restrictedUserSeesOnlyOwnDomain: the create check rejected its fixture (a length test on INT id); fixture fixed, class rerun 13/13 passed.
  • WorkflowDefinitionResourceIT.test_NewApprovalRunSupersedesStalePendingTask: a tag approval on a schema, no test case; a 60s wait timed out under load, rerun alone passed.

After moving the new-row check before suite creation: unit 377/377; TestCaseResourceIT 360 run, 0 failed (all 9 conformance ITs pass); 32 more of the classes above, 1,770 tests, 0 failed, before that run was cut short to save time.

Current design (if (!update) in prepare(), the updater for changes): unit 377/377; TestCaseResourceIT 355 run, 3 failed: the three PUT-create ITs, which depend on #35667 and were then removed from this PR, so the 352 that remain all passed or were skipped; DataContractResourceIT 410 run, 0 failed; TestCaseCsvDomainIsolationIT 7/7.

Ingestion integration tests

  • Ran locally the files that exercise the changed validators, on 64b178a3662: 48/48 passed. data_quality/test_failed_row_samples.py 10, postgres/test_data_quality.py 17, mysql/test_data_quality.py 8, datalake/test_data_quality.py 6, test_suite/test_workflow.py 6, databend/test_data_quality.py 1.

Playwright (UI) tests

  • Pages/Entity.spec.ts: the three test cases that put columnValueLengthsToBeBetween on the NUMERIC first column (now rejected by the server) use columnValuesToBeBetween with the same values. Every other Playwright test case was checked: its column type is supported and its option values are offered.

Manual testing performed

  1. Local main stack (Collate server on :8585, Postgres), table orders (100 rows: 18 statuses outside OPEN/CLOSED, 33 inactive, no negative amounts), registered through the metadata workflow.
  2. Created the failing shapes by API and ran them with main's runner, then with this branch's runner: dynamic open window 0 passed / 100 failed, now 100 / 0; forbiddenValues: [false] Aborted, now Failed with the 33 false rows.
  3. Migration, real OpenMetadataOperations migrate of this commit on fresh MySQL 8.0 and Postgres 17:
    • 2.0.5, seeded with the 2.0.5 definitions, then 2.0's own 2.0.6 scripts, then this 2.1.0: all four descriptions equal the seed, 25 definitions, parameters intact.
    • main's 2.1.0 already applied, then this 2.1.0: the new statements run on the rerun of the newest version; same result.
    • a further migrate prints "No Server Migration To be Run" on all four; on the 2.0.6 path the strategy statement is logged once, under 2.0.6.
  4. Server built with an earlier version of the review change (it also checked PUT-create, from createNewEntity), by API on orders: POST, PUT and createMany reject strategy=SUM and a length test on NUMERIC (createMany stores neither test of the batch); PATCH ROWS→SUM is rejected, ROWS→count accepted; with the column retyped VARCHAR→INT under a length test, PATCH of its description and minLength and an unchanged PUT all return 200. Before the change, PUT and PATCH accepted both. PUT-create is now left to Test case PUT-create and CSV import skip TestCaseRepository.prepare's create-time checks #35667; the PATCH and retyped-column results hold, the updater check being unchanged since.
  5. Non-OpenMetadata test cases on that server: the Great Expectations IT (test_great_expectation_integration.py, 1/1) and data diff IT (test_data_diff.py, 17 passed, 2 skipped by TODO marks) pass. dbt was not run end to end; its definition and test-case requests, built with its own dbt_utils helpers and written by PUT as its sink does, were created for not_null, unique, accepted_values and a singular test. A test library definition (VARCHAR/STRING, mode ∈ STRICT/LOOSE) accepted a valid case and rejected a NUMERIC column and mode=bogus.

UI screen recording:

Not applicable: no UI change (a Playwright spec's test data only).

Checklist:

  • I have read the CONTRIBUTING document.

  • My PR title is Fixes 35274: Check test parameters against their definitions and fix open-window and boolean-set runs

  • My PR is linked to a GitHub issue via Fixes #35274 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. (Seed data: 2.1.0 migration.)

  • For a UI feature or feature task: not applicable.

  • I have added tests (unit / integration / Playwright as applicable) and listed them above.

  • Decision check: adds docs/decisions/2026-10-12-test-cases-are-checked-against-their-definition-at-create.md and docs/decisions/2026-10-16-a-set-parameter-is-read-in-its-column-type.md.

  • I have added a test that covers the exact scenario we are fixing.

RetriggerView in GreptileConfidence Score: 5/5

The reviewed changes appear safe to merge, with no new actionable issues found.

Summary

Checks test parameters against their definitions and fixes open-window counts and boolean sets.

  • New test cases must fit their definition's options and column types.
  • Open between-test windows no longer count rows as failures.
  • Allowed and forbidden sets now parse in the form each runner expects.
  • Custom SQL tests read strategy values consistently, and definitions explain their choices.

Reviews (8) · Last reviewed commit: "test(dq): create IT fixtures with a defi..." · Reviewed by Greptile

@github-actions github-actions Bot added the safe to test Add this label to run secure Github workflows on PRs label Oct 16, 2026
…-parameters

# Conflicts:
#	bootstrap/sql/migrations/native/2.1.0/mysql/postDataMigrationSQLScript.sql
#	bootstrap/sql/migrations/native/2.1.0/postgres/postDataMigrationSQLScript.sql
@Shreyansh100704
Shreyansh100704 marked this pull request as ready for review October 16, 2026 13:56
Copilot AI balanced review requested due to automatic review settings October 16, 2026 13:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown
Contributor

🔄 Playwright impact map auto-refreshed

This PR touched specs or UI source that changed the source→spec routing map. I regenerated .github/playwright/impact-map.generated.json and pushed the diff to this branch.

- source entries: 936 → 937
- 1 added, 0 removed, 11 changed spec-list

New source→spec entries:
  openmetadata-ui/src/main/resources/ui/src/components/Database/Profiler/TableProfiler/QualityTab/QualityTab.component.tsx

Entries whose spec list changed:
  openmetadata-ui/src/main/resources/ui/playwright/e2e/fixtures/pages.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/TableClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DatabaseServiceClass.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/admin.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/apiResponse.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/common.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/scopedLocators.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/testCases.ts
  openmetadata-ui/src/main/resources/ui/playwright/utils/waitHelpers.ts
  … and 1 more

What is this file? It is the auto-generated half of Playwright's PR planner. It routes "if source X changes, run specs Y" by walking spec imports and cross-referencing getByTestId strings. Hand-authored routing in impact-map.json always wins on conflict.

What if I want to regenerate locally instead? Run this before pushing your next change to skip the bot commit:

python3 .github/scripts/generate_playwright_impact_map.py
git add .github/playwright/impact-map.generated.json
git commit --amend --no-edit  # or a separate commit

Copilot AI balanced review requested due to automatic review settings October 16, 2026 13:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 14:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread ingestion/src/metadata/data_quality/validations/table/base/tableCustomSQLQuery.py Outdated
Copilot AI balanced review requested due to automatic review settings October 16, 2026 14:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@TeddyCr TeddyCr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes on the create-only gate for TestCaseDefinitionConformance. Details inline.

Comment on lines +902 to +904
if (!update) {
TestCaseDefinitionConformance.validate(test, testDefinition, table, entityLink);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create-only makes this check easy to bypass:

  • PATCH: every PATCH calls prepareInternal(updated, true) (EntityRepository.java:4838), so it never runs this check. PATCHing strategy to SUM on a valid test case is stored unchecked.
  • PUT: EntityResource.createOrUpdate calls prepareInternal(entity, true) even when it creates a new row (see the note at EntityRepository.java:3373-3376). So every test case created by PUT skips the check, and that includes ingestion and most SDK clients.

I agree we shouldn't re-check the whole entity on update. A row saved before this rule, or one whose column was later retyped by ingestion, would return 400 on any edit, even a description change. Can we validate only what changed?

  • In TestCaseUpdater.entitySpecificUpdate, where original and updated are both available: check a parameter's optionValues only when that parameter's value changes, and check the column type only when entityLink or testDefinition changes.
  • For PUT-create: run the check from createNewEntity, the path every create goes through, for the same reason createdAt/createdBy are set there.

That keeps old and retyped rows editable and enforces the rule on every write path. The ADR's Consequences section and patch_doesNotRecheckDefinitionConformance would need updating to match, plus ITs for PATCH introducing an invalid option and for PUT creating one.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 16:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 17:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@TeddyCr TeddyCr left a comment •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: I've rewritten this review so it lists exactly what to change in this PR.

The rule itself, and the create/update split (create checks the whole test case, the updater checks only what changed), are good. What needs to change is where the create check lives. It's currently in three places, and two of them exist only to work around a test-case framework bug. I've filed that bug separately as #35667 and will fix it there.

Background. The repo's pattern is if (!update) in prepare() (there are 29 of these gates in jdbi3/, including the disabled-definition check right above this one), plus the updater for changes. That gate misses two test-case create paths, and the disabled-definition check misses them today too:

  • PUT-create: TestCaseResource.createOrUpdate prepares with update = true before it knows whether the row exists.
  • CSV import: TestCaseCsv never calls prepare at all.

These are bugs in how those callers reach prepare, not in this rule, so #35667 fixes them at the callers. With that fix, the plain !update gate covers every create path.

Changes requested in this PR

  1. TestCaseRepository.prepare: replace if (isNewTestCase(test, update)) with if (!update), keeping it where it is now (after validation, before getOrCreateTestSuite). Delete isNewTestCase.
  2. TestCaseRepository.createNewEntity: delete the override.
  3. TestCaseRepository.createManyTestCases: delete it, and change TestCaseResource.createMany back to repository.createMany(uriInfo, testCases). createMany already runs prepareInternal(e, false) on every row before any chunk is stored, so with item 1 a single bad row still means nothing is stored (createMany_withOneUnofferedOptionValue_createsNone keeps passing).
  4. validateDefinitionConformance: delete it. Nothing calls it once items 2 and 3 are done.
  5. Keep validateChangedConformance in the updater as it is. It covers PUT, PATCH and CSV updates, since updateForImport runs the updater.
  6. ITs: keep put_createWithUnofferedOptionValue_4xx, put_createOnUnsupportedColumnType_4xx and put_rejectedForConformance_leavesNoTestSuite. They depend on #35667 item 1, so this PR merges after #35667. Everything else in the PR's IT list passes with items 1–5 alone.
  7. ADR 2026-10-12-test-cases-are-checked-against-their-definition-at-create: in Decision, replace the paragraph about isNewTestCase / createNewEntity / createManyTestCases with: "prepare() checks a test case when update is false, before it creates the table's basic test suite; every create path reaches it that way (#35667)." In Consequences, replace the CSV paragraph with a reference to #35667, and remove the dropped tests from Guard if any no longer apply.

After this, every create is checked once, in prepare, before any side entity is created, and every update is checked once, in the updater. No special case for test cases is needed.

* A PUT that creates a row prepares with {@code update} true, so whether the row exists decides.
* The FQN is set here the same way prepareInternal sets it right after prepare.
*/
private boolean isNewTestCase(TestCase test, boolean update) {

@TeddyCr TeddyCr Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change: delete isNewTestCase and change the call site in prepare to if (!update).

Why: prepare(..., update) is the shared hook, and update tells it whether this is a create. It only looks unreliable here because TestCaseResource.createOrUpdate and the CSV dry run pass true without checking whether the row exists. That's a caller bug, now tracked in #35667. Working around it here costs an extra findByNameOrNull on every PUT and PATCH, on top of the lookup createOrUpdate already does, and makes prepare set the FQN itself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed; back to if (!update) like the disabled-definition check. PUT-create is left to the caller fix in #35667.

* (ADR:2026-10-12-test-cases-are-checked-against-their-definition-at-create).
*/
@Override
protected TestCase createNewEntity(TestCase test) {

@TeddyCr TeddyCr Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change: delete this override.

Why: no other repository overrides createNewEntity. With prepare doing the check, POST and PUT-create would run it twice, re-fetching the definition and table each time. The only path it covers that prepare doesn't is the CSV import, which never calls prepare. #35667 fixes that at TestCaseCsv.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Override removed. I didn't add a check in TestCaseCsv, since your summary moves the CSV caller fix to #35667

* createMany stores in chunks, each in its own transaction, so the whole batch is checked before
* any of it is stored.
*/
public List<TestCase> createManyTestCases(UriInfo uriInfo, List<TestCase> testCases) {

@TeddyCr TeddyCr Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change: delete createManyTestCases and validateDefinitionConformance, and change TestCaseResource.createMany back to repository.createMany(uriInfo, testCases).

Why: the Javadoc's reason (chunks stored in separate transactions) doesn't hold. EntityRepository.createMany runs prepareInternal(e, false) on every row before createManyEntities stores anything, so with the !update gate a single bad row already rejects the whole batch with nothing stored. This loop just checks every row a second time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dropped it; one bad row still means no test case is stored. The suites earlier rows' prepare() created stay, as with any other prepare rejection in a batch, and the ADR says so.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 19:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI balanced review requested due to automatic review settings October 16, 2026 20:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Shreyansh100704
Shreyansh100704 added this pull request to the merge queue Oct 16, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🚦 Removed from the merge queue — failed_checks (2026-10-17T03:41:14Z)

Blocked the queue: integration-tests-mysql-elasticsearch

Copilot AI balanced review requested due to automatic review settings October 17, 2026 09:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@gitar-bot

gitar-bot Bot commented Oct 17, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 1 closed / 1 findings

🟡 Medium risk · Server-side test-definition checks and revised data-quality counting/parsing could reject valid test cases or change reported failures when metadata differs.

Checks new data quality test parameters against their definitions' option values and supported column types, and fixes open-window failed-row counts and boolean set comparisons. Resolved this session: an unset or blank tableCustomSQLQuery strategy now runs as ROWS and samples failed rows as intended. No open issues found.

✅ 1 closed
✅ Edge Case: Unset/blank strategy runs as ROWS but skips failed-row samples

📄 ingestion/src/metadata/data_quality/validations/table/base/tableCustomSQLQuery.py:139-151 📄 ingestion/src/metadata/data_quality/validations/table/sqlalchemy/tableCustomSQLQuery.py:388-394
_get_strategy now returns None when strategy is blank or missing. _run_results treats None as ROWS, since it only checks == Strategy.COUNT. The tableCustomSQLQuery.json definition and the new blank-strategy fixture both say ROWS is the default. But result_with_failed_samples (sqlalchemy/tableCustomSQLQuery.py:392) only collects samples when self._get_strategy() == Strategy.ROWS. So when a test has a blank or missing strategy, computePassedFailedRowCount set and a Failed result, it runs as ROWS and still gets no failed-row sample. A test that sets ROWS explicitly does get one. The fix is to return Strategy.ROWS for an unset value, which keeps every caller on the same default.

Verification

Rules No rules evaluated

Functional validation Not enabled

Set up

Auto-approval Not enabled

Set up

For more verification details, comment gitar display:verbose.

Options

Display: compact → Showing compact verification results.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

@Shreyansh100704
Shreyansh100704 added this pull request to the merge queue Oct 17, 2026
@sonarqubecloud

Copy link
Copy Markdown

Merged via the queue into main with commit 4e57bca Oct 17, 2026
85 of 86 checks passed
@Shreyansh100704
Shreyansh100704 deleted the fix/dq-generated-test-parameters branch October 17, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Data quality: open between bounds count every row as failed, and boolean sets compare as strings

5 participants