DataSourceApi: convert interface to abstract class (#16979)

* DataSourceApi as class

* add diff signature

* Prometheus: moved directUrl to jsonData
pull/16999/head
Ryan McKinley 6 years ago committed by Torkel Ödegaard
parent 5573d28582
commit 1d7bb2a763
  1. 33
      packages/grafana-ui/src/types/datasource.ts
  2. 1
      packages/grafana-ui/src/utils/moment_wrapper.ts
  3. 12
      pkg/api/frontendsettings.go
  4. 2
      public/app/features/plugins/datasource_srv.ts
  5. 5
      public/app/plugins/datasource/cloudwatch/datasource.ts
  6. 7
      public/app/plugins/datasource/grafana-azure-monitor-datasource/datasource.ts
  7. 16
      public/app/plugins/datasource/input/InputDatasource.ts
  8. 37
      public/app/plugins/datasource/loki/datasource.test.ts
  9. 21
      public/app/plugins/datasource/loki/datasource.ts
  10. 6
      public/app/plugins/datasource/loki/types.ts
  11. 8
      public/app/plugins/datasource/mixed/datasource.ts
  12. 26
      public/app/plugins/datasource/prometheus/datasource.ts
  13. 12
      public/app/plugins/datasource/prometheus/specs/completer.test.ts
  14. 24
      public/app/plugins/datasource/prometheus/specs/datasource.test.ts
  15. 6
      public/app/plugins/datasource/prometheus/specs/metric_find_query.test.ts
  16. 9
      public/app/plugins/datasource/prometheus/types.ts
  17. 21
      public/app/plugins/datasource/stackdriver/datasource.ts
  18. 42
      public/app/plugins/datasource/stackdriver/specs/datasource.test.ts
  19. 7
      public/app/plugins/datasource/stackdriver/types.ts
  20. 5
      public/app/plugins/datasource/testdata/datasource.ts
  21. 13
      public/test/mocks/datasource_srv.ts

@ -117,15 +117,30 @@ export interface DataSourceConstructor<
/**
* The main data source abstraction interface, represents an instance of a data source
*/
export interface DataSourceApi<
export abstract class DataSourceApi<
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> {
/**
* Set in constructor
*/
readonly name: string;
/**
* Set in constructor
*/
readonly id: number;
/**
* min interval range
*/
interval?: string;
constructor(instanceSettings: DataSourceInstanceSettings<TOptions>) {
this.name = instanceSettings.name;
this.id = instanceSettings.id;
}
/**
* Imports queries from a different datasource
*/
@ -139,12 +154,12 @@ export interface DataSourceApi<
/**
* Main metrics / data query action
*/
query(options: DataQueryRequest<TQuery>, observer?: DataStreamObserver): Promise<DataQueryResponse>;
abstract query(options: DataQueryRequest<TQuery>, observer?: DataStreamObserver): Promise<DataQueryResponse>;
/**
* Test & verify datasource settings & connection details
*/
testDatasource(): Promise<any>;
abstract testDatasource(): Promise<any>;
/**
* Get hints for query improvements
@ -156,16 +171,6 @@ export interface DataSourceApi<
*/
getQueryDisplayText?(query: TQuery): string;
/**
* Set after constructor is called by Grafana
*/
name?: string;
/**
* Set after constructor is called by Grafana
*/
id?: number;
/**
* Set after constructor call, as the data source instance is the most common thing to pass around
* we attach the components to this instance for easy access
@ -178,7 +183,7 @@ export interface DataSourceApi<
meta?: DataSourcePluginMeta;
}
export interface ExploreDataSourceApi<
export abstract class ExploreDataSourceApi<
TQuery extends DataQuery = DataQuery,
TOptions extends DataSourceJsonData = DataSourceJsonData
> extends DataSourceApi<TQuery, TOptions> {

@ -59,6 +59,7 @@ export interface DateTime extends Object {
subtract: (amount?: DateTimeInput, unit?: DurationUnit) => DateTime;
toDate: () => Date;
toISOString: () => string;
diff: (amount: DateTimeInput, unit?: DurationUnit, truncate?: boolean) => number;
valueOf: () => number;
unix: () => number;
utc: () => DateTime;

@ -3,6 +3,7 @@ package api
import (
"strconv"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/bus"
@ -86,12 +87,13 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
defaultDatasource = ds.Name
}
if ds.JsonData != nil {
dsMap["jsonData"] = ds.JsonData
} else {
dsMap["jsonData"] = make(map[string]string)
jsonData := ds.JsonData
if jsonData == nil {
jsonData = simplejson.New()
}
dsMap["jsonData"] = jsonData
if ds.Access == m.DS_ACCESS_DIRECT {
if ds.BasicAuth {
dsMap["basicAuth"] = util.GetBasicAuthHeader(ds.BasicAuthUser, ds.DecryptedBasicAuthPassword())
@ -123,7 +125,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
if ds.Type == m.DS_PROMETHEUS {
// add unproxied server URL for link to Prometheus web UI
dsMap["directUrl"] = ds.Url
jsonData.Set("directUrl", ds.Url)
}
datasources[ds.Name] = dsMap

@ -65,8 +65,6 @@ export class DatasourceSrv {
instanceSettings: dsConfig,
});
instance.id = dsConfig.id;
instance.name = name;
instance.components = dsPlugin.components;
instance.meta = dsConfig.meta;

@ -9,9 +9,8 @@ import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
// import * as moment from 'moment';
export default class CloudWatchDatasource implements DataSourceApi<CloudWatchQuery> {
export default class CloudWatchDatasource extends DataSourceApi<CloudWatchQuery> {
type: any;
name: any;
proxyUrl: any;
defaultRegion: any;
standardStatistics: any;
@ -24,8 +23,8 @@ export default class CloudWatchDatasource implements DataSourceApi<CloudWatchQue
private templateSrv: TemplateSrv,
private timeSrv: TimeSrv
) {
super(instanceSettings);
this.type = 'cloudwatch';
this.name = instanceSettings.name;
this.proxyUrl = instanceSettings.url;
this.defaultRegion = instanceSettings.jsonData.defaultRegion;
this.instanceSettings = instanceSettings;

@ -7,9 +7,7 @@ import { DataSourceApi, DataQueryRequest, DataSourceInstanceSettings } from '@gr
import { BackendSrv } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
export default class Datasource implements DataSourceApi<AzureMonitorQuery, AzureDataSourceJsonData> {
id: number;
name: string;
export default class Datasource extends DataSourceApi<AzureMonitorQuery, AzureDataSourceJsonData> {
azureMonitorDatasource: AzureMonitorDatasource;
appInsightsDatasource: AppInsightsDatasource;
azureLogAnalyticsDatasource: AzureLogAnalyticsDatasource;
@ -21,8 +19,7 @@ export default class Datasource implements DataSourceApi<AzureMonitorQuery, Azur
private templateSrv: TemplateSrv,
private $q
) {
this.name = instanceSettings.name;
this.id = instanceSettings.id;
super(instanceSettings);
this.azureMonitorDatasource = new AzureMonitorDatasource(instanceSettings, this.backendSrv, this.templateSrv);
this.appInsightsDatasource = new AppInsightsDatasource(
instanceSettings,

@ -8,23 +8,13 @@ import {
} from '@grafana/ui/src/types';
import { InputQuery, InputOptions } from './types';
export class InputDatasource implements DataSourceApi<InputQuery, InputOptions> {
export class InputDatasource extends DataSourceApi<InputQuery, InputOptions> {
data: SeriesData[];
// Filled in by grafana plugin system
name?: string;
// Filled in by grafana plugin system
id?: number;
constructor(instanceSettings: DataSourceInstanceSettings<InputOptions>) {
if (instanceSettings.jsonData) {
this.data = instanceSettings.jsonData.data;
}
super(instanceSettings);
if (!this.data) {
this.data = [];
}
this.data = instanceSettings.jsonData.data ? instanceSettings.jsonData.data : [];
}
getDescription(data: SeriesData[]): string {

@ -2,6 +2,8 @@ import LokiDatasource from './datasource';
import { LokiQuery } from './types';
import { getQueryOptions } from 'test/helpers/getQueryOptions';
import { SeriesData } from '@grafana/ui';
import { BackendSrv } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
describe('LokiDatasource', () => {
const instanceSettings: any = {
@ -21,14 +23,15 @@ describe('LokiDatasource', () => {
describe('when querying', () => {
const backendSrvMock = { datasourceRequest: jest.fn() };
const backendSrv = (backendSrvMock as unknown) as BackendSrv;
const templateSrvMock = {
const templateSrvMock = ({
getAdhocFilters: () => [],
replace: a => a,
};
} as unknown) as TemplateSrv;
test('should use default max lines when no limit given', () => {
const ds = new LokiDatasource(instanceSettings, backendSrvMock, templateSrvMock);
const ds = new LokiDatasource(instanceSettings, backendSrv, templateSrvMock);
backendSrvMock.datasourceRequest = jest.fn(() => Promise.resolve(testResp));
const options = getQueryOptions<LokiQuery>({ targets: [{ expr: 'foo', refId: 'B' }] });
@ -41,7 +44,7 @@ describe('LokiDatasource', () => {
test('should use custom max lines if limit is set', () => {
const customData = { ...(instanceSettings.jsonData || {}), maxLines: 20 };
const customSettings = { ...instanceSettings, jsonData: customData };
const ds = new LokiDatasource(customSettings, backendSrvMock, templateSrvMock);
const ds = new LokiDatasource(customSettings, backendSrv, templateSrvMock);
backendSrvMock.datasourceRequest = jest.fn(() => Promise.resolve(testResp));
const options = getQueryOptions<LokiQuery>({ targets: [{ expr: 'foo', refId: 'B' }] });
@ -54,7 +57,7 @@ describe('LokiDatasource', () => {
test('should return series data', async done => {
const customData = { ...(instanceSettings.jsonData || {}), maxLines: 20 };
const customSettings = { ...instanceSettings, jsonData: customData };
const ds = new LokiDatasource(customSettings, backendSrvMock, templateSrvMock);
const ds = new LokiDatasource(customSettings, backendSrv, templateSrvMock);
backendSrvMock.datasourceRequest = jest.fn(() => Promise.resolve(testResp));
const options = getQueryOptions<LokiQuery>({
@ -77,7 +80,7 @@ describe('LokiDatasource', () => {
describe('and call succeeds', () => {
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.resolve({
status: 200,
@ -86,8 +89,8 @@ describe('LokiDatasource', () => {
},
});
},
};
ds = new LokiDatasource(instanceSettings, backendSrv, {});
} as unknown) as BackendSrv;
ds = new LokiDatasource(instanceSettings, backendSrv, {} as TemplateSrv);
result = await ds.testDatasource();
});
@ -98,7 +101,7 @@ describe('LokiDatasource', () => {
describe('and call fails with 401 error', () => {
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.reject({
statusText: 'Unauthorized',
@ -108,8 +111,8 @@ describe('LokiDatasource', () => {
},
});
},
};
ds = new LokiDatasource(instanceSettings, backendSrv, {});
} as unknown) as BackendSrv;
ds = new LokiDatasource(instanceSettings, backendSrv, {} as TemplateSrv);
result = await ds.testDatasource();
});
@ -121,7 +124,7 @@ describe('LokiDatasource', () => {
describe('and call fails with 404 error', () => {
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.reject({
statusText: 'Not found',
@ -129,8 +132,8 @@ describe('LokiDatasource', () => {
data: '404 page not found',
});
},
};
ds = new LokiDatasource(instanceSettings, backendSrv, {});
} as unknown) as BackendSrv;
ds = new LokiDatasource(instanceSettings, backendSrv, {} as TemplateSrv);
result = await ds.testDatasource();
});
@ -142,7 +145,7 @@ describe('LokiDatasource', () => {
describe('and call fails with 502 error', () => {
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.reject({
statusText: 'Bad Gateway',
@ -150,8 +153,8 @@ describe('LokiDatasource', () => {
data: '',
});
},
};
ds = new LokiDatasource(instanceSettings, backendSrv, {});
} as unknown) as BackendSrv;
ds = new LokiDatasource(instanceSettings, backendSrv, {} as TemplateSrv);
result = await ds.testDatasource();
});

@ -9,8 +9,16 @@ import { logStreamToSeriesData } from './result_transformer';
import { formatQuery, parseQuery } from './query_utils';
// Types
import { PluginMeta, DataQueryRequest, SeriesData } from '@grafana/ui/src/types';
import { LokiQuery } from './types';
import {
PluginMeta,
DataQueryRequest,
SeriesData,
DataSourceApi,
DataSourceInstanceSettings,
} from '@grafana/ui/src/types';
import { LokiQuery, LokiOptions } from './types';
import { BackendSrv } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
export const DEFAULT_MAX_LINES = 1000;
@ -30,12 +38,17 @@ function serializeParams(data: any) {
.join('&');
}
export class LokiDatasource {
export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
languageProvider: LanguageProvider;
maxLines: number;
/** @ngInject */
constructor(private instanceSettings, private backendSrv, private templateSrv) {
constructor(
private instanceSettings: DataSourceInstanceSettings<LokiOptions>,
private backendSrv: BackendSrv,
private templateSrv: TemplateSrv
) {
super(instanceSettings);
this.languageProvider = new LanguageProvider(this);
const settingsData = instanceSettings.jsonData || {};
this.maxLines = parseInt(settingsData.maxLines, 10) || DEFAULT_MAX_LINES;

@ -1,9 +1,13 @@
import { DataQuery, Labels } from '@grafana/ui/src/types';
import { DataQuery, Labels, DataSourceJsonData } from '@grafana/ui/src/types';
export interface LokiQuery extends DataQuery {
expr: string;
}
export interface LokiOptions extends DataSourceJsonData {
maxLines?: string;
}
export interface LokiLogsStream {
labels: string;
entries: LokiLogsStreamEntry[];

@ -1,11 +1,13 @@
import _ from 'lodash';
import { DataSourceApi, DataQuery, DataQueryRequest } from '@grafana/ui';
import { DataSourceApi, DataQuery, DataQueryRequest, DataSourceInstanceSettings } from '@grafana/ui';
import DatasourceSrv from 'app/features/plugins/datasource_srv';
class MixedDatasource implements DataSourceApi<DataQuery> {
class MixedDatasource extends DataSourceApi<DataQuery> {
/** @ngInject */
constructor(private datasourceSrv: DatasourceSrv) {}
constructor(instanceSettings: DataSourceInstanceSettings, private datasourceSrv: DatasourceSrv) {
super(instanceSettings);
}
query(options: DataQueryRequest<DataQuery>) {
const sets = _.groupBy(options.targets, 'datasource');

@ -14,14 +14,15 @@ import { getQueryHints } from './query_hints';
import { expandRecordingRules } from './language_utils';
// Types
import { PromQuery } from './types';
import { DataQueryRequest, DataSourceApi, AnnotationEvent } from '@grafana/ui/src/types';
import { PromQuery, PromOptions } from './types';
import { DataQueryRequest, DataSourceApi, AnnotationEvent, DataSourceInstanceSettings } from '@grafana/ui/src/types';
import { ExploreUrlState } from 'app/types/explore';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
export class PrometheusDatasource implements DataSourceApi<PromQuery> {
export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions> {
type: string;
editorSrc: string;
name: string;
ruleMappings: { [index: string]: string };
url: string;
directUrl: string;
@ -35,25 +36,32 @@ export class PrometheusDatasource implements DataSourceApi<PromQuery> {
resultTransformer: ResultTransformer;
/** @ngInject */
constructor(instanceSettings, private $q, private backendSrv: BackendSrv, private templateSrv, private timeSrv) {
constructor(
instanceSettings: DataSourceInstanceSettings<PromOptions>,
private $q,
private backendSrv: BackendSrv,
private templateSrv: TemplateSrv,
private timeSrv: TimeSrv
) {
super(instanceSettings);
this.type = 'prometheus';
this.editorSrc = 'app/features/prometheus/partials/query.editor.html';
this.name = instanceSettings.name;
this.url = instanceSettings.url;
this.directUrl = instanceSettings.directUrl;
this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials;
this.interval = instanceSettings.jsonData.timeInterval || '15s';
this.queryTimeout = instanceSettings.jsonData.queryTimeout;
this.httpMethod = instanceSettings.jsonData.httpMethod || 'GET';
this.directUrl = instanceSettings.jsonData.directUrl;
this.resultTransformer = new ResultTransformer(templateSrv);
this.ruleMappings = {};
this.languageProvider = new PrometheusLanguageProvider(this);
}
init() {
init = () => {
this.loadRules();
}
};
getQueryDisplayText(query: PromQuery) {
return query.expr;

@ -1,6 +1,10 @@
import { PromCompleter } from '../completer';
import { PrometheusDatasource } from '../datasource';
import { BackendSrv } from 'app/core/services/backend_srv';
import { DataSourceInstanceSettings } from '@grafana/ui';
import { PromOptions } from '../types';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
jest.mock('../datasource');
jest.mock('app/core/services/backend_srv');
@ -16,7 +20,13 @@ describe('Prometheus editor completer', () => {
const editor = {};
const backendSrv = {} as BackendSrv;
const datasourceStub = new PrometheusDatasource({}, {}, backendSrv, {}, {});
const datasourceStub = new PrometheusDatasource(
{} as DataSourceInstanceSettings<PromOptions>,
{},
backendSrv,
{} as TemplateSrv,
{} as TimeSrv
);
datasourceStub.metadataRequest = jest.fn(() =>
Promise.resolve({ data: { data: [{ metric: { job: 'node', instance: 'localhost:9100' } }] } })

@ -8,6 +8,10 @@ import {
prometheusSpecialRegexEscape,
} from '../datasource';
import { dateTime } from '@grafana/ui/src/utils/moment_wrapper';
import { DataSourceInstanceSettings } from '@grafana/ui';
import { PromOptions } from '../types';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
jest.mock('../metric_find_query');
@ -18,13 +22,13 @@ const DEFAULT_TEMPLATE_SRV_MOCK = {
describe('PrometheusDatasource', () => {
const ctx: any = {};
const instanceSettings = {
const instanceSettings = ({
url: 'proxied',
directUrl: 'direct',
user: 'test',
password: 'mupp',
jsonData: {} as any,
};
} as unknown) as DataSourceInstanceSettings<PromOptions>;
ctx.backendSrvMock = {};
@ -347,27 +351,27 @@ const HOUR = 60 * MINUTE;
const time = ({ hours = 0, seconds = 0, minutes = 0 }) => dateTime(hours * HOUR + minutes * MINUTE + seconds * SECOND);
const ctx = {} as any;
const instanceSettings = {
const instanceSettings = ({
url: 'proxied',
directUrl: 'direct',
user: 'test',
password: 'mupp',
jsonData: { httpMethod: 'GET' },
};
} as unknown) as DataSourceInstanceSettings<PromOptions>;
const backendSrv = {
datasourceRequest: jest.fn(),
} as any;
const templateSrv = {
const templateSrv = ({
getAdhocFilters: () => [],
replace: jest.fn(str => str),
};
} as unknown) as TemplateSrv;
const timeSrv = {
const timeSrv = ({
timeRange: () => {
return { to: { diff: () => 2000 }, from: '' };
},
};
} as unknown) as TimeSrv;
describe('PrometheusDatasource', () => {
describe('When querying prometheus with one target using query editor target spec', () => {
@ -1177,13 +1181,13 @@ describe('PrometheusDatasource', () => {
describe('PrometheusDatasource for POST', () => {
// const ctx = new helpers.ServiceTestContext();
const instanceSettings = {
const instanceSettings = ({
url: 'proxied',
directUrl: 'direct',
user: 'test',
password: 'mupp',
jsonData: { httpMethod: 'POST' },
};
} as unknown) as DataSourceInstanceSettings<PromOptions>;
describe('When querying prometheus with one target using query editor target spec', () => {
let results;

@ -2,15 +2,17 @@ import { PrometheusDatasource } from '../datasource';
import PrometheusMetricFindQuery from '../metric_find_query';
import q from 'q';
import { toUtc } from '@grafana/ui/src/utils/moment_wrapper';
import { DataSourceInstanceSettings } from '@grafana/ui';
import { PromOptions } from '../types';
describe('PrometheusMetricFindQuery', () => {
const instanceSettings = {
const instanceSettings = ({
url: 'proxied',
directUrl: 'direct',
user: 'test',
password: 'mupp',
jsonData: { httpMethod: 'GET' },
};
} as unknown) as DataSourceInstanceSettings<PromOptions>;
const raw = {
from: toUtc('2018-04-25 10:00'),
to: toUtc('2018-04-25 11:00'),

@ -1,5 +1,12 @@
import { DataQuery } from '@grafana/ui/src/types';
import { DataQuery, DataSourceJsonData } from '@grafana/ui/src/types';
export interface PromQuery extends DataQuery {
expr: string;
}
export interface PromOptions extends DataSourceJsonData {
timeInterval: string;
queryTimeout: string;
httpMethod: string;
directUrl: string;
}

@ -2,11 +2,13 @@ import { stackdriverUnitMappings } from './constants';
import appEvents from 'app/core/app_events';
import _ from 'lodash';
import StackdriverMetricFindQuery from './StackdriverMetricFindQuery';
import { StackdriverQuery, MetricDescriptor } from './types';
import { DataSourceApi, DataQueryRequest } from '@grafana/ui/src/types';
import { StackdriverQuery, MetricDescriptor, StackdriverOptions } from './types';
import { DataSourceApi, DataQueryRequest, DataSourceInstanceSettings, ScopedVars } from '@grafana/ui/src/types';
import { BackendSrv } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
export default class StackdriverDatasource implements DataSourceApi<StackdriverQuery> {
id: number;
export default class StackdriverDatasource extends DataSourceApi<StackdriverQuery, StackdriverOptions> {
url: string;
baseUrl: string;
projectName: string;
@ -15,10 +17,15 @@ export default class StackdriverDatasource implements DataSourceApi<StackdriverQ
metricTypes: any[];
/** @ngInject */
constructor(instanceSettings, private backendSrv, private templateSrv, private timeSrv) {
constructor(
instanceSettings: DataSourceInstanceSettings<StackdriverOptions>,
private backendSrv: BackendSrv,
private templateSrv: TemplateSrv,
private timeSrv: TimeSrv
) {
super(instanceSettings);
this.baseUrl = `/stackdriver/`;
this.url = instanceSettings.url;
this.id = instanceSettings.id;
this.projectName = instanceSettings.jsonData.defaultProject || '';
this.authenticationType = instanceSettings.jsonData.authenticationType || 'jwt';
this.metricTypes = [];
@ -62,7 +69,7 @@ export default class StackdriverDatasource implements DataSourceApi<StackdriverQ
}
}
interpolateFilters(filters: string[], scopedVars: object) {
interpolateFilters(filters: string[], scopedVars: ScopedVars) {
return (filters || []).map(f => {
return this.templateSrv.replace(f, scopedVars || {}, 'regex');
});

@ -3,26 +3,30 @@ import { metricDescriptors } from './testData';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { CustomVariable } from 'app/features/templating/all';
import { toUtc } from '@grafana/ui/src/utils/moment_wrapper';
import { DataSourceInstanceSettings } from '@grafana/ui';
import { StackdriverOptions } from '../types';
import { BackendSrv } from 'app/core/services/backend_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
describe('StackdriverDataSource', () => {
const instanceSettings = {
const instanceSettings = ({
jsonData: {
defaultProject: 'testproject',
},
};
} as unknown) as DataSourceInstanceSettings<StackdriverOptions>;
const templateSrv = new TemplateSrv();
const timeSrv = {};
const timeSrv = {} as TimeSrv;
describe('when performing testDataSource', () => {
describe('and call to stackdriver api succeeds', () => {
let ds;
let result;
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.resolve({ status: 200 });
},
};
} as unknown) as BackendSrv;
ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
result = await ds.testDatasource();
});
@ -35,9 +39,9 @@ describe('StackdriverDataSource', () => {
let ds;
let result;
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
datasourceRequest: async () => Promise.resolve({ status: 200, data: metricDescriptors }),
};
} as unknown) as BackendSrv;
ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
result = await ds.testDatasource();
});
@ -50,7 +54,7 @@ describe('StackdriverDataSource', () => {
let ds;
let result;
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
datasourceRequest: async () =>
Promise.reject({
statusText: 'Bad Request',
@ -58,7 +62,7 @@ describe('StackdriverDataSource', () => {
error: { code: 400, message: 'Field interval.endTime had an invalid value' },
},
}),
};
} as unknown) as BackendSrv;
ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
result = await ds.testDatasource();
});
@ -103,9 +107,9 @@ describe('StackdriverDataSource', () => {
};
beforeEach(() => {
const backendSrv = {
const backendSrv = ({
datasourceRequest: async () => Promise.resolve({ status: 200, data: response }),
};
} as unknown) as BackendSrv;
ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
});
@ -122,7 +126,7 @@ describe('StackdriverDataSource', () => {
let ds;
let result;
beforeEach(async () => {
const backendSrv = {
const backendSrv = ({
async datasourceRequest() {
return Promise.resolve({
data: {
@ -139,7 +143,7 @@ describe('StackdriverDataSource', () => {
},
});
},
};
} as unknown) as BackendSrv;
ds = new StackdriverDataSource(instanceSettings, backendSrv, templateSrv, timeSrv);
result = await ds.getMetricTypes();
});
@ -155,12 +159,14 @@ describe('StackdriverDataSource', () => {
});
});
const noopBackendSrv = ({} as unknown) as BackendSrv;
describe('when interpolating a template variable for the filter', () => {
let interpolated;
describe('and is single value variable', () => {
beforeEach(() => {
const filterTemplateSrv = initTemplateSrv('filtervalue1');
const ds = new StackdriverDataSource(instanceSettings, {}, filterTemplateSrv, timeSrv);
const ds = new StackdriverDataSource(instanceSettings, noopBackendSrv, filterTemplateSrv, timeSrv);
interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '${test}'], {});
});
@ -173,7 +179,7 @@ describe('StackdriverDataSource', () => {
describe('and is multi value variable', () => {
beforeEach(() => {
const filterTemplateSrv = initTemplateSrv(['filtervalue1', 'filtervalue2'], true);
const ds = new StackdriverDataSource(instanceSettings, {}, filterTemplateSrv, timeSrv);
const ds = new StackdriverDataSource(instanceSettings, noopBackendSrv, filterTemplateSrv, timeSrv);
interpolated = ds.interpolateFilters(['resource.label.zone', '=~', '[[test]]'], {});
});
@ -189,7 +195,7 @@ describe('StackdriverDataSource', () => {
describe('and is single value variable', () => {
beforeEach(() => {
const groupByTemplateSrv = initTemplateSrv('groupby1');
const ds = new StackdriverDataSource(instanceSettings, {}, groupByTemplateSrv, timeSrv);
const ds = new StackdriverDataSource(instanceSettings, noopBackendSrv, groupByTemplateSrv, timeSrv);
interpolated = ds.interpolateGroupBys(['[[test]]'], {});
});
@ -202,7 +208,7 @@ describe('StackdriverDataSource', () => {
describe('and is multi value variable', () => {
beforeEach(() => {
const groupByTemplateSrv = initTemplateSrv(['groupby1', 'groupby2'], true);
const ds = new StackdriverDataSource(instanceSettings, {}, groupByTemplateSrv, timeSrv);
const ds = new StackdriverDataSource(instanceSettings, noopBackendSrv, groupByTemplateSrv, timeSrv);
interpolated = ds.interpolateGroupBys(['[[test]]'], {});
});
@ -217,7 +223,7 @@ describe('StackdriverDataSource', () => {
describe('unit parsing', () => {
let ds, res;
beforeEach(() => {
ds = new StackdriverDataSource(instanceSettings, {}, templateSrv, timeSrv);
ds = new StackdriverDataSource(instanceSettings, noopBackendSrv, templateSrv, timeSrv);
});
describe('when theres only one target', () => {
describe('and the stackdriver unit doesnt have a corresponding grafana unit', () => {

@ -1,4 +1,4 @@
import { DataQuery } from '@grafana/ui/src/types';
import { DataQuery, DataSourceJsonData } from '@grafana/ui/src/types';
export enum MetricFindQueryTypes {
Services = 'services',
@ -40,6 +40,11 @@ export interface StackdriverQuery extends DataQuery {
view?: string;
}
export interface StackdriverOptions extends DataSourceJsonData {
defaultProject?: string;
authenticationType?: string;
}
export interface AnnotationTarget {
defaultProject: string;
metricType: string;

@ -17,13 +17,12 @@ export interface TestDataRegistry {
[key: string]: TestData[];
}
export class TestDataDatasource implements DataSourceApi<TestDataQuery> {
id: number;
export class TestDataDatasource extends DataSourceApi<TestDataQuery> {
streams = new StreamHandler();
/** @ngInject */
constructor(instanceSettings: DataSourceInstanceSettings) {
this.id = instanceSettings.id;
super(instanceSettings);
}
query(options: DataQueryRequest<TestDataQuery>, observer: DataStreamObserver) {

@ -1,4 +1,4 @@
import { DataSourceApi, DataQueryRequest, DataQueryResponse } from '@grafana/ui';
import { DataSourceApi, DataQueryRequest, DataQueryResponse, DataSourceInstanceSettings } from '@grafana/ui';
export class DatasourceSrvMock {
constructor(private defaultDS: DataSourceApi, private datasources: { [name: string]: DataSourceApi }) {
@ -17,14 +17,15 @@ export class DatasourceSrvMock {
}
}
export class MockDataSourceApi implements DataSourceApi {
name: string;
export class MockDataSourceApi extends DataSourceApi {
result: DataQueryResponse = { data: [] };
queryResolver: Promise<DataQueryResponse>;
constructor(DataQueryResponse, name?: string) {
this.name = name ? name : 'MockDataSourceApi';
constructor(name?: string, result?: DataQueryResponse) {
super({ name: name ? name : 'MockDataSourceApi' } as DataSourceInstanceSettings);
if (result) {
this.result = result;
}
}
query(request: DataQueryRequest): Promise<DataQueryResponse> {

Loading…
Cancel
Save