@apistudio/apim-cli
Version:
CLI for API Management Products
271 lines (235 loc) • 8.33 kB
text/typescript
/**
* Copyright IBM Corp. 2024, 2025
*/
import { processDeployment, validateGateways } from '../../src/index.js';
import fs from 'fs';
import path from 'path';
import * as GatewayService from '../../src/service/gateway-service.js';
import { AppConstants } from '../../src/constants/app-constants.js';
import { IpcError, Logger } from '@apic/studio-shared';
// Mock the Logger from studio-shared
jest.mock('@apic/studio-shared', () => ({
Logger: {
info: jest.fn(),
debug: jest.fn(),
warn: jest.fn(),
error: jest.fn(),
log: jest.fn(),
},
IpcError: class IpcError extends Error {
constructor(message: string) {
super(message);
this.name = 'IpcError';
}
},
}));
jest.mock('@apic/wmgw-smith-sdk', () => ({
WMGWRuntimeSDK: jest.fn().mockImplementation(() => ({
transformer: {
transform: jest.fn().mockResolvedValue(Buffer.from('transformed')),
},
inventory: jest.fn(),
})),
}));
jest.mock('@apic/wmgw-smith-transformer', () => ({
createWmgwOrchestrator: jest.fn().mockImplementation(() => ({
transform: jest.fn().mockResolvedValue(Buffer.from('transformed')),
})),
}));
describe('processDeployment', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should return success response on deployment', async () => {
const gatewaysJson = {
gateways: [
{
gatewayURL: 'http://example.com',
gatewayUser: 'user',
gatewaySecret: '123456',
is_mcsp_enabled: false,
},
],
overwrite: 'apis,alias',
skip: 'policies',
};
const zipBuffer = fs.readFileSync(path.resolve(__dirname, '../assets/gateway-asset.zip'));
jest.spyOn(GatewayService, 'sendToGateway').mockResolvedValue({
success: true,
statusCode: 200,
message: 'Api deployment Successful',
data: 'success',
errors: [],
});
const result = await processDeployment(gatewaysJson, zipBuffer);
expect(result).toStrictEqual([
{
success: true,
statusCode: 200,
message: 'Api deployment Successful',
data: 'success',
errors: [],
},
]);
expect(Logger.info).toHaveBeenCalledWith('Starting deployment process', { gatewayCount: 1 });
expect(Logger.debug).toHaveBeenCalledWith(
'Deploying to gateway',
expect.objectContaining({ gatewayURL: 'http://example.com' })
);
expect(Logger.debug).toHaveBeenCalledWith('Gateway deployment successful', {
response: 'success',
});
expect(Logger.info).toHaveBeenCalledWith('Deployment process completed.');
expect(Logger.error).not.toHaveBeenCalled();
expect(Logger.warn).not.toHaveBeenCalled();
});
it('should return multiple success responses on multi deployment', async () => {
const gatewaysJson = {
gateways: [
{
gatewayURL: 'http://example.com',
gatewayUser: 'user',
gatewaySecret: '123456',
is_mcsp_enabled: false,
},
{
gatewayURL: 'http://example2.com',
gatewayUser: 'user2',
gatewaySecret: 'abcdef',
is_mcsp_enabled: true,
},
],
overwrite: 'apis,alias',
skip: 'policies',
};
const zipBuffer = fs.readFileSync(path.resolve(__dirname, '../assets/gateway-asset.zip'));
jest.spyOn(GatewayService, 'sendToGateway').mockResolvedValue({
success: true,
statusCode: 200,
message: 'Api deployment Successful',
data: 'success',
errors: [],
});
const result = await processDeployment(gatewaysJson, zipBuffer);
expect(result.length).toBe(2);
expect(result[0].success).toBeTruthy();
expect(result[1].success).toBeTruthy();
expect(Logger.info).toHaveBeenCalledWith('Starting deployment process', { gatewayCount: 2 });
expect(Logger.debug).toHaveBeenCalledWith(
'Deploying to gateway',
expect.objectContaining({ gatewayURL: 'http://example.com' })
);
expect(Logger.debug).toHaveBeenCalledWith(
'Deploying to gateway',
expect.objectContaining({ gatewayURL: 'http://example2.com' })
);
expect(Logger.info).toHaveBeenCalledWith('Deployment process completed.');
expect(Logger.error).not.toHaveBeenCalled();
expect(Logger.warn).not.toHaveBeenCalled();
});
it('should return warning on deployment with no gateways provided', async () => {
const gatewaysJson = {
gateways: [],
overwrite: 'apis,alias',
skip: 'policies',
};
const zipBuffer = fs.readFileSync(path.resolve(__dirname, '../assets/gateway-asset.zip'));
const result = await processDeployment(gatewaysJson, zipBuffer);
expect(result).toStrictEqual([]);
expect(Logger.warn).toHaveBeenCalledWith('No gateways to deploy.');
expect(Logger.info).toHaveBeenCalledWith('Deployment process completed.');
expect(Logger.error).not.toHaveBeenCalled();
expect(Logger.debug).not.toHaveBeenCalled();
});
it('should return error response on deployment error', async () => {
const gatewaysJson = {
gateways: [
{
gatewayURL: 'http://example.com',
gatewayUser: 'user',
gatewaySecret: '123456',
is_mcsp_enabled: false,
},
],
overwrite: 'apis,alias',
skip: 'policies',
};
const zipBuffer = fs.readFileSync(path.resolve(__dirname, '../assets/gateway-asset.zip'));
jest.spyOn(GatewayService, 'sendToGateway').mockImplementation(() => {
throw new Error('Gateway not found');
});
const result = await processDeployment(gatewaysJson, zipBuffer);
expect(result).toStrictEqual([
{
success: false,
statusCode: 400,
message: 'Error sending to http://example.com: Gateway not found',
data: null,
errors: ['Error sending to http://example.com: Gateway not found'],
},
]);
expect(Logger.error).toHaveBeenCalledWith(
'Deployment failed',
expect.any(Error),
expect.objectContaining({ context: 'deploying to', gatewayURL: 'http://example.com' })
);
expect(Logger.warn).not.toHaveBeenCalled();
});
it('should return error response on deployment error due to promise rejection', async () => {
const gatewaysJson = {
gateways: [
{
gatewayURL: 'http://example.com',
gatewayUser: 'user',
gatewaySecret: '123456',
is_mcsp_enabled: false,
},
],
overwrite: 'apis,alias',
skip: 'policies',
};
const zipBuffer = fs.readFileSync(path.resolve(__dirname, '../assets/gateway-asset.zip'));
jest.spyOn(GatewayService, 'sendToGateway').mockRejectedValue({ some: 'random object' });
const result = await processDeployment(gatewaysJson, zipBuffer);
expect(result).toStrictEqual([
{
success: false,
statusCode: 400,
message: 'Unknown error sending to http://example.com',
data: null,
errors: ['Unknown error sending to http://example.com'],
},
]);
expect(Logger.error).toHaveBeenCalledWith(
'Unknown deployment error',
expect.any(Error),
expect.objectContaining({ gatewayURL: 'http://example.com' })
);
expect(Logger.info).toHaveBeenCalledWith('Deployment process completed.');
expect(Logger.warn).not.toHaveBeenCalled();
});
describe('validateGateways', () => {
const url = 'https://example.com';
const authHeader = 'Bearer token';
beforeEach(() => {
jest.clearAllMocks();
});
it('should call validationManager and return success', async () => {
jest
.spyOn(GatewayService, 'validationManager')
.mockResolvedValue({ data: 'OK', status: 200 });
const result = await validateGateways(url, authHeader);
expect(result).toEqual({ data: 'OK', status: 200 });
expect(GatewayService.validationManager).toHaveBeenCalledWith(
`${url}${AppConstants.GATEWAY_VALIDATION_URL}`,
authHeader
);
});
it('should throw error if URL is missing', async () => {
await expect(validateGateways('', authHeader)).rejects.toThrow(IpcError);
});
it('should throw error if authHeader is missing', async () => {
await expect(validateGateways(url, '')).rejects.toThrow(IpcError);
});
});
});