@spotinst/spinnaker-deck
Version:
Spinnaker-Deck service, forked with support to Spotinst
165 lines (141 loc) • 7.21 kB
text/typescript
import { IStageTypeConfig } from 'core/domain';
import { IDeckPlugin } from './deck.plugin';
import { RequestBuilder } from '../api';
import { IPluginMetaData, PluginRegistry } from './plugin.registry';
import { Registry } from 'core/registry';
import { mock } from 'angular';
const fakePromise = (result: any = undefined) => () => new Promise((resolve) => resolve(result));
describe('PluginRegistry', () => {
let pluginRegistry: PluginRegistry;
let loadModuleFromUrlSpy: jasmine.Spy;
beforeEach(() => {
pluginRegistry = new PluginRegistry() as any;
// @ts-ignore
loadModuleFromUrlSpy = spyOn(pluginRegistry, 'loadModuleFromUrl');
});
describe('.register()', () => {
it('should validate plugin manifests', () => {
expect(() => pluginRegistry.registerPluginMetaData('deck', {} as any)).toThrowError(/Invalid plugin manifest/);
});
it('should add plugins manifests to the registry', () => {
const plugin1 = { id: 'foo', version: '1.0.0' };
const plugin2 = { id: 'bar', version: '1.0.0' };
pluginRegistry.registerPluginMetaData('deck', plugin1);
pluginRegistry.registerPluginMetaData('deck', plugin2);
expect(pluginRegistry.getRegisteredPlugins().length).toBe(2);
expect(pluginRegistry.getRegisteredPlugins()[0]).toEqual(jasmine.objectContaining(plugin1));
expect(pluginRegistry.getRegisteredPlugins()[1]).toEqual(jasmine.objectContaining(plugin2));
});
});
it(
'loadPluginManifestFromDeck() should fetch /plugin-manifest.json from deck assets',
mock.inject(async ($http: any) => {
const spy = spyOn($http, 'get').and.callFake(() => Promise.resolve({ data: [] }));
await pluginRegistry.loadPluginManifestFromDeck();
expect(spy).toHaveBeenCalledWith('/plugin-manifest.json');
}),
);
it('loadPluginManifestFromGate() should fetch from gate /plugins/deck/plugin-manifest.json', async () => {
const spy = spyOn(RequestBuilder.defaultHttpClient, 'get').and.callFake(() => Promise.resolve([] as any));
await pluginRegistry.loadPluginManifestFromGate();
expect(spy).toHaveBeenCalled();
});
describe('loadPlugins()', () => {
let pluginModule: { plugin: IDeckPlugin };
beforeEach(() => {
pluginModule = {
plugin: {
stages: [({ id: 'mystage' } as any) as IStageTypeConfig],
initialize: () => {},
},
};
});
it('should load all registered plugins', () => {
// @ts-ignore
const loadSpy = spyOn(pluginRegistry, 'load').and.callFake(fakePromise());
const plugin1 = { id: 'foo', version: '1.0.0' };
const plugin2 = { id: 'bar', version: '1.0.0' };
pluginRegistry.registerPluginMetaData('deck', plugin1);
pluginRegistry.registerPluginMetaData('deck', plugin2);
expect(loadSpy.calls.count()).toBe(0);
pluginRegistry.loadPlugins();
expect(loadSpy.calls.count()).toBe(2);
expect(loadSpy.calls.first().args[0]).toEqual(jasmine.objectContaining(plugin1));
expect(loadSpy.calls.mostRecent().args[0]).toEqual(jasmine.objectContaining(plugin2));
});
it('should return a rejected promise if a loaded module doesnt contain an export named plugin', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise({}));
spyOn(console, 'error').and.stub();
const plugin1 = { id: 'foo', version: '1.0.0' };
pluginRegistry.registerPluginMetaData('deck', plugin1);
await expectAsync(pluginRegistry.loadPlugins()).toBeRejected();
});
it('should resolve to all loaded plugin modules', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const plugin1 = { id: 'foo', version: '1.0.0' };
pluginRegistry.registerPluginMetaData('deck', plugin1);
await expectAsync(pluginRegistry.loadPlugins()).toBeResolvedTo([pluginModule]);
});
it('should normalize the metadata object', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const plugin1 = { name: 'io.spinnaker.test.plugin', devUrl: 'abc', version: '1.0.0' } as IPluginMetaData;
pluginRegistry.registerPluginMetaData('deck', plugin1);
expect(pluginRegistry.getRegisteredPlugins()[0]).toEqual({
id: 'io.spinnaker.test.plugin',
source: 'deck',
url: 'abc',
version: '1.0.0',
});
});
it('prefers plugins from deck manifest over plugins from gate manifest', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const deckManifest = { id: 'io.spinnaker.test.plugin', version: '1.0.1', url: 'test' } as IPluginMetaData;
const gateManifest = { id: 'io.spinnaker.test.plugin', version: '1.0.0' } as IPluginMetaData;
pluginRegistry.registerPluginMetaData('deck', deckManifest);
pluginRegistry.registerPluginMetaData('gate', gateManifest);
expect(pluginRegistry.getRegisteredPlugins().length).toBe(1);
expect(pluginRegistry.getRegisteredPlugins()[0]).toEqual({
id: 'io.spinnaker.test.plugin',
source: 'deck',
url: 'test',
version: '1.0.1',
});
});
it('prefers plugins from deck manifest regardless of registration order', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const deckManifest = { id: 'io.spinnaker.test.plugin', version: '1.0.1', url: 'test' } as IPluginMetaData;
const gateManifest = { id: 'io.spinnaker.test.plugin', version: '1.0.0' } as IPluginMetaData;
pluginRegistry.registerPluginMetaData('gate', gateManifest);
pluginRegistry.registerPluginMetaData('deck', deckManifest);
expect(pluginRegistry.getRegisteredPlugins().length).toBe(1);
expect(pluginRegistry.getRegisteredPlugins()[0]).toEqual({
id: 'io.spinnaker.test.plugin',
source: 'deck',
url: 'test',
version: '1.0.1',
});
});
it('should return the normalized metadata object', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const plugin1 = { id: 'foo', version: '1.0.0' } as IPluginMetaData;
const normalized = pluginRegistry.registerPluginMetaData('deck', plugin1);
expect(pluginRegistry.getRegisteredPlugins()[0]).toBe(normalized);
});
it('should store the loaded module onto the metadata object', async () => {
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const plugin1 = { id: 'foo', version: '1.0.0' } as IPluginMetaData;
const normalized = pluginRegistry.registerPluginMetaData('deck', plugin1);
await pluginRegistry.loadPlugins();
expect(normalized.module).toBe(pluginModule);
});
it('should register stages found on the plugin', async () => {
const registerStageSpy = spyOn(Registry.pipeline, 'registerStage');
loadModuleFromUrlSpy.and.callFake(fakePromise(pluginModule));
const plugin1 = { id: 'foo', version: '1.0.0' };
pluginRegistry.registerPluginMetaData('deck', plugin1);
await pluginRegistry.loadPlugins();
expect(registerStageSpy).toHaveBeenCalledTimes(1);
expect(registerStageSpy).toHaveBeenCalledWith(pluginModule.plugin.stages[0]);
});
});
});