From bfc374068ed6a5c011b5759c2695aa75a1528bba Mon Sep 17 00:00:00 2001 From: ElaineDeMattosSilvaB Date: Tue, 15 Oct 2024 21:33:12 +0200 Subject: [PATCH] feat: add tests Signed-off-by: ElaineDeMattosSilvaB --- .../src/actions/executeShellCommand.test.ts | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 plugins/scaffolder-node/src/actions/executeShellCommand.test.ts diff --git a/plugins/scaffolder-node/src/actions/executeShellCommand.test.ts b/plugins/scaffolder-node/src/actions/executeShellCommand.test.ts new file mode 100644 index 0000000000..91ee2c52fd --- /dev/null +++ b/plugins/scaffolder-node/src/actions/executeShellCommand.test.ts @@ -0,0 +1,147 @@ +/* + * Copyright 2024 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Copyright 2024 DB Systel GmbH +// Licensed under the DBISL, see the accompanying file LICENSE. + +import { spawn } from 'child_process'; +import { PassThrough, Writable } from 'stream'; +import { Logger } from 'winston'; +import { executeShellCommand } from './executeShellCommand'; + +jest.mock('child_process', () => ({ + spawn: jest.fn(), +})); + +describe('executeShellCommand', () => { + let mockSpawn: jest.Mock; + let mockProcess: any; + let mockLogger: jest.Mocked; + let mockLogStream: Writable; + + beforeEach(() => { + mockSpawn = spawn as jest.Mock; + mockProcess = { + stdout: new PassThrough(), + stderr: new PassThrough(), + on: jest.fn((event: string, callback: (code: number) => void) => { + if (event === 'close') { + callback(0); + } + }), + }; + mockSpawn.mockReturnValue(mockProcess); + + mockLogStream = new PassThrough(); + + mockLogger = { + log: jest.fn(), + } as unknown as jest.Mocked; + jest.clearAllMocks(); + }); + + afterEach(() => { + jest.resetAllMocks(); + }); + + it('should execute without logger or logStream', async () => { + await executeShellCommand({ + command: 'echo', + args: ['Hello World'], + }); + + expect(mockSpawn).toHaveBeenCalledWith('echo', ['Hello World'], undefined); + }); + + it('should execute with logger but no logStream', async () => { + const logStreamSpy = jest.spyOn(mockLogStream, 'write'); + await executeShellCommand({ + command: 'echo', + args: ['Hello World'], + logger: mockLogger, + }); + + // Simulate command output + mockProcess.stdout.emit('data', Buffer.from('Hello World\n')); + + mockProcess.on('close', (code: any) => { + expect(code).toBe(0); + expect(logStreamSpy).not.toHaveBeenCalled(); + expect(mockLogger.log).toHaveBeenCalledWith('info', 'Hello World'); + expect(mockLogger.log).not.toHaveBeenCalledWith( + 'error', + expect.anything(), + ); + }); + }); + + it('should execute with logStream but no logger', async () => { + const logStreamSpy = jest.spyOn(mockLogStream, 'write'); + + await executeShellCommand({ + command: 'echo', + args: ['Hello World'], + logStream: mockLogStream, + }); + + mockProcess.stdout.emit('data', Buffer.from('Hello World\n')); + mockProcess.stderr.emit('data', Buffer.from('Command not found\n')); + + mockProcess.on('close', () => { + expect(logStreamSpy).toHaveBeenCalledWith(expect.any(Buffer)); + expect(logStreamSpy).toHaveBeenCalledTimes(2); + expect(mockLogger.log).not.toHaveBeenCalled(); + }); + }); + + it('should execute with both logger and logStream', async () => { + const logStreamSpy = jest.spyOn(mockLogStream, 'write'); + + await executeShellCommand({ + command: 'echo', + args: ['Hello World'], + logger: mockLogger, + logStream: mockLogStream, + }); + + mockProcess.stdout.emit('data', Buffer.from('Hello World\n')); + mockProcess.stderr.emit('data', Buffer.from('Command not found\n')); + + mockProcess.on('close', () => { + expect(mockLogger.log).toHaveBeenCalledWith('info', 'Hello World'); + expect(mockLogger.log).toHaveBeenCalledWith('error', 'Command not found'); + expect(logStreamSpy).toHaveBeenCalledTimes(2); + }); + }); + + it('should handle non-zero exit code', async () => { + mockProcess.on.mockImplementation( + (event: string, callback: (arg0: number) => void) => { + if (event === 'close') { + callback(1); // Simulate command failing + } + }, + ); + + await expect( + executeShellCommand({ + command: 'echo', + args: ['Hello World'], + logger: mockLogger, + }), + ).rejects.toThrow('Command echo failed, exit code: 1'); + }); +});