Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Kibana backend from osints/dev into main #565

Merged
merged 4 commits into from
Jun 28, 2023
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
326 changes: 326 additions & 0 deletions server/adaptors/integrations/__test__/builder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,326 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { SavedObjectsClientContract } from '../../../../../../src/core/server';
import { IntegrationInstanceBuilder } from '../integrations_builder';
import { Integration } from '../repository/integration';

const mockSavedObjectsClient: SavedObjectsClientContract = ({
bulkCreate: jest.fn(),
create: jest.fn(),
delete: jest.fn(),
find: jest.fn(),
get: jest.fn(),
update: jest.fn(),
} as unknown) as SavedObjectsClientContract;

const sampleIntegration: Integration = ({
deepCheck: jest.fn().mockResolvedValue(true),
getAssets: jest.fn().mockResolvedValue({
savedObjects: [
{
id: 'asset1',
references: [{ id: 'ref1' }],
},
{
id: 'asset2',
references: [{ id: 'ref2' }],
},
],
}),
getConfig: jest.fn().mockResolvedValue({
name: 'integration-template',
type: 'integration-type',
}),
} as unknown) as Integration;

describe('IntegrationInstanceBuilder', () => {
let builder: IntegrationInstanceBuilder;

beforeEach(() => {
builder = new IntegrationInstanceBuilder(mockSavedObjectsClient);
});

afterEach(() => {
jest.clearAllMocks();
});

describe('build', () => {
it('should build an integration instance', async () => {
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};

const remappedAssets = [
{
id: 'remapped-asset1',
references: [{ id: 'remapped-ref1' }],
},
{
id: 'remapped-asset2',
references: [{ id: 'remapped-ref2' }],
},
];
const postAssetsResponse = {
saved_objects: [
{ id: 'created-asset1', type: 'dashboard', attributes: { title: 'Dashboard 1' } },
{ id: 'created-asset2', type: 'visualization', attributes: { title: 'Visualization 1' } },
],
};
const expectedInstance = {
name: 'instance-name',
templateName: 'integration-template',
dataSource: 'instance-datasource',
creationDate: expect.any(String),
assets: [
{
assetType: 'dashboard',
assetId: 'created-asset1',
status: 'available',
isDefaultAsset: true,
description: 'Dashboard 1',
},
{
assetType: 'visualization',
assetId: 'created-asset2',
status: 'available',
isDefaultAsset: false,
description: 'Visualization 1',
},
],
};

// Mock the implementation of the methods in the Integration class
sampleIntegration.deepCheck = jest.fn().mockResolvedValue(true);
sampleIntegration.getAssets = jest.fn().mockResolvedValue({ savedObjects: remappedAssets });
sampleIntegration.getConfig = jest.fn().mockResolvedValue({
name: 'integration-template',
type: 'integration-type',
});

// Mock builder sub-methods
const remapIDsSpy = jest.spyOn(builder, 'remapIDs');
const postAssetsSpy = jest.spyOn(builder, 'postAssets');

(mockSavedObjectsClient.bulkCreate as jest.Mock).mockResolvedValue(postAssetsResponse);

const instance = await builder.build(sampleIntegration, options);

expect(sampleIntegration.deepCheck).toHaveBeenCalled();
expect(sampleIntegration.getAssets).toHaveBeenCalled();
expect(remapIDsSpy).toHaveBeenCalledWith(remappedAssets);
expect(postAssetsSpy).toHaveBeenCalledWith(remappedAssets);
expect(instance).toEqual(expectedInstance);
});

it('should reject with an error if integration is not valid', async () => {
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};
sampleIntegration.deepCheck = jest.fn().mockResolvedValue(false);

await expect(builder.build(sampleIntegration, options)).rejects.toThrowError(
'Integration is not valid'
);
});

it('should reject with an error if getAssets throws an error', async () => {
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};

const errorMessage = 'Failed to get assets';
sampleIntegration.deepCheck = jest.fn().mockResolvedValue(true);
sampleIntegration.getAssets = jest.fn().mockRejectedValue(new Error(errorMessage));

await expect(builder.build(sampleIntegration, options)).rejects.toThrowError(errorMessage);
});

it('should reject with an error if postAssets throws an error', async () => {
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};
const remappedAssets = [
{
id: 'remapped-asset1',
references: [{ id: 'remapped-ref1' }],
},
];
const errorMessage = 'Failed to post assets';
sampleIntegration.deepCheck = jest.fn().mockResolvedValue(true);
sampleIntegration.getAssets = jest.fn().mockResolvedValue({ savedObjects: remappedAssets });
builder.postAssets = jest.fn().mockRejectedValue(new Error(errorMessage));

await expect(builder.build(sampleIntegration, options)).rejects.toThrowError(errorMessage);
});

it('should reject with an error if getConfig returns null', async () => {
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};
sampleIntegration.getConfig = jest.fn().mockResolvedValue(null);

await expect(builder.build(sampleIntegration, options)).rejects.toThrowError();
});
});

describe('remapIDs', () => {
it('should remap IDs and references in assets', () => {
const assets = [
{
id: 'asset1',
references: [{ id: 'ref1' }, { id: 'ref2' }],
},
{
id: 'asset2',
references: [{ id: 'ref1' }, { id: 'ref3' }],
},
];
const expectedRemappedAssets = [
{
id: expect.any(String),
references: [{ id: expect.any(String) }, { id: expect.any(String) }],
},
{
id: expect.any(String),
references: [{ id: expect.any(String) }, { id: expect.any(String) }],
},
];

const remappedAssets = builder.remapIDs(assets);

expect(remappedAssets).toEqual(expectedRemappedAssets);
});
});

describe('postAssets', () => {
it('should post assets and return asset references', async () => {
const assets = [
{
id: 'asset1',
type: 'dashboard',
attributes: { title: 'Dashboard 1' },
},
{
id: 'asset2',
type: 'visualization',
attributes: { title: 'Visualization 1' },
},
];
const expectedRefs = [
{
assetType: 'dashboard',
assetId: 'created-asset1',
status: 'available',
isDefaultAsset: true,
description: 'Dashboard 1',
},
{
assetType: 'visualization',
assetId: 'created-asset2',
status: 'available',
isDefaultAsset: false,
description: 'Visualization 1',
},
];
const bulkCreateResponse = {
saved_objects: [
{ id: 'created-asset1', type: 'dashboard', attributes: { title: 'Dashboard 1' } },
{ id: 'created-asset2', type: 'visualization', attributes: { title: 'Visualization 1' } },
],
};

(mockSavedObjectsClient.bulkCreate as jest.Mock).mockResolvedValue(bulkCreateResponse);

const refs = await builder.postAssets(assets);

expect(mockSavedObjectsClient.bulkCreate).toHaveBeenCalledWith(assets);
expect(refs).toEqual(expectedRefs);
});

it('should reject with an error if bulkCreate throws an error', async () => {
const assets = [
{
id: 'asset1',
type: 'dashboard',
attributes: { title: 'Dashboard 1' },
},
];
const errorMessage = 'Failed to create assets';
(mockSavedObjectsClient.bulkCreate as jest.Mock).mockRejectedValue(new Error(errorMessage));

await expect(builder.postAssets(assets)).rejects.toThrowError(errorMessage);
});
});

describe('buildInstance', () => {
it('should build an integration instance', async () => {
const integration = {
getConfig: jest.fn().mockResolvedValue({
name: 'integration-template',
type: 'integration-type',
}),
};
const refs = [
{
assetType: 'dashboard',
assetId: 'created-asset1',
status: 'available',
isDefaultAsset: true,
description: 'Dashboard 1',
},
];
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};
const expectedInstance = {
name: 'instance-name',
templateName: 'integration-template',
dataSource: 'instance-datasource',
tags: undefined,
creationDate: expect.any(String),
assets: refs,
};

const instance = await builder.buildInstance(
(integration as unknown) as Integration,
refs,
options
);

expect(integration.getConfig).toHaveBeenCalled();
expect(instance).toEqual(expectedInstance);
});

it('should reject with an error if getConfig returns null', async () => {
const integration = {
getConfig: jest.fn().mockResolvedValue(null),
};
const refs = [
{
assetType: 'dashboard',
assetId: 'created-asset1',
status: 'available',
isDefaultAsset: true,
description: 'Dashboard 1',
},
];
const options = {
dataSource: 'instance-datasource',
name: 'instance-name',
};

await expect(
builder.buildInstance((integration as unknown) as Integration, refs, options)
).rejects.toThrowError();
});
});
});
Loading