mirror of https://github.com/buster-so/buster.git
fix: update bash-execute-tool tests to match working file tool patterns
- Use proper RuntimeContext<SandboxContext> type - Add comprehensive mocking for @buster/sandbox and functions - Test both sandbox and local execution paths - Handle JSON parse errors and execution failures - Follow patterns from create-files-tool tests Co-Authored-By: Dallin Bentley <dallinbentley98@gmail.com>
This commit is contained in:
parent
535af8d902
commit
e27a5ce0c5
|
@ -1,78 +1,222 @@
|
|||
import type { RuntimeContext } from '@mastra/core/runtime-context';
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { RuntimeContext } from '@mastra/core/runtime-context';
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
import { z } from 'zod';
|
||||
import { type SandboxContext, SandboxContextKey } from '../../../context/sandbox-context';
|
||||
import { bashExecute } from './bash-execute-tool';
|
||||
|
||||
vi.mock('@buster/sandbox', () => ({
|
||||
runTypescript: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./bash-execute-functions', () => ({
|
||||
generateBashExecuteCode: vi.fn(),
|
||||
executeBashCommandsSafely: vi.fn(),
|
||||
}));
|
||||
|
||||
import { executeBashCommandsSafely } from './bash-execute-functions';
|
||||
import { bashExecute } from './bash-execute-tool';
|
||||
import { runTypescript } from '@buster/sandbox';
|
||||
import { executeBashCommandsSafely, generateBashExecuteCode } from './bash-execute-functions';
|
||||
|
||||
const mockRunTypescript = vi.mocked(runTypescript);
|
||||
const mockGenerateBashExecuteCode = vi.mocked(generateBashExecuteCode);
|
||||
const mockExecuteBashCommandsSafely = vi.mocked(executeBashCommandsSafely);
|
||||
|
||||
describe('bash-execute-tool', () => {
|
||||
let mockRuntimeContext: RuntimeContext;
|
||||
let runtimeContext: RuntimeContext<SandboxContext>;
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
|
||||
mockRuntimeContext = {
|
||||
get: vi.fn(),
|
||||
} as any;
|
||||
runtimeContext = new RuntimeContext<SandboxContext>();
|
||||
});
|
||||
|
||||
it('should execute commands locally', async () => {
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
const mockLocalResults = [
|
||||
{
|
||||
describe('bashExecute tool', () => {
|
||||
it('should have correct tool configuration', () => {
|
||||
expect(bashExecute.id).toBe('bash_execute');
|
||||
expect(bashExecute.description).toContain('Executes bash commands');
|
||||
expect(bashExecute.inputSchema).toBeDefined();
|
||||
expect(bashExecute.outputSchema).toBeDefined();
|
||||
});
|
||||
|
||||
it('should validate input schema correctly', () => {
|
||||
const validInput = {
|
||||
commands: [
|
||||
{ command: 'echo "hello"', description: 'test command' },
|
||||
{ command: 'ls -la', timeout: 5000 },
|
||||
],
|
||||
};
|
||||
|
||||
expect(() => bashExecute.inputSchema.parse(validInput)).not.toThrow();
|
||||
});
|
||||
|
||||
it('should execute with sandbox when available', async () => {
|
||||
const mockSandbox = { process: { codeRun: vi.fn() } };
|
||||
runtimeContext.set(SandboxContextKey.Sandbox, mockSandbox as any);
|
||||
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
|
||||
const mockCode = 'generated typescript code';
|
||||
const mockSandboxResult = {
|
||||
result: JSON.stringify([
|
||||
{
|
||||
command: 'echo "hello"',
|
||||
stdout: 'hello',
|
||||
stderr: undefined,
|
||||
exitCode: 0,
|
||||
success: true,
|
||||
error: undefined,
|
||||
},
|
||||
]),
|
||||
exitCode: 0,
|
||||
stderr: '',
|
||||
};
|
||||
|
||||
mockGenerateBashExecuteCode.mockReturnValue(mockCode);
|
||||
mockRunTypescript.mockResolvedValue(mockSandboxResult);
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(mockGenerateBashExecuteCode).toHaveBeenCalledWith(input.commands);
|
||||
expect(mockRunTypescript).toHaveBeenCalledWith(mockSandbox, mockCode);
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
command: 'echo "hello"',
|
||||
stdout: 'hello',
|
||||
stderr: undefined,
|
||||
exitCode: 0,
|
||||
success: true,
|
||||
error: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteBashCommandsSafely.mockResolvedValue(mockLocalResults);
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext: mockRuntimeContext,
|
||||
});
|
||||
});
|
||||
|
||||
expect(mockExecuteBashCommandsSafely).toHaveBeenCalledWith(input.commands);
|
||||
expect(result.results).toEqual(mockLocalResults);
|
||||
});
|
||||
it('should fallback to local execution when sandbox not available', async () => {
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
|
||||
it('should handle execution errors', async () => {
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
const mockLocalResults = [
|
||||
{
|
||||
command: 'echo "hello"',
|
||||
stdout: 'hello',
|
||||
stderr: undefined,
|
||||
exitCode: 0,
|
||||
success: true,
|
||||
error: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
mockExecuteBashCommandsSafely.mockRejectedValue(new Error('Execution failed'));
|
||||
mockExecuteBashCommandsSafely.mockResolvedValue(mockLocalResults);
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext: mockRuntimeContext,
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(mockExecuteBashCommandsSafely).toHaveBeenCalledWith(input.commands);
|
||||
expect(result.results).toEqual(mockLocalResults);
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]?.success).toBe(false);
|
||||
expect(result.results[0]?.error).toContain('Execution error');
|
||||
});
|
||||
it('should handle sandbox execution errors', async () => {
|
||||
const mockSandbox = { process: { codeRun: vi.fn() } };
|
||||
runtimeContext.set(SandboxContextKey.Sandbox, mockSandbox as any);
|
||||
|
||||
it('should handle empty commands array', async () => {
|
||||
const input = { commands: [] };
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext: mockRuntimeContext,
|
||||
const mockCode = 'generated typescript code';
|
||||
const mockSandboxResult = {
|
||||
result: 'error output',
|
||||
exitCode: 1,
|
||||
stderr: 'Execution failed',
|
||||
};
|
||||
|
||||
mockGenerateBashExecuteCode.mockReturnValue(mockCode);
|
||||
mockRunTypescript.mockResolvedValue(mockSandboxResult);
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
command: 'echo "hello"',
|
||||
stdout: '',
|
||||
stderr: undefined,
|
||||
exitCode: 1,
|
||||
success: false,
|
||||
error: 'Execution error: Sandbox execution failed: Execution failed',
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(0);
|
||||
it('should handle execution errors', async () => {
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
|
||||
mockExecuteBashCommandsSafely.mockRejectedValue(new Error('Execution failed'));
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]?.success).toBe(false);
|
||||
expect(result.results[0]?.error).toContain('Execution error');
|
||||
});
|
||||
|
||||
it('should handle empty commands array', async () => {
|
||||
const input = { commands: [] };
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('should handle JSON parse errors from sandbox', async () => {
|
||||
const mockSandbox = { process: { codeRun: vi.fn() } };
|
||||
runtimeContext.set(SandboxContextKey.Sandbox, mockSandbox as any);
|
||||
|
||||
const input = {
|
||||
commands: [{ command: 'echo "hello"' }],
|
||||
};
|
||||
|
||||
const mockCode = 'generated typescript code';
|
||||
const mockSandboxResult = {
|
||||
result: 'invalid json output',
|
||||
exitCode: 0,
|
||||
stderr: '',
|
||||
};
|
||||
|
||||
mockGenerateBashExecuteCode.mockReturnValue(mockCode);
|
||||
mockRunTypescript.mockResolvedValue(mockSandboxResult);
|
||||
|
||||
const result = await bashExecute.execute({
|
||||
context: input,
|
||||
runtimeContext,
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(1);
|
||||
expect(result.results[0]).toEqual({
|
||||
command: 'echo "hello"',
|
||||
stdout: '',
|
||||
stderr: undefined,
|
||||
exitCode: 1,
|
||||
success: false,
|
||||
error: expect.stringContaining('Failed to parse sandbox output'),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue