forked from opensearch-project/dashboards-observability
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-apply the integrations kibana backend PR (opensearch-project#680) (o…
…pensearch-project#683) * Merge Kibana backend from osints/dev into main (opensearch-project#565) * Merge in kibana backend from osints/dev * Add integration type to .kibana from osints/dev * Re-add license header * Fix integrations type --------- * Remove extra test files --------- Signed-off-by: Simeon Widdis <sawiddis@amazon.com> (cherry picked from commit ad2c5f5)
- Loading branch information
Showing
9 changed files
with
855 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
{ | ||
"last_github_commit": "8c9814283d14403147884e4121ee8ac6211479d1", | ||
"last_gitfarm_commit": "f9f7f783a1899066cfc540bde444bfabf49064b5" | ||
"last_github_commit": "ad2c5f5c67c53ba48403b3f42a34a9f93bd0d57a", | ||
"last_gitfarm_commit": "cdeac905bfc25e495bf9a224f7e1a62fece7c2e8" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.