Files
sam-scenarios/_global-parallel-config.json
light 02a23e10d0 feat: 병렬 실행 전역 설정 추가
- 실행 모드: sequential, parallel, grouped, prioritized
- 워커 관리: 최대 4개, 독립 브라우저, 자동 조정
- 로드 밸런싱: roundRobin, leastBusy, durationBased, adaptive
- 테스트 데이터 격리: 워커 ID 접두사
- 의존성 관리: topological 정렬
- 프리셋: quick, thorough, ci, debug
- Circuit Breaker: 50% 실패 시 중단

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 12:22:02 +09:00

318 lines
9.1 KiB
JSON

{
"$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
}
}
}