OpenConfigurationSetTests.cs (56283B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="OpenConfigurationSetTests.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace Microsoft.Management.Configuration.UnitTests.Tests 8 { 9 using System; 10 using System.Collections.Generic; 11 using System.DirectoryServices; 12 using Microsoft.Management.Configuration.Processor.Extensions; 13 using Microsoft.Management.Configuration.UnitTests.Fixtures; 14 using Microsoft.Management.Configuration.UnitTests.Helpers; 15 using Microsoft.VisualBasic; 16 using Windows.Foundation.Collections; 17 using Windows.Storage.Streams; 18 using WinRT; 19 using Xunit; 20 using Xunit.Abstractions; 21 22 /// <summary> 23 /// Unit tests for parsing configuration sets from streams. 24 /// </summary> 25 [Collection("UnitTestCollection")] 26 [InProc] 27 [OutOfProc] 28 public class OpenConfigurationSetTests : ConfigurationProcessorTestBase 29 { 30 /// <summary> 31 /// The directives key for the module property. 32 /// </summary> 33 internal const string ModuleDirective = "module"; 34 35 /// <summary> 36 /// Initializes a new instance of the <see cref="OpenConfigurationSetTests"/> class. 37 /// </summary> 38 /// <param name="fixture">Unit test fixture.</param> 39 /// <param name="log">Log helper.</param> 40 public OpenConfigurationSetTests(UnitTestFixture fixture, ITestOutputHelper log) 41 : base(fixture, log) 42 { 43 } 44 45 /// <summary> 46 /// Passes a null stream as input. 47 /// </summary> 48 [Fact] 49 public void NullStream() 50 { 51 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 52 53 OpenConfigurationSetResult result = processor.OpenConfigurationSet(null); 54 Assert.Null(result.Set); 55 Assert.IsType<NullReferenceException>(result.ResultCode); 56 Assert.Equal(string.Empty, result.Field); 57 } 58 59 /// <summary> 60 /// Passes an empty stream as input. 61 /// </summary> 62 [Fact] 63 public void EmptyStream() 64 { 65 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 66 67 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(string.Empty)); 68 Assert.Null(result.Set); 69 Assert.NotNull(result.ResultCode); 70 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_YAML, result.ResultCode.HResult); 71 Assert.Equal(string.Empty, result.Field); 72 Assert.Equal(0U, result.Line); 73 Assert.Equal(0U, result.Column); 74 } 75 76 /// <summary> 77 /// Passes a stream with a single null byte in it. 78 /// </summary> 79 [Fact] 80 public void NullByteStream() 81 { 82 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 83 84 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream("\0")); 85 Assert.Null(result.Set); 86 Assert.NotNull(result.ResultCode); 87 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_YAML, result.ResultCode.HResult); 88 Assert.NotEqual(string.Empty, result.Field); 89 Assert.Equal(0U, result.Line); 90 Assert.Equal(0U, result.Column); 91 } 92 93 /// <summary> 94 /// Passes YAML, but it isn't anything like a configuration file. 95 /// </summary> 96 [Fact] 97 public void NotConfigYAML() 98 { 99 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 100 101 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream("yaml: yep")); 102 Assert.Null(result.Set); 103 Assert.NotNull(result.ResultCode); 104 Assert.Equal(Errors.WINGET_CONFIG_ERROR_MISSING_FIELD, result.ResultCode.HResult); 105 Assert.Equal("$schema", result.Field); 106 Assert.Equal(0U, result.Line); 107 Assert.Equal(0U, result.Column); 108 } 109 110 /// <summary> 111 /// Passes YAML without a schema version. 112 /// </summary> 113 [Fact] 114 public void NoConfigVersion() 115 { 116 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 117 118 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 119 properties: 120 thing: 1 121 ")); 122 Assert.Null(result.Set); 123 Assert.NotNull(result.ResultCode); 124 Assert.Equal(Errors.WINGET_CONFIG_ERROR_MISSING_FIELD, result.ResultCode.HResult); 125 Assert.Equal("configurationVersion", result.Field); 126 Assert.Equal(0U, result.Line); 127 Assert.Equal(0U, result.Column); 128 } 129 130 /// <summary> 131 /// Passes YAML that appears to be from the distant future. 132 /// </summary> 133 [Fact] 134 public void UnknownConfigVersion() 135 { 136 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 137 138 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 139 properties: 140 configurationVersion: 99999999 141 ")); 142 Assert.Null(result.Set); 143 Assert.NotNull(result.ResultCode); 144 Assert.Equal(Errors.WINGET_CONFIG_ERROR_UNKNOWN_CONFIGURATION_FILE_VERSION, result.ResultCode.HResult); 145 Assert.Equal("configurationVersion", result.Field); 146 Assert.Equal("99999999", result.Value); 147 Assert.Equal(0U, result.Line); 148 Assert.Equal(0U, result.Column); 149 } 150 151 /// <summary> 152 /// Has one of each type of intent to ensure that it is set properly. 153 /// </summary> 154 [Fact] 155 public void EnsureIntent() 156 { 157 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 158 159 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 160 properties: 161 configurationVersion: 0.1 162 assertions: 163 - resource: Assert 164 parameters: 165 - resource: Inform 166 resources: 167 - resource: Apply 168 ")); 169 170 Assert.NotNull(result.Set); 171 Assert.Null(result.ResultCode); 172 Assert.Equal(string.Empty, result.Field); 173 174 var units = result.Set.Units; 175 Assert.Equal(3, units.Count); 176 bool sawAssert = false; 177 bool sawInform = false; 178 bool sawApply = false; 179 180 foreach (var unit in units) 181 { 182 Assert.Equal(unit.Type, unit.Intent.ToString()); 183 switch (unit.Intent) 184 { 185 case ConfigurationUnitIntent.Assert: sawAssert = true; break; 186 case ConfigurationUnitIntent.Inform: sawInform = true; break; 187 case ConfigurationUnitIntent.Apply: sawApply = true; break; 188 default: Assert.Fail("Unknown intent"); break; 189 } 190 } 191 192 Assert.True(sawAssert); 193 Assert.True(sawInform); 194 Assert.True(sawApply); 195 } 196 197 /// <summary> 198 /// Passes YAML with resources being something other than a sequence. 199 /// </summary> 200 [Fact] 201 public void NonSequenceUnits() 202 { 203 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 204 205 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 206 properties: 207 configurationVersion: 0.1 208 resources: 1 209 ")); 210 Assert.Null(result.Set); 211 Assert.NotNull(result.ResultCode); 212 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_TYPE, result.ResultCode.HResult); 213 Assert.Equal("resources", result.Field); 214 Assert.Equal(4U, result.Line); 215 Assert.NotEqual(0U, result.Column); 216 } 217 218 /// <summary> 219 /// Passes YAML with a resource being something other than a map. 220 /// </summary> 221 [Fact] 222 public void NonMapSequenceUnits() 223 { 224 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 225 226 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 227 properties: 228 configurationVersion: 0.1 229 resources: 230 - string 231 ")); 232 Assert.Null(result.Set); 233 Assert.NotNull(result.ResultCode); 234 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_TYPE, result.ResultCode.HResult); 235 Assert.Equal("resources[0]", result.Field); 236 Assert.Equal(5U, result.Line); 237 Assert.NotEqual(0U, result.Column); 238 } 239 240 /// <summary> 241 /// Passes YAML with all values present. 242 /// </summary> 243 [Fact] 244 public void CheckAllUnitProperties() 245 { 246 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 247 248 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 249 properties: 250 configurationVersion: 0.1 251 resources: 252 - resource: Resource 253 id: Identifier 254 dependsOn: 255 - Dependency1 256 - Dependency2 257 directives: 258 Directive1: A 259 Directive2: B 260 settings: 261 Setting1: '1' 262 Setting2: 2 263 ")); 264 Assert.NotNull(result.Set); 265 Assert.Null(result.ResultCode); 266 Assert.Equal(string.Empty, result.Field); 267 268 Assert.NotEqual(Guid.Empty, result.Set.InstanceIdentifier); 269 270 var units = result.Set.Units; 271 Assert.NotNull(units); 272 Assert.Equal(1, units.Count); 273 274 ConfigurationUnit unit = units[0]; 275 Assert.NotNull(unit); 276 Assert.Equal("Resource", unit.Type); 277 Assert.NotEqual(Guid.Empty, unit.InstanceIdentifier); 278 Assert.Equal("Identifier", unit.Identifier); 279 Assert.Equal(ConfigurationUnitIntent.Apply, unit.Intent); 280 281 var dependencies = unit.Dependencies; 282 Assert.NotNull(dependencies); 283 Assert.Equal(2, dependencies.Count); 284 Assert.Contains("Dependency1", dependencies); 285 Assert.Contains("Dependency2", dependencies); 286 287 var directives = unit.Metadata; 288 Assert.NotNull(directives); 289 Assert.Equal(2, directives.Count); 290 Assert.Contains("Directive1", directives); 291 Assert.Equal("A", directives["Directive1"]); 292 Assert.Contains("Directive2", directives); 293 Assert.Equal("B", directives["Directive2"]); 294 295 var settings = unit.Settings; 296 Assert.NotNull(settings); 297 Assert.Equal(2, settings.Count); 298 Assert.Contains("Setting1", settings); 299 Assert.Equal("1", settings["Setting1"]); 300 Assert.Contains("Setting2", settings); 301 Assert.Equal(2L, settings["Setting2"]); 302 303 Assert.Null(unit.Details); 304 Assert.Equal(ConfigurationUnitState.Unknown, unit.State); 305 Assert.Null(unit.ResultInformation); 306 Assert.True(unit.IsActive); 307 } 308 309 /// <summary> 310 /// Test type of scalar nodes. 311 /// </summary> 312 [Fact] 313 public void CheckUnitScalarTypes() 314 { 315 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 316 317 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 318 properties: 319 configurationVersion: 0.1 320 resources: 321 - resource: Resource 322 id: Identifier 323 settings: 324 SettingInt: 1 325 SettingString: '1' 326 SettingBool: false 327 SettingStringBool: 'false' 328 ")); 329 Assert.NotNull(result.Set); 330 Assert.Null(result.ResultCode); 331 332 var units = result.Set.Units; 333 Assert.NotNull(units); 334 Assert.Equal(1, units.Count); 335 336 ConfigurationUnit unit = units[0]; 337 Assert.NotNull(unit); 338 339 var settings = unit.Settings; 340 Assert.NotNull(settings); 341 Assert.Equal(4, settings.Count); 342 Assert.Contains("SettingInt", settings); 343 Assert.Equal(1L, settings["SettingInt"]); 344 Assert.Contains("SettingString", settings); 345 Assert.Equal("1", settings["SettingString"]); 346 Assert.Contains("SettingBool", settings); 347 Assert.Equal(false, settings["SettingBool"]); 348 Assert.Contains("SettingStringBool", settings); 349 Assert.Equal("false", settings["SettingStringBool"]); 350 } 351 352 /// <summary> 353 /// Test that module gets left in resource name in 0.1. 354 /// </summary> 355 [Fact] 356 public void ModuleInResourceName_NotFor0_1() 357 { 358 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 359 360 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 361 properties: 362 configurationVersion: 0.1 363 resources: 364 - resource: Module/Resource 365 id: Identifier 366 settings: 367 SettingInt: 1 368 ")); 369 370 Assert.NotNull(result.Set); 371 Assert.Null(result.ResultCode); 372 373 Assert.Equal("0.1", result.Set.SchemaVersion); 374 Assert.Single(result.Set.Units); 375 376 var unit = result.Set.Units[0]; 377 Assert.NotNull(unit); 378 Assert.Equal("Module/Resource", unit.Type); 379 Assert.Empty(unit.Metadata); 380 } 381 382 /// <summary> 383 /// Test that module gets parsed out of resource name in 0.2. 384 /// </summary> 385 [Fact] 386 public void ModuleInResourceName() 387 { 388 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 389 390 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 391 properties: 392 configurationVersion: 0.2 393 resources: 394 - resource: Module/Resource 395 id: Identifier 396 directives: 397 module: Module 398 settings: 399 SettingInt: 1 400 ")); 401 402 Assert.NotNull(result.Set); 403 Assert.Null(result.ResultCode); 404 405 Assert.Equal("0.2", result.Set.SchemaVersion); 406 Assert.Single(result.Set.Units); 407 408 var unit = result.Set.Units[0]; 409 Assert.NotNull(unit); 410 Assert.Equal("Resource", unit.Type); 411 Assert.Single(unit.Metadata); 412 Assert.True(unit.Metadata.ContainsKey(ModuleDirective)); 413 Assert.Equal("Module", unit.Metadata[ModuleDirective]); 414 } 415 416 /// <summary> 417 /// Test that module is in the resource name and the directives and are different. 418 /// </summary> 419 [Fact] 420 public void ModuleInResourceName_DirectiveDifferent() 421 { 422 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 423 424 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 425 properties: 426 configurationVersion: 0.2 427 resources: 428 - resource: Module/Resource 429 id: Identifier 430 directives: 431 module: DifferentModule 432 settings: 433 SettingInt: 1 434 ")); 435 436 Assert.Null(result.Set); 437 Assert.NotNull(result.ResultCode); 438 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult); 439 Assert.Equal(ModuleDirective, result.Field); 440 Assert.Equal("DifferentModule", result.Value); 441 Assert.Equal(5U, result.Line); 442 Assert.NotEqual(0U, result.Column); 443 } 444 445 /// <summary> 446 /// Test that providing only the module in the qualified name is an error. 447 /// </summary> 448 [Fact] 449 public void EmptyResourceWithModule() 450 { 451 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 452 453 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 454 properties: 455 configurationVersion: 0.2 456 resources: 457 - resource: Module/ 458 id: Identifier 459 settings: 460 SettingInt: 1 461 ")); 462 463 Assert.Null(result.Set); 464 Assert.NotNull(result.ResultCode); 465 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult); 466 Assert.Equal("resource", result.Field); 467 Assert.Equal("Module/", result.Value); 468 Assert.Equal(5U, result.Line); 469 Assert.NotEqual(0U, result.Column); 470 } 471 472 /// <summary> 473 /// Verifies that the configuration set (0.2) can be serialized and reopened correctly. 474 /// </summary> 475 [Fact] 476 public void TestSet_Serialize_0_2() 477 { 478 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 479 480 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 481 properties: 482 configurationVersion: 0.2 483 assertions: 484 - resource: FakeModule/FakeResource 485 id: TestId 486 directives: 487 description: FakeDescription 488 allowPrerelease: true 489 securityContext: elevated 490 settings: 491 TestString: Hello 492 TestBool: false 493 TestInt: 1234 494 resources: 495 - resource: FakeModule2/FakeResource2 496 id: TestId2 497 dependsOn: 498 - TestId 499 - dependency2 500 - dependency3 501 directives: 502 description: FakeDescription2 503 securityContext: elevated 504 settings: 505 TestString: Bye 506 TestBool: true 507 TestInt: 4321 508 Mapping: 509 Key: TestValue 510 ")); 511 512 // Serialize set. 513 ConfigurationSet configurationSet = openResult.Set; 514 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 515 configurationSet.Serialize(stream); 516 517 string yamlOutput = this.ReadStream(stream); 518 519 // Reopen configuration set from serialized string and verify values. 520 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 521 Assert.Null(serializedSetResult.ResultCode); 522 ConfigurationSet set = serializedSetResult.Set; 523 Assert.NotNull(set); 524 525 Assert.Equal("0.2", set.SchemaVersion); 526 Assert.Equal(2, set.Units.Count); 527 528 Assert.Equal("FakeResource", set.Units[0].Type); 529 Assert.Equal(ConfigurationUnitIntent.Assert, set.Units[0].Intent); 530 Assert.Equal("TestId", set.Units[0].Identifier); 531 this.VerifyValueSet(set.Units[0].Metadata, new ("description", "FakeDescription"), new ("allowPrerelease", true), new ("module", "FakeModule")); 532 this.VerifyValueSet(set.Units[0].Settings, new ("TestString", "Hello"), new ("TestBool", false), new ("TestInt", 1234)); 533 534 Assert.Equal("FakeResource2", set.Units[1].Type); 535 Assert.Equal(ConfigurationUnitIntent.Apply, set.Units[1].Intent); 536 Assert.Equal("TestId2", set.Units[1].Identifier); 537 this.VerifyStringArray(set.Units[1].Dependencies, "TestId", "dependency2", "dependency3"); 538 this.VerifyValueSet(set.Units[1].Metadata, new ("description", "FakeDescription2"), new ("module", "FakeModule2")); 539 540 ValueSet mapping = new ValueSet(); 541 mapping.Add("Key", "TestValue"); 542 this.VerifyValueSet(set.Units[1].Settings, new ("TestString", "Bye"), new ("TestBool", true), new ("TestInt", 4321), new ("Mapping", mapping)); 543 } 544 545 /// <summary> 546 /// Verifies that the configuration set (0.3) can be serialized and reopened correctly. 547 /// </summary> 548 [Fact] 549 public void TestSet_Serialize_0_3() 550 { 551 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 552 553 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 554 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 555 metadata: 556 description: FakeSetDescription 557 variables: 558 var1: Test1 559 var2: 42 560 parameters: 561 param1: 562 type: securestring 563 param2: 564 type: int 565 defaultValue: 89 566 resources: 567 - type: FakeModule/FakeResource 568 name: TestId 569 metadata: 570 description: FakeDescription 571 allowPrerelease: true 572 myVal: mine 573 properties: 574 TestString: Hello 575 TestBool: false 576 TestInt: 1234 577 - type: FakeModule2/FakeResource2 578 name: TestId2 579 dependsOn: 580 - TestId 581 - dependency2 582 - dependency3 583 metadata: 584 description: FakeDescription2 585 myVal: yours 586 properties: 587 TestString: Bye 588 TestBool: true 589 TestInt: 4321 590 Mapping: 591 Key: TestValue 592 - type: FakeModule/FakeResource3 593 name: TestId3 594 metadata: 595 isGroup: true 596 properties: 597 other: value 598 resources: 599 - type: Grouped/Resource 600 name: Child 601 properties: 602 b: c 603 ")); 604 605 // Serialize set. 606 ConfigurationSet configurationSet = openResult.Set; 607 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 608 configurationSet.Serialize(stream); 609 610 string yamlOutput = this.ReadStream(stream); 611 612 // Reopen configuration set from serialized string and verify values. 613 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 614 Assert.Null(serializedSetResult.ResultCode); 615 ConfigurationSet set = serializedSetResult.Set; 616 Assert.NotNull(set); 617 618 Assert.Equal("0.3", set.SchemaVersion); 619 Assert.Equal(3, set.Units.Count); 620 621 this.VerifyValueSet(set.Metadata, new KeyValuePair<string, object>("description", "FakeSetDescription")); 622 this.VerifyValueSet(set.Variables, new ("var1", "Test1"), new ("var2", 42)); 623 624 Assert.Equal(2, set.Parameters.Count); 625 this.VerifyParameter(set.Parameters[0], "param1", Windows.Foundation.PropertyType.String, true); 626 this.VerifyParameter(set.Parameters[1], "param2", Windows.Foundation.PropertyType.Int64, false, 89); 627 628 Assert.Equal("FakeModule/FakeResource", set.Units[0].Type); 629 Assert.Equal("TestId", set.Units[0].Identifier); 630 this.VerifyValueSet(set.Units[0].Metadata, new ("description", "FakeDescription"), new ("allowPrerelease", true), new ("myVal", "mine")); 631 this.VerifyValueSet(set.Units[0].Settings, new ("TestString", "Hello"), new ("TestBool", false), new ("TestInt", 1234)); 632 633 Assert.Equal("FakeModule2/FakeResource2", set.Units[1].Type); 634 Assert.Equal("TestId2", set.Units[1].Identifier); 635 this.VerifyStringArray(set.Units[1].Dependencies, "TestId", "dependency2", "dependency3"); 636 this.VerifyValueSet(set.Units[1].Metadata, new ("description", "FakeDescription2"), new ("myVal", "yours")); 637 638 ValueSet mapping = new ValueSet(); 639 mapping.Add("Key", "TestValue"); 640 this.VerifyValueSet(set.Units[1].Settings, new ("TestString", "Bye"), new ("TestBool", true), new ("TestInt", 4321), new ("Mapping", mapping)); 641 642 Assert.Equal("FakeModule/FakeResource3", set.Units[2].Type); 643 Assert.Equal("TestId3", set.Units[2].Identifier); 644 Assert.True(set.Units[2].IsGroup); 645 646 ValueSet childResource = new ValueSet(); 647 childResource.Add("type", "Grouped/Resource"); 648 childResource.Add("name", "Child"); 649 ValueSet childResourceProperties = new ValueSet(); 650 childResourceProperties.Add("b", "c"); 651 childResource.Add("properties", childResourceProperties); 652 653 ValueSet resourcesArray = new ValueSet(); 654 resourcesArray.Add("treatAsArray", true); 655 resourcesArray.Add("0", childResource); 656 657 this.VerifyValueSet(set.Units[2].Settings, new ("other", "value"), new ("resources", resourcesArray)); 658 659 var groupChildren = set.Units[2].Units; 660 Assert.Single(groupChildren); 661 662 Assert.Equal("Grouped/Resource", groupChildren[0].Type); 663 Assert.Equal("Child", groupChildren[0].Identifier); 664 this.VerifyValueSet(groupChildren[0].Settings, new KeyValuePair<string, object>("b", "c")); 665 } 666 667 /// <summary> 668 /// Test for using version 0.3 schema. 669 /// </summary> 670 [Fact] 671 public void BasicVersion_0_3() 672 { 673 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 674 675 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(@" 676 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 677 metadata: 678 a: 1 679 b: '2' 680 variables: 681 v1: var1 682 v2: 42 683 resources: 684 - name: Name 685 type: Module/Resource 686 metadata: 687 e: '5' 688 f: 6 689 properties: 690 c: 3 691 d: '4' 692 dependsOn: 693 - g 694 - h 695 - name: Name2 696 type: Module/Resource2 697 dependsOn: 698 - m 699 properties: 700 l: '10' 701 metadata: 702 i: '7' 703 j: 8 704 q: 42 705 ")); 706 707 Assert.Null(result.ResultCode); 708 Assert.NotNull(result.Set); 709 Assert.Equal(string.Empty, result.Field); 710 Assert.Equal(string.Empty, result.Value); 711 Assert.Equal(0U, result.Line); 712 Assert.Equal(0U, result.Column); 713 714 ConfigurationSet set = result.Set; 715 716 Assert.Equal("0.3", set.SchemaVersion); 717 Assert.NotNull(set.SchemaUri); 718 Assert.Equal("https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json", set.SchemaUri.ToString()); 719 720 this.VerifyValueSet(set.Metadata, new ("a", 1), new ("b", "2")); 721 this.VerifyValueSet(set.Variables, new ("v1", "var1"), new ("v2", 42)); 722 723 Assert.Empty(set.Parameters); 724 725 Assert.Equal(2, set.Units.Count); 726 727 this.VerifyUnitProperties(set.Units[0], "Name", "Module/Resource"); 728 this.VerifyValueSet(set.Units[0].Metadata, new ("e", "5"), new ("f", 6)); 729 this.VerifyValueSet(set.Units[0].Settings, new ("c", 3), new ("d", "4")); 730 this.VerifyStringArray(set.Units[0].Dependencies, "g", "h"); 731 732 this.VerifyUnitProperties(set.Units[1], "Name2", "Module/Resource2"); 733 this.VerifyValueSet(set.Units[1].Metadata, new ("i", "7"), new ("j", 8), new ("q", 42)); 734 this.VerifyValueSet(set.Units[1].Settings, new KeyValuePair<string, object>("l", "10")); 735 this.VerifyStringArray(set.Units[1].Dependencies, "m"); 736 } 737 738 /// <summary> 739 /// Test for the successful parsing of default value of a parameter. 740 /// </summary> 741 /// <param name="type">The type.</param> 742 /// <param name="defaultValue">The default value.</param> 743 /// <param name="expectedValue">The expected value.</param> 744 /// <param name="expectedType">The expected type.</param> 745 /// <param name="secure">The secure state.</param> 746 [Theory] 747 [InlineData("string", "abc", "abc", Windows.Foundation.PropertyType.String)] 748 [InlineData("string", "'42'", "42", Windows.Foundation.PropertyType.String)] 749 [InlineData("securestring", "abcdef", "abcdef", Windows.Foundation.PropertyType.String, true)] 750 [InlineData("int", "42", 42, Windows.Foundation.PropertyType.Int64)] 751 [InlineData("bool", "true", true, Windows.Foundation.PropertyType.Boolean)] 752 [InlineData("object", "string", "string", Windows.Foundation.PropertyType.Inspectable)] 753 [InlineData("object", "42", 42, Windows.Foundation.PropertyType.Inspectable)] 754 [InlineData("secureobject", "string", "string", Windows.Foundation.PropertyType.Inspectable, true)] 755 [InlineData("secureobject", "42", 42, Windows.Foundation.PropertyType.Inspectable, true)] 756 public void Parameters_DefaultValue_Success(string type, string defaultValue, object expectedValue, object expectedType, bool secure = false) 757 { 758 this.TestParameterDefaultValue(type, defaultValue, expectedValue, Assert.IsType<Windows.Foundation.PropertyType>(expectedType), secure); 759 } 760 761 /// <summary> 762 /// Test for the failed parsing of default value of a parameter. 763 /// </summary> 764 /// <param name="type">The type.</param> 765 /// <param name="defaultValue">The default value.</param> 766 /// <param name="expectedValue">The expected value.</param> 767 [Theory] 768 [InlineData("string", "42")] 769 [InlineData("int", "abc")] 770 [InlineData("int", "'42'", "42")] 771 [InlineData("bool", "'true'", "true")] 772 public void Parameters_DefaultValue_Failure(string type, string defaultValue, object? expectedValue = null) 773 { 774 this.TestParameterDefaultValue(type, defaultValue, expectedValue); 775 } 776 777 /// <summary> 778 /// Test to ensure that schema version and uri is working as expected. 779 /// </summary> 780 /// <param name="version">The version.</param> 781 /// <param name="uri">The uri.</param> 782 [Theory] 783 [InlineData("0.1", null)] 784 [InlineData("0.2", null)] 785 [InlineData("0.3", "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json")] 786 public void Schema_Version_Uri(string version, string? uri) 787 { 788 ConfigurationSet set = this.ConfigurationSet(); 789 790 set.SchemaVersion = version; 791 if (uri != null) 792 { 793 Assert.Equal(uri, set.SchemaUri.AbsoluteUri); 794 } 795 else 796 { 797 Assert.Null(set.SchemaUri); 798 } 799 800 if (!string.IsNullOrEmpty(uri)) 801 { 802 set.SchemaUri = new Uri(uri); 803 Assert.Equal(version, set.SchemaVersion); 804 } 805 } 806 807 /// <summary> 808 /// Verifies that the configuration set (0.2) with environments parses and serializes. 809 /// </summary> 810 [Fact] 811 public void Environment_0_2() 812 { 813 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 814 815 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 816 properties: 817 configurationVersion: 0.2 818 resources: 819 - resource: FakeModule/FakeResource 820 id: elevated 821 directives: 822 description: FakeDescription 823 allowPrerelease: true 824 securityContext: elevated 825 settings: 826 TestString: Hello 827 - resource: FakeModule2/FakeResource2 828 id: restricted 829 directives: 830 description: FakeDescription2 831 securityContext: restricted 832 settings: 833 TestString: Bye 834 - resource: FakeModule2/FakeResource2 835 id: current 836 directives: 837 securityContext: current 838 settings: 839 TestString: Bye 840 - resource: FakeModule2/FakeResource2 841 id: default 842 settings: 843 TestString: Bye 844 ")); 845 846 Dictionary<string, SecurityContext> expectedEnvironments = new Dictionary<string, SecurityContext>(); 847 expectedEnvironments.Add("elevated", SecurityContext.Elevated); 848 expectedEnvironments.Add("restricted", SecurityContext.Restricted); 849 expectedEnvironments.Add("current", SecurityContext.Current); 850 expectedEnvironments.Add("default", SecurityContext.Current); 851 852 this.ValidateSecurityContexts(openResult, expectedEnvironments); 853 854 // Shuffle security contexts, serialize, parse and validate again 855 expectedEnvironments["elevated"] = SecurityContext.Restricted; 856 expectedEnvironments["restricted"] = SecurityContext.Current; 857 expectedEnvironments["current"] = SecurityContext.Restricted; 858 expectedEnvironments["default"] = SecurityContext.Elevated; 859 860 var units = openResult.Set.Units; 861 foreach (var unit in units) 862 { 863 SecurityContext newContext = SecurityContext.Current; 864 Assert.True(expectedEnvironments.TryGetValue(unit.Identifier, out newContext)); 865 unit.Environment.Context = newContext; 866 } 867 868 // Serialize set. 869 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 870 openResult.Set.Serialize(stream); 871 872 string yamlOutput = this.ReadStream(stream); 873 874 // Reopen configuration set from serialized string and verify values. 875 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 876 877 this.ValidateSecurityContexts(serializedSetResult, expectedEnvironments); 878 } 879 880 /// <summary> 881 /// Verifies that the configuration set (0.3) inherits set environment. 882 /// </summary> 883 [Fact] 884 public void SetMetadataEnvironmentInheritance_0_3() 885 { 886 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 887 888 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 889 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 890 metadata: 891 winget: 892 securityContext: elevated 893 processor: 894 identifier: pwsh 895 properties: 896 a: b 897 resources: 898 - name: first 899 type: Module/Resource 900 properties: 901 c: 3 902 - name: second 903 type: Module/Resource2 904 properties: 905 l: '10' 906 ")); 907 908 Dictionary<string, string> environmentProperties = new Dictionary<string, string>(); 909 environmentProperties.Add("a", "b"); 910 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties }; 911 912 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 913 expectedEnvironments.Add("first", new ConfigurationEnvironmentData()); 914 expectedEnvironments.Add("second", new ConfigurationEnvironmentData()); 915 916 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments); 917 918 // Serialize set. 919 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 920 openResult.Set.Serialize(stream); 921 922 string yamlOutput = this.ReadStream(stream); 923 924 // Reopen configuration set from serialized string and verify values. 925 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 926 927 this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments); 928 } 929 930 /// <summary> 931 /// Verifies that the configuration set (0.3) inherits set environment. 932 /// </summary> 933 [Fact] 934 public void SetMetadataEnvironmentInheritance_ProcessorOverridden_0_3() 935 { 936 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 937 938 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 939 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 940 metadata: 941 winget: 942 securityContext: elevated 943 processor: 944 identifier: pwsh 945 properties: 946 a: b 947 resources: 948 - name: first 949 type: Module/Resource 950 properties: 951 c: 3 952 - name: second 953 type: Module/Resource2 954 properties: 955 l: '10' 956 metadata: 957 winget: 958 processor: not-pwsh 959 ")); 960 961 Dictionary<string, string> environmentProperties = new Dictionary<string, string>(); 962 environmentProperties.Add("a", "b"); 963 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties }; 964 965 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 966 expectedEnvironments.Add("first", new ConfigurationEnvironmentData()); 967 expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { ProcessorIdentifier = "not-pwsh" }); 968 969 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments); 970 971 // Serialize set. 972 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 973 openResult.Set.Serialize(stream); 974 975 string yamlOutput = this.ReadStream(stream); 976 977 // Reopen configuration set from serialized string and verify values. 978 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 979 980 this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments); 981 } 982 983 /// <summary> 984 /// Verifies that the configuration set (0.3) inherits set environment. 985 /// </summary> 986 [Fact] 987 public void SetMetadataEnvironmentInheritance_ContextOverridden_0_3() 988 { 989 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 990 991 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 992 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 993 metadata: 994 winget: 995 securityContext: elevated 996 processor: 997 identifier: pwsh 998 properties: 999 a: b 1000 resources: 1001 - name: first 1002 type: Module/Resource 1003 properties: 1004 c: 3 1005 - name: second 1006 type: Module/Resource2 1007 properties: 1008 l: '10' 1009 metadata: 1010 winget: 1011 securityContext: restricted 1012 ")); 1013 1014 Dictionary<string, string> environmentProperties = new Dictionary<string, string>(); 1015 environmentProperties.Add("a", "b"); 1016 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties }; 1017 1018 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 1019 expectedEnvironments.Add("first", new ConfigurationEnvironmentData()); 1020 expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted }); 1021 1022 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments); 1023 1024 // Serialize set. 1025 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 1026 openResult.Set.Serialize(stream); 1027 1028 string yamlOutput = this.ReadStream(stream); 1029 1030 // Reopen configuration set from serialized string and verify values. 1031 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 1032 1033 this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments); 1034 } 1035 1036 /// <summary> 1037 /// Verifies that the configuration set (0.3) serializes common environment to the set metadata. 1038 /// </summary> 1039 [Fact] 1040 public void CommonEnvironmentElevatedToSetMetadata_0_3() 1041 { 1042 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 1043 1044 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 1045 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 1046 resources: 1047 - name: first 1048 type: Module/Resource 1049 metadata: 1050 winget: 1051 securityContext: elevated 1052 processor: pwsh 1053 properties: 1054 c: 3 1055 - name: second 1056 type: Module/Resource2 1057 properties: 1058 l: '10' 1059 metadata: 1060 winget: 1061 securityContext: elevated 1062 processor: 1063 identifier: pwsh 1064 ")); 1065 1066 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData(); 1067 1068 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 1069 expectedEnvironments.Add("first", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" }); 1070 expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" }); 1071 1072 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments); 1073 1074 // Serialize set. 1075 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 1076 openResult.Set.Serialize(stream); 1077 1078 string yamlOutput = this.ReadStream(stream); 1079 1080 // Reopen configuration set from serialized string and verify values. 1081 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 1082 1083 this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments); 1084 } 1085 1086 /// <summary> 1087 /// Verifies that the configuration set (0.3) serializes common environment to the set metadata. 1088 /// </summary> 1089 [Fact] 1090 public void CommonProcessorElevatedToSetMetadata_0_3() 1091 { 1092 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 1093 1094 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 1095 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 1096 resources: 1097 - name: first 1098 type: Module/Resource 1099 metadata: 1100 winget: 1101 securityContext: elevated 1102 processor: pwsh 1103 properties: 1104 c: 3 1105 - name: second 1106 type: Module/Resource2 1107 properties: 1108 l: '10' 1109 metadata: 1110 winget: 1111 securityContext: restricted 1112 processor: 1113 identifier: pwsh 1114 ")); 1115 1116 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData(); 1117 1118 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 1119 expectedEnvironments.Add("first", new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh" }); 1120 expectedEnvironments.Add("second", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted, ProcessorIdentifier = "pwsh" }); 1121 1122 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments); 1123 1124 // Serialize set. 1125 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 1126 openResult.Set.Serialize(stream); 1127 1128 string yamlOutput = this.ReadStream(stream); 1129 1130 // Reopen configuration set from serialized string and verify values. 1131 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 1132 1133 this.ValidateEnvironments(serializedSetResult, setEnvironment, expectedEnvironments); 1134 } 1135 1136 /// <summary> 1137 /// Verifies that the configuration set (0.3) environments work with group units. 1138 /// </summary> 1139 [Fact] 1140 public void EnvironmentsWithGroups_0_3() 1141 { 1142 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 1143 1144 OpenConfigurationSetResult openResult = processor.OpenConfigurationSet(this.CreateStream(@" 1145 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 1146 metadata: 1147 winget: 1148 securityContext: elevated 1149 processor: 1150 identifier: pwsh 1151 properties: 1152 a: b 1153 resources: 1154 - name: non-group 1155 type: Module/Resource2 1156 properties: 1157 l: '10' 1158 - name: group 1159 type: Module/Resource 1160 metadata: 1161 isGroup: true 1162 winget: 1163 securityContext: restricted 1164 properties: 1165 resources: 1166 - name: inherit 1167 type: Module/Resource 1168 properties: 1169 a: b 1170 - name: override 1171 type: Module/Resource 1172 properties: 1173 c: d 1174 metadata: 1175 winget: 1176 processor: not-pwsh 1177 ")); 1178 1179 Dictionary<string, string> environmentProperties = new Dictionary<string, string>(); 1180 environmentProperties.Add("a", "b"); 1181 ConfigurationEnvironmentData setEnvironment = new ConfigurationEnvironmentData() { Context = SecurityContext.Elevated, ProcessorIdentifier = "pwsh", ProcessorProperties = environmentProperties }; 1182 1183 Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 1184 expectedEnvironments.Add("non-group", new ConfigurationEnvironmentData()); 1185 expectedEnvironments.Add("group", new ConfigurationEnvironmentData() { Context = SecurityContext.Restricted }); 1186 1187 Dictionary<string, ConfigurationEnvironmentData> groupExpectedEnvironments = new Dictionary<string, ConfigurationEnvironmentData>(); 1188 groupExpectedEnvironments.Add("inherit", new ConfigurationEnvironmentData()); 1189 groupExpectedEnvironments.Add("override", new ConfigurationEnvironmentData() { ProcessorIdentifier = "not-pwsh" }); 1190 1191 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments, "group", groupExpectedEnvironments); 1192 1193 // Serialize set. 1194 InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream(); 1195 openResult.Set.Serialize(stream); 1196 1197 string yamlOutput = this.ReadStream(stream); 1198 1199 // Reopen configuration set from serialized string and verify values. 1200 OpenConfigurationSetResult serializedSetResult = processor.OpenConfigurationSet(this.CreateStream(yamlOutput)); 1201 1202 this.ValidateEnvironments(openResult, setEnvironment, expectedEnvironments, "group", groupExpectedEnvironments); 1203 } 1204 1205 private void ValidateEnvironments(OpenConfigurationSetResult openResult, ConfigurationEnvironmentData setEnvironment, Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments, string? groupToCheck = null, Dictionary<string, ConfigurationEnvironmentData>? groupExpectedEnvironments = null) 1206 { 1207 Assert.Null(openResult.ResultCode); 1208 Assert.NotNull(openResult.Set); 1209 ConfigurationSet configurationSet = openResult.Set; 1210 1211 this.ValidateEnvironment(setEnvironment, configurationSet.Environment); 1212 1213 var units = configurationSet.Units; 1214 this.ValidateEnvironments(units, expectedEnvironments, groupToCheck, groupExpectedEnvironments); 1215 } 1216 1217 private void ValidateEnvironments(IList<ConfigurationUnit> units, Dictionary<string, ConfigurationEnvironmentData> expectedEnvironments, string? groupToCheck = null, Dictionary<string, ConfigurationEnvironmentData>? groupExpectedEnvironments = null) 1218 { 1219 Assert.Equal(expectedEnvironments.Count, units.Count); 1220 foreach (var unit in units) 1221 { 1222 ConfigurationEnvironmentData? expectedEnvironment = null; 1223 Assert.True(expectedEnvironments.TryGetValue(unit.Identifier, out expectedEnvironment)); 1224 this.ValidateEnvironment(expectedEnvironment, unit.Environment); 1225 1226 if (unit.Identifier == groupToCheck) 1227 { 1228 Assert.True(unit.IsGroup); 1229 Assert.NotNull(groupExpectedEnvironments); 1230 var groupUnits = unit.Units; 1231 this.ValidateEnvironments(groupUnits, groupExpectedEnvironments); 1232 } 1233 } 1234 } 1235 1236 private void ValidateEnvironment(ConfigurationEnvironmentData? expectedEnvironment, ConfigurationEnvironment? actualEnvironment) 1237 { 1238 Assert.NotNull(expectedEnvironment); 1239 Assert.NotNull(actualEnvironment); 1240 Assert.Equal(expectedEnvironment.Context, actualEnvironment.Context); 1241 Assert.Equal(expectedEnvironment.ProcessorIdentifier, actualEnvironment.ProcessorIdentifier); 1242 Assert.True(expectedEnvironment.PropertiesEqual(actualEnvironment.ProcessorProperties)); 1243 } 1244 1245 private void ValidateSecurityContexts(OpenConfigurationSetResult openResult, Dictionary<string, SecurityContext> expectedContexts) 1246 { 1247 Assert.Null(openResult.ResultCode); 1248 Assert.NotNull(openResult.Set); 1249 ConfigurationSet configurationSet = openResult.Set; 1250 1251 var units = configurationSet.Units; 1252 Assert.Equal(expectedContexts.Count, units.Count); 1253 foreach (var unit in units) 1254 { 1255 SecurityContext expectedContext = SecurityContext.Current; 1256 Assert.True(expectedContexts.TryGetValue(unit.Identifier, out expectedContext)); 1257 Assert.Equal(expectedContext, unit.Environment.Context); 1258 } 1259 } 1260 1261 private void TestParameterDefaultValue(string type, string defaultValue, object? expectedValue = null, Windows.Foundation.PropertyType? expectedType = null, bool secure = false) 1262 { 1263 ConfigurationProcessor processor = this.CreateConfigurationProcessorWithDiagnostics(); 1264 1265 OpenConfigurationSetResult result = processor.OpenConfigurationSet(this.CreateStream(string.Format( 1266 @" 1267 $schema: https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2023/08/config/document.json 1268 parameters: 1269 {0}: 1270 type: {0} 1271 defaultValue: {1} 1272 ", 1273 type, 1274 defaultValue))); 1275 1276 if (expectedType != null) 1277 { 1278 Assert.Null(result.ResultCode); 1279 Assert.NotNull(result.Set); 1280 Assert.Equal(string.Empty, result.Field); 1281 Assert.Equal(string.Empty, result.Value); 1282 Assert.Equal(0U, result.Line); 1283 Assert.Equal(0U, result.Column); 1284 1285 var parameters = result.Set.Parameters; 1286 Assert.NotNull(parameters); 1287 Assert.Single(parameters); 1288 1289 Assert.Equal(type, parameters[0].Name); 1290 Assert.Equal(expectedType, parameters[0].Type); 1291 Assert.Equal(secure, parameters[0].IsSecure); 1292 1293 Assert.NotNull(expectedValue); 1294 this.VerifyObject(type, expectedValue, parameters[0].DefaultValue); 1295 } 1296 else 1297 { 1298 Assert.NotNull(result.ResultCode); 1299 Assert.Equal(Errors.WINGET_CONFIG_ERROR_INVALID_FIELD_VALUE, result.ResultCode.HResult); 1300 Assert.Null(result.Set); 1301 Assert.Equal("defaultValue", result.Field); 1302 Assert.Equal(expectedValue?.ToString() ?? defaultValue, result.Value); 1303 Assert.NotEqual(0U, result.Line); 1304 Assert.NotEqual(0U, result.Column); 1305 } 1306 } 1307 1308 private void VerifyUnitProperties(ConfigurationUnit unit, string identifier, string type) 1309 { 1310 Assert.NotNull(unit); 1311 Assert.Equal(identifier, unit.Identifier); 1312 Assert.Equal(type, unit.Type); 1313 } 1314 1315 private void VerifyValueSet(ValueSet values, params KeyValuePair<string, object>[] expected) 1316 { 1317 Assert.NotNull(values); 1318 Assert.Equal(expected.Length, values.Count); 1319 1320 foreach (var expectation in expected) 1321 { 1322 Assert.True(values.ContainsKey(expectation.Key), $"Not Found {expectation.Key}"); 1323 object value = values[expectation.Key]; 1324 1325 this.VerifyObject(expectation.Key, expectation.Value, value); 1326 } 1327 } 1328 1329 private void VerifyStringArray(IList<string> strings, params string[] expected) 1330 { 1331 Assert.NotNull(strings); 1332 Assert.Equal(expected.Length, strings.Count); 1333 1334 foreach (var expectation in expected) 1335 { 1336 bool found = false; 1337 foreach (var value in strings) 1338 { 1339 if (!found) 1340 { 1341 found = expectation == value; 1342 } 1343 } 1344 1345 Assert.True(found, $"Did not find {expectation} in string array"); 1346 } 1347 } 1348 1349 private void VerifyParameter(ConfigurationParameter parameter, string name, Windows.Foundation.PropertyType type, bool secure, object? defaultValue = null) 1350 { 1351 Assert.Equal(name, parameter.Name); 1352 Assert.Equal(type, parameter.Type); 1353 Assert.Equal(secure, parameter.IsSecure); 1354 this.VerifyObject(name, defaultValue, parameter.DefaultValue); 1355 } 1356 1357 private void VerifyObject(string name, object? expectedValue, object? actualValue) 1358 { 1359 if (expectedValue != null) 1360 { 1361 Assert.NotNull(actualValue); 1362 1363 switch (expectedValue) 1364 { 1365 case int i: 1366 Assert.True(i == (int)(long)actualValue, $"{name}: expected[{i}], actual[{(int)(long)actualValue}]"); 1367 break; 1368 case string s: 1369 Assert.True(s == (string)actualValue, $"{name}: expected[{s}], actual[{(string)actualValue}]"); 1370 break; 1371 case bool b: 1372 Assert.True(b == (bool)actualValue, $"{name}: expected[{b}], actual[{(bool)actualValue}]"); 1373 break; 1374 case ValueSet v: 1375 var actualValueSet = actualValue.As<ValueSet>(); 1376 Assert.True(v.ContentEquals(actualValueSet), $"ValueSets not equal: {name}\n---expected---:\n{v.ToYaml()}\n---actual---:\n{actualValueSet.ToYaml()}"); 1377 break; 1378 default: 1379 Assert.Fail($"Add expected type `{expectedValue.GetType().Name}` to switch statement for {name}."); 1380 break; 1381 } 1382 } 1383 } 1384 } 1385 }