From b4add12097e9af6c9f7bdd340a28c962fc548c18 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:12:58 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=94=A8=20Forge:=20[CI/AGENTS.md=20Cal?= =?UTF-8?q?ibration]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolved Dart SDK version conflict in `worker_flutter/pubspec.yaml` by downgrading from `^3.11.5` to `^3.11.0` to match the Flutter stable channel. Calibrated the shared CI verification scripts (`scripts/lint.sh`, `scripts/test.sh`) to include targeted Flutter commands (`flutter test` and `flutter analyze`). Updated `.github/workflows/ci.yml` jobs to provision the `subosito/flutter-action@v2` setup step for pipeline parity. Finally, updated `AGENTS.md` instructions and project structure context. --- .github/workflows/ci.yml | 10 ++++++++++ .jules/forge.md | 1 + AGENTS.md | 3 +++ scripts/lint.sh | 4 ++++ scripts/test.sh | 4 ++++ worker_flutter/pubspec.lock | 10 +++++----- worker_flutter/pubspec.yaml | 2 +- 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcc5cbeb..7deb02de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,11 @@ jobs: api/package-lock.json worker/package-lock.json + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + - run: ./scripts/lint.sh build: @@ -62,6 +67,11 @@ jobs: api/package-lock.json worker/package-lock.json + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + channel: stable + - run: ./scripts/test.sh release-scripts: diff --git a/.jules/forge.md b/.jules/forge.md index e5788bbd..a5a3477d 100644 --- a/.jules/forge.md +++ b/.jules/forge.md @@ -6,3 +6,4 @@ - **[2026-06-15]**: Removed obsolete Python/`uv` tooling from `AGENTS.md` as the project is now fully Node.js. Identified a gap where `worker` build checks were missing from `.github/workflows/ci.yml`. Added a `worker` job to `ci.yml` to run `npm ci` and `npm run build`, ensuring type safety and parity with `AGENTS.md` intent. - **[2026-04-08]**: Updated `google-github-actions/auth` from v2 to v3 in `provision-worker.yml` to prevent deprecation issues. Extracted inline YAML scripts for Doppler secrets, Forge version resolution, worker notifications, and worker host config into reusable `scripts/` to enforce execution parity and Kickstart principles. Refined `AGENTS.md` to expose CI parity scripts (`./scripts/test.sh`, etc.) alongside targeted commands. - **[2026-04-11]**: Updated `google-github-actions/auth` from v2 to v3 in `rollout-safety-net.yml` to prevent deprecation issues. Extracted inline YAML scripts for rollout safety net polling, setting image names, checking docker tags, and extracting GCP project IDs into reusable `scripts/` to enforce execution parity and Kickstart verification principles. Refined `scripts/run-analysis.js` to mitigate command injection risks by removing `shell: true` from `child_process.spawn`. +- **[2026-04-12]**: Resolved Dart SDK version conflict in `worker_flutter/pubspec.yaml` by downgrading `^3.11.5` to `^3.11.0` to match Flutter stable channel. Calibrated `scripts/lint.sh` and `scripts/test.sh` to include Flutter checks, and updated `.github/workflows/ci.yml` jobs with `subosito/flutter-action@v2` for pipeline parity. Updated `AGENTS.md` instructions. diff --git a/AGENTS.md b/AGENTS.md index fa0850de..bcd40460 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,6 +29,8 @@ - **Worker Install**: `cd worker && npm install` - **Worker Dev**: `cd worker && npm run dev` - **Worker Test**: `cd worker && npm run test:unit` +- **Worker Flutter Test**: `cd worker_flutter && flutter test` +- **Worker Flutter Lint**: `cd worker_flutter && flutter analyze --no-fatal-infos` ## Deployment - **CI**: `.github/workflows/ci.yml` (Runs on PR) @@ -38,3 +40,4 @@ - `frontend/`: React app - `api/`: Next.js API, ingestion, and analysis - `worker/`: Node.js + Docker simulation runner +- `worker_flutter/`: Cross-platform desktop worker (macOS/Windows) diff --git a/scripts/lint.sh b/scripts/lint.sh index 528e316c..af4c5369 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -15,3 +15,7 @@ cd frontend && npm ci && npm run lint && cd .. # API echo "=== API lint ===" cd api && npm ci && npm run lint && cd .. + +# Worker Flutter +echo "=== Worker Flutter lint ===" +cd worker_flutter && flutter pub get && flutter analyze --no-fatal-infos && cd .. diff --git a/scripts/test.sh b/scripts/test.sh index 31b58634..41399ecc 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -22,3 +22,7 @@ npm run test:ingestion && cd .. # Worker tests echo "=== Worker unit tests ===" cd worker && npm ci && npm run test:unit && cd .. + +# Worker Flutter tests +echo "=== Worker Flutter tests ===" +cd worker_flutter && flutter pub get && flutter test && cd .. diff --git a/worker_flutter/pubspec.lock b/worker_flutter/pubspec.lock index b7c9feee..d21e63a0 100644 --- a/worker_flutter/pubspec.lock +++ b/worker_flutter/pubspec.lock @@ -692,10 +692,10 @@ packages: dependency: transitive description: name: matcher - sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 + sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" url: "https://pub.dev" source: hosted - version: "0.12.19" + version: "0.12.18" material_color_utilities: dependency: transitive description: @@ -1193,10 +1193,10 @@ packages: dependency: transitive description: name: test_api - sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" url: "https://pub.dev" source: hosted - version: "0.7.10" + version: "0.7.9" tray_manager: dependency: "direct main" description: @@ -1374,5 +1374,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.11.5 <4.0.0" + dart: ">=3.11.0 <4.0.0" flutter: ">=3.38.4" diff --git a/worker_flutter/pubspec.yaml b/worker_flutter/pubspec.yaml index 5fb626dc..ffa79515 100644 --- a/worker_flutter/pubspec.yaml +++ b/worker_flutter/pubspec.yaml @@ -10,7 +10,7 @@ publish_to: 'none' version: 0.2.0+1 environment: - sdk: ^3.11.5 + sdk: ^3.11.0 dependencies: flutter: From 7d5b7af8f4cd77d45a33187d7105984df06ac1a4 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 3 Jun 2026 10:49:22 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=94=A8=20Forge:=20[CI/AGENTS.md=20Cal?= =?UTF-8?q?ibration]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolved Dart SDK version conflict in `worker_flutter/pubspec.yaml` by downgrading from `^3.11.5` to `^3.11.0` to match the Flutter stable channel. Calibrated the shared CI verification scripts (`scripts/lint.sh`, `scripts/test.sh`) to include targeted Flutter commands (`flutter test` and `flutter analyze`). Updated `.github/workflows/ci.yml` jobs to provision the `subosito/flutter-action@v2` setup step for pipeline parity. Additionally, resolved a GitHub Actions deprecation warning by upgrading the `actions/setup-node` version constraint from `20` to `24` in `.github/workflows/ci.yml`, `.github/workflows/deploy.yml`, and `.github/workflows/provision-worker.yml`, as well as `scripts/lint.sh`, `scripts/build.sh`, and `scripts/test.sh`. Finally, updated `AGENTS.md` instructions and project structure context, and resolved an unused import (`macos/activation_policy.dart`) in `worker_flutter/lib/main.dart` that caused a Flutter linting failure. --- .github/workflows/ci.yml | 6 +- .github/workflows/deploy.yml | 2 +- .github/workflows/provision-worker.yml | 2 +- .jules/forge.md | 1 + AGENTS.md | 2 +- scripts/build.sh | 2 +- scripts/lint.sh | 2 +- scripts/test.sh | 2 +- worker_flutter/lib/auth/desktop_oauth.dart | 3 +- worker_flutter/lib/main.dart | 13 +- worker_flutter/lib/models/sim.dart | 14 +- worker_flutter/lib/ui/dashboard.dart | 11 +- worker_flutter/lib/worker/lease_writer.dart | 5 +- worker_flutter/lib/worker/sim_claim.dart | 18 +- .../test/worker/lease_writer_test.dart | 7 +- .../test/worker/sim_claim_test.dart | 171 +++++++++++------- 16 files changed, 163 insertions(+), 98 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7deb02de..f1bfba22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: 'npm' cache-dependency-path: | frontend/package-lock.json @@ -36,7 +36,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: 'npm' cache-dependency-path: | frontend/package-lock.json @@ -60,7 +60,7 @@ jobs: - uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 cache: 'npm' cache-dependency-path: | frontend/package-lock.json diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 14682135..bb054125 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -60,7 +60,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '24' cache: 'npm' cache-dependency-path: frontend/package-lock.json diff --git a/.github/workflows/provision-worker.yml b/.github/workflows/provision-worker.yml index ef6a513c..1bd52b3e 100644 --- a/.github/workflows/provision-worker.yml +++ b/.github/workflows/provision-worker.yml @@ -48,7 +48,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 24 - name: Install root dependencies run: npm ci diff --git a/.jules/forge.md b/.jules/forge.md index a5a3477d..7a705c83 100644 --- a/.jules/forge.md +++ b/.jules/forge.md @@ -7,3 +7,4 @@ - **[2026-04-08]**: Updated `google-github-actions/auth` from v2 to v3 in `provision-worker.yml` to prevent deprecation issues. Extracted inline YAML scripts for Doppler secrets, Forge version resolution, worker notifications, and worker host config into reusable `scripts/` to enforce execution parity and Kickstart principles. Refined `AGENTS.md` to expose CI parity scripts (`./scripts/test.sh`, etc.) alongside targeted commands. - **[2026-04-11]**: Updated `google-github-actions/auth` from v2 to v3 in `rollout-safety-net.yml` to prevent deprecation issues. Extracted inline YAML scripts for rollout safety net polling, setting image names, checking docker tags, and extracting GCP project IDs into reusable `scripts/` to enforce execution parity and Kickstart verification principles. Refined `scripts/run-analysis.js` to mitigate command injection risks by removing `shell: true` from `child_process.spawn`. - **[2026-04-12]**: Resolved Dart SDK version conflict in `worker_flutter/pubspec.yaml` by downgrading `^3.11.5` to `^3.11.0` to match Flutter stable channel. Calibrated `scripts/lint.sh` and `scripts/test.sh` to include Flutter checks, and updated `.github/workflows/ci.yml` jobs with `subosito/flutter-action@v2` for pipeline parity. Updated `AGENTS.md` instructions. +- **[2026-06-03]**: Upgraded Node.js version from 20 to 24 in `.github/workflows` (ci.yml, deploy.yml, provision-worker.yml) and shared verification scripts (`scripts/lint.sh`, `scripts/build.sh`, `scripts/test.sh`) to resolve GitHub Actions deprecation failures. Updated `AGENTS.md` Tooling requirement to Node.js 24+. Fixed an unused import (`macos/activation_policy.dart`) in `worker_flutter/lib/main.dart` that caused Flutter lint failures. diff --git a/AGENTS.md b/AGENTS.md index bcd40460..802e32ad 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ - **Executable:** If it isn't an executable command or a hard constraint, it doesn't belong here. ## Tooling -- **Node.js**: 20+ (managed by `npm`) +- **Node.js**: 24+ (managed by `npm`) - **Docker**: Required for simulation engine - **Package Manager**: `npm` (Node) diff --git a/scripts/build.sh b/scripts/build.sh index 718bf5bd..293d56f8 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -5,7 +5,7 @@ set -euo pipefail if command -v nvm &>/dev/null || [ -s "$HOME/.nvm/nvm.sh" ]; then export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" - nvm install 20 && nvm use 20 + nvm install 24 && nvm use 24 fi # Frontend and worker builds in parallel (background) diff --git a/scripts/lint.sh b/scripts/lint.sh index af4c5369..9eada46d 100755 --- a/scripts/lint.sh +++ b/scripts/lint.sh @@ -5,7 +5,7 @@ set -euo pipefail if command -v nvm &>/dev/null || [ -s "$HOME/.nvm/nvm.sh" ]; then export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" - nvm install 20 && nvm use 20 + nvm install 24 && nvm use 24 fi # Frontend diff --git a/scripts/test.sh b/scripts/test.sh index 41399ecc..febb8c04 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -5,7 +5,7 @@ set -euo pipefail if command -v nvm &>/dev/null || [ -s "$HOME/.nvm/nvm.sh" ]; then export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" - nvm install 20 && nvm use 20 + nvm install 24 && nvm use 24 fi # Frontend tests diff --git a/worker_flutter/lib/auth/desktop_oauth.dart b/worker_flutter/lib/auth/desktop_oauth.dart index d206c7a5..7e8382c1 100644 --- a/worker_flutter/lib/auth/desktop_oauth.dart +++ b/worker_flutter/lib/auth/desktop_oauth.dart @@ -324,5 +324,6 @@ class GoogleRefreshTokenException implements Exception { } @override - String toString() => 'GoogleRefreshTokenException: Google token endpoint returned $statusCode: $body'; + String toString() => + 'GoogleRefreshTokenException: Google token endpoint returned $statusCode: $body'; } diff --git a/worker_flutter/lib/main.dart b/worker_flutter/lib/main.dart index af23c0da..c0cd5424 100644 --- a/worker_flutter/lib/main.dart +++ b/worker_flutter/lib/main.dart @@ -19,7 +19,6 @@ import 'installer/install_progress_app.dart'; import 'installer/installer.dart'; import 'launch/auto_start_service.dart'; import 'launch/mode_picker_screen.dart'; -import 'macos/activation_policy.dart'; import 'offline/offline_app.dart'; import 'sentry_setup.dart'; import 'telemetry.dart'; @@ -634,12 +633,12 @@ class _WorkerAppState extends State<_WorkerApp> { ), ) : (_user == null - ? AuthGateScreen( - authService: _auth, - onAuthed: _onAuthed, - onSwitchToOffline: _switchToOffline, - ) - : Dashboard(engine: widget.engine, config: widget.config)), + ? AuthGateScreen( + authService: _auth, + onAuthed: _onAuthed, + onSwitchToOffline: _switchToOffline, + ) + : Dashboard(engine: widget.engine, config: widget.config)), ); } } diff --git a/worker_flutter/lib/models/sim.dart b/worker_flutter/lib/models/sim.dart index 756df274..87de47f9 100644 --- a/worker_flutter/lib/models/sim.dart +++ b/worker_flutter/lib/models/sim.dart @@ -24,13 +24,13 @@ class SimDoc { String get compositeId => '$jobId:$simId'; Map toJson() => { - 'simId': simId, - 'jobId': jobId, - 'index': index, - 'state': state, - if (workerId != null) 'workerId': workerId, - if (workerName != null) 'workerName': workerName, - }; + 'simId': simId, + 'jobId': jobId, + 'index': index, + 'state': state, + if (workerId != null) 'workerId': workerId, + if (workerName != null) 'workerName': workerName, + }; } /// Result of running a single simulation (output from sim_runner). diff --git a/worker_flutter/lib/ui/dashboard.dart b/worker_flutter/lib/ui/dashboard.dart index ecdc8e77..5a524cd5 100644 --- a/worker_flutter/lib/ui/dashboard.dart +++ b/worker_flutter/lib/ui/dashboard.dart @@ -253,7 +253,10 @@ class _DashboardState extends State { child: Tooltip( message: 'View on GitHub', child: Container( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + padding: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 4, + ), decoration: BoxDecoration( color: const Color(0xFF1F2937), borderRadius: BorderRadius.circular(12), @@ -262,7 +265,11 @@ class _DashboardState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - const Icon(Icons.code, size: 12, color: Color(0xFF60A5FA)), + const Icon( + Icons.code, + size: 12, + color: Color(0xFF60A5FA), + ), const SizedBox(width: 6), Text( _getVersionText(), diff --git a/worker_flutter/lib/worker/lease_writer.dart b/worker_flutter/lib/worker/lease_writer.dart index 1390ac63..9bf01fa3 100644 --- a/worker_flutter/lib/worker/lease_writer.dart +++ b/worker_flutter/lib/worker/lease_writer.dart @@ -59,7 +59,10 @@ class LeaseWriter { } catch (_) { // _writeOnce already swallows; this is belt-and-suspenders. } - _timer = Timer.periodic(tickInterval, (_) => _writeOnce(status: _activeStatus())); + _timer = Timer.periodic( + tickInterval, + (_) => _writeOnce(status: _activeStatus()), + ); } Future stop() async { diff --git a/worker_flutter/lib/worker/sim_claim.dart b/worker_flutter/lib/worker/sim_claim.dart index e493e29f..04ada7a0 100644 --- a/worker_flutter/lib/worker/sim_claim.dart +++ b/worker_flutter/lib/worker/sim_claim.dart @@ -84,14 +84,16 @@ class SimClaimer { // jobId is the parent of the parent of the sim doc final jobId = simRef.parent.parent!.id; - return ClaimSucceeded(SimDoc( - simId: simRef.id, - jobId: jobId, - index: (data['index'] as num?)?.toInt() ?? 0, - state: 'RUNNING', - workerId: workerId, - workerName: workerName, - )); + return ClaimSucceeded( + SimDoc( + simId: simRef.id, + jobId: jobId, + index: (data['index'] as num?)?.toInt() ?? 0, + state: 'RUNNING', + workerId: workerId, + workerName: workerName, + ), + ); }); } on FirebaseException catch (e) { return ClaimLostRace('firestore: ${e.code}'); diff --git a/worker_flutter/test/worker/lease_writer_test.dart b/worker_flutter/test/worker/lease_writer_test.dart index dbffac26..110d626d 100644 --- a/worker_flutter/test/worker/lease_writer_test.dart +++ b/worker_flutter/test/worker/lease_writer_test.dart @@ -83,8 +83,11 @@ void main() { final doc = await firestore.collection('workers').doc('w1').get(); final lease = doc.data()!['lease'] as Map; final expiresAt = DateTime.parse(lease['expiresAt'] as String); - expect(expiresAt.isAfter(DateTime.now().toUtc()), true, - reason: 'lease should not be already-expired immediately after write'); + expect( + expiresAt.isAfter(DateTime.now().toUtc()), + true, + reason: 'lease should not be already-expired immediately after write', + ); }); }); } diff --git a/worker_flutter/test/worker/sim_claim_test.dart b/worker_flutter/test/worker/sim_claim_test.dart index 51326bbf..89a2e9c5 100644 --- a/worker_flutter/test/worker/sim_claim_test.dart +++ b/worker_flutter/test/worker/sim_claim_test.dart @@ -24,39 +24,58 @@ void main() { expect(result, isA()); }); - test('claims a PENDING sim and flips it to RUNNING with workerId', () async { - final now = DateTime.now(); - final jobRef = firestore.collection('jobs').doc('job1'); - await jobRef.collection('simulations').doc('sim1').set({ - 'simId': 'sim1', - 'index': 0, - 'state': 'PENDING', - 'createdAt': now, - }); - - final result = await claimer.tryClaim(); - expect(result, isA()); - final claimed = (result as ClaimSucceeded).sim; - expect(claimed.simId, 'sim1'); - expect(claimed.jobId, 'job1'); - expect(claimed.workerId, 'w1'); - - // Verify Firestore was updated. - final fresh = await jobRef.collection('simulations').doc('sim1').get(); - expect(fresh.data()!['state'], 'RUNNING'); - expect(fresh.data()!['workerId'], 'w1'); - expect(fresh.data()!['workerName'], 'test-worker'); - }); + test( + 'claims a PENDING sim and flips it to RUNNING with workerId', + () async { + final now = DateTime.now(); + final jobRef = firestore.collection('jobs').doc('job1'); + await jobRef.collection('simulations').doc('sim1').set({ + 'simId': 'sim1', + 'index': 0, + 'state': 'PENDING', + 'createdAt': now, + }); + + final result = await claimer.tryClaim(); + expect(result, isA()); + final claimed = (result as ClaimSucceeded).sim; + expect(claimed.simId, 'sim1'); + expect(claimed.jobId, 'job1'); + expect(claimed.workerId, 'w1'); + + // Verify Firestore was updated. + final fresh = await jobRef.collection('simulations').doc('sim1').get(); + expect(fresh.data()!['state'], 'RUNNING'); + expect(fresh.data()!['workerId'], 'w1'); + expect(fresh.data()!['workerName'], 'test-worker'); + }, + ); test('picks the oldest PENDING sim across multiple jobs', () async { final older = DateTime(2026, 1, 1); final newer = DateTime(2026, 1, 2); await firestore - .collection('jobs').doc('job-a').collection('simulations').doc('s1') - .set({'simId': 's1', 'index': 0, 'state': 'PENDING', 'createdAt': newer}); + .collection('jobs') + .doc('job-a') + .collection('simulations') + .doc('s1') + .set({ + 'simId': 's1', + 'index': 0, + 'state': 'PENDING', + 'createdAt': newer, + }); await firestore - .collection('jobs').doc('job-b').collection('simulations').doc('s2') - .set({'simId': 's2', 'index': 0, 'state': 'PENDING', 'createdAt': older}); + .collection('jobs') + .doc('job-b') + .collection('simulations') + .doc('s2') + .set({ + 'simId': 's2', + 'index': 0, + 'state': 'PENDING', + 'createdAt': older, + }); final result = await claimer.tryClaim(); expect(result, isA()); @@ -66,11 +85,27 @@ void main() { test('does not return COMPLETED or FAILED sims', () async { final now = DateTime.now(); await firestore - .collection('jobs').doc('j').collection('simulations').doc('s1') - .set({'simId': 's1', 'index': 0, 'state': 'COMPLETED', 'createdAt': now}); + .collection('jobs') + .doc('j') + .collection('simulations') + .doc('s1') + .set({ + 'simId': 's1', + 'index': 0, + 'state': 'COMPLETED', + 'createdAt': now, + }); await firestore - .collection('jobs').doc('j').collection('simulations').doc('s2') - .set({'simId': 's2', 'index': 1, 'state': 'FAILED', 'createdAt': now}); + .collection('jobs') + .doc('j') + .collection('simulations') + .doc('s2') + .set({ + 'simId': 's2', + 'index': 1, + 'state': 'FAILED', + 'createdAt': now, + }); final result = await claimer.tryClaim(); expect(result, isA()); @@ -99,42 +134,52 @@ void main() { ); // Seed Firestore with the sim in RUNNING state. await firestore - .collection('jobs').doc('job1').collection('simulations').doc('sim1') + .collection('jobs') + .doc('job1') + .collection('simulations') + .doc('sim1') .set({ - 'simId': 'sim1', - 'index': 0, - 'state': 'RUNNING', - 'workerId': 'w1', - 'workerName': 'test-worker', - }); + 'simId': 'sim1', + 'index': 0, + 'state': 'RUNNING', + 'workerId': 'w1', + 'workerName': 'test-worker', + }); await firestore.collection('jobs').doc('job1').set({ 'jobId': 'job1', 'completedSimCount': 0, }); }); - test('marks sim COMPLETED and increments completedSimCount on success', () async { - await claimer.reportTerminal( - sim: sim, - result: SimResult( - success: true, - durationMs: 5000, - winners: ['Ai(1)-Alpha'], - winningTurns: [12], - logText: 'log text', - ), - ); - - final fresh = await firestore - .collection('jobs').doc('job1').collection('simulations').doc('sim1').get(); - expect(fresh.data()!['state'], 'COMPLETED'); - expect(fresh.data()!['durationMs'], 5000); - expect(fresh.data()!['winners'], ['Ai(1)-Alpha']); - expect(fresh.data()!['winningTurns'], [12]); - - final job = await firestore.collection('jobs').doc('job1').get(); - expect(job.data()!['completedSimCount'], 1); - }); + test( + 'marks sim COMPLETED and increments completedSimCount on success', + () async { + await claimer.reportTerminal( + sim: sim, + result: SimResult( + success: true, + durationMs: 5000, + winners: ['Ai(1)-Alpha'], + winningTurns: [12], + logText: 'log text', + ), + ); + + final fresh = await firestore + .collection('jobs') + .doc('job1') + .collection('simulations') + .doc('sim1') + .get(); + expect(fresh.data()!['state'], 'COMPLETED'); + expect(fresh.data()!['durationMs'], 5000); + expect(fresh.data()!['winners'], ['Ai(1)-Alpha']); + expect(fresh.data()!['winningTurns'], [12]); + + final job = await firestore.collection('jobs').doc('job1').get(); + expect(job.data()!['completedSimCount'], 1); + }, + ); test('marks sim FAILED with errorMessage on failure', () async { await claimer.reportTerminal( @@ -150,7 +195,11 @@ void main() { ); final fresh = await firestore - .collection('jobs').doc('job1').collection('simulations').doc('sim1').get(); + .collection('jobs') + .doc('job1') + .collection('simulations') + .doc('sim1') + .get(); expect(fresh.data()!['state'], 'FAILED'); expect(fresh.data()!['errorMessage'], 'java crashed');