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:
Devin AI 2025-07-22 14:10:38 +00:00
parent 535af8d902
commit e27a5ce0c5
1 changed files with 188 additions and 44 deletions

View File

@ -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'),
});
});
});
});