Skip to content

Commit 0d2d8df

Browse files
franco-zalamena-iterablecursoragentclaude
authored
[SDK-115] Enable full BCIT on CI (#1061)
Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 2e128ae commit 0d2d8df

22 files changed

Lines changed: 685 additions & 723 deletions

.github/scripts/run-e2e.sh

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#!/usr/bin/env bash
22
# .github/scripts/run-e2e.sh
33
#
4-
# Runs the In-App Message E2E test under ReactiveCircus/android-emulator-runner
4+
# Runs the BCIT integration-test suite under ReactiveCircus/android-emulator-runner
55
# and captures diagnostics that survive the action's emulator-kill on exit.
66
#
77
# Why this is an external script and not inline YAML:
@@ -28,15 +28,14 @@
2828

2929
set -uo pipefail
3030

31-
readonly TEST_CLASS="${TEST_CLASS:-com.iterable.integration.tests.InAppMessageIntegrationTest#testInAppMessageMVP}"
3231
readonly DIAG_DIR="${GITHUB_WORKSPACE:?GITHUB_WORKSPACE must be set}/integration-tests/build/diagnostics"
3332
readonly TEST_PACKAGE="com.iterable.integration.tests"
3433

3534
mkdir -p "$DIAG_DIR"
3635

3736
log() { printf '\033[1;34m[e2e]\033[0m %s\n' "$*"; }
3837

39-
log "Running E2E test: $TEST_CLASS"
38+
log "Running BCIT integration-test suite: package=$TEST_PACKAGE"
4039
log "Diagnostics will be written to: $DIAG_DIR"
4140

4241
# Sanity-check env: don't echo secret values, only their lengths. The workflow's
@@ -45,6 +44,16 @@ log "ITERABLE_API_KEY length: ${#ITERABLE_API_KEY}"
4544
log "ITERABLE_SERVER_API_KEY length: ${#ITERABLE_SERVER_API_KEY}"
4645
log "ITERABLE_TEST_USER_EMAIL length: ${#ITERABLE_TEST_USER_EMAIL}"
4746

47+
# Fail fast if a BCIT_* secret didn't resolve. Without this, an empty secret falls
48+
# through to the gradle default 'test_api_key' (integration-tests/build.gradle) and
49+
# the suite fails later with opaque 401s instead of a clear configuration error.
50+
if [[ "${CI:-false}" == "true" ]]; then
51+
if [[ -z "${ITERABLE_API_KEY:-}" || -z "${ITERABLE_SERVER_API_KEY:-}" || -z "${ITERABLE_TEST_USER_EMAIL:-}" ]]; then
52+
log "::error::One or more BCIT_* secrets are empty. Configure BCIT_ITERABLE_API_KEY, BCIT_ITERABLE_SERVER_API_KEY, BCIT_ITERABLE_TEST_USER_EMAIL on this branch/repo."
53+
exit 1
54+
fi
55+
fi
56+
4857
# Grant permissions; ignore failures (the package may not be installed yet,
4958
# in which case AGP will install + auto-grant during the test step).
5059
for perm in POST_NOTIFICATIONS INTERNET ACCESS_NETWORK_STATE WAKE_LOCK; do
@@ -100,11 +109,12 @@ trap capture_post_test EXIT
100109
# propagate the original exit code at the end.
101110
gradle_exit=0
102111
./gradlew :integration-tests:connectedDebugAndroidTest \
103-
-Pandroid.testInstrumentationRunnerArguments.class="$TEST_CLASS" \
112+
-Pandroid.testInstrumentationRunnerArguments.package="$TEST_PACKAGE" \
113+
-Pandroid.testInstrumentationRunnerArguments.ci=true \
104114
--stacktrace --no-daemon || gradle_exit=$?
105115

106116
if [[ "$gradle_exit" -ne 0 ]]; then
107-
log "::error::Gradle test task failed with exit code $gradle_exit — see e2e-diagnostics-api artifact"
117+
log "::error::Gradle test task failed with exit code $gradle_exit — see bcit-integration-diagnostics artifact"
108118
fi
109119

110120
# capture_post_test runs via EXIT trap; just propagate the exit code.
Lines changed: 49 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
1-
name: In-App Message E2E Tests
1+
name: Integration Tests (BCIT)
22

3+
# SDK-115: single workflow that owns all BCIT integration-test runs (PR, push to
4+
# master, manual dispatch, nightly cron).
35
on:
46
push:
5-
branches: [ InApp-Display-E2E ]
7+
branches: [ master ]
8+
paths:
9+
- 'integration-tests/**'
10+
- 'iterableapi/**'
11+
- 'iterableapi-ui/**'
12+
- '.github/workflows/integration-tests-bcit.yml'
13+
- '.github/scripts/run-e2e.sh'
614
pull_request:
7-
branches: [ InApp-Display-E2E, master, develop ]
15+
# No `branches:` filter — `branches:` matches the PR's *target*, not its head, so
16+
# restricting to [master] silently skips stacked PRs that target SDK-115-* (or any
17+
# other long-lived integration branch). Path filters below still gate which PRs
18+
# actually trigger the workflow.
19+
paths:
20+
- 'integration-tests/**'
21+
- 'iterableapi/**'
22+
- 'iterableapi-ui/**'
23+
- '.github/workflows/integration-tests-bcit.yml'
24+
- '.github/scripts/run-e2e.sh'
825
workflow_dispatch: # Allow manual triggering
26+
schedule:
27+
# Nightly smoke test at 02:00 UTC against the BCIT Iterable project. Catches
28+
# backend-side drift (rotated keys, edited campaign templates, expired test
29+
# users) that a code-only PR-triggered run would miss.
30+
- cron: '0 2 * * *'
31+
32+
# SDK-115: serialise across all branches/refs. The whole suite drives a single
33+
# shared BCIT user (ITERABLE_TEST_USER_EMAIL) for tens of minutes — two PRs, or
34+
# a PR overlapping the nightly cron, race on backend state (in-app inbox,
35+
# embedded placements, device tokens). Global scope queues one behind another.
36+
# `cancel-in-progress: false` so a nightly already running isn't killed mid-suite
37+
# when a PR opens.
38+
concurrency:
39+
group: bcit-integration-${{ github.workflow }}
40+
cancel-in-progress: false
941

1042
jobs:
11-
inapp-e2e-tests:
12-
name: In-App Message E2E Tests
43+
integration-tests-bcit:
44+
name: Integration Tests (BCIT)
1345
# SDK-170: macOS Intel runners (2 cores / 3GB AVD on HVF) starved system_server during
1446
# cold boot and produced cascading ANRs (systemui / nexuslauncher / gms / phone …),
1547
# leaving a system dialog on top of MainActivity so UiAutomator could not find the
@@ -36,21 +68,21 @@ jobs:
3668
with:
3769
java-version: '17'
3870
distribution: 'temurin'
39-
71+
4072
- name: Set up Android SDK
4173
uses: android-actions/setup-android@v2
42-
74+
4375
- name: Create local.properties
4476
run: |
4577
echo "sdk.dir=$ANDROID_SDK_ROOT" > local.properties
4678
echo "ndk.dir=$ANDROID_SDK_ROOT/ndk" >> local.properties
47-
79+
4880
- name: Accept Android SDK Licenses
4981
run: |
5082
echo "Accepting Android SDK licenses..."
5183
yes | sdkmanager --licenses || true
5284
echo "SDK licenses accepted"
53-
85+
5486
- name: Setup Google Services Configuration
5587
run: |
5688
echo "Setting up Google Services configuration for CI..."
@@ -60,7 +92,7 @@ jobs:
6092
cp integration-tests/google-services.json.template integration-tests/google-services.json
6193
fi
6294
echo "Google Services configuration ready"
63-
95+
6496
- name: Cache Gradle packages
6597
uses: actions/cache@v3
6698
with:
@@ -70,17 +102,11 @@ jobs:
70102
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
71103
restore-keys: |
72104
${{ runner.os }}-gradle-
73-
74-
- name: Pre-download Gradle and Build (Parallel with Emulator)
75-
run: |
76-
echo "Pre-downloading Gradle and building while emulator boots..."
77-
# Download Gradle wrapper in background
78-
./gradlew --version &
79-
# Start building APKs in background
80-
./gradlew :integration-tests:assembleDebug :integration-tests:assembleDebugAndroidTest --no-daemon &
81-
echo "Build started in background..."
82-
83-
- name: Run UI Tests with Emulator (KVM / x86_64)
105+
106+
# SDK-170-followup: KVM-runner Gradle parallelism races on
107+
# `integration-tests/build/intermediates/merged_res_blame_folder/`; do not
108+
# reintroduce a background `assemble*` step alongside the test invocation.
109+
- name: Run BCIT Integration Tests (KVM / x86_64)
84110
uses: ReactiveCircus/android-emulator-runner@v2
85111
with:
86112
api-level: ${{ matrix.api-level }}
@@ -112,52 +138,13 @@ jobs:
112138
# built APKs which embed BuildConfig.ITERABLE_API_KEY and BuildConfig.ITERABLE_SERVER_API_KEY
113139
# as compile-time string constants. On a public repo, anyone who can download the
114140
# artifact could `strings`/`apktool` the APK and recover both keys.
115-
- name: Upload E2E diagnostics
141+
- name: Upload BCIT integration-test diagnostics
116142
if: always()
117143
uses: actions/upload-artifact@v4
118144
with:
119-
name: e2e-diagnostics-api-${{ matrix.api-level }}
145+
name: bcit-integration-diagnostics-api-${{ matrix.api-level }}
120146
path: |
121147
integration-tests/build/diagnostics/
122148
integration-tests/build/reports/
123149
if-no-files-found: warn
124150
retention-days: 7
125-
126-
# test-summary:
127-
# name: Test Summary
128-
# runs-on: ubuntu-latest
129-
# needs: inapp-e2e-tests
130-
# if: always()
131-
132-
# steps:
133-
# - name: Checkout code
134-
# uses: actions/checkout@v4
135-
136-
# - name: Download Test Results
137-
# uses: actions/download-artifact@v4
138-
# with:
139-
# name: inapp-e2e-test-results-api-34
140-
# path: test-results/
141-
142-
# - name: Generate Test Summary
143-
# run: |
144-
# echo "## In-App Message E2E Test Results" >> $GITHUB_STEP_SUMMARY
145-
# echo "" >> $GITHUB_STEP_SUMMARY
146-
# echo "### Test Execution Summary" >> $GITHUB_STEP_SUMMARY
147-
# echo "- **Branch**: InApp-Display-E2E" >> $GITHUB_STEP_SUMMARY
148-
# echo "- **API Level Tested**: 34" >> $GITHUB_STEP_SUMMARY
149-
# echo "- **Test Method**: testInAppMessageMVP" >> $GITHUB_STEP_SUMMARY
150-
# echo "- **Test Type**: E2E Integration Test" >> $GITHUB_STEP_SUMMARY
151-
# echo "" >> $GITHUB_STEP_SUMMARY
152-
# echo "### E2E Test Scenarios" >> $GITHUB_STEP_SUMMARY
153-
# echo "- ✅ User Sign-in Verification" >> $GITHUB_STEP_SUMMARY
154-
# echo "- ✅ In-App Message Trigger" >> $GITHUB_STEP_SUMMARY
155-
# echo "- ✅ Message Display Verification" >> $GITHUB_STEP_SUMMARY
156-
# echo "- ✅ Button Click Interaction" >> $GITHUB_STEP_SUMMARY
157-
# echo "- ✅ Message Dismissal" >> $GITHUB_STEP_SUMMARY
158-
# echo "" >> $GITHUB_STEP_SUMMARY
159-
# echo "### Artifacts Available" >> $GITHUB_STEP_SUMMARY
160-
# echo "- Test execution reports" >> $GITHUB_STEP_SUMMARY
161-
# echo "- Code coverage reports" >> $GITHUB_STEP_SUMMARY
162-
# echo "- Debug screenshots" >> $GITHUB_STEP_SUMMARY
163-
# echo "- Detailed test logs" >> $GITHUB_STEP_SUMMARY

0 commit comments

Comments
 (0)