DSCv3SourceResourceCommand.cs (21528B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="DSCv3SourceResourceCommand.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace AppInstallerCLIE2ETests 8 { 9 using System.Collections.Generic; 10 using System.Text.Json.Serialization; 11 using AppInstallerCLIE2ETests.Helpers; 12 using NUnit.Framework; 13 14 /// <summary> 15 /// `Configure` command tests. 16 /// </summary> 17 [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1010:Opening square brackets should be spaced correctly", Justification = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3687 pending SC 1.2 release")] 18 [System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.SpacingRules", "SA1011:Closing square brackets should be spaced correctly", Justification = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3687 pending SC 1.2 release")] 19 public class DSCv3SourceResourceCommand : DSCv3ResourceTestBase 20 { 21 private const string DefaultSourceName = "SourceResourceTestSource"; 22 private const string DefaultSourceType = "Microsoft.Test.Configurable"; 23 private const string DefaultTrustLevel = "none"; 24 private const string TrustedTrustLevel = "trusted"; 25 private const bool DefaultExplicitState = false; 26 private const string SourceResource = "source"; 27 private const string ArgumentPropertyName = "argument"; 28 private const string TypePropertyName = "type"; 29 private const string TrustLevelPropertyName = "trustLevel"; 30 private const string ExplicitPropertyName = "explicit"; 31 32 private static string DefaultSourceArgForCmdLine 33 { 34 get { return CreateSourceArgument(true); } 35 } 36 37 private static string NonDefaultSourceArgForCmdLine 38 { 39 get { return CreateSourceArgument(true, 1, 1); } 40 } 41 42 private static string DefaultSourceArgDirect 43 { 44 get { return CreateSourceArgument(false); } 45 } 46 47 private static string NonDefaultSourceArgDirect 48 { 49 get { return CreateSourceArgument(false, 1, 1); } 50 } 51 52 /// <summary> 53 /// Setup done once before all the tests here. 54 /// </summary> 55 [OneTimeSetUp] 56 public void OneTimeSetup() 57 { 58 TestCommon.SetupTestSource(); 59 EnsureTestResourcePresence(); 60 } 61 62 /// <summary> 63 /// Teardown done once after all the tests here. 64 /// </summary> 65 [OneTimeTearDown] 66 public void OneTimeTeardown() 67 { 68 RemoveTestSource(); 69 TestCommon.TearDownTestSource(); 70 } 71 72 /// <summary> 73 /// Set up. 74 /// </summary> 75 [SetUp] 76 public void Setup() 77 { 78 RemoveTestSource(); 79 } 80 81 /// <summary> 82 /// Calls `get` on the `source` resource with the value not present. 83 /// </summary> 84 [Test] 85 public void Source_Get_NotPresent() 86 { 87 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 88 89 var result = RunDSCv3Command(SourceResource, GetFunction, resourceData); 90 AssertSuccessfulResourceRun(ref result); 91 92 SourceResourceData output = GetSingleOutputLineAs<SourceResourceData>(result.StdOut); 93 Assert.IsNotNull(output); 94 Assert.False(output.Exist); 95 Assert.AreEqual(resourceData.Name, output.Name); 96 } 97 98 /// <summary> 99 /// Calls `get` on the `source` resource with the value present. 100 /// </summary> 101 [Test] 102 public void Source_Get_Present() 103 { 104 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {DefaultSourceArgForCmdLine} --type {DefaultSourceType} --explicit"); 105 Assert.AreEqual(0, setup.ExitCode); 106 107 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 108 109 var result = RunDSCv3Command(SourceResource, GetFunction, resourceData); 110 AssertSuccessfulResourceRun(ref result); 111 112 SourceResourceData output = GetSingleOutputLineAs<SourceResourceData>(result.StdOut); 113 AssertExistingSourceResourceData(output, DefaultSourceArgDirect, DefaultTrustLevel, true); 114 } 115 116 /// <summary> 117 /// Calls `test` on the `source` resource with the value not present. 118 /// </summary> 119 [Test] 120 public void Source_Test_NotPresent() 121 { 122 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 123 124 var result = RunDSCv3Command(SourceResource, TestFunction, resourceData); 125 AssertSuccessfulResourceRun(ref result); 126 127 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 128 Assert.IsNotNull(output); 129 Assert.False(output.Exist); 130 Assert.AreEqual(resourceData.Name, output.Name); 131 Assert.False(output.InDesiredState); 132 133 AssertDiffState(diff, [ ExistPropertyName ]); 134 } 135 136 /// <summary> 137 /// Calls `test` on the `source` resource with the value present. 138 /// </summary> 139 [Test] 140 public void Source_Test_SimplePresent() 141 { 142 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {DefaultSourceArgForCmdLine} --type {DefaultSourceType}"); 143 Assert.AreEqual(0, setup.ExitCode); 144 145 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 146 147 var result = RunDSCv3Command(SourceResource, TestFunction, resourceData); 148 AssertSuccessfulResourceRun(ref result); 149 150 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 151 AssertExistingSourceResourceData(output, DefaultSourceArgDirect, DefaultTrustLevel, DefaultExplicitState); 152 Assert.True(output.InDesiredState); 153 154 AssertDiffState(diff, []); 155 } 156 157 /// <summary> 158 /// Calls `test` on the `source` resource with a argument that matches. 159 /// </summary> 160 /// <param name="useDefaultArgument">The argument to use when adding the existing source.</param> 161 /// <param name="trustLevel">The trust level to use when adding the existing source.</param> 162 /// <param name="isExplicit">The explicit state to use when adding the existing source.</param> 163 /// <param name="targetProperty">The property to target for the test.</param> 164 [TestCase(false, DefaultTrustLevel, true, ArgumentPropertyName)] 165 [TestCase(true, DefaultTrustLevel, false, TypePropertyName)] 166 [TestCase(false, TrustedTrustLevel, false, TrustLevelPropertyName)] 167 [TestCase(true, DefaultTrustLevel, true, ExplicitPropertyName)] 168 public void Source_Test_PropertyMatch(bool useDefaultArgument, string trustLevel, bool isExplicit, string targetProperty) 169 { 170 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {(useDefaultArgument ? DefaultSourceArgForCmdLine : NonDefaultSourceArgForCmdLine)} --type {DefaultSourceType} --trust-level {trustLevel} {(isExplicit ? "--explicit" : string.Empty)}"); 171 Assert.AreEqual(0, setup.ExitCode); 172 173 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 174 175 switch (targetProperty) 176 { 177 case ArgumentPropertyName: 178 resourceData.Argument = useDefaultArgument ? DefaultSourceArgDirect : NonDefaultSourceArgDirect; 179 break; 180 case TypePropertyName: 181 resourceData.Type = DefaultSourceType; 182 break; 183 case TrustLevelPropertyName: 184 resourceData.TrustLevel = trustLevel; 185 break; 186 case ExplicitPropertyName: 187 resourceData.Explicit = isExplicit; 188 break; 189 default: 190 Assert.Fail($"{targetProperty} is not a handled case."); 191 break; 192 } 193 194 var result = RunDSCv3Command(SourceResource, TestFunction, resourceData); 195 AssertSuccessfulResourceRun(ref result); 196 197 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 198 AssertExistingSourceResourceData(output, useDefaultArgument ? DefaultSourceArgDirect : NonDefaultSourceArgDirect, trustLevel, isExplicit); 199 Assert.True(output.InDesiredState); 200 201 AssertDiffState(diff, []); 202 } 203 204 /// <summary> 205 /// Calls `test` on the `source` resource with a argument that does not match. 206 /// </summary> 207 /// <param name="useDefaultArgument">The argument to use when adding the existing source.</param> 208 /// <param name="trustLevel">The trust level to use when adding the existing source.</param> 209 /// <param name="isExplicit">The explicit state to use when adding the existing source.</param> 210 /// <param name="targetProperty">The property to target for the test.</param> 211 /// <param name="testValue">The value to test against.</param> 212 [TestCase(false, DefaultTrustLevel, true, ArgumentPropertyName, true)] 213 [TestCase(false, DefaultTrustLevel, false, TrustLevelPropertyName, TrustedTrustLevel)] 214 [TestCase(true, DefaultTrustLevel, true, ExplicitPropertyName, false)] 215 public void Source_Test_PropertyMismatch(bool useDefaultArgument, string trustLevel, bool isExplicit, string targetProperty, object testValue) 216 { 217 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {(useDefaultArgument ? DefaultSourceArgForCmdLine : NonDefaultSourceArgForCmdLine)} --type {DefaultSourceType} --trust-level {trustLevel} {(isExplicit ? "--explicit" : string.Empty)}"); 218 Assert.AreEqual(0, setup.ExitCode); 219 220 SourceResourceData resourceData = new SourceResourceData() { Name = DefaultSourceName }; 221 222 switch (targetProperty) 223 { 224 case ArgumentPropertyName: 225 resourceData.Argument = (bool)testValue ? DefaultSourceArgDirect : NonDefaultSourceArgDirect; 226 break; 227 case TrustLevelPropertyName: 228 resourceData.TrustLevel = (string)testValue; 229 break; 230 case ExplicitPropertyName: 231 resourceData.Explicit = (bool)testValue; 232 break; 233 default: 234 Assert.Fail($"{targetProperty} is not a handled case."); 235 break; 236 } 237 238 var result = RunDSCv3Command(SourceResource, TestFunction, resourceData); 239 AssertSuccessfulResourceRun(ref result); 240 241 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 242 AssertExistingSourceResourceData(output, useDefaultArgument ? DefaultSourceArgDirect : NonDefaultSourceArgDirect, trustLevel, isExplicit); 243 Assert.False(output.InDesiredState); 244 245 AssertDiffState(diff, [ targetProperty ]); 246 } 247 248 /// <summary> 249 /// Calls `test` on the `source` resource with all properties matching. 250 /// </summary> 251 [Test] 252 public void Source_Test_AllMatch() 253 { 254 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {NonDefaultSourceArgForCmdLine} --type {DefaultSourceType} --trust-level {TrustedTrustLevel} --explicit"); 255 Assert.AreEqual(0, setup.ExitCode); 256 257 SourceResourceData resourceData = new SourceResourceData() 258 { 259 Name = DefaultSourceName, 260 Argument = NonDefaultSourceArgDirect, 261 Type = DefaultSourceType, 262 TrustLevel = TrustedTrustLevel, 263 Explicit = true, 264 }; 265 266 var result = RunDSCv3Command(SourceResource, TestFunction, resourceData); 267 AssertSuccessfulResourceRun(ref result); 268 269 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 270 AssertExistingSourceResourceData(output, resourceData); 271 Assert.True(output.InDesiredState); 272 273 AssertDiffState(diff, []); 274 } 275 276 /// <summary> 277 /// Calls `set` on the `source` resource when the source is not present, and again afterward. 278 /// </summary> 279 [Test] 280 public void Source_Set_SimpleRepeated() 281 { 282 SourceResourceData resourceData = new SourceResourceData() 283 { 284 Name = DefaultSourceName, 285 Argument = NonDefaultSourceArgDirect, 286 Type = DefaultSourceType, 287 }; 288 289 var result = RunDSCv3Command(SourceResource, SetFunction, resourceData); 290 AssertSuccessfulResourceRun(ref result); 291 292 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 293 AssertExistingSourceResourceData(output, resourceData); 294 295 AssertDiffState(diff, [ ExistPropertyName ]); 296 297 // Set again should be a no-op 298 result = RunDSCv3Command(SourceResource, SetFunction, resourceData); 299 AssertSuccessfulResourceRun(ref result); 300 301 (output, diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 302 AssertExistingSourceResourceData(output, resourceData); 303 304 AssertDiffState(diff, []); 305 } 306 307 /// <summary> 308 /// Calls `set` on the `source` resource to ensure that it is not present. 309 /// </summary> 310 [Test] 311 public void Source_Set_Remove() 312 { 313 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {DefaultSourceArgForCmdLine} --type {DefaultSourceType} --explicit"); 314 Assert.AreEqual(0, setup.ExitCode); 315 316 SourceResourceData resourceData = new SourceResourceData() 317 { 318 Name = DefaultSourceName, 319 Exist = false, 320 }; 321 322 var result = RunDSCv3Command(SourceResource, SetFunction, resourceData); 323 AssertSuccessfulResourceRun(ref result); 324 325 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 326 Assert.IsNotNull(output); 327 Assert.False(output.Exist); 328 Assert.AreEqual(resourceData.Name, output.Name); 329 330 AssertDiffState(diff, [ ExistPropertyName ]); 331 332 // Call `get` to ensure the result 333 SourceResourceData resourceDataForGet = new SourceResourceData() 334 { 335 Name = DefaultSourceName, 336 }; 337 338 result = RunDSCv3Command(SourceResource, GetFunction, resourceDataForGet); 339 AssertSuccessfulResourceRun(ref result); 340 341 output = GetSingleOutputLineAs<SourceResourceData>(result.StdOut); 342 Assert.IsNotNull(output); 343 Assert.False(output.Exist); 344 Assert.AreEqual(resourceDataForGet.Name, output.Name); 345 } 346 347 /// <summary> 348 /// Calls `set` on the `source` resource with an existing item, replacing it. 349 /// </summary> 350 [Test] 351 public void Source_Set_Replace() 352 { 353 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {DefaultSourceArgForCmdLine} --type {DefaultSourceType}"); 354 Assert.AreEqual(0, setup.ExitCode); 355 356 SourceResourceData resourceData = new SourceResourceData() 357 { 358 Name = DefaultSourceName, 359 Argument = DefaultSourceArgDirect, 360 Type = DefaultSourceType, 361 TrustLevel = TrustedTrustLevel, 362 Explicit = true, 363 }; 364 365 var result = RunDSCv3Command(SourceResource, SetFunction, resourceData); 366 AssertSuccessfulResourceRun(ref result); 367 368 (SourceResourceData output, List<string> diff) = GetSingleOutputLineAndDiffAs<SourceResourceData>(result.StdOut); 369 AssertExistingSourceResourceData(output, resourceData); 370 371 AssertDiffState(diff, [ TrustLevelPropertyName, ExplicitPropertyName ]); 372 373 // Call `get` to ensure the result 374 SourceResourceData resourceDataForGet = new SourceResourceData() 375 { 376 Name = DefaultSourceName, 377 }; 378 379 result = RunDSCv3Command(SourceResource, GetFunction, resourceDataForGet); 380 AssertSuccessfulResourceRun(ref result); 381 382 output = GetSingleOutputLineAs<SourceResourceData>(result.StdOut); 383 AssertExistingSourceResourceData(output, resourceData); 384 } 385 386 /// <summary> 387 /// Calls `export` on the `source` resource without providing any input. 388 /// </summary> 389 [Test] 390 public void Source_Export_NoInput() 391 { 392 var setup = TestCommon.RunAICLICommand("source add", $"--name {DefaultSourceName} --arg {DefaultSourceArgForCmdLine} --type {DefaultSourceType}"); 393 Assert.AreEqual(0, setup.ExitCode); 394 395 var result = RunDSCv3Command(SourceResource, ExportFunction, " "); 396 AssertSuccessfulResourceRun(ref result); 397 398 List<SourceResourceData> output = GetOutputLinesAs<SourceResourceData>(result.StdOut); 399 400 bool foundDefaultSource = false; 401 foreach (SourceResourceData item in output) 402 { 403 if (item.Name == DefaultSourceName) 404 { 405 foundDefaultSource = true; 406 Assert.AreEqual(DefaultSourceName, item.Name); 407 Assert.AreEqual(DefaultSourceArgDirect, item.Argument); 408 Assert.AreEqual(DefaultSourceType, item.Type); 409 Assert.AreEqual(DefaultTrustLevel, item.TrustLevel); 410 Assert.AreEqual(DefaultExplicitState, item.Explicit); 411 break; 412 } 413 } 414 415 Assert.IsTrue(foundDefaultSource); 416 } 417 418 private static void RemoveTestSource() 419 { 420 SourceResourceData resourceData = new SourceResourceData() 421 { 422 Name = DefaultSourceName, 423 Exist = false, 424 }; 425 426 var result = RunDSCv3Command(SourceResource, SetFunction, resourceData); 427 AssertSuccessfulResourceRun(ref result); 428 } 429 430 private static void AssertExistingSourceResourceData(SourceResourceData output, SourceResourceData input) 431 { 432 AssertExistingSourceResourceData(output, input.Argument, input.TrustLevel, input.Explicit); 433 } 434 435 private static void AssertExistingSourceResourceData(SourceResourceData output, string argument, string trustLevel = null, bool? isExplicit = null) 436 { 437 Assert.IsNotNull(output); 438 Assert.True(output.Exist); 439 Assert.AreEqual(DefaultSourceName, output.Name); 440 Assert.AreEqual(argument, output.Argument); 441 Assert.AreEqual(DefaultSourceType, output.Type); 442 443 if (trustLevel != null) 444 { 445 Assert.AreEqual(trustLevel, output.TrustLevel); 446 } 447 448 if (isExplicit != null) 449 { 450 Assert.AreEqual(isExplicit, output.Explicit); 451 } 452 } 453 454 private static string CreateSourceArgument(bool forCommandLine = false, int openHR = 0, int searchHR = 0) 455 { 456 const string CommandLineFormat = @"""{{""""OpenHR"""": {0}, """"SearchHR"""": {1} }}"""; 457 const string DirectFormat = @"{{""OpenHR"": {0}, ""SearchHR"": {1} }}"; 458 return string.Format(forCommandLine ? CommandLineFormat : DirectFormat, openHR, searchHR); 459 } 460 461 private class SourceResourceData 462 { 463 [JsonPropertyName(ExistPropertyName)] 464 public bool? Exist { get; set; } 465 466 [JsonPropertyName(InDesiredStatePropertyName)] 467 public bool? InDesiredState { get; set; } 468 469 public string Name { get; set; } 470 471 public string Argument { get; set; } 472 473 public string Type { get; set; } 474 475 public string TrustLevel { get; set; } 476 477 public bool? Explicit { get; set; } 478 479 public bool? AcceptAgreements { get; set; } 480 } 481 } 482 }