godcrm/backend/routes/v3/__tests__/code.test.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

517 lines
15 KiB
JavaScript

/**
* Code Execution API Tests
* ADR-032: Code Execution Engine — Piston Integration
*
* BEHAVIOR: AI Agent can execute code in multiple languages via Piston
*
* Acceptance Criteria:
* - POST /api/v3/code/execute - executes code and returns result
* - GET /api/v3/code/languages - returns list of supported languages
* - POST /api/v3/code/validate - validates code syntax
* - POST /api/v3/code/execute-loop - executes with Agent callback
*/
import { describe, it, expect, beforeAll, vi, beforeEach } from 'vitest';
import express from 'express';
import request from 'supertest';
// Mock axios before importing the router
vi.mock('axios');
let codeRouter;
let app;
beforeAll(async () => {
// Set up test environment
process.env.PISTON_URL = 'http://localhost:2000';
process.env.BACKEND_URL = 'http://localhost:5001';
// Import the router
const module = await import('../code.js');
codeRouter = module.default;
// Create Express app for testing
app = express();
app.use(express.json());
app.use('/api/v3/code', codeRouter);
});
beforeEach(() => {
vi.clearAllMocks();
});
describe('Code Execution API - ADR-032 (Piston)', () => {
// ============================================
// GET /api/v3/code/languages
// ============================================
describe('GET /api/v3/code/languages', () => {
it('Given Piston is available, When requested, Then returns list of runtimes', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.get = vi.fn().mockResolvedValue({
data: [
{ language: 'python', version: '3.10.0', aliases: ['py', 'py3'] },
{ language: 'javascript', version: '20.11.1', aliases: ['js', 'node'] },
{ language: 'typescript', version: '5.0.3', aliases: ['ts'] }
]
});
// Act
const response = await request(app)
.get('/api/v3/code/languages');
// Assert
expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
expect(response.body.length).toBe(3);
expect(response.body[0]).toHaveProperty('language');
expect(response.body[0]).toHaveProperty('version');
});
it('Given Piston is unavailable, When requested, Then returns fallback aliases', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.get = vi.fn().mockRejectedValue(new Error('ECONNREFUSED'));
// Act
const response = await request(app)
.get('/api/v3/code/languages');
// Assert
expect(response.status).toBe(200);
expect(Array.isArray(response.body)).toBe(true);
expect(response.body.some(lang => lang.language === 'python')).toBe(true);
});
});
// ============================================
// POST /api/v3/code/execute
// ============================================
describe('POST /api/v3/code/execute', () => {
it('Given valid Python code, When executed, Then returns successful result', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: 'Hello, World!\n',
stderr: '',
code: 0,
signal: null,
cpu_time: 15,
wall_time: 42,
memory: 3500000
},
language: 'python',
version: '3.10.0'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'print("Hello, World!")',
language: 'python'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.stdout).toBe('Hello, World!\n');
expect(response.body.stderr).toBe('');
expect(response.body.code).toBe(0);
expect(response.body.time).toEqual({ cpu_ms: 15, wall_ms: 42 });
expect(response.body.memory_bytes).toBe(3500000);
expect(response.body.language).toBe('python');
});
it('Given code with syntax error, When executed, Then returns error with stderr', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: '',
stderr: 'SyntaxError: invalid syntax\n',
code: 1,
signal: null,
cpu_time: 10,
wall_time: 20,
memory: 2000000
},
language: 'python',
version: '3.10.0'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'print("Hello',
language: 'python'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.success).toBe(false);
expect(response.body.code).toBe(1);
expect(response.body.stderr).toContain('SyntaxError');
});
it('Given runtime error, When executed, Then returns error details', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: '',
stderr: 'ZeroDivisionError: division by zero\n',
code: 1,
signal: null,
cpu_time: 12,
wall_time: 25,
memory: 3000000
},
language: 'python',
version: '3.10.0'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'print(1/0)',
language: 'python'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.success).toBe(false);
expect(response.body.stderr).toContain('ZeroDivisionError');
});
it('Given JavaScript code with "js" alias, When executed, Then uses javascript runtime', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: '42\n',
stderr: '',
code: 0,
cpu_time: 30,
wall_time: 50,
memory: 7000000
},
language: 'javascript',
version: '20.11.1'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'console.log(42)',
language: 'js'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.stdout).toBe('42\n');
// Verify Piston was called with correct language
expect(axios.post).toHaveBeenCalledWith(
expect.stringContaining('/api/v2/execute'),
expect.objectContaining({
language: 'javascript',
version: '20.11.1'
})
);
});
it('Given no source_code, When executed, Then returns 400 bad request', async () => {
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
language: 'python'
});
// Assert
expect(response.status).toBe(400);
});
it('Given Piston unavailable, When executed, Then returns 500 error', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockRejectedValue(new Error('ECONNREFUSED'));
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'print(1)',
language: 'python'
});
// Assert
expect(response.status).toBe(500);
expect(response.body.error.message).toContain('ECONNREFUSED');
});
it('Given code with stdin, When executed, Then passes stdin to Piston', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: 'Hello\n',
stderr: '',
code: 0,
cpu_time: 10,
wall_time: 20,
memory: 3000000
},
language: 'python',
version: '3.10.0'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute')
.send({
source_code: 'print(input())',
language: 'python',
stdin: 'Hello'
});
// Assert
expect(response.status).toBe(200);
expect(axios.post).toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({
stdin: 'Hello'
})
);
});
});
// ============================================
// POST /api/v3/code/validate
// ============================================
describe('POST /api/v3/code/validate', () => {
it('Given valid Python syntax, When validated, Then returns valid: true', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: 'valid\n',
stderr: '',
code: 0
}
}
});
// Act
const response = await request(app)
.post('/api/v3/code/validate')
.send({
source_code: 'def hello(): pass',
language: 'python'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.valid).toBe(true);
expect(response.body.errors).toEqual([]);
});
it('Given invalid Python syntax, When validated, Then returns valid: false', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: 'SyntaxError: unexpected EOF at line 1\n',
stderr: '',
code: 0 // ast.parse catches error, prints it, exits 0
}
}
});
// Act
const response = await request(app)
.post('/api/v3/code/validate')
.send({
source_code: 'def hello(',
language: 'python'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.valid).toBe(false);
expect(response.body.errors.length).toBeGreaterThan(0);
expect(response.body.errors[0].message).toContain('SyntaxError');
});
it('Given non-Python language, When validated, Then returns valid: true (not implemented)', async () => {
// Act
const response = await request(app)
.post('/api/v3/code/validate')
.send({
source_code: 'console.log("hi")',
language: 'javascript'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.valid).toBe(true);
expect(response.body.message).toContain('not implemented');
});
it('Given no source_code, When validated, Then returns 400', async () => {
// Act
const response = await request(app)
.post('/api/v3/code/validate')
.send({
language: 'python'
});
// Assert
expect(response.status).toBe(400);
});
});
// ============================================
// POST /api/v3/code/execute-loop
// ============================================
describe('POST /api/v3/code/execute-loop', () => {
it('Given code execution succeeds, When executed with callback, Then returns success', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn()
// First call: Piston execute
.mockResolvedValueOnce({
data: {
run: {
stdout: '4\n',
stderr: '',
code: 0,
cpu_time: 15,
wall_time: 30,
memory: 3000000
},
language: 'python',
version: '3.10.0'
}
})
// Second call: Agent callback (might fail, that's ok)
.mockRejectedValueOnce(new Error('Agent not running'));
// Act
const response = await request(app)
.post('/api/v3/code/execute-loop')
.send({
source_code: 'print(2+2)',
language: 'python',
conversation_id: 'conv-123',
agent_id: 'agent-456',
next_prompt: 'Continue processing'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.status).toBe('completed');
expect(response.body.success).toBe(true);
expect(response.body.stdout).toBe('4\n');
});
it('Given no callback configured, When executed, Then still returns result', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn().mockResolvedValue({
data: {
run: {
stdout: '100\n',
stderr: '',
code: 0,
cpu_time: 10,
wall_time: 20,
memory: 3000000
},
language: 'python',
version: '3.10.0'
}
});
// Act
const response = await request(app)
.post('/api/v3/code/execute-loop')
.send({
source_code: 'print(10*10)',
language: 'python'
// No conversation_id, agent_id
});
// Assert
expect(response.status).toBe(200);
expect(response.body.success).toBe(true);
expect(response.body.message).toContain('No callback');
// Only one axios call (no callback attempt)
expect(axios.post).toHaveBeenCalledTimes(1);
});
it('Given code execution fails, When executed with callback, Then returns error info', async () => {
// Arrange
const axios = (await import('axios')).default;
axios.post = vi.fn()
.mockResolvedValueOnce({
data: {
run: {
stdout: '',
stderr: 'NameError: name "x" is not defined\n',
code: 1,
cpu_time: 8,
wall_time: 15,
memory: 2500000
},
language: 'python',
version: '3.10.0'
}
})
.mockRejectedValueOnce(new Error('Agent not running'));
// Act
const response = await request(app)
.post('/api/v3/code/execute-loop')
.send({
source_code: 'print(x)',
language: 'python',
conversation_id: 'conv-123',
agent_id: 'agent-456'
});
// Assert
expect(response.status).toBe(200);
expect(response.body.status).toBe('completed');
expect(response.body.success).toBe(false);
expect(response.body.stderr).toContain('NameError');
});
});
});