DSCv3UserSettingsFileResourceCommand.cs (14835B)
1 // ----------------------------------------------------------------------------- 2 // <copyright file="DSCv3UserSettingsFileResourceCommand.cs" company="Microsoft Corporation"> 3 // Copyright (c) Microsoft Corporation. Licensed under the MIT License. 4 // </copyright> 5 // ----------------------------------------------------------------------------- 6 7 namespace AppInstallerCLIE2ETests; 8 9 using AppInstallerCLIE2ETests.Helpers; 10 using NUnit.Framework; 11 using System.Collections.Generic; 12 using System.IO; 13 using System.Text.Json.Nodes; 14 using System.Text.Json.Serialization; 15 16 /// <summary> 17 /// `Configure` command tests. 18 /// </summary> 19 [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")] 20 [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")] 21 public class DSCv3UserSettingsFileResourceCommand : DSCv3ResourceTestBase 22 { 23 private const string UserSettingsFileResource = "user-settings-file"; 24 private const string SettingsPropertyName = "settings"; 25 private const string ActionPropertyValueFull = "Full"; 26 private const string ActionPropertyValuePartial = "Partial"; 27 private const string SettingsMock = "mock"; 28 private const string SettingsMockObject = "mockObject"; 29 private const string SettingsMockNested = "mockNested"; 30 31 /// <summary> 32 /// Setup done once before all the tests here. 33 /// </summary> 34 [OneTimeSetUp] 35 public void OneTimeSetup() 36 { 37 TestCommon.SetupTestSource(); 38 EnsureTestResourcePresence(); 39 } 40 41 /// <summary> 42 /// Teardown done once after all the tests here. 43 /// </summary> 44 [OneTimeTearDown] 45 public void OneTimeTeardown() 46 { 47 WinGetSettingsHelper.InitializeWingetSettings(); 48 } 49 50 /// <summary> 51 /// Set up. 52 /// </summary> 53 [SetUp] 54 public void Setup() 55 { 56 // Reset the settings to default before each test. 57 WinGetSettingsHelper.InitializeWingetSettings(); 58 WinGetSettingsHelper.ConfigureFeature("dsc3", true); 59 } 60 61 /// <summary> 62 /// Calls `get` on the `user-settings-file` resource. 63 /// </summary> 64 [Test] 65 public void UserSettingsFile_Get() 66 { 67 var expected = GetCurrentUserSettings(); 68 var getOutput = Get(new ()); 69 70 Assert.IsNotNull(getOutput); 71 Assert.IsNull(getOutput.Action); 72 AssertSettingsAreEqual(expected, getOutput.Settings); 73 } 74 75 /// <summary> 76 /// Calls `set` on the `user-settings-file` resource with no diff. 77 /// </summary> 78 /// <param name="action">The action value.</param> 79 [Test] 80 [TestCase(ActionPropertyValueFull)] 81 [TestCase(ActionPropertyValuePartial)] 82 public void UserSettingsFile_Set_NoDiff(string action) 83 { 84 var setSettings = GetSettingsArg(action); 85 86 (var setOutput, var setDiff) = Set(new () { Action = action, Settings = setSettings }); 87 88 var expected = GetCurrentUserSettings(); 89 90 Assert.IsNotNull(setOutput); 91 Assert.AreEqual(action, setOutput.Action); 92 AssertSettingsAreEqual(expected, setOutput.Settings); 93 AssertDiffState(setDiff, []); 94 } 95 96 /// <summary> 97 /// Calls `set` on the `user-settings-file` resource to add fields. 98 /// </summary> 99 /// <param name="action">The action value.</param> 100 [Test] 101 [TestCase(ActionPropertyValueFull)] 102 [TestCase(ActionPropertyValuePartial)] 103 public void UserSettingsFile_Set_AddFields(string action) 104 { 105 // Call `set` to add mock properties to the settings 106 var setSettings = GetSettingsArg(action); 107 AddOrModifyMockProperties(setSettings, "mock"); 108 109 (var setOutput, var setDiff) = Set(new () { Action = action, Settings = setSettings }); 110 111 var expected = GetCurrentUserSettings(); 112 113 // Assert that the settings are added 114 Assert.IsNotNull(setOutput); 115 Assert.AreEqual(action, setOutput.Action); 116 AssertMockProperties(setOutput.Settings, "mock"); 117 AssertSettingsAreEqual(expected, setOutput.Settings); 118 AssertDiffState(setDiff, [ SettingsPropertyName ]); 119 } 120 121 /// <summary> 122 /// Calls `set` on the `user-settings-file` resource to ensure action is partial by default. 123 /// </summary> 124 [Test] 125 public void UserSettingsFile_Set_ActionIsPartialByDefault() 126 { 127 // Call `set` to add mock properties to the settings 128 var setSettings = GetSettingsArg(ActionPropertyValuePartial); 129 AddOrModifyMockProperties(setSettings, "mock"); 130 131 var expected = GetCurrentUserSettings(); 132 AddOrModifyMockProperties(expected, "mock"); 133 134 (var setOutput, var setDiff) = Set(new () { Settings = setSettings }); 135 136 // Assert that the settings are added 137 Assert.IsNotNull(setOutput); 138 Assert.AreEqual(setOutput.Action, ActionPropertyValuePartial); 139 AssertMockProperties(setOutput.Settings, "mock"); 140 AssertSettingsAreEqual(expected, setOutput.Settings); 141 AssertDiffState(setDiff, [ SettingsPropertyName ]); 142 } 143 144 /// <summary> 145 /// Calls `set` on the `user-settings-file` resource to update fields. 146 /// </summary> 147 /// <param name="action">The action value.</param> 148 [Test] 149 [TestCase(ActionPropertyValueFull)] 150 [TestCase(ActionPropertyValuePartial)] 151 public void UserSettingsFile_Set_UpdateFields(string action) 152 { 153 // Add mock properties to the settings 154 var set1Settings = new JsonObject(); 155 AddOrModifyMockProperties(set1Settings, "mock_old"); 156 Set(new () { Action = ActionPropertyValuePartial, Settings = set1Settings }); 157 158 // Call `set` to update the settings 159 var set2Settings = GetSettingsArg(action); 160 AddOrModifyMockProperties(set2Settings, "mock_new"); 161 162 (var setOutput, var setDiff) = Set(new () { Action = action, Settings = set2Settings }); 163 164 var expected = GetCurrentUserSettings(); 165 166 // Assert that the settings are updated 167 Assert.IsNotNull(setOutput); 168 Assert.AreEqual(action, setOutput.Action); 169 AssertMockProperties(setOutput.Settings, "mock_new"); 170 AssertSettingsAreEqual(expected, setOutput.Settings); 171 AssertDiffState(setDiff, [ SettingsPropertyName ]); 172 } 173 174 /// <summary> 175 /// Calls `test` on the `user-settings-file` resource to check if the settings are in desired state. 176 /// </summary> 177 /// <param name="action">The action value.</param> 178 [Test] 179 [TestCase(ActionPropertyValueFull)] 180 [TestCase(ActionPropertyValuePartial)] 181 public void UserSettingsFile_Test_InDesiredState(string action) 182 { 183 // Add mock properties to the settings 184 var setSettings = new JsonObject(); 185 AddOrModifyMockProperties(setSettings, "mock"); 186 Set(new () { Action = ActionPropertyValuePartial, Settings = setSettings }); 187 188 // Call `test` to check the settings 189 var testSettings = GetSettingsArg(action); 190 AddOrModifyMockProperties(testSettings, "mock"); 191 192 (var testOutput, var testDiff) = Test(new () { Action = action, Settings = testSettings }); 193 194 var expected = GetCurrentUserSettings(); 195 196 // Assert that the settings are in desired state 197 Assert.IsNotNull(testOutput); 198 Assert.AreEqual(action, testOutput.Action); 199 AssertMockProperties(testOutput.Settings, "mock"); 200 AssertSettingsAreEqual(expected, testOutput.Settings); 201 Assert.IsTrue(testOutput.InDesiredState); 202 AssertDiffState(testDiff, []); 203 } 204 205 /// <summary> 206 /// Calls `test` on the `user-settings-file` resource to check if the settings are not in desired state. 207 /// </summary> 208 /// <param name="action">The action value.</param> 209 [Test] 210 [TestCase(ActionPropertyValueFull)] 211 [TestCase(ActionPropertyValuePartial)] 212 public void UserSettingsFile_Test_NotInDesiredState(string action) 213 { 214 // Add mock properties to the settings 215 var setSettings = new JsonObject(); 216 AddOrModifyMockProperties(setSettings, "mock_set"); 217 Set(new () { Action = ActionPropertyValuePartial, Settings = setSettings }); 218 219 // Call `test` to check the settings 220 var testSettings = GetSettingsArg(action); 221 AddOrModifyMockProperties(testSettings, "mock_test"); 222 223 (var testOutput, var testDiff) = Test(new () { Action = action, Settings = testSettings }); 224 225 var expected = GetCurrentUserSettings(); 226 227 // Assert that the settings are not in desired state 228 Assert.IsNotNull(testOutput); 229 Assert.AreEqual(action, testOutput.Action); 230 AssertMockProperties(testOutput.Settings, "mock_set"); 231 AssertSettingsAreEqual(expected, testOutput.Settings); 232 Assert.IsFalse(testOutput.InDesiredState); 233 AssertDiffState(testDiff, [ SettingsPropertyName ]); 234 } 235 236 /// <summary> 237 /// Calls `export` on the `user-settings-file` resource to export the settings. 238 /// </summary> 239 [Test] 240 public void UserSettingsFile_Export() 241 { 242 var expected = GetCurrentUserSettings(); 243 var exportOutput = Export(new ()); 244 245 Assert.IsNotNull(exportOutput); 246 Assert.IsNull(exportOutput.Action); 247 AssertSettingsAreEqual(expected, exportOutput.Settings); 248 } 249 250 /// <summary> 251 /// Calls `get` on the `user-settings-file` resource. 252 /// </summary> 253 /// <param name="resourceData">The input resource data.</param> 254 /// <returns>The output resource data.</returns> 255 private static UserSettingsFileResourceData Get(UserSettingsFileResourceData resourceData) 256 { 257 var result = RunDSCv3Command(UserSettingsFileResource, GetFunction, resourceData); 258 AssertSuccessfulResourceRun(ref result); 259 return GetSingleOutputLineAs<UserSettingsFileResourceData>(result.StdOut); 260 } 261 262 /// <summary> 263 /// Calls `set` on the `user-settings-file` resource. 264 /// </summary> 265 /// <param name="resourceData">The input resource data.</param> 266 /// <returns>The output resource data and the diff.</returns> 267 private static (UserSettingsFileResourceData, List<string>) Set(UserSettingsFileResourceData resourceData) 268 { 269 var result = RunDSCv3Command(UserSettingsFileResource, SetFunction, resourceData); 270 AssertSuccessfulResourceRun(ref result); 271 return GetSingleOutputLineAndDiffAs<UserSettingsFileResourceData>(result.StdOut); 272 } 273 274 /// <summary> 275 /// Calls `test` on the `user-settings-file` resource. 276 /// </summary> 277 /// <param name="resourceData">The input resource data.</param> 278 /// <returns>The output resource data and the diff.</returns> 279 private static (UserSettingsFileResourceData, List<string>) Test(UserSettingsFileResourceData resourceData) 280 { 281 var result = RunDSCv3Command(UserSettingsFileResource, TestFunction, resourceData); 282 AssertSuccessfulResourceRun(ref result); 283 return GetSingleOutputLineAndDiffAs<UserSettingsFileResourceData>(result.StdOut); 284 } 285 286 /// <summary> 287 /// Calls `export` on the `user-settings-file` resource. 288 /// </summary> 289 /// <param name="resourceData">The input resource data.</param> 290 /// <returns>The output resource data.</returns> 291 private static UserSettingsFileResourceData Export(UserSettingsFileResourceData resourceData) 292 { 293 var result = RunDSCv3Command(UserSettingsFileResource, ExportFunction, resourceData); 294 AssertSuccessfulResourceRun(ref result); 295 return GetSingleOutputLineAs<UserSettingsFileResourceData>(result.StdOut); 296 } 297 298 /// <summary> 299 /// Gets the current user settings from the settings file. 300 /// </summary> 301 /// <returns>The current user settings as a JsonObject.</returns> 302 private static JsonObject GetCurrentUserSettings() 303 { 304 var settingsContent = File.ReadAllText(WinGetSettingsHelper.GetUserSettingsPath()); 305 return JsonNode.Parse(settingsContent).AsObject(); 306 } 307 308 /// <summary> 309 /// Adds or modifies mock properties in the settings. 310 /// </summary> 311 /// <param name="settings">Target settings.</param> 312 /// <param name="value">The mock value.</param> 313 private static void AddOrModifyMockProperties(JsonObject settings, string value) 314 { 315 settings[SettingsMock] = value; 316 settings[SettingsMockObject] ??= new JsonObject(); 317 settings[SettingsMockObject][SettingsMockNested] = value; 318 } 319 320 /// <summary> 321 /// Asserts that the settings contain the expected mock properties. 322 /// </summary> 323 /// <param name="settings">Target settings.</param> 324 /// <param name="value">The expected mock value.</param> 325 private static void AssertMockProperties(JsonObject settings, string value) 326 { 327 Assert.IsNotNull(settings); 328 Assert.IsTrue(settings.ContainsKey(SettingsMock)); 329 Assert.AreEqual(settings[SettingsMock].ToString(), value); 330 Assert.IsTrue(settings.ContainsKey(SettingsMockObject)); 331 Assert.IsTrue(settings[SettingsMockObject].AsObject().ContainsKey(SettingsMockNested)); 332 Assert.AreEqual(settings[SettingsMockObject][SettingsMockNested].ToString(), value); 333 } 334 335 /// <summary> 336 /// Asserts that the diff state is as expected. 337 /// </summary> 338 /// <param name="expected">The expected settings.</param> 339 /// <param name="actual">The actual settings.</param> 340 private static void AssertSettingsAreEqual(JsonObject expected, JsonObject actual) 341 { 342 Assert.IsTrue(JsonNode.DeepEquals(expected, actual)); 343 } 344 345 /// <summary> 346 /// Gets the settings argument based on the action. 347 /// </summary> 348 /// <param name="action">The action value.</param> 349 /// <returns>The settings argument as a JsonObject.</returns> 350 private static JsonObject GetSettingsArg(string action) => action == ActionPropertyValueFull ? GetCurrentUserSettings() : new (); 351 352 private class UserSettingsFileResourceData 353 { 354 [JsonPropertyName(InDesiredStatePropertyName)] 355 public bool? InDesiredState { get; set; } 356 357 [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)] 358 public string Action { get; set; } 359 360 public JsonObject Settings { get; set; } 361 } 362 }