chore: upgrade Node.js runtime to v24 across codebase #419
@@ -3,7 +3,6 @@ import { QueueService } from "../../queue/queue.service";
|
|||||||
import { AgentSpawnerService } from "../../spawner/agent-spawner.service";
|
import { AgentSpawnerService } from "../../spawner/agent-spawner.service";
|
||||||
import { AgentLifecycleService } from "../../spawner/agent-lifecycle.service";
|
import { AgentLifecycleService } from "../../spawner/agent-lifecycle.service";
|
||||||
import { KillswitchService } from "../../killswitch/killswitch.service";
|
import { KillswitchService } from "../../killswitch/killswitch.service";
|
||||||
import { BadRequestException } from "@nestjs/common";
|
|
||||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||||
|
|
||||||
describe("AgentsController", () => {
|
describe("AgentsController", () => {
|
||||||
@@ -289,80 +288,6 @@ describe("AgentsController", () => {
|
|||||||
expect(result.agentId).toBe(agentId);
|
expect(result.agentId).toBe(agentId);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should throw BadRequestException when taskId is missing", async () => {
|
|
||||||
// Arrange
|
|
||||||
const invalidRequest = {
|
|
||||||
agentType: "worker" as const,
|
|
||||||
context: validRequest.context,
|
|
||||||
} as unknown as typeof validRequest;
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await expect(controller.spawn(invalidRequest)).rejects.toThrow(BadRequestException);
|
|
||||||
expect(spawnerService.spawnAgent).not.toHaveBeenCalled();
|
|
||||||
expect(queueService.addTask).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw BadRequestException when agentType is invalid", async () => {
|
|
||||||
// Arrange
|
|
||||||
const invalidRequest = {
|
|
||||||
...validRequest,
|
|
||||||
agentType: "invalid" as unknown as "worker",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await expect(controller.spawn(invalidRequest)).rejects.toThrow(BadRequestException);
|
|
||||||
expect(spawnerService.spawnAgent).not.toHaveBeenCalled();
|
|
||||||
expect(queueService.addTask).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw BadRequestException when repository is missing", async () => {
|
|
||||||
// Arrange
|
|
||||||
const invalidRequest = {
|
|
||||||
...validRequest,
|
|
||||||
context: {
|
|
||||||
...validRequest.context,
|
|
||||||
repository: "",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await expect(controller.spawn(invalidRequest)).rejects.toThrow(BadRequestException);
|
|
||||||
expect(spawnerService.spawnAgent).not.toHaveBeenCalled();
|
|
||||||
expect(queueService.addTask).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw BadRequestException when branch is missing", async () => {
|
|
||||||
// Arrange
|
|
||||||
const invalidRequest = {
|
|
||||||
...validRequest,
|
|
||||||
context: {
|
|
||||||
...validRequest.context,
|
|
||||||
branch: "",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await expect(controller.spawn(invalidRequest)).rejects.toThrow(BadRequestException);
|
|
||||||
expect(spawnerService.spawnAgent).not.toHaveBeenCalled();
|
|
||||||
expect(queueService.addTask).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should throw BadRequestException when workItems is empty", async () => {
|
|
||||||
// Arrange
|
|
||||||
const invalidRequest = {
|
|
||||||
...validRequest,
|
|
||||||
context: {
|
|
||||||
...validRequest.context,
|
|
||||||
workItems: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act & Assert
|
|
||||||
await expect(controller.spawn(invalidRequest)).rejects.toThrow(BadRequestException);
|
|
||||||
expect(spawnerService.spawnAgent).not.toHaveBeenCalled();
|
|
||||||
expect(queueService.addTask).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should propagate errors from spawner service", async () => {
|
it("should propagate errors from spawner service", async () => {
|
||||||
// Arrange
|
// Arrange
|
||||||
const error = new Error("Spawner failed");
|
const error = new Error("Spawner failed");
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import {
|
|||||||
Get,
|
Get,
|
||||||
Body,
|
Body,
|
||||||
Param,
|
Param,
|
||||||
BadRequestException,
|
|
||||||
NotFoundException,
|
NotFoundException,
|
||||||
Logger,
|
Logger,
|
||||||
UsePipes,
|
UsePipes,
|
||||||
@@ -57,8 +56,9 @@ export class AgentsController {
|
|||||||
this.logger.log(`Received spawn request for task: ${dto.taskId}`);
|
this.logger.log(`Received spawn request for task: ${dto.taskId}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Validate request manually (in addition to ValidationPipe)
|
// Validation is handled by:
|
||||||
this.validateSpawnRequest(dto);
|
// 1. ValidationPipe + DTO decorators at the HTTP layer
|
||||||
|
// 2. AgentSpawnerService.validateSpawnRequest for business logic
|
||||||
|
|
||||||
// Spawn agent using spawner service
|
// Spawn agent using spawner service
|
||||||
const spawnResponse = this.spawnerService.spawnAgent({
|
const spawnResponse = this.spawnerService.spawnAgent({
|
||||||
@@ -243,32 +243,4 @@ export class AgentsController {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate spawn request
|
|
||||||
* @param dto Spawn request to validate
|
|
||||||
* @throws BadRequestException if validation fails
|
|
||||||
*/
|
|
||||||
private validateSpawnRequest(dto: SpawnAgentDto): void {
|
|
||||||
if (!dto.taskId || dto.taskId.trim() === "") {
|
|
||||||
throw new BadRequestException("taskId is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const validAgentTypes = ["worker", "reviewer", "tester"];
|
|
||||||
if (!validAgentTypes.includes(dto.agentType)) {
|
|
||||||
throw new BadRequestException(`agentType must be one of: ${validAgentTypes.join(", ")}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dto.context.repository || dto.context.repository.trim() === "") {
|
|
||||||
throw new BadRequestException("context.repository is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dto.context.branch || dto.context.branch.trim() === "") {
|
|
||||||
throw new BadRequestException("context.branch is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dto.context.workItems.length === 0) {
|
|
||||||
throw new BadRequestException("context.workItems must not be empty");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user