diff options
| author | Abhi <[email protected]> | 2025-08-17 00:02:54 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-17 04:02:54 +0000 |
| commit | 33b9bdb11e9371dfa6891ba1be47a12b958f493d (patch) | |
| tree | 46ac192df7dd2aeaf35cb5eef5c121bc5decada9 /integration-tests | |
| parent | e7dbc607a598c5270507d0ce7d55a3c98dcb0c0c (diff) | |
feat(cli): Introduce arguments for shell execution in custom commands (#5966)
Diffstat (limited to 'integration-tests')
| -rw-r--r-- | integration-tests/shell-service.test.ts | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/integration-tests/shell-service.test.ts b/integration-tests/shell-service.test.ts new file mode 100644 index 00000000..58cf65e5 --- /dev/null +++ b/integration-tests/shell-service.test.ts @@ -0,0 +1,122 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect, beforeAll } from 'vitest'; +import { ShellExecutionService } from '../packages/core/src/services/shellExecutionService.js'; +import * as fs from 'fs/promises'; +import * as path from 'path'; +import { vi } from 'vitest'; + +describe('ShellExecutionService programmatic integration tests', () => { + let testDir: string; + + beforeAll(async () => { + // Create a dedicated directory for this test suite to avoid conflicts. + testDir = path.join( + process.env.INTEGRATION_TEST_FILE_DIR!, + 'shell-service-tests', + ); + await fs.mkdir(testDir, { recursive: true }); + }); + + it('should execute a simple cross-platform command (echo)', async () => { + const command = 'echo "hello from the service"'; + const onOutputEvent = vi.fn(); + const abortController = new AbortController(); + + const handle = ShellExecutionService.execute( + command, + testDir, + onOutputEvent, + abortController.signal, + ); + + const result = await handle.result; + + expect(result.error).toBeNull(); + expect(result.exitCode).toBe(0); + // Output can vary slightly between shells (e.g., quotes), so check for inclusion. + expect(result.output).toContain('hello from the service'); + }); + + it.runIf(process.platform === 'win32')( + 'should execute "dir" on Windows', + async () => { + const testFile = 'test-file-windows.txt'; + await fs.writeFile(path.join(testDir, testFile), 'windows test'); + + const command = 'dir'; + const onOutputEvent = vi.fn(); + const abortController = new AbortController(); + + const handle = ShellExecutionService.execute( + command, + testDir, + onOutputEvent, + abortController.signal, + ); + + const result = await handle.result; + + expect(result.error).toBeNull(); + expect(result.exitCode).toBe(0); + expect(result.output).toContain(testFile); + }, + ); + + it.skipIf(process.platform === 'win32')( + 'should execute "ls -l" on Unix', + async () => { + const testFile = 'test-file-unix.txt'; + await fs.writeFile(path.join(testDir, testFile), 'unix test'); + + const command = 'ls -l'; + const onOutputEvent = vi.fn(); + const abortController = new AbortController(); + + const handle = ShellExecutionService.execute( + command, + testDir, + onOutputEvent, + abortController.signal, + ); + + const result = await handle.result; + + expect(result.error).toBeNull(); + expect(result.exitCode).toBe(0); + expect(result.output).toContain(testFile); + }, + ); + + it('should abort a running process', async () => { + // A command that runs for a bit. 'sleep' on unix, 'timeout' on windows. + const command = process.platform === 'win32' ? 'timeout /t 20' : 'sleep 20'; + const onOutputEvent = vi.fn(); + const abortController = new AbortController(); + + const handle = ShellExecutionService.execute( + command, + testDir, + onOutputEvent, + abortController.signal, + ); + + // Abort shortly after starting + setTimeout(() => abortController.abort(), 50); + + const result = await handle.result; + + // For debugging the flaky test. + console.log('Abort test result:', result); + + expect(result.aborted).toBe(true); + // A clean exit is exitCode 0 and no signal. If the process was truly + // aborted, it should not have exited cleanly. + const exitedCleanly = result.exitCode === 0 && result.signal === null; + expect(exitedCleanly, 'Process should not have exited cleanly').toBe(false); + }); +}); |
