Skip to content

Upload videos of instrumented tests in CI#218

Open
JordanLongstaff wants to merge 51 commits intomainfrom
record-instrumented-tests
Open

Upload videos of instrumented tests in CI#218
JordanLongstaff wants to merge 51 commits intomainfrom
record-instrumented-tests

Conversation

@JordanLongstaff
Copy link
Copy Markdown
Collaborator

@JordanLongstaff JordanLongstaff commented May 8, 2025

Summary by CodeRabbit

  • Tests

    • Added automated test recording functionality to capture test execution on Android emulators
    • Enhanced network connectivity tests with improved coverage and assertion reliability
  • Chores

    • Updated CI/CD workflow to generate and archive test recordings alongside test results

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (app)

Total Project Coverage 20.86%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/udp)

Total Project Coverage 100.00%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/vesseldata)

Total Project Coverage 98.91%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN)

Total Project Coverage 97.75%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Konsist Test Results

 16 files  ±0   16 suites  ±0   38s ⏱️ ±0s
137 tests ±0  137 ✅ ±0  0 💤 ±0  0 ❌ ±0 
737 runs  ±0  737 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit ab570b2. ± Comparison against base commit f577e5c.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Instrumented Test Results

   27 files   27 suites   9h 47m 7s ⏱️
   44 tests  11 ✅ 0 💤 33 ❌
1 029 runs  959 ✅ 0 💤 70 ❌

For more details on these failures, see this check.

Results for commit ab570b2.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/listener)

Total Project Coverage 100.00%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/util)

Total Project Coverage 100.00%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Unit Test Results

  165 files  ±0    165 suites  ±0   26m 20s ⏱️ ±0s
1 560 tests ±0  1 560 ✅ ±0  0 💤 ±0  0 ❌ ±0 
5 003 runs  ±0  5 003 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit ab570b2. ± Comparison against base commit f577e5c.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/packets)

Total Project Coverage 98.93%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/world)

Total Project Coverage 99.45%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Code Coverage (IAN/enums)

Total Project Coverage 100.00%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Total Code Coverage

Total Project Coverage 91.39%

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented May 8, 2025

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/AnimMouse/setup-ffmpeg 1.*.* UnknownUnknown

Scanned Files

  • .github/workflows/instrumented-tests.yml

uses: gradle/actions/setup-gradle@ed408507eac070d1f99cc633dbcf757c94c7933a # v4

- name: Setup FFmpeg
uses: AnimMouse/setup-ffmpeg@v1

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow Medium

Unpinned 3rd party Action 'Android Instrumented Tests' step
Uses Step
uses 'AnimMouse/setup-ffmpeg' with ref 'v1', not a pinned commit hash
@JordanLongstaff
Copy link
Copy Markdown
Collaborator Author

LGTM

Generated by 🚫 Danger

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Nov 4, 2025

No dependency violations found. 👍

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Dec 29, 2025

Code Coverage (IAN/grid)

Total Project Coverage 98.04%

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

A new shell script automates Android instrumented test execution with concurrent screen recording via FFmpeg. The CI workflow updated to invoke this recording script and upload MP4 artifacts. Test files enhanced with network connectivity enable/disable steps and assertion refactoring to support network-related test scenarios.

Changes

Cohort / File(s) Summary
Test Recording Infrastructure
.github/workflows/instrumented-test-recording.sh, .github/workflows/instrumented-tests.yml
New shell script orchestrates Gradle test execution alongside continuous screen recording to MP4 via FFmpeg. CI workflow installs FFmpeg, makes script executable, and routes emulator runner through the recording script while adding artifact upload step for MP4 files.
Connect Screen Test Utilities
app/src/androidTest/kotlin/artemis/agent/screens/ConnectPageScreen.kt
Exposes addressLabel, networkTypeLabel, and networkInfoDivider from private val to public val for external test access.
Connect Scenario & Fragment Tests
app/src/androidTest/kotlin/artemis/agent/scenario/ConnectScenario.kt, app/src/androidTest/kotlin/artemis/agent/setup/ConnectFragmentTest.kt
Added network enable step at start of ConnectScenario. In ConnectFragmentTest, refactored network-info visibility helper into separate toggleShowingInfo() and testShowingInfo() methods, added network preconditions to existing tests, and introduced new noNetworkTest with network disable/assertion flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop, skip, and jump—the tests now record their song,
While networks dance along,
FFmpeg weaves through adb's flow,
Each frame a test's bright glow! 📹✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Upload videos of instrumented tests in CI' accurately reflects the main changes: adding shell scripts and CI workflow steps to record and upload test execution videos as artifacts.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 record-instrumented-tests

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
.github/workflows/instrumented-tests.yml (2)

104-109: Inconsistent action pinning: use commit hash instead of @v4.

Line 98 pins actions/upload-artifact to commit hash @bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0, but line 105 uses @ea165f8d65b6e75b540449e92b4886f43607fa02 # v4. This appears to be an older version (v4 vs v7) and the comment format differs. Consider using the same version consistently across both upload steps.

♻️ Proposed fix
       - name: Upload Test Recordings
-        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
+        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
         if: always()
         with:
           name: "Instrumented Test Recording (API ${{ matrix.api-level }}, ${{ matrix.orientation.name }})"
           path: testRecording-${{ matrix.api-level }}-${{ matrix.orientation.rotation }}.mp4
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/instrumented-tests.yml around lines 104 - 109, The "Upload
Test Recordings" workflow step inconsistently pins actions/upload-artifact to
`@ea165f8`... (# v4); update that step (the one named "Upload Test Recordings" and
the uses: line referencing actions/upload-artifact) to use the same pin style
and commit hash as the other upload step (replace `@ea165f8`... with
`@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f` and update the inline comment to match
# v7.0.0) so both upload-artifact usages are consistently pinned to the same
version.

83-84: Consider setting execute permission in the repository instead of at runtime.

The script should be committed with executable permission (git update-index --chmod=+x). This avoids the extra step and ensures the script is always executable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/instrumented-tests.yml around lines 83 - 84, Remove the
runtime chmod step in the "Enable script execution" job and instead commit the
script with executable permission; run git update-index --chmod=+x
.github/workflows/instrumented-test-recording.sh locally (or mark it executable
in your git client) so the script
.github/workflows/instrumented-test-recording.sh is stored executable in the
repo and you can delete the `run: chmod +x
.github/workflows/instrumented-test-recording.sh` step from the workflow.
.github/workflows/instrumented-test-recording.sh (1)

1-1: Consider using #!/bin/bash for better portability of process handling.

The script uses #!/bin/sh, but relies on behavior ($!, kill, process management) that is more predictable in bash. Additionally, if you need to use arrays or other bash-specific features in the future, this will be limiting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/instrumented-test-recording.sh at line 1, The script uses
a POSIX sh shebang but relies on process-handling behavior better provided by
bash; update the shebang from "#!/bin/sh" to "#!/bin/bash" at the top of the
script to ensure predictable handling of background PIDs ($!), kill, and future
bash-specific features (and confirm the script remains executable).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/instrumented-test-recording.sh:
- Around line 9-19: Move the PID capture for the Gradle test runner so TEST_PID
is assigned immediately after backgrounding ./gradlew connectedCheck (&) to
ensure it refers to that process; then start the adb exec-out | ffmpeg pipeline
in the background and capture its PID (the $! returned right after that
backgrounding) into a RECORDING_PID variable; after wait $TEST_PID completes,
send a graceful termination to the recording process (use a signal that lets
ffmpeg finalize the MP4, e.g., kill -INT $RECORDING_PID or kill -TERM then wait)
and then wait for $RECORDING_PID to exit so the recording is finalized and
resources are cleaned up.

In `@app/src/androidTest/kotlin/artemis/agent/setup/ConnectFragmentTest.kt`:
- Around line 201-234: The noNetworkTest disables networking via
device.network.disable() but never restores it; update the noNetworkTest (inside
mainScreenTest and around the device.network.disable() call) to ensure
device.network.enable() is always called (e.g., wrap the disable + assertions in
a try/finally or call enable at the end), so network is re-enabled for
subsequent tests while preserving existing steps like toggleShowingInfo() and
ConnectPageScreen checks.

---

Nitpick comments:
In @.github/workflows/instrumented-test-recording.sh:
- Line 1: The script uses a POSIX sh shebang but relies on process-handling
behavior better provided by bash; update the shebang from "#!/bin/sh" to
"#!/bin/bash" at the top of the script to ensure predictable handling of
background PIDs ($!), kill, and future bash-specific features (and confirm the
script remains executable).

In @.github/workflows/instrumented-tests.yml:
- Around line 104-109: The "Upload Test Recordings" workflow step inconsistently
pins actions/upload-artifact to `@ea165f8`... (# v4); update that step (the one
named "Upload Test Recordings" and the uses: line referencing
actions/upload-artifact) to use the same pin style and commit hash as the other
upload step (replace `@ea165f8`... with `@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f`
and update the inline comment to match # v7.0.0) so both upload-artifact usages
are consistently pinned to the same version.
- Around line 83-84: Remove the runtime chmod step in the "Enable script
execution" job and instead commit the script with executable permission; run git
update-index --chmod=+x .github/workflows/instrumented-test-recording.sh locally
(or mark it executable in your git client) so the script
.github/workflows/instrumented-test-recording.sh is stored executable in the
repo and you can delete the `run: chmod +x
.github/workflows/instrumented-test-recording.sh` step from the workflow.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 760e2d51-7e0c-401f-a348-d2934f079031

📥 Commits

Reviewing files that changed from the base of the PR and between f577e5c and ab570b2.

📒 Files selected for processing (5)
  • .github/workflows/instrumented-test-recording.sh
  • .github/workflows/instrumented-tests.yml
  • app/src/androidTest/kotlin/artemis/agent/scenario/ConnectScenario.kt
  • app/src/androidTest/kotlin/artemis/agent/screens/ConnectPageScreen.kt
  • app/src/androidTest/kotlin/artemis/agent/setup/ConnectFragmentTest.kt

Comment on lines +9 to +19
./gradlew connectedCheck &
sleep 10
TEST_PID=$!
echo "Starting the screen recording..."
adb exec-out "while true; do screenrecord --bugreport --output-format=h264 -; done" | ffmpeg -i - testRecording-$API_LEVEL-$ORIENTATION.mp4 &
sleep 1
echo "Waiting for instrumented tests to finish..."
wait $TEST_PID
TEST_STATUS=$?
# Wait for the screen recording process to exit
sleep 1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical bugs: PID captured from wrong process and recording process never terminated.

Two issues here:

  1. Wrong PID captured (Line 11): $! captures the PID of the most recently backgrounded command. Since sleep 10 runs after ./gradlew connectedCheck &, by line 11 the $! still refers to the gradle process—but placing the capture after the sleep is fragile and confusing. Move it immediately after backgrounding gradle.

  2. Recording process never killed (Lines 13-19): The adb exec-out + ffmpeg pipeline runs an infinite while true loop that never terminates. After wait $TEST_PID completes, the script exits but leaves the recording process orphaned. This can corrupt the MP4 (no proper finalization) and leak resources across matrix jobs.

🐛 Proposed fix
 set -x
 set +e
 echo "Starting instrumented tests..."
 ./gradlew connectedCheck &
+TEST_PID=$!
 sleep 10
-TEST_PID=$!
 echo "Starting the screen recording..."
 adb exec-out "while true; do screenrecord --bugreport --output-format=h264 -; done" | ffmpeg -i - testRecording-$API_LEVEL-$ORIENTATION.mp4 &
+RECORD_PID=$!
 sleep 1
 echo "Waiting for instrumented tests to finish..."
 wait $TEST_PID
 TEST_STATUS=$?
-# Wait for the screen recording process to exit
-sleep 1
+# Terminate the screen recording process
+kill $RECORD_PID 2>/dev/null || true
+wait $RECORD_PID 2>/dev/null || true
 exit $TEST_STATUS
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
./gradlew connectedCheck &
sleep 10
TEST_PID=$!
echo "Starting the screen recording..."
adb exec-out "while true; do screenrecord --bugreport --output-format=h264 -; done" | ffmpeg -i - testRecording-$API_LEVEL-$ORIENTATION.mp4 &
sleep 1
echo "Waiting for instrumented tests to finish..."
wait $TEST_PID
TEST_STATUS=$?
# Wait for the screen recording process to exit
sleep 1
./gradlew connectedCheck &
TEST_PID=$!
sleep 10
echo "Starting the screen recording..."
adb exec-out "while true; do screenrecord --bugreport --output-format=h264 -; done" | ffmpeg -i - testRecording-$API_LEVEL-$ORIENTATION.mp4 &
RECORD_PID=$!
sleep 1
echo "Waiting for instrumented tests to finish..."
wait $TEST_PID
TEST_STATUS=$?
# Terminate the screen recording process
kill $RECORD_PID 2>/dev/null || true
wait $RECORD_PID 2>/dev/null || true
exit $TEST_STATUS
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/instrumented-test-recording.sh around lines 9 - 19, Move
the PID capture for the Gradle test runner so TEST_PID is assigned immediately
after backgrounding ./gradlew connectedCheck (&) to ensure it refers to that
process; then start the adb exec-out | ffmpeg pipeline in the background and
capture its PID (the $! returned right after that backgrounding) into a
RECORDING_PID variable; after wait $TEST_PID completes, send a graceful
termination to the recording process (use a signal that lets ffmpeg finalize the
MP4, e.g., kill -INT $RECORDING_PID or kill -TERM then wait) and then wait for
$RECORDING_PID to exit so the recording is finalized and resources are cleaned
up.

Comment on lines +201 to +234
@Test
fun noNetworkTest() {
run {
mainScreenTest {
step("Disable network connections") { device.network.disable() }

val showingInfo = AtomicBoolean()
step("Fetch showing network info setting") {
activityScenarioRule.scenario.onActivity { activity ->
showingInfo.lazySet(
activity.viewModels<AgentViewModel>().value.showingNetworkInfo
)
}
}
val settingValue = showingInfo.get()

if (!settingValue) {
toggleShowingInfo()
}

ConnectPageScreen {
step("Check \"Network not found\" text") {
networkTypeLabel.isDisplayedWithText(R.string.network_not_found)
}

step("Check for no address") { addressLabel.isNotDisplayed() }
}

if (!settingValue) {
toggleShowingInfo()
}
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Test does not re-enable network after disabling it.

The test disables network at line 205 but never re-enables it. If tests share process state or run in a specific order, this could cause subsequent tests (e.g., scanTest, showNetworkInfoTest) to fail due to disabled network. Consider re-enabling network in a finally block or at the end of the test.

🛡️ Proposed fix
     `@Test`
     fun noNetworkTest() {
         run {
             mainScreenTest {
                 step("Disable network connections") { device.network.disable() }

                 val showingInfo = AtomicBoolean()
                 step("Fetch showing network info setting") {
                     activityScenarioRule.scenario.onActivity { activity ->
                         showingInfo.lazySet(
                             activity.viewModels<AgentViewModel>().value.showingNetworkInfo
                         )
                     }
                 }
                 val settingValue = showingInfo.get()

                 if (!settingValue) {
                     toggleShowingInfo()
                 }

                 ConnectPageScreen {
                     step("Check \"Network not found\" text") {
                         networkTypeLabel.isDisplayedWithText(R.string.network_not_found)
                     }

                     step("Check for no address") { addressLabel.isNotDisplayed() }
                 }

                 if (!settingValue) {
                     toggleShowingInfo()
                 }
+
+                step("Re-enable network connections") { device.network.enable() }
             }
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
fun noNetworkTest() {
run {
mainScreenTest {
step("Disable network connections") { device.network.disable() }
val showingInfo = AtomicBoolean()
step("Fetch showing network info setting") {
activityScenarioRule.scenario.onActivity { activity ->
showingInfo.lazySet(
activity.viewModels<AgentViewModel>().value.showingNetworkInfo
)
}
}
val settingValue = showingInfo.get()
if (!settingValue) {
toggleShowingInfo()
}
ConnectPageScreen {
step("Check \"Network not found\" text") {
networkTypeLabel.isDisplayedWithText(R.string.network_not_found)
}
step("Check for no address") { addressLabel.isNotDisplayed() }
}
if (!settingValue) {
toggleShowingInfo()
}
}
}
}
`@Test`
fun noNetworkTest() {
run {
mainScreenTest {
step("Disable network connections") { device.network.disable() }
val showingInfo = AtomicBoolean()
step("Fetch showing network info setting") {
activityScenarioRule.scenario.onActivity { activity ->
showingInfo.lazySet(
activity.viewModels<AgentViewModel>().value.showingNetworkInfo
)
}
}
val settingValue = showingInfo.get()
if (!settingValue) {
toggleShowingInfo()
}
ConnectPageScreen {
step("Check \"Network not found\" text") {
networkTypeLabel.isDisplayedWithText(R.string.network_not_found)
}
step("Check for no address") { addressLabel.isNotDisplayed() }
}
if (!settingValue) {
toggleShowingInfo()
}
step("Re-enable network connections") { device.network.enable() }
}
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/androidTest/kotlin/artemis/agent/setup/ConnectFragmentTest.kt` around
lines 201 - 234, The noNetworkTest disables networking via
device.network.disable() but never restores it; update the noNetworkTest (inside
mainScreenTest and around the device.network.disable() call) to ensure
device.network.enable() is always called (e.g., wrap the disable + assertions in
a try/finally or call enable at the end), so network is re-enabled for
subsequent tests while preserving existing steps like toggleShowingInfo() and
ConnectPageScreen checks.

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