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,27 +1,102 @@
import type { RuntimeContext } from '@mastra/core/runtime-context'; import { RuntimeContext } from '@mastra/core/runtime-context';
import { beforeEach, describe, expect, it, vi } from 'vitest'; 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', () => ({ vi.mock('./bash-execute-functions', () => ({
generateBashExecuteCode: vi.fn(),
executeBashCommandsSafely: vi.fn(), executeBashCommandsSafely: vi.fn(),
})); }));
import { executeBashCommandsSafely } from './bash-execute-functions'; import { runTypescript } from '@buster/sandbox';
import { bashExecute } from './bash-execute-tool'; import { executeBashCommandsSafely, generateBashExecuteCode } from './bash-execute-functions';
const mockRunTypescript = vi.mocked(runTypescript);
const mockGenerateBashExecuteCode = vi.mocked(generateBashExecuteCode);
const mockExecuteBashCommandsSafely = vi.mocked(executeBashCommandsSafely); const mockExecuteBashCommandsSafely = vi.mocked(executeBashCommandsSafely);
describe('bash-execute-tool', () => { describe('bash-execute-tool', () => {
let mockRuntimeContext: RuntimeContext; let runtimeContext: RuntimeContext<SandboxContext>;
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
runtimeContext = new RuntimeContext<SandboxContext>();
mockRuntimeContext = {
get: vi.fn(),
} as any;
}); });
it('should execute commands locally', async () => { afterEach(() => {
vi.restoreAllMocks();
});
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,
});
});
it('should fallback to local execution when sandbox not available', async () => {
const input = { const input = {
commands: [{ command: 'echo "hello"' }], commands: [{ command: 'echo "hello"' }],
}; };
@ -41,13 +116,47 @@ describe('bash-execute-tool', () => {
const result = await bashExecute.execute({ const result = await bashExecute.execute({
context: input, context: input,
runtimeContext: mockRuntimeContext, runtimeContext,
}); });
expect(mockExecuteBashCommandsSafely).toHaveBeenCalledWith(input.commands); expect(mockExecuteBashCommandsSafely).toHaveBeenCalledWith(input.commands);
expect(result.results).toEqual(mockLocalResults); expect(result.results).toEqual(mockLocalResults);
}); });
it('should handle sandbox execution errors', 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: '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',
});
});
it('should handle execution errors', async () => { it('should handle execution errors', async () => {
const input = { const input = {
commands: [{ command: 'echo "hello"' }], commands: [{ command: 'echo "hello"' }],
@ -57,7 +166,7 @@ describe('bash-execute-tool', () => {
const result = await bashExecute.execute({ const result = await bashExecute.execute({
context: input, context: input,
runtimeContext: mockRuntimeContext, runtimeContext,
}); });
expect(result.results).toHaveLength(1); expect(result.results).toHaveLength(1);
@ -70,9 +179,44 @@ describe('bash-execute-tool', () => {
const result = await bashExecute.execute({ const result = await bashExecute.execute({
context: input, context: input,
runtimeContext: mockRuntimeContext, runtimeContext,
}); });
expect(result.results).toHaveLength(0); 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'),
});
});
});
}); });