318 lines
9.1 KiB
JSON
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
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|