public void SkipsInstallation() { // Setup _fileSystemMock .Setup(x => x.DirectoryExists(It.IsAny <string>())) .Returns(true); var collection = CreateMockServiceCollection(); _task.ConfigureServices(collection); // Act using var provider = collection.BuildServiceProvider(); _task.InvokeExecute(provider).Should().BeTrue(); // Verify _commandFactoryMock .Verify( x => x.Create( It.Is <string>(dotnet => dotnet == _dotnetPath), It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))), Times.Never); _commandMock.Verify(x => x.Execute(), Times.Never); }
public async Task InstallsInParallelWithRealMutex() { // Setup var fileSystemMock1 = new Mock <IFileSystem>(); fileSystemMock1 .Setup(x => x.DirectoryExists(It.IsAny <string>())) .Returns(false); var fileSystemMock2 = new Mock <IFileSystem>(); fileSystemMock2 .Setup(x => x.DirectoryExists(It.IsAny <string>())) .Returns(true); var helpers = new Helpers(); var hangingCommandCalled = new TaskCompletionSource <bool>(); var dotnetToolInstalled = new TaskCompletionSource <bool>(); var hangingCommand = new Mock <ICommand>(); hangingCommand .Setup(x => x.Execute()) .Callback(() => { hangingCommandCalled.SetResult(true); dotnetToolInstalled.Task.GetAwaiter().GetResult(); }) .Returns(new CommandResult(new ProcessStartInfo(), 0, "Tool installed", null)); var hangingCommandFactoryMock = new Mock <ICommandFactory>(); hangingCommandFactoryMock .Setup(x => x.Create( It.Is <string>(s => s == _dotnetPath), It.Is <IEnumerable <string> >(args => args.All(y => _expectedArgs.Contains(y))))) .Returns(hangingCommand.Object) .Verifiable(); var collection1 = new ServiceCollection(); collection1.AddSingleton(hangingCommandFactoryMock.Object); collection1.AddSingleton(fileSystemMock1.Object); collection1.AddTransient <IHelpers, Helpers>(); var collection2 = new ServiceCollection(); collection2.AddSingleton(_commandFactoryMock.Object); collection2.AddSingleton(fileSystemMock2.Object); collection2.AddTransient <IHelpers, Helpers>(); var task1 = new InstallDotNetTool() { DestinationPath = InstallPath, Name = ToolName, Version = ToolVersion, BuildEngine = new MockBuildEngine(), }; var task2 = new InstallDotNetTool() { DestinationPath = InstallPath, Name = ToolName, Version = ToolVersion, BuildEngine = new MockBuildEngine(), }; // Act using var provider1 = collection1.BuildServiceProvider(); using var provider2 = collection2.BuildServiceProvider(); var installationTask = Task.Run(() => task1.InvokeExecute(provider1).Should().BeTrue()); // Let's wait for the first `dotnet tool install` to be called (it will stay spinning) await hangingCommandCalled.Task; var skipTask = Task.Run(() => task2.InvokeExecute(provider2).Should().BeTrue()); // The first command must have been executed, let's verify the parameters hangingCommandFactoryMock .Verify( x => x.Create( It.Is <string>(dotnet => dotnet == _dotnetPath), It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))), Times.Once); // The other command is waiting on the Mutex now skipTask.IsCompleted.Should().BeFalse(); _commandFactoryMock .Verify( x => x.Create( It.Is <string>(dotnet => dotnet == _dotnetPath), It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))), Times.Never); // We now let `dotnet tool install` run to completion dotnetToolInstalled.SetResult(true); // Let's give the installation task time to evaluate the command result // Let's give the skip task get its own Mutex and verify existence of the installation await Task.WhenAll(installationTask, skipTask); // Verify _commandFactoryMock .Verify( x => x.Create( It.Is <string>(dotnet => dotnet == _dotnetPath), It.Is <IEnumerable <string> >(args => args.Count() == _expectedArgs.Count() && args.All(y => _expectedArgs.Contains(y)))), Times.Never); task1.ToolPath.Should().Be(task2.ToolPath); task1.ToolPath.Should().Be(s_installedPath); }