197 lines
6.4 KiB
Markdown
197 lines
6.4 KiB
Markdown
# E2E Test Parallel Execution Feasibility
|
||
|
||
**Author**: assistant-engineer-2
|
||
**Date**: 2026-04-21
|
||
**Purpose**: Investigate whether Assistant E2E tests and Skills E2E tests can run in parallel
|
||
|
||
---
|
||
|
||
## Executive Summary
|
||
|
||
**Conclusion**: ❌ **Cannot run in parallel** (current architecture)
|
||
|
||
**Reason**: Shared singleton Electron app instance + shared database + explicit `workers: 1` configuration
|
||
|
||
**Recommendation**: Keep sequential execution. If parallel needed in future, requires architectural refactoring (see Solutions section).
|
||
|
||
---
|
||
|
||
## Current Architecture Analysis
|
||
|
||
### 1. Playwright Configuration
|
||
|
||
**File**: `playwright.config.ts`
|
||
|
||
```typescript
|
||
fullyParallel: false, // Electron tests share one app instance
|
||
workers: 1, // Must be 1: tests share a singleton Electron app instance
|
||
```
|
||
|
||
**Critical constraint**: Playwright explicitly enforces `workers: 1` with comment explaining singleton architecture.
|
||
|
||
### 2. Electron App Singleton Pattern
|
||
|
||
**File**: `tests/e2e/fixtures.ts:26-28`
|
||
|
||
```typescript
|
||
// Singleton – one app per test worker
|
||
let app: ElectronApplication | null = null;
|
||
let mainPage: Page | null = null;
|
||
```
|
||
|
||
**Design**: One Electron app instance shared across ALL test files in the worker. The app:
|
||
|
||
- Launches once at worker startup
|
||
- Persists across all `test.describe()` blocks
|
||
- Closes only when worker exits
|
||
- Reuses same `BrowserWindow` and renderer process
|
||
|
||
**Rationale** (from `tests/e2e/README.md:48-50`):
|
||
|
||
> One Electron instance shared across all tests. Restarting costs ~25-30 seconds, so tests reuse the same app process.
|
||
|
||
### 3. Shared Resources
|
||
|
||
#### 3.1 Database
|
||
|
||
**Path resolution** (`src/process/utils/utils.ts:getDataPath()` + backend `--data-dir`):
|
||
|
||
```typescript
|
||
return path.join(getDataPath(), 'aionui.db');
|
||
```
|
||
|
||
**userData directory** (`src/process/utils/configureChromium.ts:18-26`):
|
||
|
||
- Dev mode: `~/Library/Application Support/AionUi-Dev/` (macOS)
|
||
- Database: `{userData}/config/aionui.db`
|
||
- Shared by all E2E tests
|
||
|
||
**Conflict scenario**: If Assistant tests and Skills tests run in parallel workers:
|
||
|
||
1. Both access same `aionui.db` file
|
||
2. SQLite allows multiple readers, but writes lock the entire database
|
||
3. Test data pollution: Assistant test creates custom assistant → Skills test sees it
|
||
|
||
#### 3.2 Extension State File
|
||
|
||
**File**: `tests/e2e/fixtures.ts:29-30`
|
||
|
||
```typescript
|
||
const e2eStateSandboxDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aionui-e2e-state-'));
|
||
const e2eStateFile = path.join(e2eStateSandboxDir, 'extension-states.json');
|
||
```
|
||
|
||
**Environment variable** (L113):
|
||
|
||
```typescript
|
||
AIONUI_EXTENSION_STATES_FILE: process.env.AIONUI_EXTENSION_STATES_FILE || e2eStateFile;
|
||
```
|
||
|
||
**Current isolation**: Each worker creates unique temp directory → **no conflict** (✅ parallel-safe for this resource)
|
||
|
||
#### 3.3 Network Ports
|
||
|
||
**CDP disabled** (`tests/e2e/fixtures.ts:117`):
|
||
|
||
```typescript
|
||
AIONUI_CDP_PORT: '0';
|
||
```
|
||
|
||
**Result**: No port binding conflicts → **parallel-safe** (✅)
|
||
|
||
---
|
||
|
||
## Why Parallel Execution Fails
|
||
|
||
| Resource | Isolation Level | Conflict Type | Impact |
|
||
| --------------------- | ------------------- | -------------------------- | --------------------------------------- |
|
||
| Electron app instance | Worker-scoped | Single instance | 2 workers → 2 apps compete for userData |
|
||
| SQLite database | Global (userData) | File lock + data pollution | Write contention + test interference |
|
||
| Extension state file | Worker temp dir | ✅ No conflict | - |
|
||
| Network ports | None (CDP disabled) | ✅ No conflict | - |
|
||
|
||
**Critical bottleneck**: `workers: 1` enforced + shared `aionui.db` → parallel execution impossible without refactoring.
|
||
|
||
---
|
||
|
||
## Solutions (Future Work)
|
||
|
||
### Option 1: Multi-Instance Mode (Recommended)
|
||
|
||
**Approach**: Isolate userData per worker using environment variables
|
||
|
||
**Implementation**:
|
||
|
||
1. Extend `AIONUI_E2E_TEST` to include worker ID:
|
||
```typescript
|
||
AIONUI_E2E_TEST_WORKER_ID: process.env.PLAYWRIGHT_WORKER_INDEX || '0';
|
||
```
|
||
2. Modify `getDevAppName()` to return worker-specific name:
|
||
```typescript
|
||
const workerId = process.env.AIONUI_E2E_TEST_WORKER_ID || '0';
|
||
return `AionUi-E2E-Worker-${workerId}`;
|
||
```
|
||
3. Each worker gets isolated:
|
||
- `~/Library/Application Support/AionUi-E2E-Worker-0/config/aionui.db`
|
||
- `~/Library/Application Support/AionUi-E2E-Worker-1/config/aionui.db`
|
||
4. Update `playwright.config.ts`:
|
||
```typescript
|
||
workers: 2, // or process.env.CI ? 1 : 2
|
||
fullyParallel: true
|
||
```
|
||
|
||
**Cost**: ~50-60 seconds total (2 workers × 25-30s startup), but parallel → net time ≈ 30s
|
||
|
||
### Option 2: Test Sharding
|
||
|
||
**Approach**: Run Assistant and Skills tests in separate Playwright invocations
|
||
|
||
**Implementation**:
|
||
|
||
```bash
|
||
# Sequential npm scripts
|
||
bun run test:e2e:assistants # Matches tests/e2e/specs/assistant-*.e2e.ts
|
||
bun run test:e2e:skills # Matches tests/e2e/specs/skills-*.e2e.ts
|
||
```
|
||
|
||
**Pros**: No code changes, explicit separation
|
||
**Cons**: Still sequential, no speedup
|
||
|
||
### Option 3: Database Isolation Per Test File
|
||
|
||
**Approach**: Pass unique database path via environment variable per spec
|
||
|
||
**Complexity**: High (requires main process to read `AIONUI_DATABASE_PATH`, conflicts with userData convention)
|
||
|
||
**Not recommended**: Breaks Electron's standard paths, hard to maintain
|
||
|
||
---
|
||
|
||
## Recommendation for Gate 3 Implementation
|
||
|
||
**Keep sequential execution**:
|
||
|
||
1. Assistant tests and Skills tests run in same worker (current `workers: 1`)
|
||
2. Total runtime = sum of both modules (~2-5 minutes typical)
|
||
3. No risk of test interference
|
||
|
||
**If parallel needed later**:
|
||
|
||
- Implement **Option 1** (Multi-Instance Mode) as part of separate infrastructure task
|
||
- Requires changes to:
|
||
- `src/common/platform/index.ts` (`getDevAppName`)
|
||
- `tests/e2e/fixtures.ts` (worker ID injection)
|
||
- `playwright.config.ts` (workers count)
|
||
- Estimated effort: 2-3 hours implementation + testing
|
||
|
||
---
|
||
|
||
## References
|
||
|
||
- `playwright.config.ts:8-10` — Singleton architecture comment
|
||
- `tests/e2e/fixtures.ts:26-28` — App singleton declaration
|
||
- `tests/e2e/README.md:42-50` — Shared instance design rationale
|
||
- `src/process/utils/utils.ts` — `getDataPath()` database directory resolution
|
||
- `src/process/utils/configureChromium.ts:18-26` — userData isolation in dev mode
|
||
- `src/common/platform/index.ts` — `getDevAppName()` implementation
|