1 Import-Module Pester
2 
3 
4 BeforeAll {
5     . $PSScriptRoot/../job-matrix-functions.ps1
6 
CompareMatrices([Array] $matrix, [Array] $expected)7     function CompareMatrices([Array]$matrix, [Array]$expected) {
8         $matrix.Length | Should -Be $expected.Length
9 
10         for ($i = 0; $i -lt $matrix.Length; $i++) {
11             foreach ($entry in $matrix[$i]) {
12                 $entry.name | Should -Be $expected[$i].name
13                 foreach ($param in $entry.parameters.GetEnumerator()) {
14                     $param.Value | Should -Be $expected[$i].parameters[$param.Name]
15                 }
16             }
17         }
18     }
19 }
20 
21 Describe "Platform Matrix nonSparse" -Tag "nonsparse" {
22     BeforeEach {
23         $matrixJson = @'
24 {
25     "matrix": {
26         "testField1": [ 1, 2 ],
27         "testField2": [ 1, 2, 3 ],
28         "testField3": [ 1, 2, 3, 4 ],
29     }
30 }
31 '@
32         $config = GetMatrixConfigFromJson $matrixJson
33     }
34 
35     It "Should process nonSparse parameters" {
36         $parameters, $nonSparse = ProcessNonSparseParameters $config.matrixParameters "testField1","testField3"
37 
38         $parameters.Count | Should -Be 1
39         $parameters[0].Name | Should -Be "testField2"
40         $parameters[0].Value | Should -Be 1,2,3
41 
42         $nonSparse.Count | Should -Be 2
43         $nonSparse[0].Name | Should -Be "testField1"
44         $nonSparse[0].Value | Should -Be 1,2
45         $nonSparse[1].Name | Should -Be "testField3"
46         $nonSparse[1].Value | Should -Be 1,2,3,4
47 
48         $parameters, $nonSparse = ProcessNonSparseParameters $config.matrixParameters "testField3"
49         $parameters.Count | Should -Be 2
50         ($parameters).Name -match "testField3" | Should -Be $null
51 
52         $nonSparse.Count | Should -Be 1
53         $nonSparse[0].Name | Should -Be "testField3"
54         $nonSparse[0].Value | Should -Be 1,2,3,4
55     }
56 
57     It "Should ignore nonSparse with all selection" {
58         $matrix = GenerateMatrix $config "all" -nonSparseParameters "testField3"
59         $matrix.Length | Should -Be 24
60     }
61 
62     It "Should combine sparse matrix with nonSparse parameters" {
63         $matrix = GenerateMatrix $config "sparse" -nonSparseParameters "testField3"
64         $matrix.Length | Should -Be 12
65     }
66 
67     It "Should combine with multiple nonSparse fields" {
68         $matrixJson = @'
69 {
70     "matrix": {
71         "testField1": [ 1, 2 ],
72         "testField2": [ 1, 2 ],
73         "testField3": [ 31, 32 ],
74         "testField4": [ 41, 42 ]
75     }
76 }
77 '@
78         $config = GetMatrixConfigFromJson $matrixJson
79 
80         $matrix = GenerateMatrix $config "all" -nonSparseParameters "testField3","testField4"
81         $matrix.Length | Should -Be 16
82 
83         $matrix = GenerateMatrix $config "sparse" -nonSparseParameters "testField3","testField4"
84         $matrix.Length | Should -Be 8
85     }
86 
87     It "Should apply nonSparseParameters to an imported matrix" {
88         $matrixJson = @'
89 {
90     "matrix": {
91         "$IMPORT": "./test-import-matrix.json",
92         "TestField1": "test1"
93     },
94     "exclude": [ { "Baz": "importedBaz" } ]
95 }
96 '@
97 
98         $expectedMatrix = @'
99 [
100   {
101     "parameters": { "TestField1": "test1", "Foo": "foo1", "Bar": "bar1" },
102     "name": "test1_foo1_bar1"
103   },
104   {
105     "parameters": { "TestField1": "test1", "Foo": "foo1", "Bar": "bar2" },
106     "name": "test1_foo1_bar2"
107   },
108   {
109     "parameters": { "TestField1": "test1", "Foo": "foo2", "Bar": "bar1" },
110     "name": "test1_foo2_bar1"
111   },
112   {
113     "parameters": { "TestField1": "test1", "Foo": "foo2", "Bar": "bar2" },
114     "name": "test1_foo2_bar2"
115   }
116 ]
117 '@
118 
119         $importConfig = GetMatrixConfigFromJson $matrixJson
120         $matrix = GenerateMatrix $importConfig "sparse" -nonSparseParameters "Foo"
121         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
122 
123         $matrix.Length | Should -Be 4
124         CompareMatrices $matrix $expected
125     }
126 }
127 
128 Describe "Platform Matrix Import" -Tag "import" {
129     It "Should generate a sparse matrix where the entire base matrix is imported" {
130         $matrixJson = @'
131 {
132     "matrix": {
133         "$IMPORT": "./test-import-matrix.json"
134     },
135     "include": [
136         {
137             "fooinclude": "fooinclude"
138         }
139     ]
140 }
141 '@
142 
143         $expectedMatrix = @'
144 [
145   {
146     "parameters": { "Foo": "foo1", "Bar": "bar1" },
147     "name": "foo1_bar1"
148   },
149   {
150     "parameters": { "Foo": "foo2", "Bar": "bar2" },
151     "name": "foo2_bar2"
152   },
153   {
154     "parameters": { "Baz": "importedBaz" },
155     "name": "importedBazName"
156   },
157   {
158     "parameters": { "fooinclude": "fooinclude" },
159     "name": "fooinclude"
160   },
161 ]
162 '@
163 
164         $importConfig = GetMatrixConfigFromJson $matrixJson
165         $matrix = GenerateMatrix $importConfig "sparse"
166         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
167 
168         $matrix.Length | Should -Be 4
169         CompareMatrices $matrix $expected
170     }
171 
172     It "Should import a matrix and combine with length=1 vectors" {
173         $matrixJson = @'
174 {
175     "matrix": {
176         "$IMPORT": "./test-import-matrix.json",
177         "TestField1": "test1",
178         "TestField2": "test2"
179     },
180     "exclude": [ { "Baz": "importedBaz" } ]
181 }
182 '@
183 
184         $expectedMatrix = @'
185 [
186   {
187     "parameters": { "TestField1": "test1", "TestField2": "test2", "Foo": "foo1", "Bar": "bar1" },
188     "name": "test1_test2_foo1_bar1"
189   },
190   {
191     "parameters": { "TestField1": "test1", "TestField2": "test2", "Foo": "foo2", "Bar": "bar2" },
192     "name": "test1_test2_foo2_bar2"
193   }
194 ]
195 '@
196 
197         $importConfig = GetMatrixConfigFromJson $matrixJson
198         $matrix = GenerateMatrix $importConfig "sparse"
199         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
200 
201         $matrix.Length | Should -Be 2
202         CompareMatrices $matrix $expected
203     }
204 
205     It "Should generate a matrix with nonSparseParameters and an imported sparse matrix" {
206         $matrixJson = @'
207 {
208     "matrix": {
209         "$IMPORT": "./test-import-matrix.json",
210         "testField": [ "test1", "test2" ]
211     }
212 }
213 '@
214         $importConfig = GetMatrixConfigFromJson $matrixJson
215         $matrix = GenerateMatrix $importConfig "sparse" -nonSparseParameters "testField"
216 
217         $matrix.Length | Should -Be 6
218 
219         $matrix[0].name | Should -Be test1_foo1_bar1
220         $matrix[0].parameters.testField | Should -Be "test1"
221         $matrix[0].parameters.Foo | Should -Be "foo1"
222         $matrix[2].name | Should -Be test1_importedBazName
223         $matrix[2].parameters.testField | Should -Be "test1"
224         $matrix[2].parameters.Baz | Should -Be "importedBaz"
225         $matrix[4].name | Should -Be test2_foo2_bar2
226         $matrix[4].parameters.testField | Should -Be "test2"
227         $matrix[4].parameters.Foo | Should -Be "foo2"
228     }
229 
230     It "Should source imported display name lookups" {
231         $matrixJson = @'
232 {
233     "displayNames": {
234         "test1": "test1DisplayName",
235         "importedBaz": "importedBazNameOverride"
236     },
237     "matrix": {
238         "$IMPORT": "./test-import-matrix.json",
239         "testField": [ "test1", "test2" ]
240     }
241 }
242 '@
243         $importConfig = GetMatrixConfigFromJson $matrixJson
244         $matrix = GenerateMatrix $importConfig "sparse" -nonSparseParameters "testField"
245 
246         $matrix[0].name | Should -Be test1DisplayName_foo1_bar1
247         $matrix[2].name | Should -Be test1DisplayName_importedBazNameOverride
248     }
249 
250     It "Should generate a sparse matrix with an imported sparse matrix" {
251         $matrixJson = @'
252 {
253     "matrix": {
254         "$IMPORT": "./test-import-matrix.json",
255         "testField1": [ "test11", "test12" ],
256         "testField2": [ "test21", "test22" ]
257     }
258 }
259 '@
260 
261         $expectedMatrix = @'
262 [
263   {
264     "parameters": { "testField1": "test11", "testField2": "test21", "Foo": "foo1", "Bar": "bar1" },
265     "name": "test11_test21_foo1_bar1"
266   },
267   {
268     "parameters": { "testField1": "test11", "testField2": "test21", "Foo": "foo2", "Bar": "bar2" },
269     "name": "test11_test21_foo2_bar2"
270   },
271   {
272     "parameters": { "testField1": "test11", "testField2": "test21", "Baz": "importedBaz" },
273     "name": "test11_test21_importedBazName"
274   },
275   {
276     "parameters": { "testField1": "test12", "testField2": "test22", "Foo": "foo1", "Bar": "bar1" },
277     "name": "test12_test22_foo1_bar1"
278   },
279   {
280     "parameters": { "testField1": "test12", "testField2": "test22", "Foo": "foo2", "Bar": "bar2" },
281     "name": "test12_test22_foo2_bar2"
282   },
283   {
284     "parameters": { "testField1": "test12", "testField2": "test22", "Baz": "importedBaz" },
285     "name": "test12_test22_importedBazName"
286   }
287 ]
288 '@
289 
290         $importConfig = GetMatrixConfigFromJson $matrixJson
291         $matrix = GenerateMatrix $importConfig "sparse"
292         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
293 
294         $matrix.Length | Should -Be 6
295         CompareMatrices $matrix $expected
296     }
297 
298     It "Should import a sparse matrix with import, include, and exclude" {
299         $matrixJson = @'
300 {
301     "matrix": {
302         "$IMPORT": "./test-import-matrix.json",
303         "testField": [ "test1", "test2", "test3" ],
304     },
305     "include": [
306       {
307         "testImportIncludeName": [ "testInclude1", "testInclude2" ]
308       }
309     ],
310     "exclude": [
311       {
312         "testField": "test1"
313       },
314       {
315         "testField": "test3",
316         "Baz": "importedBaz"
317       }
318     ]
319 }
320 '@
321 
322         $expectedMatrix = @'
323 [
324   {
325     "parameters": { "testField": "test2", "Foo": "foo1", "Bar": "bar1" },
326     "name": "test2_foo1_bar1"
327   },
328   {
329     "parameters": { "testField": "test2", "Foo": "foo2", "Bar": "bar2" },
330     "name": "test2_foo2_bar2"
331   },
332   {
333     "parameters": { "testField": "test2", "Baz": "importedBaz" },
334     "name": "test2_importedBazName"
335   },
336   {
337     "parameters": { "testField": "test3", "Foo": "foo1", "Bar": "bar1" },
338     "name": "test3_foo1_bar1"
339   },
340   {
341     "parameters": { "testField": "test3", "Foo": "foo2", "Bar": "bar2" },
342     "name": "test3_foo2_bar2"
343   },
344   {
345     "parameters": { "testImportIncludeName": "testInclude1" },
346     "name": "testInclude1"
347   },
348   {
349     "parameters": { "testImportIncludeName": "testInclude2" },
350     "name": "testInclude2"
351   }
352 ]
353 '@
354 
355         $importConfig = GetMatrixConfigFromJson $matrixJson
356         $matrix = GenerateMatrix $importConfig "sparse"
357         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
358 
359         $matrix.Length | Should -Be 7
360         CompareMatrices $matrix $expected
361     }
362 
363     It "Should not combine matrices with duplicate keys" {
364         $matrixJson = @'
365 {
366     "matrix": {
367         "$IMPORT": "./test-import-matrix.json",
368         "Foo": [ "fooOverride1", "fooOverride2" ],
369     }
370 }
371 '@
372 
373         $importConfig = GetMatrixConfigFromJson $matrixJson
374         { GenerateMatrix $importConfig "sparse" } | Should -Throw
375     }
376 
377 }
378 
379 Describe "Platform Matrix Replace" -Tag "replace" {
380     It "Should parse replacement syntax" -TestCases @(
381          @{ query = 'foo=bar/baz'; key = '^foo$'; value = '^bar$'; replace = 'baz' },
382          @{ query = 'foo=\/p:bar/\/p:baz'; key = '^foo$'; value = '^\/p:bar$'; replace = '/p:baz' },
383          @{ query = 'f\=o\/o=\/p:b\=ar/\/p:b\=az'; key = '^f\=o\/o$'; value = '^\/p:b\=ar$'; replace = '/p:b=az' },
384          @{ query = 'foo=bar/'; key = '^foo$'; value = '^bar$'; replace = '' },
385          @{ query = 'foo=/baz'; key = '^foo$'; value = '^$'; replace = 'baz' }
386     ) {
387         $parsed = ParseReplacement $query
388         $parsed.key | Should -Be $key
389         $parsed.value | Should -Be $value
390         $parsed.replace | Should -Be $replace
391     }
392 
393     It "Should fail for invalid replacement syntax" -TestCases @(
394         @{ query = '' },
395         @{ query = 'asdf' },
396         @{ query = 'asdf=foo/bar/baz' },
397         @{ query = 'asdf=foo=bar/baz' },
398         @{ query = 'asdf=foo' }
399     ) {
400         { $parsed = ParseReplacement $query } | Should -Throw
401         { $parsed = ParseReplacement $query } | Should -Throw
402         { $parsed = ParseReplacement $query } | Should -Throw
403         { $parsed = ParseReplacement $query } | Should -Throw
404         { $parsed = ParseReplacement $query } | Should -Throw
405     }
406 
407     It "Should replace values in a matrix" {
408         $matrixJson = @'
409 {
410     "matrix": {
411         "Foo": [ "foo1", "foo2" ],
412         "Bar": [ "bar1", "bar2" ]
413     },
414     "include": [ { "Baz": "baz1" } ]
415 }
416 '@
417 
418         $expectedMatrix = @'
419 [
420   {
421     "parameters": { "Foo": "foo1Replaced", "Bar": "bar1" },
422     "name": "foo1Replaced_bar1"
423   },
424   {
425     "parameters": { "Foo": "fooDefaultReplaced", "Bar": "bar2" },
426     "name": "fooDefaultReplaced_bar2"
427   },
428   {
429     "parameters": { "Baz": "bazReplaced" },
430     "name": "bazReplaced"
431   }
432 ]
433 '@
434 
435         $replace = @(
436             "Foo=foo1/foo1Replaced",
437             "Foo=foo.*/fooDefaultReplaced",
438             ".*=B.z\d/bazReplaced"
439         )
440 
441         $importConfig = GetMatrixConfigFromJson $matrixJson
442         $matrix = GenerateMatrix -config $importConfig -selectFromMatrixType "sparse" -replace $replace
443         $expected = $expectedMatrix | ConvertFrom-Json -AsHashtable
444 
445         $matrix.Length | Should -Be 3
446         CompareMatrices $matrix $expected
447     }
448 
449     It "Should replace values in a matrix with import and nonSparseParameters" {
450         $matrixJson = @'
451 {
452     "matrix": {
453         "$IMPORT": "./test-import-matrix.json",
454         "testField": [ "test1", "test2" ]
455     }
456 }
457 '@
458         $importConfig = GetMatrixConfigFromJson $matrixJson
459         $matrix = GenerateMatrix $importConfig "sparse" -nonSparseParameters "testField" -replace @("testField=test1/testReplaced", "Baz=.*/bazReplaced")
460 
461         $matrix.Length | Should -Be 6
462 
463         $matrix[0].name | Should -Be testReplaced_foo1_bar1
464         $matrix[0].parameters.testField | Should -Be "testReplaced"
465         $matrix[0].parameters.Foo | Should -Be "foo1"
466         $matrix[2].name | Should -Be testReplaced_bazReplaced
467         $matrix[2].parameters.testField | Should -Be "testReplaced"
468         $matrix[2].parameters.Baz | Should -Be "bazReplaced"
469         $matrix[4].name | Should -Be test2_foo2_bar2
470         $matrix[4].parameters.testField | Should -Be "test2"
471         $matrix[4].parameters.Foo | Should -Be "foo2"
472     }
473 
474     It "Should replace values in groupings" {
475         $matrixJson = @'
476 {
477   "matrix": {
478     "Agent": {
479       "ubuntu-1804": { "OSVmImage": "MMSUbuntu18.04", "Pool": "azsdk-pool-mms-ubuntu-1804-general" }
480     },
481     "JavaTestVersion": [ "1.8", "1.11" ]
482   }
483 }
484 '@
485         $importConfig = GetMatrixConfigFromJson $matrixJson
486         $matrix = GenerateMatrix $importConfig "all" -replace @("JavaTestVersion=1.8/2.0", "Pool=.*ubuntu.*/custom-ubuntu-pool")
487 
488         $matrix.Length | Should -Be 2
489         # Replacements of inner values will preserve the grouping name
490         $matrix[0].name | Should -Be "ubuntu1804_20"
491         $matrix[0].parameters.JavaTestVersion | Should -Be "2.0"
492         $matrix[0].parameters.Pool | Should -Be "custom-ubuntu-pool"
493         $matrix[0].parameters.OSVmImage | Should -Be "MMSUbuntu18.04"
494 
495         # Make sure non-literal keys still replace under the hood
496         $matrix = GenerateMatrix $importConfig "all" -replace ".*=.*ubuntu.*/custom-ubuntu-pool"
497 
498         $matrix.Length | Should -Be 2
499         $matrix[0].name | Should -Be "ubuntu1804_18"
500         $matrix[0].parameters.Pool | Should -Be "custom-ubuntu-pool"
501     }
502 
503     It "Should replace values and apply regex capture groups" {
504         $matrixJson = @'
505 {
506   "matrix": {
507     "Foo": [ "foo1", "foo2" ],
508     "Bar": [ "bar1", "bar2" ]
509   }
510 }
511 '@
512         $importConfig = GetMatrixConfigFromJson $matrixJson
513         $replace = 'Foo=(foo)1/$1ReplacedFoo1', 'B.*=(.*)2/$1ReplacedBar2'
514         $matrix = GenerateMatrix $importConfig "sparse" -replace $replace
515 
516         $matrix.Length | Should -Be 2
517         $matrix[0].name | Should -Be "fooReplacedFoo1_bar1"
518         $matrix[0].parameters.Foo | Should -Be "fooReplacedFoo1"
519 
520         $matrix[1].name | Should -Be "foo2_barReplacedBar2"
521         $matrix[1].parameters.Bar | Should -Be "barReplacedBar2"
522     }
523 
524     It "Should only fully match a string for replace" {
525         $matrixJson = @'
526 {
527     "matrix": {
528         "Foo": [ "foo1", "foo2" ],
529         "Bar": "bar1"
530     }
531 }
532 '@
533 
534         $importConfig = GetMatrixConfigFromJson $matrixJson
535 
536         $replace = @("Foo=foo/shouldNotReplaceFoo", "B=bar1/shouldNotReplaceBar")
537         $matrix = GenerateMatrix -config $importConfig -selectFromMatrixType "sparse" -replace $replace
538 
539         $matrix.Length | Should -Be 2
540         $matrix[0].parameters.Foo | Should -Be "foo1"
541         $matrix[0].parameters.Bar | Should -Be "bar1"
542         $matrix[1].parameters.Foo | Should -Be "foo2"
543         $matrix[1].parameters.Bar | Should -Be "bar1"
544     }
545 }
546