Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions tools/integration/src/__tests__/handlers/export.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as utils from '../../utils';
import * as validators from '../../validators';

import axios from 'axios';
import fs from 'fs';
Expand All @@ -11,11 +12,13 @@ jest.mock('axios');
jest.mock('fs');
jest.mock('../../logger');
jest.mock('../../utils');
jest.mock('../../validators');

const mockedAxios = axios as jest.Mocked<typeof axios>;
const mockedFs = fs as jest.Mocked<typeof fs>;
const mockedLogger = logger as jest.Mocked<typeof logger>;
const mockedUtils = utils as jest.Mocked<typeof utils>;
const mockedValidators = validators as jest.Mocked<typeof validators>;

describe('handleExport', () => {
let mockAxiosInstance: any;
Expand Down Expand Up @@ -60,6 +63,137 @@ describe('handleExport', () => {
mockFilterElementsBy.mockRestore();
});

describe('Include Type Validation', () => {
it('should reject invalid include type "dashboards"', async () => {
process.argv = ['node', 'script.js', 'export', '--include', 'type=dashboards'];

const argv = {
server: 'test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn();
mockedValidators.validateIncludeTypes = jest.fn().mockImplementation(() => {
throw new Error('Invalid --include type value(s): "dashboards". Valid types are: "dashboard", "event", "entity", "smart-alert", "all"');
});

await expect(handleExport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid --include type value(s): "dashboards"')
);
});

it('should reject invalid include type "events"', async () => {
process.argv = ['node', 'script.js', 'export', '--include', 'type=events'];

const argv = {
server: 'test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn();
mockedValidators.validateIncludeTypes = jest.fn().mockImplementation(() => {
throw new Error('Invalid --include type value(s): "events". Valid types are: "dashboard", "event", "entity", "smart-alert", "all"');
});

await expect(handleExport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid --include type value(s): "events"')
);
});

it('should accept valid include type "dashboard"', async () => {
process.argv = ['node', 'script.js', 'export', '--include', 'type=dashboard'];

const argv = {
server: 'test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn();
mockedValidators.validateIncludeTypes = jest.fn();
mockedFs.existsSync = jest.fn().mockReturnValue(false);
mockedFs.mkdirSync = jest.fn();
mockedFs.readdirSync = jest.fn().mockReturnValue([]);
mockedUtils.parseIncludesFromArgv = jest.fn().mockReturnValue([
{ type: 'dashboard', conditions: [], explicitlyTyped: true }
]);
mockedUtils.sanitizeTitles = jest.fn().mockReturnValue([]);
mockAxiosInstance.get.mockResolvedValue({ status: 200, data: [] });

await handleExport(argv);

expect(mockedValidators.validateIncludeTypes).toHaveBeenCalled();
});
});

describe('Server Validation', () => {
it('should reject server address with https:// protocol', async () => {
const argv = {
server: 'https://test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn().mockImplementation(() => {
throw new Error('Invalid server address: Do not include protocol (http:// or https://). Please use only the hostname, e.g., "example.com" instead of "https://test-server.com"');
});

await expect(handleExport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid server address: Do not include protocol')
);
});

it('should reject server address with http:// protocol', async () => {
const argv = {
server: 'http://test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn().mockImplementation(() => {
throw new Error('Invalid server address: Do not include protocol (http:// or https://). Please use only the hostname, e.g., "example.com" instead of "http://test-server.com"');
});

await expect(handleExport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid server address: Do not include protocol')
);
});

it('should accept valid server address without protocol', async () => {
const argv = {
server: 'test-server.com',
token: 'test-token',
location: '/test/export',
debug: false
};

mockedValidators.validateServerAddress = jest.fn();
mockedFs.existsSync = jest.fn().mockReturnValue(false);
mockedFs.mkdirSync = jest.fn();
mockedFs.readdirSync = jest.fn().mockReturnValue([]);
mockedUtils.parseIncludesFromArgv = jest.fn().mockReturnValue([
{ type: 'all', conditions: [], explicitlyTyped: false }
]);
mockedUtils.sanitizeTitles = jest.fn().mockReturnValue([]);
mockAxiosInstance.get.mockResolvedValue({ status: 200, data: [] });

await handleExport(argv);

expect(mockedValidators.validateServerAddress).toHaveBeenCalledWith('test-server.com');
});
});

describe('Directory Validation', () => {
it('should create export directory if it does not exist', async () => {
const argv = {
Expand Down
66 changes: 66 additions & 0 deletions tools/integration/src/__tests__/handlers/import.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,72 @@ describe('handleImport', () => {
mockProcessExit.mockRestore();
});

describe('Server Validation', () => {
it('should reject server address with https:// protocol', async () => {
const argv = {
package: '/test/package',
server: 'https://test-server.com',
token: 'test-token',
location: '/test/location',
debug: false
};

mockedValidators.validateServerAddress = jest.fn().mockImplementation(() => {
throw new Error('Invalid server address: Do not include protocol (http:// or https://). Please use only the hostname, e.g., "example.com" instead of "https://test-server.com"');
});

await expect(handleImport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid server address: Do not include protocol')
);
});

it('should reject server address with http:// protocol', async () => {
const argv = {
package: '/test/package',
server: 'http://test-server.com',
token: 'test-token',
location: '/test/location',
debug: false
};

mockedValidators.validateServerAddress = jest.fn().mockImplementation(() => {
throw new Error('Invalid server address: Do not include protocol (http:// or https://). Please use only the hostname, e.g., "example.com" instead of "http://test-server.com"');
});

await expect(handleImport(argv)).rejects.toThrow('process.exit(1)');
expect(mockedLogger.error).toHaveBeenCalledWith(
expect.stringContaining('Invalid server address: Do not include protocol')
);
});

it('should accept valid server address without protocol', async () => {
const argv = {
package: '/test/package',
server: 'test-server.com',
token: 'test-token',
location: '/test/location',
include: 'dashboards/**/*.json',
debug: false
};

mockedValidators.validateServerAddress = jest.fn();
mockedFs.existsSync = jest.fn().mockReturnValue(true);
mockedGlobSync.mockReturnValue(['/test/package/dashboards/test.json']);
mockedFs.readFileSync = jest.fn().mockReturnValue(JSON.stringify({
title: 'Test Dashboard',
accessRules: [{ accessType: 'READ_WRITE', relationType: 'GLOBAL' }]
}));
mockAxiosInstance.post.mockResolvedValue({ status: 200 });
mockedValidators.getEntityDashboardRefs = jest.fn().mockReturnValue(new Set());

await handleImport(argv);

expect(mockedValidators.validateServerAddress).toHaveBeenCalledWith('test-server.com');
expect(mockAxiosInstance.post).toHaveBeenCalled();
});
});

describe('Basic Import Functionality', () => {
it('should import dashboards successfully', async () => {
const argv = {
Expand Down
Loading
Loading