-
Notifications
You must be signed in to change notification settings - Fork 0
test: 통합 테스트 수정 - 타입 및 시간 제한 개선 #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
fcb706a
2a93b5c
3efd7fa
fa18906
e982e72
bc534ca
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,11 @@ import { TaskRequestHandler } from '../../src/app/TaskRequestHandler'; | |
| import { WorkerPoolManager } from '../../src/services/manager/worker-pool-manager'; | ||
| import { WorkspaceManager } from '../../src/services/manager/workspace-manager'; | ||
| import { StateManager } from '../../src/services/state-manager'; | ||
| import { Logger } from '../../src/services/logger'; | ||
| import { TaskRequest, ResponseStatus, WorkerAction } from '../../src/types'; | ||
| import { Logger, LogLevel } from '../../src/services/logger'; | ||
| import { TaskRequest, ResponseStatus, WorkerAction, TaskAction } from '../../src/types'; | ||
| import { ManagerServiceConfig } from '../../src/types/manager.types'; | ||
| import { DeveloperConfig } from '../../src/types/developer.types'; | ||
| import { ProjectBoardItem } from '../../src/types/project-board.types'; | ||
| import fs from 'fs/promises'; | ||
| import path from 'path'; | ||
| import os from 'os'; | ||
|
|
@@ -26,8 +27,8 @@ describe('Task Reassignment Integration Tests', () => { | |
|
|
||
| // Logger 초기화 | ||
| logger = new Logger({ | ||
| serviceName: 'task-reassignment-test', | ||
| logLevel: 'debug', | ||
| level: LogLevel.DEBUG, | ||
| filePath: path.join(testDataDir, 'test.log'), | ||
| enableConsole: false | ||
| }); | ||
|
|
||
|
|
@@ -36,9 +37,13 @@ describe('Task Reassignment Integration Tests', () => { | |
| await stateManager.initialize(); | ||
|
|
||
| // WorkspaceManager 초기화 | ||
| const workspaceConfig = { | ||
| const workspaceConfig: ManagerServiceConfig = { | ||
| workspaceBasePath: testWorkspaceDir, | ||
| repositoriesBasePath: testWorkspaceDir, | ||
| minWorkers: 1, | ||
| maxWorkers: 3, | ||
| workerRecoveryTimeoutMs: 30000, | ||
| gitOperationTimeoutMs: 60000, | ||
| repositoryCacheTimeoutMs: 300000, | ||
| workerLifecycle: { | ||
| idleTimeoutMinutes: 30, | ||
| cleanupIntervalMinutes: 60, | ||
|
|
@@ -75,10 +80,12 @@ describe('Task Reassignment Integration Tests', () => { | |
|
|
||
| // WorkerPoolManager 초기화 | ||
| const managerConfig: ManagerServiceConfig = { | ||
| workspaceBasePath: testWorkspaceDir, | ||
| minWorkers: 1, | ||
| maxWorkers: 3, | ||
| workspaceBasePath: testWorkspaceDir, | ||
| repositoriesBasePath: testWorkspaceDir, | ||
| workerRecoveryTimeoutMs: 30000, | ||
| gitOperationTimeoutMs: 60000, | ||
| repositoryCacheTimeoutMs: 300000, | ||
| workerLifecycle: { | ||
| idleTimeoutMinutes: 30, | ||
| cleanupIntervalMinutes: 60, | ||
|
|
@@ -87,20 +94,47 @@ describe('Task Reassignment Integration Tests', () => { | |
| }; | ||
|
|
||
| const developerConfig: DeveloperConfig = { | ||
| claude: { | ||
| apiKey: 'test-key', | ||
| model: 'claude-3-sonnet-20240229', | ||
| maxTokens: 4000 | ||
| timeoutMs: 60000, | ||
| maxRetries: 3, | ||
| retryDelayMs: 1000, | ||
| mock: { | ||
| responseDelay: 100 | ||
| } | ||
| }; | ||
|
|
||
| // Mock Developer Factory 생성 | ||
| const mockDeveloper = { | ||
| type: 'mock' as const, | ||
| initialize: jest.fn().mockResolvedValue(undefined), | ||
| executePrompt: jest.fn().mockResolvedValue({ | ||
| rawOutput: 'test output', | ||
| result: { success: true, prLink: 'https://github.com/test/pr/1' }, | ||
| executedCommands: [], | ||
| modifiedFiles: [], | ||
| metadata: { | ||
| startTime: new Date(), | ||
| endTime: new Date(), | ||
| duration: 1000, | ||
| developerType: 'mock' as const | ||
| } | ||
| }), | ||
| cleanup: jest.fn().mockResolvedValue(undefined), | ||
| isAvailable: jest.fn().mockResolvedValue(true), | ||
| setTimeout: jest.fn() | ||
| }; | ||
|
|
||
| const mockDeveloperFactory = { | ||
| create: jest.fn().mockReturnValue(mockDeveloper) | ||
| } as any; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| workerPoolManager = new WorkerPoolManager( | ||
| managerConfig, | ||
| { | ||
| logger, | ||
| stateManager, | ||
| workspaceManager, | ||
| developerConfig | ||
| developerConfig, | ||
| developerFactory: mockDeveloperFactory | ||
| } | ||
| ); | ||
|
|
||
|
|
@@ -113,28 +147,38 @@ describe('Task Reassignment Integration Tests', () => { | |
| undefined, // pullRequestService | ||
| logger | ||
| ); | ||
|
|
||
| // WorkerTaskExecutor의 assignAndExecuteTask를 mock | ||
| jest.spyOn(taskRequestHandler['workerTaskExecutor'], 'assignAndExecuteTask') | ||
| .mockResolvedValue(undefined); | ||
| }); | ||
|
|
||
| afterEach(async () => { | ||
| // 정리 | ||
| await workerPoolManager.shutdown(); | ||
| await fs.rmdir(testDataDir, { recursive: true }).catch(() => {}); | ||
| await fs.rmdir(testWorkspaceDir, { recursive: true }).catch(() => {}); | ||
| await fs.rm(testDataDir, { recursive: true, force: true }).catch(() => {}); | ||
| await fs.rm(testWorkspaceDir, { recursive: true, force: true }).catch(() => {}); | ||
| }); | ||
|
|
||
| describe('진행중 작업 재할당', () => { | ||
| it('workspace가 존재하지 않는 idle Worker에는 RESUME_TASK를 할당하지 않는다', async () => { | ||
| // Given: 작업 요청 | ||
| const taskRequest: TaskRequest = { | ||
| taskId: 'test-task-1', | ||
| action: 'check_status', | ||
| action: TaskAction.CHECK_STATUS, | ||
| boardItem: { | ||
| id: 'test-task-1', | ||
| title: '테스트 작업', | ||
| status: 'Todo', | ||
| assignee: null, | ||
| labels: [], | ||
| createdAt: new Date(), | ||
| updatedAt: new Date(), | ||
| pullRequestUrls: [], | ||
| metadata: { | ||
| repository: 'test-owner/test-repo' | ||
| } | ||
| } | ||
| } as ProjectBoardItem | ||
| }; | ||
|
|
||
| // When: 작업 상태 확인 요청 (Worker가 없어서 재할당 시도) | ||
|
|
@@ -166,22 +210,60 @@ describe('Task Reassignment Integration Tests', () => { | |
| 'gitdir: /path/to/repo/.git/worktrees/test' | ||
| ); | ||
|
|
||
| // Validation: workspace가 올바르게 저장되었는지 확인 | ||
| const savedWorkspaceInfo = await workspaceManager.getWorkspaceInfo(taskId); | ||
| expect(savedWorkspaceInfo).not.toBeNull(); | ||
| expect(savedWorkspaceInfo?.taskId).toBe(taskId); | ||
|
|
||
| // Validation: workspace가 유효한지 확인 | ||
| const isValid = await workspaceManager.isWorktreeValid(workspaceInfo); | ||
| expect(isValid).toBe(true); | ||
|
|
||
| // Given: 작업 요청 | ||
| const taskRequest: TaskRequest = { | ||
| taskId, | ||
| action: 'check_status', | ||
| action: TaskAction.CHECK_STATUS, | ||
| boardItem: { | ||
| id: taskId, | ||
| title: '테스트 작업 2', | ||
| status: 'In Progress', | ||
| assignee: null, | ||
| labels: [], | ||
| createdAt: new Date(), | ||
| updatedAt: new Date(), | ||
| pullRequestUrls: [], | ||
| metadata: { | ||
| repository: 'test-owner/test-repo' | ||
| } | ||
| } | ||
| } as ProjectBoardItem | ||
| }; | ||
|
|
||
| // Debug: reassignTask 단계별 확인 | ||
| const availableWorker = await workerPoolManager.getAvailableWorker(); | ||
| if (!availableWorker) { | ||
| throw new Error('No available worker found for reassignment test'); | ||
| } | ||
|
Comment on lines
+242
to
+245
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 테스트 코드에 "Debug:" 주석과 함께 |
||
|
|
||
| const workerInstance = await workerPoolManager.getWorkerInstance(availableWorker.id); | ||
| if (!workerInstance) { | ||
| throw new Error(`Worker instance not found for worker ID: ${availableWorker.id}`); | ||
| } | ||
|
|
||
| // 재할당 체크 테스트 | ||
| const taskAssignmentValidator = taskRequestHandler['taskAssignmentValidator']; | ||
| const reassignmentCheck = await taskAssignmentValidator.validateTaskReassignment(taskId); | ||
| if (!reassignmentCheck.allowed || !reassignmentCheck.hasWorkspace) { | ||
| throw new Error(`Reassignment validation failed: ${reassignmentCheck.reason}`); | ||
| } | ||
|
|
||
| // When: 작업 상태 확인 요청 | ||
| const response = await taskRequestHandler.handleTaskRequest(taskRequest); | ||
|
|
||
| // Debug: 실제 응답 확인 | ||
| if (response.status === ResponseStatus.ERROR) { | ||
| throw new Error(`Expected IN_PROGRESS but got ERROR. Message: ${response.message}`); | ||
| } | ||
|
|
||
| // Then: workspace가 있으므로 재할당 성공 | ||
| expect(response.status).toBe(ResponseStatus.IN_PROGRESS); | ||
| expect(response.message).toContain('reassigned'); | ||
|
|
@@ -201,18 +283,24 @@ describe('Task Reassignment Integration Tests', () => { | |
| // When: workspace 유효성 검증 | ||
| const isValid = await workspaceManager.isWorktreeValid(workspaceInfo); | ||
|
|
||
| // Then: .git 파일이 없어도 디렉토리가 있으면 유효한 것으로 판단 (재사용 가능) | ||
| expect(isValid).toBe(true); | ||
| // Then: .git 파일이 없으면 유효하지 않은 worktree로 판단 | ||
| expect(isValid).toBe(false); | ||
| }); | ||
|
|
||
| it('WorkerPoolManager의 canAssignIdleWorkerToTask가 올바르게 작동한다', async () => { | ||
| // Given: workspace가 있는 작업 | ||
| // Given: 유효한 workspace가 있는 작업 | ||
| const taskId = 'test-task-4'; | ||
| const workspaceInfo = await workspaceManager.createWorkspace( | ||
| taskId, | ||
| 'test-owner/test-repo' | ||
| ); | ||
| await fs.mkdir(workspaceInfo.workspaceDir, { recursive: true }); | ||
|
|
||
| // .git 파일 생성 (유효한 worktree로 만들기) | ||
| await fs.writeFile( | ||
| path.join(workspaceInfo.workspaceDir, '.git'), | ||
| 'gitdir: /path/to/repo/.git/worktrees/test' | ||
| ); | ||
|
|
||
| // Given: idle 상태 Worker | ||
| const worker = await workerPoolManager.getAvailableWorker(); | ||
|
|
@@ -225,29 +313,35 @@ describe('Task Reassignment Integration Tests', () => { | |
| { id: taskId, title: '테스트 작업 4' } | ||
| ); | ||
|
|
||
| // Then: workspace가 있으므로 할당 가능 | ||
| // Then: 유효한 workspace가 있으므로 할당 가능 | ||
| expect(canAssign).toBe(true); | ||
| }); | ||
|
|
||
| it('TaskAssignmentValidator의 우선순위 시스템이 올바르게 작동한다', async () => { | ||
| // Given: workspace가 있는 작업과 없는 작업 | ||
| // Given: 유효한 workspace가 있는 작업과 없는 작업 | ||
| const taskWithWorkspace = 'task-with-workspace'; | ||
| const taskWithoutWorkspace = 'task-without-workspace'; | ||
|
|
||
| // workspace 생성 | ||
| // 유효한 workspace 생성 | ||
| const workspaceInfo = await workspaceManager.createWorkspace( | ||
| taskWithWorkspace, | ||
| 'test-owner/test-repo' | ||
| ); | ||
| await fs.mkdir(workspaceInfo.workspaceDir, { recursive: true }); | ||
|
|
||
| // .git 파일 생성 (유효한 worktree로 만들기) | ||
| await fs.writeFile( | ||
| path.join(workspaceInfo.workspaceDir, '.git'), | ||
| 'gitdir: /path/to/repo/.git/worktrees/test' | ||
| ); | ||
|
|
||
| // When: 우선순위 확인 | ||
| const priorityWithWorkspace = await workerPoolManager['taskAssignmentValidator'] | ||
| .getTaskReassignmentPriority(taskWithWorkspace); | ||
| const priorityWithoutWorkspace = await workerPoolManager['taskAssignmentValidator'] | ||
| .getTaskReassignmentPriority(taskWithoutWorkspace); | ||
|
|
||
| // Then: workspace가 있는 작업이 더 높은 우선순위를 가짐 | ||
| // Then: 유효한 workspace가 있는 작업이 더 높은 우선순위를 가짐 | ||
| expect(priorityWithWorkspace).toBe(10); // 높은 우선순위 | ||
| expect(priorityWithoutWorkspace).toBe(5); // 중간 우선순위 | ||
| }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getWorkspaceManager의 모의(mock) 구현이WorkspaceManagerInterface와 일치하지 않습니다. 현재 모의 구현된getWorkerWorkspace,checkWorkspaceExists등은 인터페이스에 존재하지 않는 메서드입니다. 이로 인해 테스트가 의도와 다르게 동작하거나 혼란을 줄 수 있습니다.WorkspaceManagerInterface에 정의된 메서드들(예:createWorkspace,isWorktreeValid등)을 모의 구현하도록 수정하는 것이 좋습니다.