Skip to content

test: de-flake scheduled ITs (test-planted handle collisions, leaked bitstream formats, stale Solr searcher) - #1413

Merged
milanmajchrak merged 2 commits into
dtq-devfrom
fix/flaky-integration-tests
Aug 18, 2026
Merged

test: de-flake scheduled ITs (test-planted handle collisions, leaked bitstream formats, stale Solr searcher)#1413
milanmajchrak merged 2 commits into
dtq-devfrom
fix/flaky-integration-tests

Conversation

@milanmajchrak

@milanmajchrak milanmajchrak commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

References

Description

Scheduled integration-test builds on dtq-dev fail intermittently (~1 in 5 runs), each time in a different test. This PR removes the three sources of cross-test interference behind those failures. Test-only changes, no production code touched.

Instructions for Reviewers

List of changes in this PR:

  • RequiredMetadataIT, ItemHandleCheckerIT: the explicit collection handle is a deterministic non-numeric suffix (e.g. 123456789/required-metadata-test) instead of 123456789/<1000 + Random.nextInt(1000)>. Handle rows survive object deletion and handle_seq reaches 1000+ late in the module run, so the random handle was intermittently re-minted by the sequence and killed whichever test was minting at that moment (Unique index or primary key violation ... PUBLIC.HANDLE ... '123456789/1154', session left MARKED_ROLLBACK). A non-numeric suffix can never be produced by the sequence; per-class constants keep the Fixing RequiredMetadataIT ufal/clarin-dspace#1273 protection against cross-class handle reuse. XmlWorkflowFactoryTest gets the same treatment for its 123456789/999.
  • PreviewContentServiceImplIT: the custom bitstream format is deleted by id in its own Context after super.destroy(). The previous delete went through the shared test context, where it is never committed, leaking one registry row per test (13 total) and breaking BitstreamFormatRestRepositoryIT count assertions whenever class scan order put Preview first.
  • BitstreamFormatRestRepositoryIT: short descriptions derived from the test method name instead of Random (also removes the accidental "Test shortnull"), the created format id is captured on the POST so the finally-block cleans up even when a later assertion fails, and count assertions compare against a baseline read at test start instead of the hardcoded registry size.
  • StatisticsRestRepositoryIT#totalVisitsReport_Item_Visited: an explicit statistics-core commit (waitSearcher=true) between posting the view event and querying the report, as topCountriesReport_Community_Visited already does. The report could otherwise read a stale Solr searcher and see 0 views. The same pattern exists in the other view-then-assert tests of this class; only the one observed failing is changed here.

To reproduce the two main failures on dtq-dev (both verified in Docker, maven:3.9-eclipse-temurin-11, CI flags):

  • Pin the explicit handle in RequiredMetadataIT.randomString() to "20" and run mvn -pl dspace-api verify -DskipIntegrationTests=false -Dit.test=RequiredMetadataIT,SubscribeServiceIT - fails with the exact CI signature. With this PR the planted handle is gone and the same selection is green.
  • mvn -pl dspace-server-webapp verify -DskipIntegrationTests=false -Dit.test=PreviewContentServiceImplIT,BitstreamFormatRestRepositoryIT -Dfailsafe.runOrder=reversealphabetical - 4 failures (totalElements 95 vs 108). With this PR: green.

Notes:

  • The mint path itself (HandleServiceImpl.createId) still trusts the sequence blindly; hardening it (skip suffixes whose handle already exists) would also cover production minting after handle imports, and is prepared as a possible follow-up PR.
  • The IT job's -Dfailsafe.rerunFailingTestsCount=2 is ignored by maven-failsafe-plugin 2.22.x (it reads surefire.rerunFailingTestsCount), so IT reruns never actually ran; the one-line workflow fix comes separately.

Checklist

  • My PR is small in size (e.g. less than 1,000 lines of code, not including comments & integration tests). Exceptions may be made if previously agreed upon.
  • My PR passes Checkstyle validation based on the Code Style Guide.
  • My PR includes Javadoc for all new (or modified) public methods and classes. It also includes Javadoc for large or complex private methods.
  • My PR passes all tests and includes new/updated Unit or Integration Tests based on the Code Testing Guide.
  • If my PR includes new libraries/dependencies (in any pom.xml), I've made sure their licenses align with the DSpace BSD License based on the Licensing of Contributions documentation.
  • If my PR modifies REST API endpoints, I've opened a separate REST Contract PR related to this change.
  • If my PR includes new configurations, I've provided basic technical documentation in the PR itself.
  • If my PR fixes an issue ticket, I've linked them together.

Copilot AI left a comment

Copy link
Copy Markdown

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 aims to eliminate intermittent failures in scheduled integration-test runs by addressing three independent sources of flakiness: handle mint collisions, leaked BitstreamFormat test data, and Solr statistics visibility races. It does so via a small production change in handle minting plus several test harness adjustments to make test data and timing deterministic.

Changes:

  • Make handle minting skip already-existing handle suffixes (sequence catch-up safety) and add an integration test to cover the behavior.
  • Fix BitstreamFormat test flakiness by ensuring cleanup is committed and by removing Random-based uniqueness/count assumptions.
  • Stabilize statistics report assertions by forcing a Solr commit (waitSearcher) after posting view events.

Reviewed changes

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

Show a summary per file
File Description
dspace-server-webapp/src/test/java/org/dspace/app/rest/StatisticsRestRepositoryIT.java Forces a Solr commit after posting view events to avoid stale-searcher reads in report assertions.
dspace-server-webapp/src/test/java/org/dspace/app/rest/PreviewContentServiceImplIT.java Ensures BitstreamFormat cleanup runs in its own committed Context to prevent leaked rows across tests.
dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java Makes test data deterministic (method-name-based shortDescription), captures created IDs for robust cleanup, and asserts counts relative to a baseline.
dspace-api/src/test/java/org/dspace/xmlworkflow/XmlWorkflowFactoryTest.java Switches to a non-numeric handle suffix to avoid collisions with the numeric handle sequence.
dspace-api/src/test/java/org/dspace/handle/HandleServiceIT.java Adds IT coverage ensuring sequence-based minting skips existing handle rows (including unbound rows after deletion).
dspace-api/src/test/java/org/dspace/curate/RequiredMetadataIT.java Replaces randomized numeric handle suffixes with deterministic non-numeric suffixes that cannot collide with the sequence.
dspace-api/src/test/java/org/dspace/curate/ItemHandleCheckerIT.java Same as above: deterministic non-numeric handle suffixes to prevent sequence collisions.
dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java Updates handle minting to skip already-existing handle IDs instead of assuming sequence uniqueness.
dspace-api/src/main/java/org/dspace/handle/HandleClarinServiceImpl.java Mirrors the handle minting skip logic for the CLARIN handle service implementation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java Outdated
Comment thread dspace-api/src/main/java/org/dspace/handle/HandleClarinServiceImpl.java Outdated

Copilot AI left a comment

Copy link
Copy Markdown

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 9 out of 9 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

dspace-api/src/main/java/org/dspace/handle/HandleClarinServiceImpl.java:380

  • The new regression tests only exercise HandleServiceImpl through collection creation. HandleClarinServiceImplIT never invokes either blank-handle branch that reaches this new loop, so duplicate skipping in this separate production path remains unverified. Add a test that occupies the next sequence suffix, calls createHandle(context, null) or createExternalHandle with a blank handle, and asserts that the occupied suffix is skipped.
        for (int attempt = 0; attempt < MAX_SUFFIX_ATTEMPTS; attempt++) {
            Long handleSuffix = handleDAO.getNextHandleSuffix(context);
            String handleId = handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + handleSuffix;
            if (handleDAO.findByHandle(context, handleId) == null) {
                return handleId;

dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java:159

  • The ID is still captured only after both POST assertions run. If the POST successfully inserts the format but matchNoEmbeds() fails, andDo is never reached, idRef remains null, and this test leaks the row—the cleanup failure this change is meant to prevent. Register andDo immediately after perform, before any assertions.
                                                  .andDo(result -> idRef
                                                          .set(read(result.getResponse().getContentAsString(),
                                                                  "$.id")))

Comment thread dspace-api/src/main/java/org/dspace/handle/HandleServiceImpl.java Outdated
@milanmajchrak

Copy link
Copy Markdown
Collaborator Author

Restructured to test-only changes (2 commits): the mint-path hardening in HandleServiceImpl/HandleClarinServiceImpl and its HandleServiceIT regression tests were dropped from this PR and are prepared separately. The earlier resolved review threads refer to that removed code.

@milanmajchrak
milanmajchrak force-pushed the fix/flaky-integration-tests branch from 8632977 to f469544 Compare August 18, 2026 08:42
@milanmajchrak milanmajchrak changed the title fix: de-flake scheduled ITs (duplicate handle mints, leaked bitstream formats, stale Solr searcher) test: de-flake scheduled ITs (test-planted handle collisions, leaked bitstream formats, stale Solr searcher) Aug 18, 2026
@milanmajchrak
milanmajchrak requested a balanced review from Copilot August 18, 2026 09:01

Copilot AI left a comment

Copy link
Copy Markdown

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 6 out of 6 changed files in this pull request and generated no new comments.

Suppressed comments (1)

dspace-server-webapp/src/test/java/org/dspace/app/rest/BitstreamFormatRestRepositoryIT.java:159

  • Move the ID capture before the HAL assertion. andExpect(...) evaluates immediately, so if matchNoEmbeds() fails, this andDo is never reached, idRef remains null, and the newly created format leaks—the cleanup path this change is intended to guarantee. Keeping the status check first avoids parsing an error response while still capturing the ID before later assertions.
                                                  .andDo(result -> idRef
                                                          .set(read(result.getResponse().getContentAsString(),
                                                                  "$.id")))

RequiredMetadataIT and ItemHandleCheckerIT planted a random numeric
handle (1000-1999) that handle_seq reaches late in the module run; the
sequence mint path does no existence check, so the flush of whichever
test was minting at that moment died on the handle unique index. Replace
the random handles with deterministic non-numeric suffixes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@milanmajchrak
milanmajchrak force-pushed the fix/flaky-integration-tests branch from f469544 to 3899124 Compare August 18, 2026 10:07
…iew event

PreviewContentServiceImplIT deleted its custom format through the shared
test context after earlier builder deletes had detached it from the
thread-bound session, so the delete was silently lost - one leaked row
per test broke BitstreamFormatRestRepositoryIT counts when class order
put Preview first. totalVisitsReport_Item_Visited could query a stale
Solr searcher before its posted view event became visible.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

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 6 out of 6 changed files in this pull request and generated no new comments.

@milanmajchrak
milanmajchrak merged commit 23f3786 into dtq-dev Aug 18, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants