UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

240 lines (189 loc) 7.48 kB
/** * Copyright Super iPaaS Integration LLC, an IBM Company 2024 */ /* eslint-disable @typescript-eslint/no-explicit-any */ import AdmZip from 'adm-zip'; import { getRandomFileName, isDirectory, isDirOrFileExists, normalizePath } from '../common/fs-helper.js'; import { showInfo } from '../common/message-helper.js'; import { addDependencyAsset, isSameAsset, searchAsset, fromAssetRefValue, } from './build-helper.js'; import fs from 'fs'; import { Metadata } from '@apic/api-model/common/Metadata.js'; // Mock implementation jest.mock('adm-zip', () => { let entries: any[] = []; const mockAddFile = jest.fn((name: string, data: Buffer) => { entries = [...entries, { entryName: name, getData: () => data, isDirectory: false, }]; }); const mockGetEntries = jest.fn(() => entries); return jest.fn().mockImplementation(() => ({ addFile: mockAddFile, getEntries: mockGetEntries, })); }); jest.mock('../common/yaml-helper', () => ({ convertToYAMLString: jest.fn(), readMultiYaml: jest.fn(), readYaml: jest.fn(), })); jest.mock('../common/fs-helper', () => ({ getRandomFileName: jest.fn(), isDirectory: jest.fn(), isDirOrFileExists: jest.fn(), isYamlFile: jest.fn(), readFile: jest.fn(), normalizePath: jest.fn(), })); jest.mock('./asset-helper', () => ({ findFirstAPIAssetInZip: jest.fn(), getTargetModelAssetKind: jest.fn(), isValidAsset: jest.fn(), })); jest.mock('./asset-kinds/policy-helper', () => ({ getDeploymentMode: jest.fn(), })); jest.mock('../common/message-helper', () => ({ showInfo: jest.fn(), showWarning: jest.fn(), })); jest.mock('fs', () => ({ readdirSync: jest.fn(), existsSync: jest.fn(), Dirent: jest.fn().mockImplementation((name: string, isDirectory: boolean) => ({ name, isDirectory: () => isDirectory, })), readFileSync: jest.fn(), readfileSync: jest.fn() })); jest.mock('./api-build-helper.js', () => ({})) describe('Build helper function test suite', () => { afterEach(() => { jest.clearAllMocks(); }); describe('addDependencyAsset function', () => { let zip: AdmZip; beforeEach(() => { zip = new AdmZip(); zip.addLocalFile = jest.fn(); }); it('should add a dependency asset to the zip', () => { const mockDirent: fs.Dirent = { name: 'testName.yml', isDirectory: () => false, isFile: () => true, isBlockDevice: () => false, isCharacterDevice: () => false, isFIFO: () => false, isSocket: () => false, isSymbolicLink: () => false, [Symbol.toStringTag]: 'Dirent', parentPath: '/mock/path', } as unknown as fs.Dirent; const mockFileName = 'randomFileName.yml'; (getRandomFileName as jest.Mock).mockReturnValue(mockFileName); (normalizePath as jest.Mock).mockReturnValue(`/mock/path/${mockDirent.name}`); addDependencyAsset(mockDirent, zip); expect(getRandomFileName).toHaveBeenCalledWith('.yml'); expect(normalizePath).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`); expect(zip.addLocalFile).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`, 'dependencies', mockFileName); }); it('should not add a null asset to the zip', () => { addDependencyAsset(null as unknown as fs.Dirent, zip); expect(showInfo).not.toHaveBeenCalled(); expect(zip.addLocalFile).not.toHaveBeenCalled(); }); it('should not add an undefined asset to the zip', () => { addDependencyAsset(undefined as unknown as fs.Dirent, zip); expect(showInfo).not.toHaveBeenCalled(); expect(zip.addLocalFile).not.toHaveBeenCalled(); }); it('should add a dependency asset to the zip with a different file extension', () => { const mockDirent: fs.Dirent = { name: 'testName.json', isDirectory: () => false, isFile: () => true, isBlockDevice: () => false, isCharacterDevice: () => false, isFIFO: () => false, isSocket: () => false, isSymbolicLink: () => false, [Symbol.toStringTag]: 'Dirent', parentPath: '/mock/path', } as unknown as fs.Dirent; const mockFileName = 'randomFileName.json'; (getRandomFileName as jest.Mock).mockReturnValue(mockFileName); (normalizePath as jest.Mock).mockReturnValue(`/mock/path/${mockDirent.name}`); addDependencyAsset(mockDirent, zip, '.json'); expect(getRandomFileName).toHaveBeenCalledWith('.json'); expect(normalizePath).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`); expect(zip.addLocalFile).toHaveBeenCalledWith(`/mock/path/${mockDirent.name}`, 'dependencies', mockFileName); }); }); describe('isSameAsset function', () => { it('should return true for mixed version assets', () => { const metadata1 = { namespace: 'ns', name: 'asset', version: '1' }; const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' }; expect(isSameAsset(metadata1, metadata2)).toBe(true); }); it('should return true for identical assets', () => { const metadata1 = { namespace: 'ns', name: 'asset', version: '1.0' }; const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' }; expect(isSameAsset(metadata1, metadata2)).toBe(true); }); it('should return false for different namespace assets', () => { const metadata1 = { namespace: 'ns2', name: 'asset', version: '1.0.0' }; const metadata2 = { namespace: 'ns', name: 'asset', version: '1.0' }; expect(isSameAsset(metadata1, metadata2)).toBe(false); }); it('should return false for different assets', () => { const metadata1: Metadata = { namespace: 'ns', name: 'name', version: '1.0.0' }; const metadata2: Metadata = { namespace: 'ns', name: 'name2', version: '1.0.0' }; expect(isSameAsset(metadata1, metadata2)).toBe(false); }); }); describe('searchAsset function', () => { const projectDirPath = '/path/to/project'; it('should throw an error for invalid directory', () => { const projectDirPath = 'invalidPath'; (isDirOrFileExists as jest.Mock).mockReturnValue(false); expect(() => searchAsset('kind', 'ref', projectDirPath)).toThrow(`Invalid directory ${projectDirPath}`); }); it('should return undefined and show warning if no entries found', () => { (isDirOrFileExists as jest.Mock).mockReturnValue(true); (isDirectory as jest.Mock).mockReturnValue(true); (fs.readdirSync as jest.Mock).mockReturnValue([]); const result = searchAsset('kind', 'ref', projectDirPath); expect(result).toBeUndefined(); }); }); describe('fromAssetRefValue function', () => { it('should parse asset ref value with name only', () => { const refValue = 'name'; expect(fromAssetRefValue(refValue)).toEqual({ name: 'name' }); }); it('should parse asset ref value with name and version', () => { const refValue = 'name:1.0.0'; expect(fromAssetRefValue(refValue)).toEqual({ name: 'name', version: '1.0.0' }); }); it('should handle asset ref value with only colons', () => { const refValue = ':::'; const expectedMetadata: Metadata = { namespace: '', name: '', version: '' }; const result = fromAssetRefValue(refValue); expect(result).toEqual(expectedMetadata); }); it('should parse asset ref value with namespace, name, and version', () => { const refValue = 'ns:name:1.0.0'; expect(fromAssetRefValue(refValue)).toEqual({ namespace: 'ns', name: 'name', version: '1.0.0' }); }); it('should handle empty asset ref value', () => { const refValue = ''; const expectedMetadata: Metadata = { name: '' }; const result = fromAssetRefValue(refValue); expect(result).toEqual(expectedMetadata); }); }); });