UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

242 lines (210 loc) 9.05 kB
/** * Copyright Super iPaaS Integration LLC, an IBM Company 2024 */ import { prepareGatewayJson, prepareArchiveBuffer, executeDeployment } from './projects-deployer.js'; import { processDeployment } from '@apic/studio-deploy'; import { showError, showInfo, showSuccess } from '../../helpers/common/message-helper.js'; import { readFileAsBuffer } from '../../helpers/common/fs-helper.js'; import { APIENDPOINTS, DEPLOY_STARTED, DEPLOYMENT_FAILURE, LINE, } from '../../constants/message-constants.js'; let mockExit: jest.SpyInstance; jest.mock('@apic/studio-deploy', () => ({ processDeployment: jest.fn() as jest.MockedFunction<typeof processDeployment>, })); jest.mock('../../helpers/common/message-helper.js', () => ({ showError: jest.fn(), showInfo: jest.fn(), showSuccess: jest.fn() })); jest.mock('@apic/studio-build', () => ({ processProjectBuild: jest.fn(), })); beforeEach(() => { // @ts-ignore mockExit = jest.spyOn(process, 'exit').mockImplementation(() => { }); }); jest.mock('env-paths', () => { return jest.fn((name: string) => ({ data: `/mock/path/${name}-data`, config: `/mock/path/${name}-config`, cache: `/mock/path/${name}-cache`, log: `/mock/path/${name}-log`, temp: `/mock/path/${name}-temp`, })); }); jest.mock('../../helpers/common/fs-helper.js', () => ({ readFileAsBuffer: jest.fn() as jest.MockedFunction<typeof readFileAsBuffer>, })); jest.mock('cli-table3', () => { return jest.fn().mockImplementation(() => ({ push: jest.fn(), toString: jest.fn().mockReturnValue( '┌──────────┬─────────────────────┐\n' + '│ APIs │ Gateway Endpoints │\n' + '├──────────┼─────────────────────┤\n' + '│ Test API │ http://example.com │\n' + '│ │ http://example2.com │\n' + '└──────────┴─────────────────────┘' ) })); }); describe('Projects deployer, Test suite', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('prepareGatewayJson', () => { it('should return correct GatewaysJson', () => { const result = prepareGatewayJson('http://example.com', 'user', '', true,false); expect(result).toEqual({ gateways: [{ gatewayURL: 'http://example.com', gatewayUser: 'user', gatewaySecret: '', is_mcsp_enabled: false }], overwrite: 'all', skip: 'none', }); }); it('should handle skip and overwrite correctly when false', () => { const result = prepareGatewayJson('http://example.com', 'user', '', false,false); expect(result).toEqual({ gateways: [{ gatewayURL: 'http://example.com', gatewayUser: 'user', gatewaySecret: '', is_mcsp_enabled: false }], overwrite: 'none', skip: 'all', }); }); it('should handle non-URL strings for target', () => { const result = prepareGatewayJson('not-a-url', 'user', 'xyz', true,false); expect(result).toEqual({ gateways: [ { gatewayURL: 'not-a-url', gatewayUser: 'user', gatewaySecret: 'xyz', is_mcsp_enabled: false }, ], overwrite: 'all', skip: 'none', }); }); it('should handle special characters in username and password', () => { const result = prepareGatewayJson('http://example.com', 'user!@#$', 'xyz', true,false); expect(result).toEqual({ gateways: [ { gatewayURL: 'http://example.com', gatewayUser: 'user!@#$', gatewaySecret: 'xyz', is_mcsp_enabled: false }, ], overwrite: 'all', skip: 'none', }); }); }); describe('prepareArchiveBuffer', () => { it('should call readFileAsBuffer with the correct path', () => { const mockBuffer = Buffer.from('test'); (readFileAsBuffer as jest.Mock).mockReturnValue(mockBuffer); const result = prepareArchiveBuffer('path/to/archive.zip'); expect(readFileAsBuffer).toHaveBeenCalledWith('path/to/archive.zip'); expect(result).toBe(mockBuffer); }); it('should handle large file buffer', () => { const largeBuffer = Buffer.alloc(1024 * 1024 * 100); // 100MB (readFileAsBuffer as jest.Mock).mockReturnValue(largeBuffer); const result = prepareArchiveBuffer('/path/to/large-file'); expect(result.byteLength).toBe(1024 * 1024 * 100); }); it('should handle files with special characters in path', () => { const mockBuffer = Buffer.from('special content'); (readFileAsBuffer as jest.Mock).mockReturnValue(mockBuffer); const result = prepareArchiveBuffer('/path/to/file-with-特殊字符'); expect(result).toBe(mockBuffer); }); it('should handle non-existent file gracefully', () => { (readFileAsBuffer as jest.Mock).mockImplementation(() => { throw new Error('File not found'); }); expect(() => prepareArchiveBuffer('/path/to/non-existent-file')).toThrow('File not found'); }); }); describe('executeDeployment', () => { const mockConsoleLog = jest.spyOn(console, 'log').mockImplementation(() => {}); beforeEach(() => { jest.clearAllMocks(); }); it('should handle successful deployments without errors', async () => { const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' }; const fileBuffer = Buffer.from('mock data'); const mockResponses = [ { error: false, data: { StudioResult: [{ API: { name: 'Test API', gatewayEndpoints: ['http://example.com', 'http://example2.com'] } }] } } ]; (processDeployment as jest.Mock).mockResolvedValue(mockResponses); await executeDeployment(gatewayJson, fileBuffer); expect(showInfo).toHaveBeenCalledWith(LINE); expect(showInfo).toHaveBeenCalledWith(DEPLOY_STARTED); expect(showSuccess).toHaveBeenCalledWith(APIENDPOINTS); expect(mockConsoleLog).toHaveBeenCalledWith( '┌──────────┬─────────────────────┐\n' + '│ APIs │ Gateway Endpoints │\n' + '├──────────┼─────────────────────┤\n' + '│ Test API │ http://example.com │\n' + '│ │ http://example2.com │\n' + '└──────────┴─────────────────────┘' ); }); it('should handle deployment errors and log them correctly', async () => { const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' }; const fileBuffer = Buffer.from('mock data'); const mockResponses = [{ error: true, message: 'Deployment failed' }]; (processDeployment as jest.Mock).mockResolvedValue(mockResponses); await executeDeployment(gatewayJson, fileBuffer); expect(showError).toHaveBeenCalledWith(DEPLOYMENT_FAILURE); expect(showError).toHaveBeenCalledWith('Deployment failed'); }); it('should handle responses with successful deployments and log API endpoints', async () => { const gatewayJson = { gateways: [], overwrite: 'ALL', skip: 'NONE' }; const fileBuffer = Buffer.from('mock data'); const mockResponses = [ { error: false, data: { StudioResult: [{ API: { name: 'Test API', gatewayEndpoints: ['http://example.com', 'http://example2.com'], kind: 'API', namespace: 'test', version: '1.0', assetName: 'testAPI' } }] } } ]; (processDeployment as jest.Mock).mockResolvedValue(mockResponses); await executeDeployment(gatewayJson, fileBuffer); expect(showInfo).toHaveBeenCalledWith(LINE); expect(showInfo).toHaveBeenCalledWith(DEPLOY_STARTED); expect(showSuccess).toHaveBeenCalledWith(APIENDPOINTS); expect(mockConsoleLog).toHaveBeenCalledWith( '┌──────────┬─────────────────────┐\n' + '│ APIs │ Gateway Endpoints │\n' + '├──────────┼─────────────────────┤\n' + '│ Test API │ http://example.com │\n' + '│ │ http://example2.com │\n' + '└──────────┴─────────────────────┘' ); }); it('should handle partial success in deployment', async () => { const mockGatewayJson = { gateways: [], overwrite: '', skip: '' }; const mockBuffer = Buffer.from('test buffer'); const partialSuccessResponse = [{ data: { StudioResult: [{ API: { status: 'Success', name: 'API1', namespace: 'ns', version: 'v1', assetName: 'asset1', gatewayEndpoints: ['endpoint1'] } }, { API: { status: 'Failure', name: 'API2', namespace: 'ns2', version: 'v2', assetName: 'asset2', gatewayEndpoints: ['endpoint2'] } }] } }]; (processDeployment as jest.Mock).mockResolvedValue(partialSuccessResponse); await executeDeployment(mockGatewayJson, mockBuffer); expect(showSuccess).toHaveBeenCalledWith('\nGateway endpoints of the APIs in the project'); }); }); });