From 5008398b4fe9c6d3e714f73a5aaf11f257686e6d Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 12 Jan 2022 22:09:02 -0600 Subject: [PATCH 1/8] (#1759) apikey command - use exit code 2 If enhanced exit codes are enabled, this sets the apikey command to exit with 2 if there is nothing to do (i.e. if NOCHANGEMESSAGE is output). --- .../infrastructure.app/commands/ChocolateyApiKeyCommand.cs | 7 ++++++- .../services/ChocolateyConfigSettingsService.cs | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs index 88d8f0889..407494440 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs @@ -167,12 +167,17 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do, apikey already set (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{0}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. If you find other exit codes that we have not yet documented, please file a ticket so we can document it at https://github.com/chocolatey/choco/issues/new/choose. -"); +".FormatWith(ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); } diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs index 1fbcadefd..d629df2cf 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs @@ -396,6 +396,11 @@ public void SetApiKey(ChocolateyConfiguration configuration) else { this.Log().Warn(NoChangeMessage); + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } } From 810fa6531673aa584b6eb7ddaf48a37f821b127d Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 12 Jan 2022 22:12:27 -0600 Subject: [PATCH 2/8] (#1760) config command - use exit code 2 If enhanced exit codes are enabled, this sets the config command to exit with 2 if there is nothing to do (i.e. if NOCHANGEMESSAGE is output). --- .../commands/ChocolateyConfigCommand.cs | 7 ++++++- .../services/ChocolateyConfigSettingsService.cs | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyConfigCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyConfigCommand.cs index 517807bdc..98c860336 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyConfigCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyConfigCommand.cs @@ -138,12 +138,17 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do, config already set/unset (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{0}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. If you find other exit codes that we have not yet documented, please file a ticket so we can document it at https://github.com/chocolatey/choco/issues/new/choose. -"); +".FormatWith(ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "See It In Action"); "chocolatey".Log().Info(@" diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs index d629df2cf..675f56193 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs @@ -492,6 +492,11 @@ public void SetConfig(ChocolateyConfiguration configuration) if (configuration.ConfigCommand.ConfigValue.IsEqualTo(currentValue.ToStringSafe())) { this.Log().Warn(NoChangeMessage); + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } else { @@ -509,6 +514,11 @@ public void UnsetConfig(ChocolateyConfiguration configuration) if (config == null || string.IsNullOrEmpty(config.Value)) { this.Log().Warn(NoChangeMessage); + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } else { From 31752561838e7d2bb4624b5b524262196c702559 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 12 Jan 2022 22:17:20 -0600 Subject: [PATCH 3/8] (#1761) feature command - use exit code 2 If enhanced exit codes are enabled, this sets the feature command to exit with 2 if there is nothing to do (i.e. if NOCHANGEMESSAGE is output). --- .../commands/ChocolateyFeatureCommand.cs | 7 ++++++- .../services/ChocolateyConfigSettingsService.cs | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyFeatureCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyFeatureCommand.cs index a1c824110..e1da01847 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyFeatureCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyFeatureCommand.cs @@ -124,12 +124,17 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do, feature already set (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{0}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. If you find other exit codes that we have not yet documented, please file a ticket so we can document it at https://github.com/chocolatey/choco/issues/new/choose. -"); +".FormatWith(ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); } diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs index 675f56193..4388aa33e 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs @@ -307,6 +307,11 @@ public void DisableFeature(ChocolateyConfiguration configuration) else { this.Log().Warn(NoChangeMessage); + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } @@ -335,6 +340,11 @@ public void EnableFeature(ChocolateyConfiguration configuration) else { this.Log().Warn(NoChangeMessage); + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } From e13c927e4d1c90d63c459879fc50d34d7ddb97ed Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 12 Jan 2022 22:20:12 -0600 Subject: [PATCH 4/8] (#1762) pin command - use exit code 2 If enhanced exit codes are enabled, this sets the pin command to exit with 2 if there is nothing to do (i.e. if NOCHANGEMESSAGE is output). --- .../commands/ChocolateyPinCommand.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs index a8ca34318..81e0809b5 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs @@ -134,12 +134,17 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{0}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. If you find other exit codes that we have not yet documented, please file a ticket so we can document it at https://github.com/chocolatey/choco/issues/new/choose. -"); +".FormatWith(ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); } @@ -222,6 +227,11 @@ public virtual void SetPin(ChocolateyConfiguration config) else { this.Log().Warn(NoChangeMessage); + + if (config.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } From fbc69dcf23c756335a3d5d96c60b1ace4e53cc99 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Wed, 12 Jan 2022 22:35:29 -0600 Subject: [PATCH 5/8] (#1764) source command - use exit code 2 If enhanced exit codes are enabled, this sets the source command to exit with 2 if there is nothing to do (i.e. if NOCHANGEMESSAGE is output). --- .../commands/ChocolateySourceCommand.cs | 7 ++++++- .../ChocolateyConfigSettingsService.cs | 20 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs index dc5975fa5..874d4471e 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs @@ -164,12 +164,17 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{0}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. If you find other exit codes that we have not yet documented, please file a ticket so we can document it at https://github.com/chocolatey/choco/issues/new/choose. -"); +".FormatWith(ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); } diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs index 4388aa33e..a54391a4f 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyConfigSettingsService.cs @@ -160,6 +160,11 @@ public void AddSource(ChocolateyConfiguration configuration) { this.Log().Warn(NoChangeMessage); } + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } else { @@ -201,6 +206,11 @@ public void RemoveSource(ChocolateyConfiguration configuration) { this.Log().Warn(NoChangeMessage); } + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } @@ -222,6 +232,11 @@ public void DisableSource(ChocolateyConfiguration configuration) { this.Log().Warn(NoChangeMessage); } + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } @@ -243,6 +258,11 @@ public void EnableSource(ChocolateyConfiguration configuration) { this.Log().Warn(NoChangeMessage); } + + if (configuration.Features.UseEnhancedExitCodes && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } } } From bcc3146463021692cf33ba602fac64d6f60e3d58 Mon Sep 17 00:00:00 2001 From: TheCakeIsNaOH Date: Fri, 14 Jan 2022 21:53:28 -0600 Subject: [PATCH 6/8] (#2200) upgrade command - use exit code 2 If enhanced exit codes are enabled, this sets the upgrade command to exit with 2 if there is nothing to do (i.e. if no packages are upgraded). This entails returning the number of successful package results from the report_action_summary method. --- .../commands/ChocolateyUpgradeCommand.cs | 7 +++++- .../services/ChocolateyPackageService.cs | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs index 2b5d47b94..c7b6e94b5 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyUpgradeCommand.cs @@ -351,6 +351,11 @@ Exit codes that normally result from running this command. Normal: - 0: operation was successful, no issues detected - -1 or 1: an error has occurred + - 2: nothing to do, no packages outdated (enhanced) + +NOTE: Starting in v2.3.0, if you have the feature '{2}' + turned on, then choco will provide enhanced exit codes that allow + better integration and scripting. Package Exit Codes: - 1641: success, reboot initiated @@ -368,7 +373,7 @@ turned on. Uninstall command has additional valid exit codes. In addition to the above exit codes, you may also see reboot exit codes when the feature '{1}' is turned on. It typically requires the feature '{0}' to also be turned on to work properly. -".FormatWith(ApplicationParameters.Features.UsePackageExitCodes, ApplicationParameters.Features.ExitOnRebootDetected)); +".FormatWith(ApplicationParameters.Features.UsePackageExitCodes, ApplicationParameters.Features.ExitOnRebootDetected, ApplicationParameters.Features.UseEnhancedExitCodes)); "chocolatey".Log().Info(ChocolateyLoggers.Important, "See It In Action"); "chocolatey".Log().Info(@" diff --git a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs index 1e0f1d2bf..c3a3747d1 100644 --- a/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs +++ b/src/chocolatey/infrastructure.app/services/ChocolateyPackageService.cs @@ -812,8 +812,8 @@ public virtual ConcurrentDictionary Install(ChocolateyCon } finally { - var installFailures = ReportActionSummary(packageInstalls, "installed"); - if (installFailures != 0 && Environment.ExitCode == 0) + var actionSummaryResult = ReportActionSummary(packageInstalls, "installed"); + if (actionSummaryResult.Failures != 0 && Environment.ExitCode == 0) { Environment.ExitCode = 1; } @@ -1117,7 +1117,7 @@ public void UpgradeDryRun(ChocolateyConfiguration config) if (config.RegularOutput) { - var noopFailures = ReportActionSummary(noopUpgrades, "can upgrade"); + var actionSummaryResult = ReportActionSummary(noopUpgrades, "can upgrade"); } RandomlyNotifyAboutLicensedFeatures(config); @@ -1177,12 +1177,17 @@ public virtual ConcurrentDictionary Upgrade(ChocolateyCon } finally { - var upgradeFailures = ReportActionSummary(packageUpgrades, "upgraded"); - if (upgradeFailures != 0 && Environment.ExitCode == 0) + var actionSummaryResult = ReportActionSummary(packageUpgrades, "upgraded"); + if (actionSummaryResult.Failures != 0 && Environment.ExitCode == 0) { Environment.ExitCode = 1; } + if (config.Features.UseEnhancedExitCodes && (actionSummaryResult.Successes + actionSummaryResult.Failures == 0) && Environment.ExitCode == 0) + { + Environment.ExitCode = 2; + } + RandomlyNotifyAboutLicensedFeatures(config); } @@ -1274,13 +1279,13 @@ public virtual ConcurrentDictionary Uninstall(ChocolateyC } finally { - var uninstallFailures = ReportActionSummary(packageUninstalls, "uninstalled"); - if (uninstallFailures != 0 && Environment.ExitCode == 0) + var actionSummaryResult = ReportActionSummary(packageUninstalls, "uninstalled"); + if (actionSummaryResult.Failures != 0 && Environment.ExitCode == 0) { Environment.ExitCode = 1; } - if (uninstallFailures != 0) + if (actionSummaryResult.Failures != 0) { this.Log().Warn(@" If a package uninstall is failing and/or you've already uninstalled the @@ -1428,7 +1433,7 @@ private void BuildInstallExample(string packageName, StringBuilder sb, string co } } - private int ReportActionSummary(ConcurrentDictionary packageResults, string actionName) + private (int Successes, int Failures, int Warnings, int RebootPackages) ReportActionSummary(ConcurrentDictionary packageResults, string actionName) { var successes = packageResults.OrEmpty().Where(p => p.Value.Success && !p.Value.Inconclusive).OrderBy(p => p.Value.Name); var failures = packageResults.Count(p => !p.Value.Success); @@ -1496,7 +1501,7 @@ The recent package changes indicate a reboot is necessary. } } - return failures; + return (successes.Count(), failures, warnings, rebootPackages); } public virtual void HandlePackageUninstall(PackageResult packageResult, ChocolateyConfiguration config) From e129a426bc7112ef4145c1175657858f76e07465 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Fri, 19 Apr 2024 06:08:52 -0700 Subject: [PATCH 7/8] (doc) Change command output to be consistent In other commands, when the package exit code is only available when the UseEnhancedExitCodes feature is enabled, it is marked with "(enhanced)". This was missing on this command, and this commit addresses this. --- .../infrastructure.app/commands/ChocolateyOutdatedCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs index bf45ef4e0..275f2d075 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyOutdatedCommand.cs @@ -130,7 +130,7 @@ Exit codes that normally result from running this command. Enhanced: - 0: no outdated packages - -1 or 1: an error has occurred - - 2: outdated packages have been found + - 2: outdated packages have been found (enhanced) NOTE: If you have the feature '{0}' turned on, then choco will provide enhanced exit codes that allow From 65098d149341d99260ddf58be47aa3c666b8be02 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Tue, 23 Apr 2024 03:59:50 -0700 Subject: [PATCH 8/8] (test) Add unit tests to cover exit code changes Within the following issues, a number of changes were made to allow Chocolatey CLI to exit with a ExitCode of 2, when no action was taken: #2200 - Upgrade #1764 - Source #1762 - Pin #1761 - Feature #1760 - Config #1759 - ApiKey This commit adds the unit tests to exercise these changes to ensure that they work as expected, and also that they continue to work as additional changes are made. No new test files have been created in this commit, but rather test were added to existing test files. The tests that have been added are a carbon copy of each other, to an extent, i.e. setup and run the required action, then assert the logs and ExitCode of 0. Then enable the UseEnhancedExitCodes feature and run the action again and assert the logs and ExitCode of 2. One change was made to the TinySpec file to ensure that the Environment.ExitCode is set to 0 (default) at the start of each test execution. This was required due to the fact that some test executions result in the ExitCode being set to 2 explicitly, but the next test didn't set it to 0, due to the fact that it relies on the default value being returned. Since this is a concern across all test executions, the decision was made to put it into the TinySpec file. --- src/chocolatey.tests/TinySpec.cs | 8 + .../commands/ChocolateyPinCommandSpecs.cs | 135 +++ .../ChocolateyConfigSettingsServiceSpecs.cs | 904 +++++++++++++++++- .../services/ChocolateyPackageServiceSpecs.cs | 83 +- 4 files changed, 1126 insertions(+), 4 deletions(-) diff --git a/src/chocolatey.tests/TinySpec.cs b/src/chocolatey.tests/TinySpec.cs index fe0f02604..02a8f1679 100644 --- a/src/chocolatey.tests/TinySpec.cs +++ b/src/chocolatey.tests/TinySpec.cs @@ -67,6 +67,14 @@ public void Setup() { MockLogger.Reset(); } + + // Chocolatey CLI by default will exit with Code 0, when everything work as expected, even if it doesn't + // set this explicitly. + // However, in some tests, we are testing for the setting of an explicit exit code, and when we do this, + // it can have an impact on other tests, since it may not have been reset. Let's explicitly set it to + // 0 before running each test, so that everything starts off at the right place. + Environment.ExitCode = default; + //Log.InitializeWith(MockLogger); NugetCommon.ClearRepositoriesCache(); Context(); diff --git a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyPinCommandSpecs.cs b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyPinCommandSpecs.cs index ece60dea8..37208c8c8 100644 --- a/src/chocolatey.tests/infrastructure.app/commands/ChocolateyPinCommandSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/commands/ChocolateyPinCommandSpecs.cs @@ -33,6 +33,7 @@ using NUnit.Framework; using FluentAssertions; +using FluentAssertions.Execution; namespace chocolatey.tests.infrastructure.app.commands { @@ -537,5 +538,139 @@ public void Should_remove_pin_from_correct_package() n.Package.Id.Equals("mingw"))), Times.Once); } } + + public class When_adding_a_pin_on_an_already_pinned_package : ChocolateyPinCommandSpecsBase + { + public override void Context() + { + base.Context(); + Configuration.Sources = ApplicationParameters.PackagesLocation; + Configuration.ListCommand.LocalOnly = true; + Configuration.AllVersions = true; + + var packageResults = new[] + { + new PackageResult(PinnedPackage.Object, null) + }; + NugetService.Setup(n => n.List(It.IsAny())).Returns(packageResults); + } + + public new void Reset() + { + Context(); + base.Reset(); + } + + public override void AfterEachSpec() + { + base.AfterEachSpec(); + MockLogger.Messages.Clear(); + } + + public override void Because() + { + } + + [Fact] + public void Should_Return_0_ExitCode_When_Pinning_An_Already_Pinned_Package() + { + Reset(); + Configuration.Features.UseEnhancedExitCodes = false; + Configuration.PinCommand.Name = "pinned"; + Configuration.PinCommand.Command = PinCommandType.Add; + + Command.SetPin(Configuration); + + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Pin already set or removed."); + Environment.ExitCode.Should().Be(0); + } + } + + [Fact] + public void Should_Return_2_ExitCode_When_Pinning_An_Already_Pinned_Package_With_UseEnhancedExitCodes_Enabled() + { + Reset(); + Configuration.Features.UseEnhancedExitCodes = true; + Configuration.PinCommand.Name = "pinned"; + Configuration.PinCommand.Command = PinCommandType.Add; + + Command.SetPin(Configuration); + + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Pin already set or removed."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_removing_a_pin_on_a_package_with_no_pin : ChocolateyPinCommandSpecsBase + { + public override void Context() + { + base.Context(); + Configuration.Sources = ApplicationParameters.PackagesLocation; + Configuration.ListCommand.LocalOnly = true; + Configuration.AllVersions = true; + + var packageResults = new[] + { + new PackageResult(Package.Object, null) + }; + NugetService.Setup(n => n.List(It.IsAny())).Returns(packageResults); + } + + public new void Reset() + { + Context(); + base.Reset(); + } + + public override void AfterEachSpec() + { + base.AfterEachSpec(); + MockLogger.Messages.Clear(); + } + + public override void Because() + { + } + + [Fact] + public void Should_Return_0_ExitCode_When_Pinning_An_Already_Pinned_Package() + { + Reset(); + Configuration.Features.UseEnhancedExitCodes = false; + Configuration.PinCommand.Name = "regular"; + Configuration.PinCommand.Command = PinCommandType.Remove; + + Command.SetPin(Configuration); + + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Pin already set or removed."); + Environment.ExitCode.Should().Be(0); + } + } + + [Fact] + public void Should_Return_2_ExitCode_When_Pinning_An_Already_Pinned_Package_With_UseEnhancedExitCodes_Enabled() + { + Reset(); + Configuration.Features.UseEnhancedExitCodes = true; + Configuration.PinCommand.Name = "regular"; + Configuration.PinCommand.Command = PinCommandType.Remove; + + Command.SetPin(Configuration); + + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Pin already set or removed."); + Environment.ExitCode.Should().Be(2); + } + } + } } } diff --git a/src/chocolatey.tests/infrastructure.app/services/ChocolateyConfigSettingsServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/ChocolateyConfigSettingsServiceSpecs.cs index f1c3a973b..6ac4f3e0e 100644 --- a/src/chocolatey.tests/infrastructure.app/services/ChocolateyConfigSettingsServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/ChocolateyConfigSettingsServiceSpecs.cs @@ -3,10 +3,12 @@ using System.Linq; using chocolatey.infrastructure.app; using chocolatey.infrastructure.app.configuration; +using chocolatey.infrastructure.app.nuget; using chocolatey.infrastructure.app.services; using chocolatey.infrastructure.services; -using Moq; using FluentAssertions; +using FluentAssertions.Execution; +using Moq; namespace chocolatey.tests.integration.infrastructure.app.services { @@ -572,5 +574,905 @@ public void Should_return_feature_status() infoMessages[0].Should().Contain("Enabled"); } } + + public class When_ChocolateyConfigSettingsService_AddSource_When_Source_Already_Exists : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Add + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.AddSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet + { + new ConfigFileSourceSetting() + { + Id = "testSource", + Value = "https://test.org/api/v2" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_AddSource_When_Source_Already_Exists_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Add + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.AddSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet + { + new ConfigFileSourceSetting() + { + Id = "testSource", + Value = "https://test.org/api/v2" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_RemoveSource_When_Source_Doesnt_Exist : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Remove + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.RemoveSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_RemoveSource_When_Source_Doesnt_Exist_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Remove + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.RemoveSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_DisableSource_When_Source_Doesnt_Exist : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Disable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.DisableSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_DisableSource_When_Source_Doesnt_Exist_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Disable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.DisableSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_EnableSource_When_Source_Doesnt_Exist : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Enable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.EnableSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_EnableSource_When_Source_Doesnt_Exist_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + SourceCommand = new SourcesCommandConfiguration() + { + Name = "testSource", + Command = chocolatey.infrastructure.app.domain.SourceCommandType.Enable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.EnableSource(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Sources = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_DisableFeature_When_Feature_Already_Disabled : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + FeatureCommand = new FeatureCommandConfiguration() + { + Name = ApplicationParameters.Features.ChecksumFiles, + Command = chocolatey.infrastructure.app.domain.FeatureCommandType.Disable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.DisableFeature(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Features = new HashSet + { + new ConfigFileFeatureSetting + { + Name = ApplicationParameters.Features.ChecksumFiles, + Enabled = false, + SetExplicitly = true + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_DisableFeature_When_Feature_Already_Disabled_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + FeatureCommand = new FeatureCommandConfiguration() + { + Name = ApplicationParameters.Features.ChecksumFiles, + Command = chocolatey.infrastructure.app.domain.FeatureCommandType.Disable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.DisableFeature(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Features = new HashSet + { + new ConfigFileFeatureSetting + { + Name = ApplicationParameters.Features.ChecksumFiles, + Enabled = false, + SetExplicitly = true + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_EnableFeature_When_Feature_Already_Enabled: ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + FeatureCommand = new FeatureCommandConfiguration() + { + Name = ApplicationParameters.Features.ChecksumFiles, + Command = chocolatey.infrastructure.app.domain.FeatureCommandType.Enable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.EnableFeature(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Features = new HashSet + { + new ConfigFileFeatureSetting + { + Name = ApplicationParameters.Features.ChecksumFiles, + Enabled = true, + SetExplicitly = true + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_EnableFeature_When_Feature_Already_Enabled_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + FeatureCommand = new FeatureCommandConfiguration() + { + Name = ApplicationParameters.Features.ChecksumFiles, + Command = chocolatey.infrastructure.app.domain.FeatureCommandType.Enable + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.EnableFeature(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + Features = new HashSet + { + new ConfigFileFeatureSetting + { + Name = ApplicationParameters.Features.ChecksumFiles, + Enabled = true, + SetExplicitly = true + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + [WindowsOnly] + public class When_ChocolateyConfigSettingsService_SetApiKey_When_ApiKey_Already_Exists : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + ApiKeyCommand = new ApiKeyCommandConfiguration() + { + Key = "bob", + Command = chocolatey.infrastructure.app.domain.ApiKeyCommandType.Add + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.SetApiKey(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ApiKeys = new HashSet + { + new ConfigFileApiKeySetting + { + Key = NugetEncryptionUtility.EncryptString("bob"), + Source = "https://test.org/api/v2" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + [WindowsOnly] + public class When_ChocolateyConfigSettingsService_SetApiKey_When_ApiKey_Already_Exists_With_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + Sources = "https://test.org/api/v2", + ApiKeyCommand = new ApiKeyCommandConfiguration() + { + Key = "bob", + Command = chocolatey.infrastructure.app.domain.ApiKeyCommandType.Add + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.SetApiKey(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ApiKeys = new HashSet + { + new ConfigFileApiKeySetting + { + Key = NugetEncryptionUtility.EncryptString("bob"), + Source = "https://test.org/api/v2" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_SetConfig_When_Config_Already_Set : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + ConfigCommand = new ConfigCommandConfiguration() + { + Name = ApplicationParameters.ConfigSettings.CacheLocation, + Command = chocolatey.infrastructure.app.domain.ConfigCommandType.Set, + ConfigValue = @"C:\temp" + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.SetConfig(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ConfigSettings = new HashSet() + { + new ConfigFileConfigSetting() + { + Key = ApplicationParameters.ConfigSettings.CacheLocation, + Value = @"C:\temp" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_SetConfig_When_Config_Already_Set_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + ConfigCommand = new ConfigCommandConfiguration() + { + Name = ApplicationParameters.ConfigSettings.CacheLocation, + Command = chocolatey.infrastructure.app.domain.ConfigCommandType.Set, + ConfigValue = @"C:\temp" + + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.SetConfig(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ConfigSettings = new HashSet() + { + new ConfigFileConfigSetting() + { + Key = ApplicationParameters.ConfigSettings.CacheLocation, + Value = @"C:\temp" + } + } + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } + + public class When_ChocolateyConfigSettingsService_UnSetConfig_When_Config_Already_UnSet : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + ConfigCommand = new ConfigCommandConfiguration() + { + Name = ApplicationParameters.ConfigSettings.CacheLocation, + Command = chocolatey.infrastructure.app.domain.ConfigCommandType.Unset + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = false + } + }; + + Service.UnsetConfig(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ConfigSettings = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_0() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyConfigSettingsService_UnSetConfig_When_Config_Already_UnSet_Enhanced_Exit_Codes : ChocolateyConfigSettingsServiceSpecsBase + { + public override void Because() + { + var config = new ChocolateyConfiguration() + { + RegularOutput = true, + ConfigCommand = new ConfigCommandConfiguration() + { + Name = ApplicationParameters.ConfigSettings.CacheLocation, + Command = chocolatey.infrastructure.app.domain.ConfigCommandType.Unset + + }, + Features = new FeaturesConfiguration() + { + UseEnhancedExitCodes = true + } + }; + + Service.UnsetConfig(config); + } + + public override void Context() + { + base.Context(); + + XmlService.Setup(x => x.Deserialize(ApplicationParameters.GlobalConfigFileLocation)) + .Returns(new ConfigFileSettings + { + ConfigSettings = new HashSet() + }); + + Service = new ChocolateyConfigSettingsService(XmlService.Object); + } + + [Fact] + public void Should_return_exit_code_2() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().ContainSingle().And.Contain("Nothing to change. Config already set."); + Environment.ExitCode.Should().Be(2); + } + } + } } } diff --git a/src/chocolatey.tests/infrastructure.app/services/ChocolateyPackageServiceSpecs.cs b/src/chocolatey.tests/infrastructure.app/services/ChocolateyPackageServiceSpecs.cs index d972ea0b3..d4f8c5f03 100644 --- a/src/chocolatey.tests/infrastructure.app/services/ChocolateyPackageServiceSpecs.cs +++ b/src/chocolatey.tests/infrastructure.app/services/ChocolateyPackageServiceSpecs.cs @@ -17,10 +17,12 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using chocolatey.infrastructure.app.configuration; using chocolatey.infrastructure.app.domain; +using chocolatey.infrastructure.app.registration; using chocolatey.infrastructure.app.services; using chocolatey.infrastructure.filesystem; using chocolatey.infrastructure.results; @@ -28,9 +30,8 @@ using Moq; using NUnit.Framework; using FluentAssertions; +using FluentAssertions.Execution; using IFileSystem = chocolatey.infrastructure.filesystem.IFileSystem; -using System.IO; -using chocolatey.infrastructure.app.registration; using NuGet.Packaging; namespace chocolatey.tests.infrastructure.app.services @@ -395,7 +396,7 @@ public override void Context() Action = () => Service.Upgrade(Configuration); Configuration.CommandName = "upgrade"; } - } + } public class When_ChocolateyPackageService_tries_to_upgrade_noop_nupkg_file : When_ChocolateyPackageService_tries_to_install_nupkg_file { @@ -406,5 +407,81 @@ public override void Context() Configuration.CommandName = "upgrade"; } } + + public class When_ChocolateyPackageService_tries_to_upgrade_a_package_that_doesnt_need_upgraded : ChocolateyPackageServiceSpecsBase + { + private ConcurrentDictionary _result; + + public override void Context() + { + base.Context(); + Configuration.PackageNames = "alreadyupgraded"; + Configuration.Sources = @"c:\packages"; + Configuration.Features.UseEnhancedExitCodes = false; + + var package = new Mock(); + var expectedResult = new ConcurrentDictionary(); + var packageResult = new PackageResult(package.Object, @"c:\programdata\chocolatey\lib\alreadyupgraded", null); + var logMessage = "alreadyupgraded v1.2.3 is the latest version available based on your source(s)."; + packageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, logMessage)); + expectedResult.TryAdd("alreadyupgraded", packageResult); + + NugetService.Setup(n => n.Upgrade(It.IsAny(), It.IsAny>(), It.IsAny>())) + .Returns(expectedResult); + } + + public override void Because() + { + _result = Service.Upgrade(Configuration); + } + + [Fact] + public void Should_Return_0_Exit_Code() + { + using(new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().Contain(m => m.Contains("Chocolatey upgraded 0/1 packages.")); + Environment.ExitCode.Should().Be(0); + } + } + } + + public class When_ChocolateyPackageService_tries_to_upgrade_a_package_that_doesnt_need_upgraded_using_enhanced_exitcodes : ChocolateyPackageServiceSpecsBase + { + private ConcurrentDictionary _result; + + public override void Context() + { + base.Context(); + Configuration.PackageNames = "alreadyupgraded"; + Configuration.Sources = @"c:\packages"; + Configuration.Features.UseEnhancedExitCodes = true; + + var package = new Mock(); + var expectedResult = new ConcurrentDictionary(); + var packageResult = new PackageResult(package.Object, @"c:\programdata\chocolatey\lib\alreadyupgraded", null); + var logMessage = "alreadyupgraded v1.2.3 is the latest version available based on your source(s)."; + packageResult.Messages.Add(new ResultMessage(ResultType.Inconclusive, logMessage)); + expectedResult.TryAdd("alreadyupgraded", packageResult); + + NugetService.Setup(n => n.Upgrade(It.IsAny(), It.IsAny>(), It.IsAny>())) + .Returns(expectedResult); + } + + public override void Because() + { + _result = Service.Upgrade(Configuration); + } + + [Fact] + public void Should_Return_0_Exit_Code() + { + using (new AssertionScope()) + { + MockLogger.Messages.Should().ContainKey("Warn").WhoseValue.Should().Contain(m => m.Contains("Chocolatey upgraded 0/1 packages.")); + Environment.ExitCode.Should().Be(2); + } + } + } } }