{ "$schema": "E2E Parallel Execution Configuration", "version": "1.0.0", "description": "테스트 시나리오 병렬 실행 및 최적화 설정", "lastUpdated": "2026-01-31", "parallel": { "enabled": true, "maxWorkers": 4, "defaultConcurrency": 2, "isolatedBrowsers": true, "sharedLogin": false }, "workerConfig": { "maxWorkers": { "description": "최대 동시 실행 워커 수", "default": 4, "min": 1, "max": 8, "autoDetect": true, "cpuMultiplier": 0.5 }, "workerTimeout": { "description": "워커별 최대 실행 시간", "default": 300000, "perScenario": 60000 }, "workerRetry": { "enabled": true, "maxRetries": 1 } }, "executionModes": { "sequential": { "description": "순차 실행 (기본)", "concurrency": 1, "useCase": "디버깅, 의존성 있는 테스트" }, "parallel": { "description": "병렬 실행", "concurrency": 4, "useCase": "독립적인 테스트, 빠른 실행" }, "grouped": { "description": "그룹별 병렬 실행", "groupConcurrency": 2, "withinGroupSequential": true, "useCase": "관련 테스트 그룹화" }, "prioritized": { "description": "우선순위 기반 실행", "highPriorityFirst": true, "concurrency": 3, "useCase": "중요 테스트 먼저" } }, "grouping": { "byModule": { "description": "모듈별 그룹화", "groups": { "auth": ["login", "logout", "session"], "hr": ["attendance-*", "vacation-*", "employee-*"], "accounting": ["vendor-*", "deposit-*", "card-*"], "approval": ["approval-*", "draft-*", "reference-*"], "boards": ["free-board", "notice-board", "popup-*"] } }, "byPriority": { "description": "우선순위별 그룹화", "groups": { "critical": ["login", "dashboard", "approval-box"], "high": ["vendor-management", "attendance-*"], "medium": ["*-board", "popup-*"], "low": ["settings-*", "help-*"] } }, "byDuration": { "description": "실행 시간별 그룹화", "groups": { "fast": { "maxDuration": 30000, "concurrency": 4 }, "medium": { "maxDuration": 60000, "concurrency": 3 }, "slow": { "maxDuration": 120000, "concurrency": 2 } } } }, "dependencies": { "description": "테스트 간 의존성 관리", "rules": [ { "scenario": "approval-box", "dependsOn": ["login"], "reason": "로그인 필요" }, { "scenario": "crud-*-delete", "dependsOn": ["crud-*-create"], "reason": "삭제 전 생성 필요" } ], "resolutionStrategy": "topological", "blockOnFailure": true }, "isolation": { "browserContext": { "description": "브라우저 컨텍스트 격리", "newContextPerWorker": true, "newContextPerScenario": false, "sharedCookies": false, "sharedStorage": false }, "testData": { "description": "테스트 데이터 격리", "prefixWithWorkerId": true, "format": "E2E_TEST_W{workerId}_{entity}_{timestamp}" }, "ports": { "description": "포트 격리 (로컬 서버)", "basePort": 3000, "portPerWorker": true } }, "loadBalancing": { "strategy": "roundRobin", "strategies": { "roundRobin": { "description": "순환 분배", "algorithm": "각 워커에 순서대로 할당" }, "leastBusy": { "description": "최소 부하 분배", "algorithm": "가장 적은 작업 가진 워커에 할당" }, "durationBased": { "description": "실행 시간 기반", "algorithm": "예상 실행 시간으로 균등 분배" }, "adaptive": { "description": "적응형", "algorithm": "실시간 성능 기반 동적 조절" } } }, "resourceManagement": { "memory": { "maxPerWorker": "512MB", "warningThreshold": "400MB", "killOnExceed": true }, "cpu": { "maxPerWorker": 25, "throttleOnHigh": true }, "network": { "rateLimit": false, "maxConcurrentRequests": 10 } }, "scheduling": { "order": "dependency-aware", "orders": { "fifo": "선입선출", "priority": "우선순위순", "duration": "짧은 것 먼저", "dependency-aware": "의존성 고려" }, "batchSize": 10, "batchDelay": 1000 }, "failureHandling": { "onWorkerFailure": { "action": "reassign", "maxReassigns": 2, "reassignDelay": 5000 }, "onScenarioFailure": { "continueOthers": true, "isolateFailedWorker": false }, "failFast": { "enabled": false, "threshold": 50, "description": "50% 이상 실패 시 중단" } }, "scripts": { "createWorkerPool": "(function(maxWorkers) { const pool = { workers: [], available: [], busy: [] }; for (let i = 0; i < maxWorkers; i++) { pool.workers.push({ id: i, status: 'idle', currentTask: null, completedTasks: 0 }); pool.available.push(i); } return pool; })", "assignTask": "(function(pool, task) { if (pool.available.length === 0) return null; const workerId = pool.available.shift(); const worker = pool.workers[workerId]; worker.status = 'busy'; worker.currentTask = task; pool.busy.push(workerId); return workerId; })", "releaseWorker": "(function(pool, workerId) { const worker = pool.workers[workerId]; worker.status = 'idle'; worker.currentTask = null; worker.completedTasks++; pool.busy = pool.busy.filter(id => id !== workerId); pool.available.push(workerId); })", "getPoolStatus": "(function(pool) { return { total: pool.workers.length, available: pool.available.length, busy: pool.busy.length, tasks: pool.workers.map(w => ({ id: w.id, status: w.status, completed: w.completedTasks })) }; })", "partitionScenarios": "(function(scenarios, workerCount) { const partitions = Array.from({ length: workerCount }, () => []); scenarios.forEach((scenario, index) => { partitions[index % workerCount].push(scenario); }); return partitions; })", "sortByDependency": "(function(scenarios, dependencies) { const graph = new Map(); const inDegree = new Map(); scenarios.forEach(s => { graph.set(s, []); inDegree.set(s, 0); }); dependencies.forEach(dep => { if (graph.has(dep.from) && graph.has(dep.to)) { graph.get(dep.from).push(dep.to); inDegree.set(dep.to, inDegree.get(dep.to) + 1); } }); const queue = scenarios.filter(s => inDegree.get(s) === 0); const result = []; while (queue.length > 0) { const current = queue.shift(); result.push(current); graph.get(current).forEach(next => { inDegree.set(next, inDegree.get(next) - 1); if (inDegree.get(next) === 0) queue.push(next); }); } return result; })" }, "reporting": { "aggregateResults": true, "perWorkerReport": true, "timeline": true, "format": { "summary": { "totalScenarios": "총 시나리오", "totalWorkers": "사용 워커", "totalDuration": "총 실행 시간", "parallelEfficiency": "병렬 효율" }, "perWorker": { "workerId": "워커 ID", "scenarios": "실행 시나리오", "passed": "성공", "failed": "실패", "duration": "소요 시간" } }, "template": { "header": "## ⚡ 병렬 실행 결과", "sections": { "summary": "### 실행 요약", "timeline": "### 타임라인", "workers": "### 워커별 결과" } } }, "optimization": { "autoTuning": { "enabled": true, "adjustWorkersOnLoad": true, "minWorkers": 1, "maxWorkers": 8 }, "caching": { "shareAuthTokens": false, "shareStaticAssets": true, "cacheTestData": false }, "warmup": { "enabled": true, "preloadBrowsers": true, "preloadPages": ["login"] } }, "monitoring": { "realtime": true, "metrics": [ "activeWorkers", "queuedTasks", "completedTasks", "failedTasks", "averageTaskDuration", "cpuUsage", "memoryUsage" ], "alertThresholds": { "queueBacklog": 20, "workerIdleTime": 30000, "memoryUsage": 80 } }, "integration": { "withRetry": { "retryFailedOnDifferentWorker": true, "maxWorkerRetries": 1 }, "withReporting": { "consolidateReports": true, "generateTimeline": true }, "withCI": { "supportSharding": true, "shardIndex": "auto", "totalShards": "auto" } }, "presets": { "quick": { "description": "빠른 실행 (4 워커)", "maxWorkers": 4, "timeout": 180000, "failFast": true }, "thorough": { "description": "철저한 실행 (2 워커)", "maxWorkers": 2, "timeout": 600000, "failFast": false }, "ci": { "description": "CI 환경 (CPU 기반)", "maxWorkers": "auto", "timeout": 300000, "headless": true }, "debug": { "description": "디버그 (1 워커)", "maxWorkers": 1, "timeout": 600000, "verbose": true } } }