Skip to content

fix: stabilize flaky pre-translation and list handler tests#2114

Open
Tlaster wants to merge 3 commits intomasterfrom
bugfix/flaky-tests
Open

fix: stabilize flaky pre-translation and list handler tests#2114
Tlaster wants to merge 3 commits intomasterfrom
bugfix/flaky-tests

Conversation

@Tlaster
Copy link
Copy Markdown
Contributor

@Tlaster Tlaster commented May 7, 2026

Summary

  • MixedRemoteMediatorTest.homeTimelineAcceptsAiSkippedTranslationResult was asserting on the first emission from the translation flow, but enqueueStatuses runs in a fire-and-forget coroutine that writes Pending / Translating rows before reaching Skipped. On a slower CI scheduler the test caught an intermediate state and failed. The test now uses withTimeout(5_000) { ... .first { it.status == TranslationStatus.Skipped } } and cancels its coroutineScope in a finally block (matching neighbouring tests) so leftover work cannot leak between tests.
  • ListHandlerTest.tearDown now closes the database inside try/finally so stopKoin() always runs even if db.close() throws. This prevents leftover Koin state from cascading into a UncaughtExceptionsBeforeTest failure on the next test (e.g. withDatabaseUpdatesContent).

Test plan

  • ./gradlew :shared:jvmTest --tests dev.dimension.flare.data.datasource.microblog.MixedRemoteMediatorTest.homeTimelineAcceptsAiSkippedTranslationResult
  • ./gradlew :shared:jvmTest --tests dev.dimension.flare.data.datasource.microblog.handler.ListHandlerTest
  • ./gradlew :shared:jvmTest

🤖 Generated with Claude Code

Tlaster and others added 3 commits May 7, 2026 14:39
homeTimelineAcceptsAiSkippedTranslationResult was reading the first
emission of the translation flow, but pre-translation runs in a
fire-and-forget coroutine that goes through Pending/Translating before
reaching Skipped. The test now waits for the Skipped state and cancels
its coroutine scope on teardown like neighbouring tests.

ListHandlerTest.tearDown now closes the database in a try/finally so
stopKoin always runs even if close throws, preventing leaked Koin state
from cascading uncaught exceptions into the next test.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The test launched two UNDISPATCHED requests and relied on a single
CompletableDeferred to gate them, but the second async could fail to
reach the mock handler before the test scheduler advanced. When that
happened the deferred was never completed and runTest tripped its
dispatch timeout with UncompletedCoroutinesError on CI.

Use a pair of deferreds and only start the second request after the
first has parked inside the mock, with a withTimeout to fail fast.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous attempt still relied on UNDISPATCHED async + sequential
deferreds to coordinate the two requests. On iOS the request body did
not park inside the mock the way the JVM did, so the first synchronizer
never fired and withTimeout(5_000) tripped instead.

Drop UNDISPATCHED and the staged deferreds in favour of a single
barrier inside the mock handler: the first expired call waits, the
second one releases both. This works regardless of dispatcher and
guarantees both requests observe the expired token concurrently.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant