1// Copyright 2021 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14import { buildVectorMatching } from './vector';
15import { createEditorState } from '../test/utils.test';
16import { walkThrough } from './path-finder';
17import { BinaryExpr, Expr } from '../grammar/parser.terms';
18import chai from 'chai';
19import { syntaxTree } from '@codemirror/language';
20import { VectorMatchCardinality } from '../types';
21
22describe('buildVectorMatching test', () => {
23  const testCases = [
24    {
25      binaryExpr: 'foo * bar',
26      expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] },
27    },
28    {
29      binaryExpr: 'foo * sum',
30      expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] },
31    },
32    {
33      binaryExpr: 'foo == 1',
34      expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] },
35    },
36    {
37      binaryExpr: 'foo == bool 1',
38      expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] },
39    },
40    {
41      binaryExpr: '2.5 / bar',
42      expectedVectorMatching: { card: VectorMatchCardinality.CardOneToOne, matchingLabels: [], on: false, include: [] },
43    },
44    {
45      binaryExpr: 'foo and bar',
46      expectedVectorMatching: {
47        card: VectorMatchCardinality.CardManyToMany,
48        matchingLabels: [],
49        on: false,
50        include: [],
51      },
52    },
53    {
54      binaryExpr: 'foo or bar',
55      expectedVectorMatching: {
56        card: VectorMatchCardinality.CardManyToMany,
57        matchingLabels: [],
58        on: false,
59        include: [],
60      },
61    },
62    {
63      binaryExpr: 'foo unless bar',
64      expectedVectorMatching: {
65        card: VectorMatchCardinality.CardManyToMany,
66        matchingLabels: [],
67        on: false,
68        include: [],
69      },
70    },
71    {
72      // Test and/or precedence and reassigning of operands.
73      // Here it will test only the first VectorMatching so (a + b) or (c and d) ==> ManyToMany
74      binaryExpr: 'foo + bar or bla and blub',
75      expectedVectorMatching: {
76        card: VectorMatchCardinality.CardManyToMany,
77        matchingLabels: [],
78        on: false,
79        include: [],
80      },
81    },
82    {
83      // Test and/or/unless precedence.
84      // Here it will test only the first VectorMatching so ((a and b) unless c) or d ==> ManyToMany
85      binaryExpr: 'foo and bar unless baz or qux',
86      expectedVectorMatching: {
87        card: VectorMatchCardinality.CardManyToMany,
88        matchingLabels: [],
89        on: false,
90        include: [],
91      },
92    },
93    {
94      binaryExpr: 'foo * on(test,blub) bar',
95      expectedVectorMatching: {
96        card: VectorMatchCardinality.CardOneToOne,
97        matchingLabels: ['test', 'blub'],
98        on: true,
99        include: [],
100      },
101    },
102    {
103      binaryExpr: 'foo * on(test,blub) group_left bar',
104      expectedVectorMatching: {
105        card: VectorMatchCardinality.CardManyToOne,
106        matchingLabels: ['test', 'blub'],
107        on: true,
108        include: [],
109      },
110    },
111    {
112      binaryExpr: 'foo and on(test,blub) bar',
113      expectedVectorMatching: {
114        card: VectorMatchCardinality.CardManyToMany,
115        matchingLabels: ['test', 'blub'],
116        on: true,
117        include: [],
118      },
119    },
120    {
121      binaryExpr: 'foo and on() bar',
122      expectedVectorMatching: {
123        card: VectorMatchCardinality.CardManyToMany,
124        matchingLabels: [],
125        on: true,
126        include: [],
127      },
128    },
129    {
130      binaryExpr: 'foo and ignoring(test,blub) bar',
131      expectedVectorMatching: {
132        card: VectorMatchCardinality.CardManyToMany,
133        matchingLabels: ['test', 'blub'],
134        on: false,
135        include: [],
136      },
137    },
138    {
139      binaryExpr: 'foo and ignoring() bar',
140      expectedVectorMatching: {
141        card: VectorMatchCardinality.CardManyToMany,
142        matchingLabels: [],
143        on: false,
144        include: [],
145      },
146    },
147    {
148      binaryExpr: 'foo unless on(bar) baz',
149      expectedVectorMatching: {
150        card: VectorMatchCardinality.CardManyToMany,
151        matchingLabels: ['bar'],
152        on: true,
153        include: [],
154      },
155    },
156    {
157      binaryExpr: 'foo / on(test,blub) group_left(bar) bar',
158      expectedVectorMatching: {
159        card: VectorMatchCardinality.CardManyToOne,
160        matchingLabels: ['test', 'blub'],
161        on: true,
162        include: ['bar'],
163      },
164    },
165    {
166      binaryExpr: 'foo / ignoring(test,blub) group_left(blub) bar',
167      expectedVectorMatching: {
168        card: VectorMatchCardinality.CardManyToOne,
169        matchingLabels: ['test', 'blub'],
170        on: false,
171        include: ['blub'],
172      },
173    },
174    {
175      binaryExpr: 'foo / ignoring(test,blub) group_left(bar) bar',
176      expectedVectorMatching: {
177        card: VectorMatchCardinality.CardManyToOne,
178        matchingLabels: ['test', 'blub'],
179        on: false,
180        include: ['bar'],
181      },
182    },
183    {
184      binaryExpr: 'foo - on(test,blub) group_right(bar,foo) bar',
185      expectedVectorMatching: {
186        card: VectorMatchCardinality.CardOneToMany,
187        matchingLabels: ['test', 'blub'],
188        on: true,
189        include: ['bar', 'foo'],
190      },
191    },
192    {
193      binaryExpr: 'foo - ignoring(test,blub) group_right(bar,foo) bar',
194      expectedVectorMatching: {
195        card: VectorMatchCardinality.CardOneToMany,
196        matchingLabels: ['test', 'blub'],
197        on: false,
198        include: ['bar', 'foo'],
199      },
200    },
201  ];
202  testCases.forEach((value) => {
203    it(value.binaryExpr, () => {
204      const state = createEditorState(value.binaryExpr);
205      const node = walkThrough(syntaxTree(state).topNode, Expr, BinaryExpr);
206      chai.expect(node).to.not.null;
207      chai.expect(node).to.not.undefined;
208      if (node) {
209        chai.expect(value.expectedVectorMatching).to.deep.equal(buildVectorMatching(state, node));
210      }
211    });
212  });
213});
214