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