From 03109873c71a04039576ba165fd99a31b75ce2c6 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 5 Oct 2015 11:50:57 -0500 Subject: [PATCH] (GH-452) Fix broken pin command Choco pin list used to ensure that the output from the local `list_run` command did not output on stdout. However a commit in GH-132 caused pin to start outputting the list output as well as pin output. Fix this by adding `config.QuietOutput = true;` around the call to List_run. Also add integration spec scenarios to ensure this is not subject to happen again. --- Scenarios.md | 41 +++ src/chocolatey.tests.integration/Scenario.cs | 8 + .../chocolatey.tests.integration.csproj | 1 + .../scenarios/PinScenarios.cs | 306 ++++++++++++++++++ .../commands/ChocolateyPinCommand.cs | 10 +- 5 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 src/chocolatey.tests.integration/scenarios/PinScenarios.cs diff --git a/Scenarios.md b/Scenarios.md index f016d4bfe9..b9b1af05b7 100644 --- a/Scenarios.md +++ b/Scenarios.md @@ -396,6 +396,47 @@ * should contain tags * should not contain packages and versions with a pipe between them +### ChocolateyPinCommand [ 9 Scenario(s), 12 Observation(s) ] + +#### when listing pins with an existing pin + + * should contain existing pin messages + * should not contain list results + +#### when listing pins with existing pins + + * should contain a pin message for each existing pin + * should not contain list results + +#### when listing pins with no pins + + * should not contain any pins by default + * should not contain list results + +#### when removing a pin for a non installed package + + * should throw an error about not finding the package + +#### when removing a pin for a pinned package + + * should contain success message + +#### when removing a pin for an unpinned package + + * should contain nothing to do message + +#### when setting a pin for a non installed package + + * should throw an error about not finding the package + +#### when setting a pin for an already pinned package + + * should contain nothing to do message + +#### when setting a pin for an installed package + + * should contain success message + ### ChocolateyUninstallCommand [ 13 Scenario(s), 90 Observation(s) ] #### when force uninstalling a package diff --git a/src/chocolatey.tests.integration/Scenario.cs b/src/chocolatey.tests.integration/Scenario.cs index aa077fe571..a9631037ce 100644 --- a/src/chocolatey.tests.integration/Scenario.cs +++ b/src/chocolatey.tests.integration/Scenario.cs @@ -174,5 +174,13 @@ public static ChocolateyConfiguration list() return config; } + + public static ChocolateyConfiguration pin() + { + var config = baseline_configuration(); + config.CommandName = CommandNameType.pin.to_string(); + + return config; + } } } \ No newline at end of file diff --git a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj index a32033b14a..24c6f35b7c 100644 --- a/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj +++ b/src/chocolatey.tests.integration/chocolatey.tests.integration.csproj @@ -87,6 +87,7 @@ + diff --git a/src/chocolatey.tests.integration/scenarios/PinScenarios.cs b/src/chocolatey.tests.integration/scenarios/PinScenarios.cs new file mode 100644 index 0000000000..cd1e5b6f93 --- /dev/null +++ b/src/chocolatey.tests.integration/scenarios/PinScenarios.cs @@ -0,0 +1,306 @@ +// Copyright © 2011 - Present RealDimensions Software, LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace chocolatey.tests.integration.scenarios +{ + using System; + using System.Collections.Generic; + using System.Linq; + using NuGet; + using Should; + using bdddoc.core; + using chocolatey.infrastructure.app; + using chocolatey.infrastructure.app.attributes; + using chocolatey.infrastructure.app.commands; + using chocolatey.infrastructure.app.configuration; + using chocolatey.infrastructure.app.domain; + using chocolatey.infrastructure.commands; + using chocolatey.infrastructure.results; + + public class PinScenarios + { + public abstract class ScenariosBase : TinySpec + { + protected IList Results; + protected ChocolateyConfiguration Configuration; + protected ChocolateyPinCommand Service; + + public override void Context() + { + Configuration = Scenario.pin(); + Scenario.reset(Configuration); + Scenario.add_packages_to_source_location(Configuration, Configuration.Input + "*" + Constants.PackageExtension); + Scenario.add_packages_to_source_location(Configuration, "installpackage*" + Constants.PackageExtension); + Scenario.install_package(Configuration, "installpackage", "1.0.0"); + Scenario.install_package(Configuration, "upgradepackage", "1.0.0"); + Scenario.install_package(Configuration, "hasdependency", "1.0.0"); + + var commands = NUnitSetup.Container.GetAllInstances(); + Service = commands.Where( + (c) => + { + var attributes = c.GetType().GetCustomAttributes(typeof(CommandForAttribute), false); + return attributes.Cast().Any(attribute => attribute.CommandName.is_equal_to(Configuration.CommandName)); + }).FirstOrDefault() as ChocolateyPinCommand; + + Configuration.Sources = ApplicationParameters.PackagesLocation; + Configuration.ListCommand.LocalOnly = true; + Configuration.AllVersions = true; + Configuration.Prerelease = true; + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_listing_pins_with_no_pins : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.list; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_not_contain_list_results() + { + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Info).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Warn).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Error).ShouldBeFalse(); + } + + [Fact] + public void should_not_contain_any_pins_by_default() + { + MockLogger.contains_message("upgradepackage|1.0.0").ShouldBeFalse(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_listing_pins_with_an_existing_pin : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "upgradepackage"; + Service.run(Configuration); + Configuration.PinCommand.Command = PinCommandType.list; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_not_contain_list_results() + { + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Info).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Warn).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Error).ShouldBeFalse(); + } + + [Fact] + public void should_contain_existing_pin_messages() + { + MockLogger.contains_message("upgradepackage|1.0.0").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_listing_pins_with_existing_pins : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "upgradepackage"; + Service.run(Configuration); + Configuration.PinCommand.Name = "installpackage"; + Service.run(Configuration); + Configuration.PinCommand.Command = PinCommandType.list; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_not_contain_list_results() + { + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Info).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Warn).ShouldBeFalse(); + MockLogger.contains_message("upgradepackage 1.0.0", LogLevel.Error).ShouldBeFalse(); + } + + [Fact] + public void should_contain_a_pin_message_for_each_existing_pin() + { + MockLogger.contains_message("installpackage|1.0.0").ShouldBeTrue(); + MockLogger.contains_message("upgradepackage|1.0.0").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_setting_a_pin_for_an_installed_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "upgradepackage"; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_contain_success_message() + { + MockLogger.contains_message("Successfully added a pin for upgradepackage").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_setting_a_pin_for_an_already_pinned_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "upgradepackage"; + Service.run(Configuration); + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_contain_nothing_to_do_message() + { + MockLogger.contains_message("Nothing to change. Pin already set or removed.").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_setting_a_pin_for_a_non_installed_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "whatisthis"; + } + + public override void Because() + { + MockLogger.reset(); + } + + [ExpectedException(typeof(ApplicationException), ExpectedMessage = "Unable to find package named 'whatisthis' to pin. Please check to ensure it is installed.")] + [Fact] + public void should_throw_an_error_about_not_finding_the_package() + { + Service.run(Configuration); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_removing_a_pin_for_a_pinned_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.add; + Configuration.PinCommand.Name = "upgradepackage"; + Service.run(Configuration); + + Configuration.PinCommand.Command = PinCommandType.remove; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_contain_success_message() + { + MockLogger.contains_message("Successfully removed a pin for upgradepackage").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_removing_a_pin_for_an_unpinned_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.remove; + Configuration.PinCommand.Name = "upgradepackage"; + } + + public override void Because() + { + MockLogger.reset(); + Service.run(Configuration); + } + + [Fact] + public void should_contain_nothing_to_do_message() + { + MockLogger.contains_message("Nothing to change. Pin already set or removed.").ShouldBeTrue(); + } + } + + [Concern(typeof(ChocolateyPinCommand))] + public class when_removing_a_pin_for_a_non_installed_package : ScenariosBase + { + public override void Context() + { + base.Context(); + Configuration.PinCommand.Command = PinCommandType.remove; + Configuration.PinCommand.Name = "whatisthis"; + } + + public override void Because() + { + MockLogger.reset(); + } + + [ExpectedException(typeof(ApplicationException), ExpectedMessage = "Unable to find package named 'whatisthis' to pin. Please check to ensure it is installed.")] + [Fact] + public void should_throw_an_error_about_not_finding_the_package() + { + Service.run(Configuration); + } + } + } +} diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs index e82b88e58c..5bdfa34bac 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyPinCommand.cs @@ -139,7 +139,15 @@ public void run(ChocolateyConfiguration configuration) public void list_pins(IPackageManager packageManager, ChocolateyConfiguration config) { - foreach (var pkg in _nugetService.list_run(config)) + var input = config.Input; + config.Input = string.Empty; + var quiet = config.QuietOutput; + config.QuietOutput = true; + var packages = _nugetService.list_run(config).ToList(); + config.QuietOutput = quiet; + config.Input = input; + + foreach (var pkg in packages.or_empty_list_if_null()) { var pkgInfo = _packageInfoService.get_package_information(pkg.Package); if (pkgInfo != null && pkgInfo.IsPinned)