Skip to content

e2e: Harden the test harness: retry visibility, video on retries only, cleanup#6568

Merged
andremion merged 5 commits into
developfrom
andrerego/and-1302-harden-and-clean-up-the-e2e-harness
Jul 10, 2026
Merged

e2e: Harden the test harness: retry visibility, video on retries only, cleanup#6568
andremion merged 5 commits into
developfrom
andrerego/and-1302-harden-and-clean-up-the-e2e-harness

Conversation

@andremion

@andremion andremion commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Goal

Make the E2E pipeline cheaper and its flakiness measurable: report retry attempts to Allure TestOps, record video only on retries, and clean up the harness.

Resolves AND-1302

Implementation

  • RetryRule: each failed attempt that is retried becomes its own Allure result (same historyId), so TestOps shows retries and can flag flaky tests. Before, a pass-on-retry looked identical to a stable pass.
  • RetryRule: screen recording runs only on retry attempts. Before, every test recorded an 8 Mbit/s video and discarded it on pass.
  • assertSystemMessage asserted nothing; fixed, and six copies of the appear/disappear assert pattern merged into one helper.
  • waitForCount polls at 50ms instead of spinning the CPU until timeout.
  • fastlane batch_tests splits round-robin (the old slicing could crash on the last shard), and manual runs of the nightly workflow are no longer named "Cron checks" in TestOps.
  • Dead code removed, pinMesage typos fixed, the uiautomator package now matches its location, and the module-vs-sample convention is documented in AGENTS.md.

Out of scope: the remaining fixed sleeps are wall-clock by design (token expiry, cooldown) or load-bearing; they belong to the flaky-test work in AND-1303.

Metrics

E2E CI duration. Wall clock is what the Actions page shows (the 3 batches run in parallel); total is the compute across the 3 batch jobs. Baselines are the four most recent full runs on other branches:

Run Wall clock Total across batches
migrate/query-reactions 42 min 89.4 min
port/v6 video-disk-cache 43 min 86.4 min
migrate/cast-poll-vote 40 min 83.7 min
migrate/send-reaction 35 min 79.3 min
this PR (run 1) 25 min 60.0 min
this PR (run 2) 24 min 61.3 min

Shared runners, so the nightly trend after merge is the authoritative signal.

Screen recordings: 99.9% of nightly test executions pass (27,704 of the last 27,734) and every one recorded a video that was thrown away. Now only retries record.

Retry visibility:

Before After
Test passes on retry invisible, looks like a stable pass failed attempt shown as a retry with its own error and artifacts
TestOps flaky flag never triggers set automatically
First-attempt pass rate unmeasurable measurable

It already fired for real: test_threadIsNotLocked_afterParentMessageDeletedByParticipant flaked during this PR's CI run and its failed attempt is visible in the TestOps launch.

Local A/B (full ReactionsTests class, same emulator and mock server): 124.2s on develop vs 113.6s on this branch (-8.5%), 10/10 passed on both.

Testing

With the mock server and an emulator running:

  1. Passing test writes one result and no video: run ReactionsTests#test_addsReaction via connectedE2eDebugAndroidTest, then check adb shell ls /sdcard/googletest/test_outputfiles/allure-results (one -result.json, no .mp4).
  2. Flip any assertion temporarily and run that test: one result JSON per failed attempt, all with the same historyId, video attached only to retry attempts.
  3. In TestOps, open this PR's launch and check the Retries tab of any test that flaked.

No UI changes.

- waitForCount now polls at the existing interval instead of spinning the CPU until timeout
- MockServer.execute throws on failure instead of calling fail() and returning an unreachable empty Response
- Remove unused helpers (stopApp, nameOf, stringOf, testAssets, bottomPoint, leftPoint, toSeconds, UiObject2.width, waitForTextToChange)
- Drop the redundant ParticipantRobot.sleep and the no-op parentId parameter on readMessage
- Fix pinMesage/unpinMesage typos
…E split

- Rename io.getstream.chat.android.compose.uiautomator to io.getstream.chat.android.e2e.test.uiautomator so the package matches its location and the module's other packages (mockserver, robots, rules)
- Move VisualOrder into the e2e-test module's uiautomator toolkit (now public), since it is app-agnostic infrastructure
- Document the module-vs-sample E2E convention in AGENTS.md
- Each failed attempt that is retried is written as its own Allure result sharing the real test's historyId, with that attempt's steps, error and artifacts, so TestOps groups attempts as retries and can flag flaky tests
- Screen recording now runs only on retry attempts; previously every test, including the ~99.9% that pass on the first attempt, recorded and discarded an 8 Mbit/s video
- Remove the unused Retry annotation and simplify DatabaseOperations (private, no self-instantiation)
- Name Allure launches 'Cron checks' only for real scheduled events, so manual dispatches of the nightly workflow no longer pollute TestOps analytics
… split

- assertSystemMessage asserted nothing: the positive path discarded the check and the negative path never throws; both now assert via a shared assertVisibility helper
- Collapse the duplicated reaction selector mappings into a single By.res template
- batch_tests now splits round-robin, always yielding exactly batch_count groups; the previous rounded-up slicing could produce fewer groups and crash on nil for the last batch
- Remove a redundant 5s sleep before an assertion that already polls for disappearance
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@andremion andremion added the pr:ci CI changes label Jul 10, 2026
@andremion

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 5.94 MB 5.94 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.21 MB 11.21 MB 0.00 MB 🟢
stream-chat-android-compose 12.68 MB 12.68 MB 0.00 MB 🟢

@andremion andremion added pr:internal Internal changes / housekeeping and removed pr:internal Internal changes / housekeeping labels Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR moves shared UIAutomator utilities into the E2E module, updates Compose sample consumers, refactors retry and batching behavior, improves Allure failure reporting, and documents E2E test structure and execution.

Changes

E2E UIAutomator contracts

Layer / File(s) Summary
Shared utility namespace and behavior
stream-chat-android-e2e-test/src/main/.../uiautomator/*
UIAutomator APIs move to the E2E package; obsolete helpers are removed, polling is updated, and visual-order helpers become public.

E2E runtime and sample integration

Layer / File(s) Summary
Runtime retry and robot updates
stream-chat-android-e2e-test/src/main/.../mockserver/MockServer.kt, .../robots/ParticipantRobot.kt, .../rules/RetryRule.kt
Mock-server exceptions preserve causes, participant robot APIs are corrected, and retries now capture artifacts and finished Allure attempt results.
Compose sample migration
stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/.../robots/*, .../tests/*, .../pages/MessageListPage.kt
Sample tests use shared E2E utilities, visibility assertions are consolidated, reaction selectors are derived dynamically, and a fixed reaction delay is removed.

Execution and documentation

Layer / File(s) Summary
Fastlane and E2E guidance
fastlane/Allurefile, fastlane/Fastfile, AGENTS.md
Scheduled Allure launches, round-robin test batching, empty-batch errors, and E2E code-placement guidance are updated.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant RetryRule
  participant Test
  participant DatabaseOperations
  participant Allure
  RetryRule->>Test: execute attempt
  Test-->>RetryRule: failure
  RetryRule->>DatabaseOperations: clear databases
  RetryRule->>Allure: write failed attempt artifacts
  RetryRule->>Test: retry or throw final exception
Loading

Suggested labels: pr:test, pr:improvement

Suggested reviewers: gpunto, aleksandar-apostolov, VelikovPetar

Poem

A rabbit hops through tests tonight,
With UiAutomator paths aligned just right.
Retries leave their traces bright,
Batches march in round-robin flight.
Allure records each moonlit run—
E2E burrows, work is done! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main E2E harness hardening work around retries, recording, and cleanup.
Description check ✅ Passed The description covers Goal, Implementation, Metrics, and Testing, but omits non-critical template items like UI assets, checklist, and GIF.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch andrerego/and-1302-harden-and-clean-up-the-e2e-harness

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@fastlane/Fastfile`:
- Around line 154-159: Validate batch_count immediately after parsing in the
batch-processing logic, raising UI.user_error! with a clear message when it is
zero or negative before the modulo operation. Then validate that batch is within
0...batch_count and report an out-of-range batch index explicitly; retain the
existing empty-batch error only for valid indices that receive no tests. Use the
existing batch, batch_count, and current_batch logic to make these checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: aa6f9969-8f7b-453c-8a25-e0cb3da66024

📥 Commits

Reviewing files that changed from the base of the PR and between 5a468b4 and ac44fdf.

📒 Files selected for processing (25)
  • AGENTS.md
  • fastlane/Allurefile
  • fastlane/Fastfile
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/pages/MessageListPage.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/robots/UserRobot.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/robots/UserRobotChannelListAsserts.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/robots/UserRobotMessageListAsserts.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/AuthTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/ChannelListTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/DraftMessagesTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/MessageListTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/QuotedReplyTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/ReactionsTests.kt
  • stream-chat-android-compose-sample/src/androidTestE2eDebug/kotlin/io/getstream/chat/android/compose/tests/StreamTestCase.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/mockserver/MockServer.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/robots/ParticipantRobot.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/rules/RetryRule.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Actions.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Base.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Element.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/FindBy.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Math.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Permissions.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/VisualOrder.kt
  • stream-chat-android-e2e-test/src/main/kotlin/io/getstream/chat/android/e2e/test/uiautomator/Wait.kt

Comment thread fastlane/Fastfile
…llure

TestOps picks the same-historyId result with the latest start as the launch's current one. The real result starts a few ms before any retry attempt, so the attempt results were shown as current and a test that passed on retry displayed as broken. Each attempt's start is now shifted just below the real result's start, keeping attempt order and leaving the final result current. Verified by uploading pre-fix and post-fix result sets to scratch TestOps launches.
@sonarqubecloud

Copy link
Copy Markdown

@andremion andremion requested a review from testableapple July 10, 2026 13:16
@andremion andremion marked this pull request as ready for review July 10, 2026 13:16
@andremion andremion requested a review from a team as a code owner July 10, 2026 13:16
@andremion andremion merged commit e27199c into develop Jul 10, 2026
25 checks passed
@andremion andremion deleted the andrerego/and-1302-harden-and-clean-up-the-e2e-harness branch July 10, 2026 14:10
@stream-public-bot stream-public-bot added the released Included in a release label Jul 13, 2026
@stream-public-bot

Copy link
Copy Markdown
Contributor

🚀 Available in v7.6.0

andremion added a commit to GetStream/stream-video-android that referenced this pull request Jul 13, 2026
… on retries only (#1746)

- RetryRule: each failed attempt that is retried is written as its own Allure result sharing the real test's historyId, with that attempt's steps, error and artifacts, so TestOps groups attempts as retries and can flag flaky tests
- RetryRule: screen recording runs only on retry attempts; previously every test recorded an 8 Mbit/s video that was discarded on pass
- RetryRule: the recording file uses methodName instead of displayName (the display name's parentheses break when the recording commands go through the device shell), and a recording stop failure no longer replaces the test result
- RetryRule: move to io.getstream.video.android.rules (the file declared a chat package), remove the unused Retry annotation, simplify DatabaseOperations
- Wait: waitForText and waitForCount poll at 50ms instead of spinning the CPU until timeout; remove the unused waitForTextToChange
- Allurefile: name launches 'Cron checks' only for real scheduled events, so manual dispatches stay distinguishable in TestOps
- Fastfile: batch_tests splits round-robin, always yielding exactly batch_count groups; the previous rounded-up slicing could produce fewer groups and crash on nil for the last batch

Ported from GetStream/stream-chat-android#6568.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:ci CI changes released Included in a release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants