From 50c22eda5e8f1ba4892755405b61d2bbbc81f084 Mon Sep 17 00:00:00 2001 From: Gary Ewan Park Date: Tue, 23 Apr 2024 03:59:50 -0700 Subject: [PATCH] (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 | 902 +++++++++++++++++- .../services/ChocolateyPackageServiceSpecs.cs | 83 +- 4 files changed, 1124 insertions(+), 4 deletions(-) diff --git a/src/chocolatey.tests/TinySpec.cs b/src/chocolatey.tests/TinySpec.cs index fe0f026048..02a8f16797 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 ece60dea8a..37208c8c80 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 f1c3a973bd..1efa97e54b 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,903 @@ 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); + } + } + } + + 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); + } + } + } + + 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 d972ea0b33..3adeedf945 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().ContainSingle().And.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().ContainSingle().And.Contain(m => m.Contains("Chocolatey upgraded 0/1 packages.")); + Environment.ExitCode.Should().Be(2); + } + } + } } }