1+ import { MutableDataFrame } from '@grafana/data' ;
2+ import { cloneDeep } from 'lodash' ;
3+
4+ import { DataSource } from '../../src/DataSource' ;
5+ import { RequestSpec } from '../../src/RequestSpec' ;
6+ import RestApiBackend from '../../src/backend/rest' ;
7+ import WebApiBackend from '../../src/backend/web' ;
8+ import { Edition } from '../../src/types' ;
9+ import { labelForRequestSpecKey } from '../../src/ui/utils' ;
10+ import * as utils from '../../src/utils' ;
111import { buildRequestBody , buildUrlWithParams } from '../../src/webapi' ;
212
13+ jest . mock ( '../../src/utils' ) ;
14+
315describe ( 'URL conversions' , ( ) => {
416 it ( 'Params' , ( ) => {
517 expect ( buildUrlWithParams ( 'hi' , { A : '5' , TE : 'TTI' } ) ) . toBe ( 'hi?A=5&TE=TTI' ) ;
@@ -8,3 +20,113 @@ describe('URL conversions', () => {
820 expect ( buildRequestBody ( { spec : [ 'comb' , { site : 'heute' } ] } ) ) . toBe ( 'request={"spec":["comb",{"site":"heute"}]}' ) ;
921 } ) ;
1022} ) ;
23+
24+ // from https://stackoverflow.com/questions/42773836/how-to-find-all-subsets-of-a-set-in-javascript-powerset-of-array
25+ const allSubsets = ( values : string [ ] ) : string [ ] [ ] =>
26+ values . reduce ( ( subsets , value ) => subsets . concat ( subsets . map ( ( set ) => [ value , ...set ] ) ) , [ [ ] ] ) ;
27+
28+ const fullExampleRequestSpec : RequestSpec = {
29+ graph_type : 'predefined_graph' ,
30+ aggregation : 'off' ,
31+ site : 'monitoring' ,
32+ host_name : 'example.com' ,
33+ host_name_regex : {
34+ value : '*.org' ,
35+ negated : false ,
36+ } ,
37+ host_in_group : {
38+ value : 'printers' ,
39+ negated : true ,
40+ } ,
41+ host_labels : [ 'os:linux' ] ,
42+ host_tags : [ { } , { } , { } ] ,
43+ service : 'CPU load' ,
44+ service_regex : {
45+ value : 'CPU*' ,
46+ negated : true ,
47+ } ,
48+ service_in_group : {
49+ value : 'web_servers' ,
50+ negated : false ,
51+ } ,
52+ graph : 'Load Average' ,
53+ } ;
54+
55+ const getRequiredFields = ( edition : Edition ) : Array < keyof RequestSpec > => {
56+ const result : Array < keyof RequestSpec > = [ 'graph' ] ;
57+ if ( edition === 'RAW' ) {
58+ result . push ( 'site' , 'host_name' , 'service' ) ;
59+ }
60+ return result . sort ( ) ;
61+ } ;
62+
63+ describe . each ( [ { edition : 'RAW' } , { edition : 'CEE' } ] ) (
64+ 'Query Validation in Edition $edition' ,
65+ ( editionConfig : { edition : Edition } ) => {
66+ describe . each ( [ { backend : 'rest' } , { backend : 'web' } ] ) (
67+ 'with backend $backend' ,
68+ ( backendConfig : { backend : string } ) => {
69+ let subject : DataSource ;
70+ const requiredFields = getRequiredFields ( editionConfig . edition ) ;
71+ const cases = allSubsets ( requiredFields )
72+ . filter ( ( arr ) => arr . length > 0 )
73+ . map ( ( arr ) => arr . sort ( ) )
74+ . map ( ( value ) => ( { fields : value } ) ) ;
75+
76+ jest
77+ . spyOn ( RestApiBackend . prototype , 'getSingleGraph' )
78+ . mockImplementation ( ( ) => Promise . resolve ( 'It did succeed, sadly.' ) ) ;
79+
80+ jest
81+ . spyOn ( WebApiBackend . prototype , 'getGraphQuery' )
82+ . mockImplementation ( ( ) => Promise . resolve ( new MutableDataFrame ( ) ) ) ;
83+
84+ utils . replaceVariables . mockImplementation ( ( rq ) => rq ) ;
85+
86+ beforeEach ( ( ) => {
87+ subject = new DataSource ( { jsonData : { backend : backendConfig , edition : editionConfig . edition } } as any ) ;
88+ } ) ;
89+
90+ it . each ( cases ) (
91+ 'throws an informative error if the required fields $fields are missing in a query' ,
92+ async ( { fields } ) => {
93+ const requestSpec = cloneDeep ( fullExampleRequestSpec ) ;
94+ for ( const key of fields ) {
95+ delete requestSpec [ key ] ;
96+ }
97+ const dataQueryRequest = {
98+ targets : [
99+ {
100+ requestSpec,
101+ } ,
102+ ] ,
103+ range : [ 1 , 2 ] ,
104+ } as any ;
105+
106+ const errorMessageRegex = fields
107+ . map ( ( value ) => labelForRequestSpecKey ( value as keyof RequestSpec , requestSpec ) )
108+ . join ( ', ' ) ;
109+
110+ // make sure this test doesn't fail pass on a resolved promise
111+ expect . assertions ( 1 ) ;
112+ await expect ( subject . query ( dataQueryRequest ) ) . rejects . toThrow ( errorMessageRegex ) ;
113+ }
114+ ) ;
115+
116+ it ( 'validates even if site is an empty string' , async ( ) => {
117+ const requestSpec = cloneDeep ( fullExampleRequestSpec ) ;
118+ requestSpec [ 'site' ] = '' ;
119+ const dataQueryRequest = {
120+ targets : [
121+ {
122+ requestSpec,
123+ } ,
124+ ] ,
125+ range : [ 1 , 2 ] ,
126+ } as any ;
127+ await expect ( subject . query ( dataQueryRequest ) ) . resolves . not . toThrow ( ) ;
128+ } ) ;
129+ }
130+ ) ;
131+ }
132+ ) ;
0 commit comments