@apistudio/apim-cli
Version:
CLI for API Management Products
294 lines (245 loc) • 11.3 kB
text/typescript
/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
/* eslint-disable @typescript-eslint/no-var-requires */
import AdmZip from 'adm-zip';
import path from 'path';
import { addValidAssetsToZip, checkAndAddValidYamlFile, checkAndAddValidJsonFile, checkAndAddOtherFile } from './zip-helper';
import { isDirOrFileExists, readDirectoryContents, isDirectory, isYamlFile, isJsonFile, readFile, getFileNameFromPath, isOtherFile } from '../../helpers/common/fs-helper';
import { DIRECTORY_DOESNT_EXIST, ASSERT_ADDED } from '../../constants/message-constants.js';
import { showInfo, showWarning } from './message-helper';
import { readMultiYaml, convertToYAMLString } from '../../helpers/common/yaml-helper.js';
import { readJson } from '../../helpers/common/json-helper.js';
import { DebugManager } from "../../debug/debug-manager.js";
import { isValidRestAPI } from './rest-api-validation-helper.js';
import { isValidAsset } from '../apim/asset-helper.js';
jest.mock('../../helpers/common/fs-helper', () => ({
isDirOrFileExists: jest.fn(),
readDirectoryContents: jest.fn(),
isDirectory: jest.fn(),
isYamlFile: jest.fn(),
isJsonFile: jest.fn(),
isOtherFile: jest.fn(),
readFile: jest.fn(),
getFileNameFromPath: jest.fn()
}));
jest.mock('../../helpers/common/message-helper', () => ({
showWarning: jest.fn(),
showError: jest.fn(),
showInfo: jest.fn()
}));
jest.mock('../../debug/debug-manager.js', () => ({
DebugManager: {
getInstance: () => ({
isDebugEnabled: jest.fn().mockReturnValue(true),
setDebugEnabled: jest.fn(),
})
}
}));
jest.mock('../../helpers/apim/asset-helper.js', () => ({
isValidAsset: jest.fn(),
}));
jest.mock('../../helpers/common/rest-api-validation-helper.js', () => ({
isValidRestAPI: jest.fn(),
}));
jest.mock('../../helpers/common/yaml-helper.js', () => ({
readMultiYaml: jest.fn(),
convertToYAMLString: jest.fn()
}));
jest.mock('../../helpers/common/json-helper.js', () => ({
readJson: jest.fn()
}));
describe('Zip Helper Recursive and File Skipping Tests', () => {
let mockZipFile: jest.Mocked<AdmZip>;
beforeEach(() => {
jest.clearAllMocks();
mockZipFile = new AdmZip() as jest.Mocked<AdmZip>;
mockZipFile.addLocalFile = jest.fn();
mockZipFile.addFile = jest.fn();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should add valid assets recursively and handle directory structure', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
const mockItems = ['file.yaml', 'subfolder'];
(readMultiYaml as jest.Mock).mockReturnValue([{ kind: 'api' }, { kind: 'transport' }]);
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(mockItems);
(isDirectory as jest.Mock).mockImplementation((itemPath) => itemPath === path.join(mockFolderPath, 'subfolder'));
(isYamlFile as jest.Mock).mockReturnValue(true);
(isJsonFile as jest.Mock).mockReturnValue(false);
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(mockZipFile.addFile).toHaveBeenCalledWith(
`${mockZipFolderPath}/`,
Buffer.from("")
);
// Check if the YAML file is added
expect(mockZipFile.addFile).toHaveBeenCalledWith(
`${mockZipFolderPath}/`,
expect.any(Buffer)
);
});
it('should skip non-supported files', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = [];
const mockItems = ['file.txt'];
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(mockItems);
(isDirectory as jest.Mock).mockReturnValue(false);
(isYamlFile as jest.Mock).mockReturnValue(false);
(isJsonFile as jest.Mock).mockReturnValue(false);
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(mockZipFile.addFile).not.toHaveBeenCalledWith(
`${mockZipFolderPath}/file.txt`,
expect.any(Buffer)
);
});
});
describe('Zip Helper Test Suite', () => {
let mockZipFile: jest.Mocked<AdmZip>;
beforeEach(() => {
jest.clearAllMocks();
mockZipFile = new AdmZip() as jest.Mocked<AdmZip>;
mockZipFile.addLocalFile = jest.fn();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should not add files if directory has no files, but should add the empty directory', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue([]);
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
const expectedPath = path.join(mockZipFolderPath, '/');
expect(mockZipFile.getEntries().length).toBe(1);
expect(mockZipFile.getEntries()[0].entryName).toBe(expectedPath);
});
it('should not add files if directory does not exist', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
(isDirOrFileExists as jest.Mock).mockReturnValue(false);
(showWarning as jest.Mock).mockImplementation((message) => {
expect(message).toBe(`${DIRECTORY_DOESNT_EXIST} ${mockFolderPath}`);
});
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(showWarning).toHaveBeenCalledWith(`${DIRECTORY_DOESNT_EXIST} ${mockFolderPath}`);
expect(mockZipFile.getEntries().length).toBe(0);
});
it('should add yaml files to the zip', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
const mockYamlContent = 'yaml content';
const mockCombinedYaml = 'combined yaml content';
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['api.yaml']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isYamlFile as jest.Mock).mockReturnValue(true);
(readFile as jest.Mock).mockReturnValue(mockYamlContent);
(readMultiYaml as jest.Mock).mockReturnValue([{ kind: 'api' }]);
(isValidRestAPI as jest.Mock).mockReturnValue(false);
(isValidAsset as jest.Mock).mockReturnValue(true);
(convertToYAMLString as jest.Mock).mockReturnValue(mockCombinedYaml);
checkAndAddValidYamlFile('zip/folder/api.yaml', mockZipFolderPath, mockZipFile, []);
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(mockZipFile.getEntries().length).toBe(1);
const yamlEntry = mockZipFile.getEntry('zip/folder/api.yaml');
expect(yamlEntry).toBeDefined();
});
it('should handle YAML files with errors gracefully', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = [];
const mockFilePath = 'folder/error.yaml';
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['error.yaml']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isYamlFile as jest.Mock).mockReturnValue(true);
(readFile as jest.Mock).mockImplementation(() => { throw new Error('File read error'); });
expect(() => {
checkAndAddValidYamlFile(mockFilePath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
}).toThrow(new Error(`File read error`));
});
it('should handle JSON files with errors gracefully', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockFilePath = 'folder/error.json';
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['error.json']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isJsonFile as jest.Mock).mockReturnValue(true);
(readFile as jest.Mock).mockImplementation(() => { throw new Error('File read error'); });
expect(() => {
checkAndAddValidJsonFile(mockFilePath, mockZipFolderPath, mockZipFile, []);
}).toThrow(new Error(`File read error`));
});
test('should handle files that are not JSON or YAML', () => {
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['other.txt']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isYamlFile as jest.Mock).mockReturnValue(false);
(isJsonFile as jest.Mock).mockReturnValue(false);
addValidAssetsToZip('folder', 'zip/folder', mockZipFile, []);
const entry = mockZipFile.getEntry('zip/folder/other.txt');
expect(entry).toBeNull();
});
test('should handle multi YAML contents and add it to zip', () => {
const mockZipFolderPath = 'zip/folder';
const mockFileName = 'file.yaml';
const mockExcludeKinds: string[] = ['kindToExclude'];
const mockYamlContents = [
{ kind: 'api', name: 'API Asset' },
{ kind: 'transport', name: 'Transport Asset' },
{ kind: 'kindToExclude', name: 'Excluded Asset' },
];
const convertedYaml = "---\nname: Converted Asset\n";
(readMultiYaml as jest.Mock).mockReturnValue(mockYamlContents);
(getFileNameFromPath as jest.Mock).mockReturnValue(mockFileName);
(isValidRestAPI as jest.Mock).mockReturnValue(false);
(isValidAsset as jest.Mock).mockReturnValue(true);
(convertToYAMLString as jest.Mock).mockReturnValue(convertedYaml);
addValidAssetsToZip('folder', mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(mockZipFile.getEntries().length).toBe(1);
const yamlEntry = mockZipFile.getEntry('zip/folder/file.yaml');
expect(yamlEntry).toBeDefined();
});
it('should add non-YAML/JSON files to the zip', () => {
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['otherFile.txt']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isOtherFile as jest.Mock).mockReturnValue(true);
checkAndAddOtherFile('zip/folder/otherFile.txt', mockZipFolderPath, mockZipFile);
addValidAssetsToZip('folder', mockZipFolderPath, mockZipFile, mockExcludeKinds);
console.log(mockZipFile);
expect(mockZipFile.getEntries().length).toBe(1);
const otherEntry = mockZipFile.getEntry('zip/folder/otherFile.txt');
expect(otherEntry).toBeDefined();
});
it('should add json files to the zip', () => {
const mockFolderPath = 'folder';
const mockZipFolderPath = 'zip/folder';
const mockExcludeKinds: string[] = ['kindToExclude'];
const mockJsonContent = 'json content';
(isDirOrFileExists as jest.Mock).mockReturnValue(true);
(readDirectoryContents as jest.Mock).mockReturnValue(['swagger.json']);
(isDirectory as jest.Mock).mockReturnValue(false);
(isJsonFile as jest.Mock).mockReturnValue(true);
(readFile as jest.Mock).mockReturnValue(mockJsonContent);
(readJson as jest.Mock).mockReturnValue({ "swagger": "2.0" });
(isValidRestAPI as jest.Mock).mockReturnValue(true);
checkAndAddValidJsonFile('zip/folder/swagger.json', mockZipFolderPath, mockZipFile, []);
addValidAssetsToZip(mockFolderPath, mockZipFolderPath, mockZipFile, mockExcludeKinds);
expect(mockZipFile.getEntries().length).toBe(1);
const jsonEntry = mockZipFile.getEntry('zip/folder/swagger.json');
expect(jsonEntry).toBeDefined();
});
});