fix(40639): datasource should not be visible after uninstall (#43625)

* fix(40639): datasource should not be visible after uninstall
This commit is contained in:
Timur Olzhabayev 2022-01-07 09:54:02 +01:00 committed by GitHub
parent ea478dec22
commit 8717bc7ef4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 142 additions and 0 deletions

View File

@ -1,3 +1,5 @@
import { clearPluginSettingsCache } from './pluginSettings';
const cache: Record<string, string> = {};
const initializedAt: number = Date.now();
@ -17,6 +19,7 @@ export function invalidatePluginInCache(pluginId: string): void {
if (cache[path]) {
delete cache[path];
}
clearPluginSettingsCache(pluginId);
}
export function locateWithCache(load: { address: string }, defaultBust = initializedAt): string {

View File

@ -0,0 +1,116 @@
import { getPluginSettings, clearPluginSettingsCache } from './pluginSettings';
import { getBackendSrv } from '@grafana/runtime';
jest.mock('@grafana/runtime', () => ({
getBackendSrv: jest.fn().mockReturnValue({
get: jest.fn(),
}),
}));
describe('PluginSettings', () => {
beforeEach(() => {
jest.clearAllMocks();
clearPluginSettingsCache();
});
it('should fetch settings when cache is empty', async () => {
// arrange
const testPluginResponse = {
name: 'TestPlugin',
type: 'datasource',
id: 'test-plugin',
enabled: true,
};
getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse);
const getRequestSpy = jest.spyOn(getBackendSrv(), 'get');
// act
const response = await getPluginSettings('test');
// assert
expect(response).toEqual(testPluginResponse);
expect(getRequestSpy).toHaveBeenCalledTimes(1);
expect(getRequestSpy).toHaveBeenCalledWith('/api/plugins/test/settings');
});
it('should fetch settings from cache when it has a hit', async () => {
// arrange
const testPluginResponse = {
name: 'TestPlugin',
type: 'datasource',
id: 'test-plugin',
enabled: true,
};
getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse);
const getRequestSpy = jest.spyOn(getBackendSrv(), 'get');
// act
const response1 = await getPluginSettings('test');
const response2 = await getPluginSettings('test');
// assert
expect(response1).toEqual(testPluginResponse);
expect(response2).toEqual(testPluginResponse);
expect(getRequestSpy).toHaveBeenCalledTimes(1);
});
it('should refetch from backend when cache is cleared', async () => {
// arrange
const testPluginResponse = {
name: 'TestPlugin',
type: 'datasource',
id: 'test-plugin',
enabled: true,
};
getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse);
const getRequestSpy = jest.spyOn(getBackendSrv(), 'get');
// act
const response1 = await getPluginSettings('test');
await clearPluginSettingsCache('test');
const response2 = await getPluginSettings('test');
// assert
expect(response1).toEqual(testPluginResponse);
expect(response2).toEqual(testPluginResponse);
expect(getRequestSpy).toHaveBeenCalledTimes(2);
});
it('should fetch from cache when it is cleared for another plugin setting', async () => {
// arrange
const testPluginResponse = {
name: 'TestPlugin',
type: 'datasource',
id: 'test-plugin',
enabled: true,
};
getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse);
const getRequestSpy = jest.spyOn(getBackendSrv(), 'get');
// act
const response1 = await getPluginSettings('test');
await clearPluginSettingsCache('another-test');
const response2 = await getPluginSettings('test');
// assert
expect(response1).toEqual(testPluginResponse);
expect(response2).toEqual(testPluginResponse);
expect(getRequestSpy).toHaveBeenCalledTimes(1);
});
it('should clear all cache when no plugin id is provided to the clear function', async () => {
// arrange
const testPluginResponse = {
name: 'TestPlugin',
type: 'datasource',
id: 'test-plugin',
enabled: true,
};
getBackendSrv().get = jest.fn().mockResolvedValue(testPluginResponse);
const getRequestSpy = jest.spyOn(getBackendSrv(), 'get');
// act
const response1 = await getPluginSettings('test');
await clearPluginSettingsCache();
const response2 = await getPluginSettings('test');
// assert
expect(response1).toEqual(testPluginResponse);
expect(response2).toEqual(testPluginResponse);
expect(getRequestSpy).toHaveBeenCalledTimes(2);
});
});

View File

@ -22,3 +22,11 @@ export function getPluginSettings(pluginId: string): Promise<PluginMeta> {
return Promise.reject(new Error('Unknown Plugin'));
});
}
export const clearPluginSettingsCache = (pluginId?: string) => {
if (pluginId) {
return delete pluginInfoCache[pluginId];
}
// clear all
return Object.keys(pluginInfoCache).forEach((key) => delete pluginInfoCache[key]);
};

View File

@ -1,4 +1,5 @@
import { invalidatePluginInCache, locateWithCache, registerPluginInCache } from '../pluginCacheBuster';
import * as pluginSettings from '../pluginSettings';
describe('PluginCacheBuster', () => {
const now = 12345;
@ -35,6 +36,20 @@ describe('PluginCacheBuster', () => {
const url = `${address}?_cache=${encodeURI(String(now))}`;
expect(locateWithCache({ address }, now)).toBe(url);
});
it('should also clear plugin settings cache', () => {
const slug = 'bubble-chart-3';
const version = 'v1.0.0';
const path = resolvePath(slug);
const clearPluginSettingsCacheSpy = jest.spyOn(pluginSettings, 'clearPluginSettingsCache');
registerPluginInCache({ path, version });
invalidatePluginInCache(slug);
expect(clearPluginSettingsCacheSpy).toBeCalledTimes(1);
expect(clearPluginSettingsCacheSpy).toBeCalledWith('bubble-chart-3');
});
});
function resolvePath(slug: string): string {