Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
042bb49
Add emulator config, feature flag, and Android target types
joyzoursky Feb 20, 2026
5fa33c8
Add ReliableAdb: ADB wrapper with retry, timeout, health checks
joyzoursky Feb 20, 2026
e88c8bd
Add EmulatorPool singleton with full state machine
joyzoursky Feb 20, 2026
9cc1785
Integrate android targets into test runner
joyzoursky Feb 20, 2026
ba86878
Add AvdProfile and ProjectApk models to schema
joyzoursky Feb 20, 2026
22d2a04
Add APK management and AVD profile API routes
joyzoursky Feb 20, 2026
f9d4342
Add Android target configuration UI
joyzoursky Feb 20, 2026
517b0f8
Add Results viewer android support and admin emulator dashboard
joyzoursky Feb 20, 2026
e7def22
Harden Android emulator feature with startup cleanup and feature flags
joyzoursky Feb 20, 2026
90fad58
Add dockerImage to AvdProfile and androidEnabled to User schema
joyzoursky Feb 21, 2026
96c6df4
Add Docker pool support, STARTING state, user-level Android feature flag
joyzoursky Feb 21, 2026
1e6f4b3
Add PREPARING status, shared status helpers, and emulator color utils
joyzoursky Feb 21, 2026
6a084bc
Add APK delete API with active-run guard
joyzoursky Feb 21, 2026
9e865ef
Add APK management tab and emulator status panel to project page
joyzoursky Feb 21, 2026
97acc02
Add inline APK upload button to ConfigurationsSection APK dropdown
joyzoursky Feb 21, 2026
a29ed3b
Add PREPARING status across all active-run checks
joyzoursky Feb 21, 2026
08b2608
Replace android_ heuristic with targetType prop in TimelineEvent
joyzoursky Feb 21, 2026
1ac8255
Add onPreparing callback for Android test setup phase
joyzoursky Feb 21, 2026
d5719b4
Remove system-level Android feature flag
joyzoursky Feb 21, 2026
94519e8
Remove browser and phone emojis from UI
joyzoursky Feb 21, 2026
8499ab0
Change upload apk button style
joyzoursky Feb 21, 2026
a546f3c
Add per-project AVD profile management
joyzoursky Feb 21, 2026
b94c394
Replace AVD preset selector with 3-field form and help text
joyzoursky Feb 21, 2026
1c84e41
Add missing + icon to Add Android Target button
joyzoursky Feb 21, 2026
d59e922
Move AVD selector and Boot button into emulator list box
joyzoursky Feb 21, 2026
3256b7b
Remove admin paths and orphaned admin emulators page
joyzoursky Feb 21, 2026
b70d227
Redesign emulator pool layout with compact header
joyzoursky Feb 21, 2026
005843e
Merge APKs and Emulators into single Android Setup tab
joyzoursky Feb 21, 2026
e423202
Show android apk metadata
joyzoursky Feb 21, 2026
1327a55
Allow Android-only test case creation
joyzoursky Feb 21, 2026
a977f69
Enforce runtime Android profiles and clean emulator lifecycle
joyzoursky Feb 21, 2026
b7042df
Switch Android profile management to runtime inventory
joyzoursky Feb 21, 2026
70a6499
Enforce docker-only Android profiles from config presets
joyzoursky Feb 21, 2026
9c5d896
Reuse project-scoped emulators with run cleanup
joyzoursky Feb 21, 2026
30f45d4
Handle Docker hosts without /dev/kvm support
joyzoursky Feb 21, 2026
f45e306
Fix Android emulator pool reliability and preset images
joyzoursky Feb 21, 2026
dadc867
Fail fast when Docker host lacks /dev/kvm
joyzoursky Feb 21, 2026
9cfc011
Add Midscene Android runtime dependency
joyzoursky Feb 21, 2026
e3b9138
Switch Android runtime from Docker to native AVD
joyzoursky Feb 21, 2026
b568de6
Update Android preparing copy for emulator startup time
joyzoursky Feb 21, 2026
68e4dd2
Fix Midscene langfuse module resolution
joyzoursky Feb 21, 2026
6fd9752
Refactor Android runs to emulator app IDs
joyzoursky Feb 21, 2026
7da01d0
Use AVD targets and App ID variables for Android runs
joyzoursky Feb 21, 2026
d9c17e2
Run Android emulators headless by default
joyzoursky Feb 21, 2026
ad4d80f
Refine App ID labels and Android URL placeholders
joyzoursky Feb 21, 2026
af3ace4
Sync emulator pool with AVD inventory and status
joyzoursky Feb 21, 2026
b2afeed
Fix target sync after removing browser entries
joyzoursky Feb 21, 2026
3247650
Add Android result artifacts and improve emulator pool status
joyzoursky Feb 21, 2026
b31283e
Fix duplicate live run events and missing history logs
joyzoursky Feb 21, 2026
2d57a59
Add emulator boot modes and enforce stop lifecycle
joyzoursky Feb 21, 2026
5d38a12
Rename AppID to App ID
joyzoursky Feb 21, 2026
4c008f9
Add troubleshoot guide for android emulator setup
joyzoursky Feb 21, 2026
15f9c6a
Fix test run status phase synchronization
joyzoursky Feb 22, 2026
f0f4343
Add Android state and permission toggles
joyzoursky Feb 22, 2026
7bac90b
Refine entry points UI and snapshot read-only display
joyzoursky Feb 22, 2026
24417da
Rename clear app data toggle and trim checkbox copy
joyzoursky Feb 22, 2026
8c6e959
Adjust Android target name placeholder copy
joyzoursky Feb 22, 2026
291d238
Move test step variable help and simplify examples
joyzoursky Feb 22, 2026
c3e7f13
Support Android entry points in test case import/export
joyzoursky Feb 22, 2026
afd33d0
Mask copied test result logs with secret config values
joyzoursky Feb 22, 2026
5da2512
Preserve unnamed entry point labels during Excel import
joyzoursky Feb 22, 2026
89842a2
Simplify Excel entry point import to value-only columns
joyzoursky Feb 22, 2026
5cee975
Harden emulator API visibility and stop access
joyzoursky Feb 22, 2026
52c9a08
Fix emulator reuse cleanup and stop lifecycle
joyzoursky Feb 22, 2026
d79af7a
Remove legacy Excel import compatibility parser
joyzoursky Feb 22, 2026
06c1d1d
Load secrets lazily for copy log masking
joyzoursky Feb 22, 2026
8da201e
Remove unused emulator pool state accessor
joyzoursky Feb 22, 2026
d30d2bc
Document Android runtime constraints and Excel format
joyzoursky Feb 22, 2026
369e891
Refine emulator API and result viewer cleanup
joyzoursky Feb 22, 2026
a34533d
Refactor emulator pool stop lifecycle helpers
joyzoursky Feb 22, 2026
350421a
Refactor Android app launch setup helpers
joyzoursky Feb 22, 2026
70d9fae
Extract Android setup checks in test runner
joyzoursky Feb 22, 2026
a29d514
Rename target display label variables in test runner
joyzoursky Feb 22, 2026
e104ee0
Make test-runner cleanup idempotent on cancel
joyzoursky Feb 22, 2026
e23b74e
Remove unused emulator pool public methods
joyzoursky Feb 22, 2026
9a58b10
Add Android runtime deployment checklist
joyzoursky Feb 22, 2026
ab155dd
Prevent queue stalls on startup status sync errors
joyzoursky Feb 22, 2026
ed7d014
Preserve cancelled status when job finishes after abort
joyzoursky Feb 22, 2026
0a07998
Refactor queue run status event publishing
joyzoursky Feb 22, 2026
377553c
Guard queue fire-and-forget promises
joyzoursky Feb 22, 2026
837235f
Refactor queue test-case status updates
joyzoursky Feb 22, 2026
bf74de7
Extract queue active status sync helper
joyzoursky Feb 22, 2026
497489f
Unify queue cancelled-run persistence paths
joyzoursky Feb 22, 2026
602a981
Guard queue advancement call sites
joyzoursky Feb 22, 2026
3efbc35
Unify queue terminal result persistence
joyzoursky Feb 22, 2026
8e21bda
Reorganize docs for operators and maintainers
joyzoursky Feb 22, 2026
07144b3
Enforce Android feature flags for test runs
joyzoursky Feb 22, 2026
8e52442
Remove extra line in .env.example
joyzoursky Feb 22, 2026
def433d
Remove user APK management surface
joyzoursky Feb 22, 2026
ea957d0
Remove unused ADB APK install helper
joyzoursky Feb 22, 2026
51d86ee
Remove unused AVD profile management code
joyzoursky Feb 22, 2026
3e048c4
Limit emulator env override to max instances
joyzoursky Feb 22, 2026
fcc209f
Fix queue gating and global emulator lifecycle flow
joyzoursky Feb 23, 2026
6d2f1ab
Refine emulator panel boot and stop UI states
joyzoursky Feb 23, 2026
fcf4f9e
Gate Android features by server runtime capability
joyzoursky Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ MIDSCENE_INSIGHT_MODEL_NAME=google/gemini-2.5-flash

# AI Model Behavior (stricter = lower temperature)
MIDSCENE_MODEL_TEMPERATURE=0.2

# Android Emulator Pool (optional overrides)
EMULATOR_MAX_INSTANCES=2
16 changes: 16 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ src/
- Prisma + SQLite, Server-Sent Events
- Playwright 1.57, Midscene.js

## Docs To Read First
- `docs/README.md` - Documentation index and audience split
- `docs/maintainers/coding-agent-maintenance-guide.md` - Maintainer/coding-agent runtime invariants and footguns
- `docs/maintainers/android-runtime-maintenance.md` - Android runtime behavior, isolation model, and hosting constraints
- `docs/maintainers/test-case-excel-format.md` - Current import/export format contract (no backward compatibility)

If you are changing operator-facing Android behavior, also read:
- `docs/operators/mac-android-emulator-guide.md`
- `docs/operators/android-runtime-deployment-checklist.md`

## Docs Structure (Audience Split)
- `docs/operators/` - Self-hosting / setup / runbooks for repo users and operators
- `docs/maintainers/` - Technical maintenance notes for developers and coding agents
- `docs/plans/` - Design notes and implementation plans (historical context, not stable contract)

## Rules
1. **No `any`** - All types in `src/types/index.ts`
2. **Singletons only** - Use `lib/prisma.ts` and `lib/queue.ts`, never create new instances
Expand All @@ -65,6 +80,7 @@ src/
- Align on intent and success criteria before coding.
- For non-trivial changes, capture design notes in `docs/plans/YYYY-MM-DD-<slug>-design.md`.
- For multi-step work, write a plan in `docs/plans/YYYY-MM-DD-<slug>.md`.
- When changing runtime behavior (Android emulator pool, queueing, import/export), update the relevant docs in `docs/operators/` and/or `docs/maintainers/`.
- Prefer test-first for new behavior; reproduce and trace root causes before fixes.
- Self-review spec compliance first, then code quality; verify before completion claims.
- Run `npx tsc --noEmit` to verify TypeScript compilation before committing.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Users provide their own [OpenRouter](https://openrouter.ai/) API keys via the ap
- **Database errors**: `rm -f dev.db && npx prisma db push`
- **View database**: `npx prisma studio`
- **Auth redirect issues**: Check Authgear redirect URI matches your domain
- **Android emulator (feature-flagged)**: See `docs/operators/mac-android-emulator-guide.md`

## Community & Contributing

Expand Down
38 changes: 38 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Documentation Index

This `docs/` folder contains two types of documentation:

- Operator / self-hosting docs: for people setting up and running SkyTest on their own machines/servers
- Maintainer / coding-agent docs: for developers working on this repo and Android runtime behavior

## Operator / Self-Hosting Docs

Core SkyTest can run without Android SDK/emulator tooling. Android operator docs below apply only when enabling Android testing on a host.

- `docs/operators/mac-android-emulator-guide.md`
- macOS setup, emulator creation, operations, troubleshooting
- `docs/operators/android-runtime-deployment-checklist.md`
- preflight checklist for enabling Android runtime on a host/environment

## Maintainer / Coding-Agent Docs

- `docs/maintainers/coding-agent-maintenance-guide.md`
- code map, invariants, and maintenance traps for queue/emulator runtime
- `docs/maintainers/android-runtime-maintenance.md`
- Android runtime behavior, isolation model, and operational constraints
- `docs/maintainers/test-case-excel-format.md`
- current import/export Excel format contract and compatibility policy

## Design Notes / Plans

- `docs/plans/`
- implementation plans and design notes used during feature development
- useful for historical context, but not a stable contract

## Maintenance Guidance

- Prefer treating operator docs and maintainer docs as separate audiences.
- When runtime behavior changes (queueing, emulator cleanup, isolation, API visibility), update both:
- operator runbooks/checklists
- maintainer/runtime notes
- If import/export behavior changes, update `docs/maintainers/test-case-excel-format.md`.
108 changes: 108 additions & 0 deletions docs/maintainers/android-runtime-maintenance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Android Runtime Maintenance Notes

Audience: maintainers / coding agents changing Android runtime behavior.

This document describes the current Android emulator runtime behavior and operational constraints for SkyTest.

Related docs:

- `docs/maintainers/coding-agent-maintenance-guide.md`
- `docs/operators/android-runtime-deployment-checklist.md`
- `docs/operators/mac-android-emulator-guide.md`

## Runtime Capability Gating (Important)

- Android support is now gated by two conditions:
- per-user feature flag (`androidEnabled`)
- server runtime capability (Android tooling available on the host)
- Effective Android availability is `androidEnabled && androidRuntimeAvailable`.
- Non-Android servers are supported: the app should still boot and serve browser-only features.
- Android UI/API surfaces should be hidden or rejected when the server runtime is not Android-capable (do not rely on the user flag alone).

## Deployment Model (Important)

- `src/lib/queue.ts` and `src/lib/emulator-pool.ts` are in-process singletons.
- Queue state, emulator ownership, and emulator wait queues live only in memory.
- This runtime is currently intended for a single long-lived app process.

Implications:

- Do not run multiple app replicas against the same host emulator environment without adding centralized coordination/locking.
- Serverless/ephemeral runtimes are not compatible with the current emulator pool design.
- Process restart will clear queue/pool state and active runs are marked failed on startup.

## Managed vs Unmanaged Emulators

- Managed emulators are those started and tracked by `emulatorPool`.
- Unmanaged emulators are any host emulators visible to `adb` but not tracked by SkyTest (for example, Android Studio/manual launches).

Security behavior:

- `/api/emulators` now returns only pool-managed emulators owned by the current user’s projects.
- `/api/emulators` stop action only allows stopping owned managed emulators.
- SkyTest does not expose or control unmanaged host emulators through the user API.

## Reuse and Isolation Model

- Emulator reuse is project-scoped (`projectId` + emulator template name).
- After a run, Android targets are released back to the pool (not always fully shut down).
- Cleanup is best-effort and includes:
- returning to home
- `am kill-all`
- optional app-specific `am force-stop` + `pm clear` (depends on target toggle)

What persists across runs by design:

- Emulator disk state outside the explicitly targeted app package
- Other installed apps and their data
- System settings and general device state changes that cleanup does not revert

If stronger isolation is required in the future:

- dedicated emulator per run, or
- full wipe/cold-boot policy, or
- tenant-isolated emulator hosts/containers

## Clear App Data Toggle Semantics

- `clearAppData: true`:
- app data is cleared before launch
- app data is also cleared during release cleanup
- `clearAppData: false`:
- app data is not cleared before launch
- app data is not cleared during release cleanup

This preserves app state across runs when the emulator is reused.

## Queueing and Capacity Behavior

- If no matching idle emulator is available and pool capacity is available, the pool boots a new emulator.
- If capacity is full, requests wait in an in-memory wait queue until:
- a matching emulator is released, or
- capacity is freed and a replacement boot is triggered, or
- the acquire timeout is reached

Capacity-freeing events that now wake waiters:

- manual stop
- idle timeout stop
- health-check failure stop
- force reclaim stop
- cleanup failure stop fallback

## Stop Lifecycle Notes

- Stop requests attempt `adb emu kill` and process termination.
- The pool now waits for process exit (bounded timeout) before freeing ports and marking the emulator dead.
- If the process does not exit after `SIGTERM`, a `SIGKILL` attempt is made before final cleanup.

## Copy Log Secret Masking

- The "Copy Log" action masks secret values.
- Secret values are fetched lazily on copy (not preloaded in page state anymore).
- Masking uses current project/test case secret values at copy time.

Known limitation:

- If secret values were rotated after the run, older secret values that appear in historical logs may not be masked.
- Fully solving this requires masking at event-write time (or another server-side historical redaction strategy).
92 changes: 92 additions & 0 deletions docs/maintainers/coding-agent-maintenance-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Coding Agent Maintenance Guide

This guide is for developers and coding agents making changes in this repository.

It complements `AGENTS.md` with project-specific runtime invariants that are easy to break when changing Android support, queueing, and run lifecycle logic.

## Read These First (For Android Runtime Changes)

- `AGENTS.md` (repo workflow, constraints, style)
- `docs/maintainers/android-runtime-maintenance.md` (runtime behavior + hosting constraints)
- `docs/operators/android-runtime-deployment-checklist.md` (operator expectations you should not accidentally invalidate)

## High-Risk Runtime Areas

### 1. Test Queue (`src/lib/queue.ts`)

Responsibilities:

- enqueue / dequeue runs
- in-process concurrency control
- run status transitions (`QUEUED`, `PREPARING`, `RUNNING`, terminal states)
- event buffering + incremental log persistence
- cancellation handling

Key invariants:

- queue advancement must not depend on unguarded async calls
- cancellation should not be overwritten by late job completion
- cleanup may be triggered from both queue cancellation and test-runner teardown, so cleanup paths must be idempotent

### 2. Test Runner (`src/lib/test-runner.ts`)

Responsibilities:

- resolve runtime targets (browser + Android)
- setup browsers/emulators
- execute steps
- capture screenshots/logs
- cleanup targets

Key invariants:

- Android emulator handles should be released through `EmulatorPool.release(...)` (not always force-stopped)
- Android `clearAppData` semantics must remain consistent between pre-launch and release cleanup
- cleanup must remain safe if called more than once

### 3. Emulator Pool (`src/lib/emulator-pool.ts`)

Responsibilities:

- manage emulator lifecycle (boot, acquire, release, stop)
- enforce pool capacity
- wait queue for emulator acquisition
- health checks / idle shutdown

Key invariants:

- any capacity-freeing stop path should wake waiters
- stop lifecycle should wait for process exit before freeing ports
- pool state is in-memory and process-local (single-process runtime assumption)

## Hosted Runtime Constraints (Do Not “Accidentally Scale”)

- `TestQueue` and `EmulatorPool` are process-local singletons.
- Android runtime is not safe for multi-replica/serverless deployments without redesign.
- Avoid adding behavior that assumes cross-process visibility of in-memory queue/emulator state.

If you add features that expose emulator state or control:

- preserve ownership checks
- avoid exposing unmanaged host emulators to normal users

## Documentation Update Checklist for Code Changes

When changing Android runtime behavior, update docs in the same PR/commit series:

- Operator-facing impact:
- `docs/operators/mac-android-emulator-guide.md`
- `docs/operators/android-runtime-deployment-checklist.md`
- Maintainer-facing impact:
- `docs/maintainers/android-runtime-maintenance.md`
- Import/export behavior:
- `docs/maintainers/test-case-excel-format.md`

## Common Footguns

- Reintroducing backward-compat import logic after policy changed to current-format-only
- Bypassing `EmulatorPool.release(...)` in normal Android run teardown
- Adding unguarded fire-and-forget promises in queue processing
- Overwriting `CANCELLED` status after the job finishes late
- Changing operator-visible emulator behavior without updating setup/runbook docs

78 changes: 78 additions & 0 deletions docs/maintainers/test-case-excel-format.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Test Case Excel Import/Export Format

Audience: maintainers / coding agents changing import/export behavior.

This document describes the current supported Excel format for test case import/export.

Related docs:

- `docs/maintainers/coding-agent-maintenance-guide.md`

## Compatibility Policy

- Only the current `Configurations` + `Test Steps` workbook format is supported for import.
- Legacy multi-sheet import formats are not supported.
- No backward compatibility is maintained for old Excel layouts.

## Sheets

- `Configurations`
- `Test Steps`

## Configurations Sheet

The `Configurations` sheet is a row-based table with sections such as:

- `Basic Info` / `Test Case`
- `Project Variable`
- `Test Case Variable`
- `Entry Point`
- `File`

### Entry Points

- One row per entry point.
- Browser entry points:
- `Type = Browser`
- `Name` (optional label)
- `Value` (URL)
- Android entry points:
- `Type = Android`
- `Name` (optional label)
- `Emulator`
- `Value` (App ID)
- `Clear App Data` (boolean)
- `Allow All Permissions` (boolean)

Notes:

- `URL` and `App ID` dedicated columns are not used in the current format.
- Entry point values must be read from the shared `Value` column.

## Test Steps Sheet

- Steps include action text and target mapping.
- Target mapping supports both browser and Android entry points from the current `Configurations` sheet.

## Import Behavior (Current Product Policy)

Import does:

- import test case metadata (name, test case ID)
- import entry points (browser + Android)
- import test steps
- import test case variables (supported non-file types)

Import does not:

- import project variables
- import file variables
- import attached files from export zip bundles (run-page import is Excel-only)

Warnings may still be produced during parsing for invalid/unsupported rows.

## Export Behavior

- Export includes the current workbook format.
- Android entry points are exported with emulator name, app ID (in `Value`), and toggles.
- Some export surfaces may support zipped attachments for download, but run-page import is designed for Excel workbook import.
Loading