Skip to content

Fixes #21203: Attach TestCases to TestSuites upon creation cleanly via Resource layer#27398

Open
mohitjeswani01 wants to merge 7 commits intoopen-metadata:mainfrom
mohitjeswani01:feat/21203-testsuites-createtestcase-api
Open

Fixes #21203: Attach TestCases to TestSuites upon creation cleanly via Resource layer#27398
mohitjeswani01 wants to merge 7 commits intoopen-metadata:mainfrom
mohitjeswani01:feat/21203-testsuites-createtestcase-api

Conversation

@mohitjeswani01
Copy link
Copy Markdown

Description:

Fixes #21203

I worked on fully enabling CreateTestCase entities to be attached to Logical TestSuites during the POST/PUT creation workflows.

Why this approach is safe and highly optimized:
Unlike previous attempts which introduced massive N+1 queries and caused 34+ failures due to PATCH regressions, this implementation is heavily optimized. I moved the validation logic directly into the REST Resource boundary (TestCaseResource.java).

  1. Regression Safe: Only triggers on create(), createMany(), and createOrUpdate(). It totally ignores PATCH, cleanly side-stepping the "basic test suite" failure loops.
  2. Batch Fetching: Uses Entity.getEntityByNames() to resolve all testSuites in a single query upfront, ensuring high performance even in createMany() bursts.
  3. Fail-Fast: Validates all logical suites before persisting the main Test Case.

Proof of Verification:

image

Type of change:

  • Bug fix
  • Improvement

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes #21203: Attach TestCases to TestSuites upon creation cleanly via Resource layer
  • 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. (Explanation: No mapping/migration script is needed because testSuites was only added to the CreateTestCase request schema to generate relationship links, not to the core TestCase database storage schema itself).
  • I have added a test that covers the exact scenario we are fixing. For complex issues, comment the issue number in the test for future reference.
  • I have added tests around the new logic.

@mohitjeswani01 mohitjeswani01 requested a review from a team as a code owner April 15, 2026 13:34
Copilot AI review requested due to automatic review settings April 15, 2026 13:34
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR extends the TestCase creation API to optionally attach newly created/updated TestCases to one or more logical (non-basic) TestSuites, adding schema/UI support plus server-side validation and integration tests.

Changes:

  • Add testSuites to CreateTestCase request schema and generated UI API types.
  • Implement server-side batch resolution/authorization for requested logical TestSuites and attach created TestCases to them on create/createMany/createOrUpdate.
  • Add integration tests covering logical suite attachment, rejection of basic suites, non-existent suites, and PATCH regression safety.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 7 comments.

File Description
openmetadata-ui/src/main/resources/ui/src/generated/api/tests/createTestCase.ts Adds testSuites to the generated TS CreateTestCase type.
openmetadata-spec/src/main/resources/json/schema/api/tests/createTestCase.json Adds testSuites array field to the CreateTestCase API schema.
openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java Resolves/validates logical suites and attaches TestCases during POST/PUT/bulk creation flows.
openmetadata-integration-tests/src/test/java/org/openmetadata/it/tests/TestCaseResourceIT.java Adds IT coverage for logical suite attachment and PATCH non-regression.

Comment thread openmetadata-spec/src/main/resources/json/schema/api/tests/createTestCase.json Outdated
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copilot AI review requested due to automatic review settings April 15, 2026 13:55
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

Copilot AI review requested due to automatic review settings April 15, 2026 14:02
@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Apr 15, 2026

Code Review ✅ Approved 5 resolved / 5 findings

Refactors TestSuite attachment logic to prevent duplicate inserts and partial states during creation. All identified validation and state consistency issues have been addressed.

✅ 5 resolved
Bug: createOrUpdate attaches suites unconditionally, causing duplicate insert failures

📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:897-901
In createOrUpdate() (lines 897-901), resolveAndValidateLogicalSuites and the attachment loop run on every PUT request regardless of whether the entity was created or updated. The underlying bulkInsertToRelationship performs a raw SQL INSERT without ON CONFLICT / INSERT IGNORE handling (confirmed in CollectionDAO.EntityRelationshipDAO). This means a second PUT with the same testSuites will attempt to re-insert the same relationship rows and throw a duplicate-key exception.

The PutResponse returned by repository.createOrUpdate() carries a status (CREATED vs UPDATED) that should be checked to gate the attachment logic.

Performance: createMany calls addTestCasesToLogicalTestSuite per test case per suite

📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:790-802
In createMany() (lines 791-802), the inner loop calls repository.addTestCasesToLogicalTestSuite(suite, List.of(tc.getId())) once per test-case-per-suite combination. Since addTestCasesToLogicalTestSuite already accepts a List<UUID>, you could group test case IDs by suite and make one call per suite instead of O(testCases × suites) calls. The PR description mentions batch optimization, but this path isn't batched.

Bug: Partial state if suite attachment fails after entity creation

📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:713-717 📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:790-802
In both create() (lines 713-717) and createMany() (lines 790-802), the test case is persisted first and then logical-suite attachments happen in a separate, non-transactional loop. If the attachment loop fails midway (e.g., authorization failure on the second suite, or a DB error), the test case is already committed but only partially linked to its requested suites. The caller receives an error, so they may retry and hit duplicates.

Consider either: (a) moving validation + authorization entirely before repository.create() (which is partially done), then wrapping the attachment in the same transaction, or (b) performing all authorization checks upfront (already done) and accepting the current best-effort model with a note in the API docs.

Edge Case: PUT updates reject invalid testSuites even though they're ignored

📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:902-910
In createOrUpdate(), resolveAndValidateLogicalSuites() was moved before the repository.createOrUpdate() call (lines 902-903). This means validation now runs unconditionally for every PUT request—including updates to existing entities. However, suite attachment only happens when response.getStatus() == CREATED (line 906). For PUT updates, the suites field is effectively ignored, yet the request will fail with an IllegalArgumentException if any referenced suite doesn't exist or is a basic suite.

This is a regression for clients that send PUT requests for existing test cases with stale or invalid testSuites values—previously these would succeed silently, now they'll get a 400.

The fix is to either (a) keep the validation inside the CREATED branch (reverting to the previous position but losing the fail-fast benefit), or (b) skip validation when the entity already exists by checking existence first, or (c) only resolve suites lazily after knowing the response status.

Quality: Schema says "best-effort" but code does fail-fast validation

📄 openmetadata-spec/src/main/resources/json/schema/api/tests/createTestCase.json:77 📄 openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:1625-1631
The JSON schema description (line 77) was updated to say "test suite attachment is performed as a best-effort operation after test case creation," but the actual implementation in resolveAndValidateLogicalSuites throws IllegalArgumentException for missing or basic suites before entity creation. This mismatch between documented and actual behavior can confuse API consumers who expect best-effort semantics (i.e., create succeeds, bad suites silently skipped).

Either update the description to reflect the fail-fast behavior, or make the attachment truly best-effort by catching/logging errors during suite attachment.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

openmetadata-service/src/main/java/org/openmetadata/service/resources/dqtests/TestCaseResource.java:905

  • createOrUpdate always calls resolveAndValidateLogicalSuites(create.getTestSuites(), ...) before knowing whether the request will create vs update. If a client includes testSuites during an update (status OK), the request can now fail due to suite validation/authorization even though the field is effectively ignored for updates (you only attach when status is CREATED). Consider skipping validation unless the entity will be created (e.g., pre-check existence via repository.getByNameOrNull(...) when testSuites is non-empty, or move validation inside the CREATED branch and accept the tradeoff).
    EntityLink entityLink = EntityLink.parse(create.getEntityLink());
    OperationContext tableOpContext =
        new OperationContext(Entity.TABLE, MetadataOperation.EDIT_TESTS);
    ResourceContextInterface tableResourceContext =
        TestCaseResourceContext.builder().entityLink(entityLink).build();

@github-actions
Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@mohitjeswani01
Copy link
Copy Markdown
Author

Hi @TeddyCr @mohityadav766 All automated review feedback (Gitar & Copilot) regarding batch optimizations, validation safety, and edge-cases has been fully addressed and pushed.

Could you please add the safe to test label so the GitHub CI pipelines can officially run? Thanks!🙏

@PubChimps PubChimps added the safe to test Add this label to run secure Github workflows on PRs label Apr 16, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The Java checkstyle failed.

Please run mvn spotless:apply in the root of your repository and commit the changes to this PR.
You can also use pre-commit to automate the Java code formatting.

You can install the pre-commit hooks with make install_test precommit_install.

@github-actions
Copy link
Copy Markdown
Contributor

⚠️ TypeScript Types Need Update

The generated TypeScript types are out of sync with the JSON schema changes.

Since this is a pull request from a forked repository, the types cannot be automatically committed.
Please generate and commit the types manually:

cd openmetadata-ui/src/main/resources/ui
./json2ts-generate-all.sh -l true
git add src/generated/
git commit -m "Update generated TypeScript types"
git push

After pushing the changes, this check will pass automatically.

@github-actions
Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 63%
63.82% (59797/93684) 43.62% (31326/71807) 46.69% (9415/20161)

@mohitjeswani01
Copy link
Copy Markdown
Author

Hi @PubChimps👋

I saw the issue #21203 was closed with a note that the team is working on
this internally. I understand completely.

My PR #27398 implements the same feature via the Resource layer with batch
fetch validation (addressing @mohityadav766's review comment on #26960
directly).

Could you let me know:

  1. Should I keep this PR open for review once the internal work is ready?
  2. Are there specific changes needed before you can consider merging?

In the meantime, I'll continue resolving any failing CI checks on my end.
Happy to address any feedback immediately.

Thank you for all the work you're doing on this! 🙏

@sonarqubecloud
Copy link
Copy Markdown

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

🟡 Playwright Results — all passed (26 flaky)

✅ 3639 passed · ❌ 0 failed · 🟡 26 flaky · ⏭️ 84 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 478 0 2 4
🟡 Shard 2 644 0 3 7
🟡 Shard 3 645 0 8 1
🟡 Shard 4 625 0 4 22
✅ Shard 5 616 0 0 42
🟡 Shard 6 631 0 9 8
🟡 26 flaky test(s) (passed on retry)
  • Features/CustomizeDetailPage.spec.ts › API Collection - customization should work (shard 1, 1 retry)
  • Pages/UserCreationWithPersona.spec.ts › Create user with persona and verify on profile (shard 1, 1 retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/BulkImport.spec.ts › Database (shard 2, 1 retry)
  • Features/ChangeSummaryBadge.spec.ts › Automated badge should appear on entity description with Automated source (shard 2, 1 retry)
  • Features/Permissions/GlossaryPermissions.spec.ts › Team-based permissions work correctly (shard 3, 1 retry)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 2 retries)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 1 retry)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 2 retries)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 1 retry)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 2 retries)
  • Features/RestoreEntityInheritedFields.spec.ts › Validate restore with Inherited domain and data products assigned (shard 3, 2 retries)
  • Flow/ExploreDiscovery.spec.ts › Should not display deleted assets when showDeleted is not checked and deleted is not present in queryFilter (shard 3, 1 retry)
  • Pages/Customproperties-part2.spec.ts › entityReferenceList shows item count, scrollable list, no expand toggle (shard 4, 1 retry)
  • Pages/DataContracts.spec.ts › Create Data Contract and validate for DashboardDataModel (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Rename domain with assets (tables, topics, dashboards) preserves associations (shard 4, 1 retry)
  • Pages/Domains.spec.ts › Rename domain with owners and experts preserves assignments (shard 4, 1 retry)
  • Pages/HyperlinkCustomProperty.spec.ts › should accept valid http and https URLs (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › verify create lineage for entity - Stored Procedure (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › verify create lineage for entity - Metric (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)
  • Pages/Lineage/LineageRightPanel.spec.ts › Verify custom properties tab IS visible for supported type: searchIndex (shard 6, 1 retry)
  • Pages/Lineage/PlatformLineage.spec.ts › Verify domain platform view (shard 6, 1 retry)
  • Pages/Users.spec.ts › Permissions for table details page for Data Consumer (shard 6, 1 retry)
  • Pages/Users.spec.ts › Check permissions for Data Steward (shard 6, 1 retry)
  • VersionPages/EntityVersionPages.spec.ts › Directory (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

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.

Adding Test Case to Bundle Test Suite w/ API

3 participants