mirror of https://github.com/grafana/grafana
SSE: limit allowed input/output to/from classic conditions (#33337)
* add tests for graph and specific cases in this prpull/33420/head
parent
83d24b5aee
commit
f5efe97763
@ -0,0 +1,220 @@ |
|||||||
|
package expr |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"testing" |
||||||
|
|
||||||
|
"github.com/stretchr/testify/require" |
||||||
|
) |
||||||
|
|
||||||
|
func TestServicebuildPipeLine(t *testing.T) { |
||||||
|
var tests = []struct { |
||||||
|
name string |
||||||
|
req *Request |
||||||
|
expectedOrder []string |
||||||
|
expectErrContains string |
||||||
|
}{ |
||||||
|
{ |
||||||
|
name: "simple: a requires b", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "B", |
||||||
|
"reducer": "mean", |
||||||
|
"type": "reduce" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "B", |
||||||
|
DatasourceUID: "Fake", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectedOrder: []string{"B", "A"}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "cycle will error", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "$B", |
||||||
|
"type": "math" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "B", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "$A", |
||||||
|
"type": "math" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectErrContains: "cyclic components", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "self reference will error", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "$A", |
||||||
|
"type": "math" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectErrContains: "self referencing node", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "missing dependency will error", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "$B", |
||||||
|
"type": "math" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectErrContains: "find dependent", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "classic can not take input from another expression", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"type": "classic_conditions", |
||||||
|
"conditions": [ |
||||||
|
{ |
||||||
|
"evaluator": { |
||||||
|
"params": [ |
||||||
|
2, |
||||||
|
3 |
||||||
|
], |
||||||
|
"type": "within_range" |
||||||
|
}, |
||||||
|
"operator": { |
||||||
|
"type": "or" |
||||||
|
}, |
||||||
|
"query": { |
||||||
|
"params": [ |
||||||
|
"B" |
||||||
|
] |
||||||
|
}, |
||||||
|
"reducer": { |
||||||
|
"params": [], |
||||||
|
"type": "diff" |
||||||
|
}, |
||||||
|
"type": "query" |
||||||
|
} |
||||||
|
] |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "B", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "C", |
||||||
|
"reducer": "mean", |
||||||
|
"type": "reduce" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "C", |
||||||
|
DatasourceUID: "Fake", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectErrContains: "only data source queries may be inputs to a classic condition", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "classic can not output to another expression", |
||||||
|
req: &Request{ |
||||||
|
Queries: []Query{ |
||||||
|
{ |
||||||
|
RefID: "A", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"type": "classic_conditions", |
||||||
|
"conditions": [ |
||||||
|
{ |
||||||
|
"evaluator": { |
||||||
|
"params": [ |
||||||
|
2, |
||||||
|
3 |
||||||
|
], |
||||||
|
"type": "within_range" |
||||||
|
}, |
||||||
|
"operator": { |
||||||
|
"type": "or" |
||||||
|
}, |
||||||
|
"query": { |
||||||
|
"params": [ |
||||||
|
"C" |
||||||
|
] |
||||||
|
}, |
||||||
|
"reducer": { |
||||||
|
"params": [], |
||||||
|
"type": "diff" |
||||||
|
}, |
||||||
|
"type": "query" |
||||||
|
} |
||||||
|
] |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "B", |
||||||
|
DatasourceUID: DatasourceUID, |
||||||
|
JSON: json.RawMessage(`{ |
||||||
|
"expression": "A", |
||||||
|
"reducer": "mean", |
||||||
|
"type": "reduce" |
||||||
|
}`), |
||||||
|
}, |
||||||
|
{ |
||||||
|
RefID: "C", |
||||||
|
DatasourceUID: "Fake", |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
expectErrContains: "classic conditions may not be the input for other expressions", |
||||||
|
}, |
||||||
|
} |
||||||
|
s := Service{} |
||||||
|
for _, tt := range tests { |
||||||
|
t.Run(tt.name, func(t *testing.T) { |
||||||
|
nodes, err := s.buildPipeline(tt.req) |
||||||
|
if tt.expectErrContains != "" { |
||||||
|
require.Error(t, err) |
||||||
|
require.Contains(t, err.Error(), tt.expectErrContains) |
||||||
|
} else { |
||||||
|
require.NoError(t, err) |
||||||
|
require.Equal(t, tt.expectedOrder, getRefIDOrder(nodes)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
func getRefIDOrder(nodes []Node) []string { |
||||||
|
ids := make([]string, 0, len(nodes)) |
||||||
|
for _, n := range nodes { |
||||||
|
ids = append(ids, n.RefID()) |
||||||
|
} |
||||||
|
return ids |
||||||
|
} |
||||||
Loading…
Reference in new issue