| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | package expr | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/stretchr/testify/require" | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana/pkg/services/datasources" | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 							"expression": "B", | 
					
						
							|  |  |  | 							"reducer": "mean", | 
					
						
							|  |  |  | 							"type": "reduce" | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID: "B", | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 						DataSource: &datasources.DataSource{ | 
					
						
							| 
									
										
										
										
											2023-02-03 00:22:43 +08:00
										 |  |  | 							UID: "Fake", | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2022-10-27 04:13:58 +08:00
										 |  |  | 						TimeRange: AbsoluteTimeRange{}, | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedOrder: []string{"B", "A"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "cycle will error", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 								"expression": "$B", | 
					
						
							|  |  |  | 								"type": "math" | 
					
						
							|  |  |  | 							}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "B", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 								"expression": "$A", | 
					
						
							|  |  |  | 								"type": "math" | 
					
						
							|  |  |  | 							}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectErrContains: "cyclic components", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "self reference will error", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 								"expression": "$A", | 
					
						
							|  |  |  | 								"type": "math" | 
					
						
							|  |  |  | 							}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2022-09-22 03:14:11 +08:00
										 |  |  | 			expectErrContains: "expression 'A' cannot reference itself. Must be query or another expression", | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "missing dependency will error", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 								"expression": "$B", | 
					
						
							|  |  |  | 								"type": "math" | 
					
						
							|  |  |  | 							}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectErrContains: "find dependent", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "classic can not take input from another expression", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						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" | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							] | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "B", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 							"expression": "C", | 
					
						
							|  |  |  | 							"reducer": "mean", | 
					
						
							|  |  |  | 							"type": "reduce" | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID: "C", | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 						DataSource: &datasources.DataSource{ | 
					
						
							| 
									
										
										
										
											2023-02-03 00:22:43 +08:00
										 |  |  | 							UID: "Fake", | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2022-10-27 04:13:58 +08:00
										 |  |  | 						TimeRange: AbsoluteTimeRange{}, | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectErrContains: "only data source queries may be inputs to a classic condition", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			name: "classic can not output to another expression", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						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" | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							] | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "B", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 							"expression": "A", | 
					
						
							|  |  |  | 							"reducer": "mean", | 
					
						
							|  |  |  | 							"type": "reduce" | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID: "C", | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 						DataSource: &datasources.DataSource{ | 
					
						
							| 
									
										
										
										
											2023-02-03 00:22:43 +08:00
										 |  |  | 							UID: "Fake", | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2022-10-27 04:13:58 +08:00
										 |  |  | 						TimeRange: AbsoluteTimeRange{}, | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectErrContains: "classic conditions may not be the input for other expressions", | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			name: "Queries with new datasource ref object", | 
					
						
							|  |  |  | 			req: &Request{ | 
					
						
							|  |  |  | 				Queries: []Query{ | 
					
						
							|  |  |  | 					{ | 
					
						
							| 
									
										
										
										
											2021-12-17 00:51:46 +08:00
										 |  |  | 						RefID:      "A", | 
					
						
							|  |  |  | 						DataSource: DataSourceModel(), | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 						JSON: json.RawMessage(`{ | 
					
						
							|  |  |  | 							"expression": "B", | 
					
						
							|  |  |  | 							"reducer": "mean", | 
					
						
							|  |  |  | 							"type": "reduce" | 
					
						
							|  |  |  | 						}`), | 
					
						
							|  |  |  | 					}, | 
					
						
							|  |  |  | 					{ | 
					
						
							|  |  |  | 						RefID: "B", | 
					
						
							| 
									
										
										
										
											2022-06-28 00:23:15 +08:00
										 |  |  | 						DataSource: &datasources.DataSource{ | 
					
						
							| 
									
										
										
										
											2023-02-03 00:22:43 +08:00
										 |  |  | 							UID: "Fake", | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 						}, | 
					
						
							| 
									
										
										
										
											2022-10-27 04:13:58 +08:00
										 |  |  | 						TimeRange: AbsoluteTimeRange{}, | 
					
						
							| 
									
										
										
										
											2021-11-05 23:12:55 +08:00
										 |  |  | 					}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			expectedOrder: []string{"B", "A"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2021-04-27 19:22:11 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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 | 
					
						
							|  |  |  | } |