private void PromoteToInstalledOrRemove( string installingPath, string installedPath, DependencySnapshotInstallationMode installationMode, ILogger logger) { var latestSnapshot = _storage.GetLatestInstalledSnapshot(); if (latestSnapshot != null && _snapshotComparer.AreEquivalent(installingPath, latestSnapshot, logger)) { logger.Log( isUserOnlyLog: false, LogLevel.Trace, string.Format(PowerShellWorkerStrings.RemovingEquivalentDependencySnapshot, installingPath, latestSnapshot)); // The new snapshot is not better than the latest installed snapshot, // so remove the new snapshot and update the timestamp of the latest snapshot // in order to avoid unnecessary worker restarts. _storage.RemoveSnapshot(installingPath); _storage.SetSnapshotCreationTimeToUtcNow(latestSnapshot); } else { PromoteToInstalled(installingPath, installedPath, installationMode, logger); } }
public void DoesNotPromoteSnapshotIfSaveModuleKeepsThrowing(DependencySnapshotInstallationMode installationMode) { var manifestEntries = new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") }; var dummyPowerShell = PowerShell.Create(); var injectedException = new Exception("Couldn't save module"); _mockModuleProvider.Setup( _ => _.SaveModule(It.IsAny <PowerShell>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())) .Throws(injectedException); _mockStorage.Setup(_ => _.RemoveSnapshot(_targetPathInstalling)); var installer = CreateDependenciesSnapshotInstallerWithMocks(); var thrownException = Assert.Throws <DependencyInstallationException>( () => installer.InstallSnapshot(manifestEntries, _targetPathInstalled, dummyPowerShell, installationMode, _mockLogger.Object)); Assert.Contains(injectedException.Message, thrownException.Message); _mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(It.IsAny <string>()), Times.Never); _mockStorage.Verify(_ => _.RemoveSnapshot(_targetPathInstalling), Times.Once); _mockModuleProvider.Verify(_ => _.Cleanup(dummyPowerShell), Times.Once); }
public void PromotesInstallingSnapshotToInstalledIfSaveModuleDoesNotThrow(DependencySnapshotInstallationMode installationMode) { var manifestEntries = new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") }; var installer = CreateDependenciesSnapshotInstallerWithMocks(); installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object); _mockStorage.Verify(_ => _.CreateInstallingSnapshot(_targetPathInstalled), Times.Once); _mockStorage.Verify(_ => _.PromoteInstallingSnapshotToInstalledAtomically(_targetPathInstalled), Times.Once); _mockSnapshotContentLogger.Verify(_ => _.LogDependencySnapshotContent(_targetPathInstalled, _mockLogger.Object), Times.Once); }
public void CleansUpPowerShellRunspaceAfterSuccessfullySavingModule(DependencySnapshotInstallationMode installationMode) { var manifestEntries = new[] { new DependencyManifestEntry("Module", VersionSpecificationType.ExactVersion, "Version") }; var dummyPowerShell = PowerShell.Create(); var installer = CreateDependenciesSnapshotInstallerWithMocks(); installer.InstallSnapshot(manifestEntries, _targetPathInstalled, dummyPowerShell, installationMode, _mockLogger.Object); _mockModuleProvider.Verify(_ => _.Cleanup(dummyPowerShell), Times.Once); }
private void PromoteToInstalled( string installingPath, string installedPath, DependencySnapshotInstallationMode installationMode, ILogger logger) { _storage.PromoteInstallingSnapshotToInstalledAtomically(installedPath); logger.Log( isUserOnlyLog: false, LogLevel.Trace, string.Format(PowerShellWorkerStrings.PromotedDependencySnapshot, installingPath, installedPath, installationMode)); _snapshotContentLogger.LogDependencySnapshotContent(installedPath, logger); }
public void SavesLatestPublishedVersion_WhenMajorVersionIsSpecified(DependencySnapshotInstallationMode installationMode) { var manifestEntries = new[] { new DependencyManifestEntry("Module", VersionSpecificationType.MajorVersion, "Major version") }; _mockModuleProvider.Setup( _ => _.GetLatestPublishedModuleVersion("Module", "Major version")) .Returns("Latest version"); var installer = CreateDependenciesSnapshotInstallerWithMocks(); installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object); _mockModuleProvider.Verify( _ => _.SaveModule(It.IsAny <PowerShell>(), "Module", "Latest version", _targetPathInstalling), Times.Once); }
public void LogsInstallationStartAndFinish(DependencySnapshotInstallationMode installationMode) { var manifestEntries = new[] { new DependencyManifestEntry("A", VersionSpecificationType.ExactVersion, "Exact A version"), new DependencyManifestEntry("B", VersionSpecificationType.MajorVersion, "Major B version") }; _mockModuleProvider.Setup( _ => _.GetLatestPublishedModuleVersion(It.IsAny <string>(), It.IsAny <string>())) .Returns("Exact B version"); var installer = CreateDependenciesSnapshotInstallerWithMocks(); installer.InstallSnapshot(manifestEntries, _targetPathInstalled, PowerShell.Create(), installationMode, _mockLogger.Object); VerifyLoggedOnce(new[] { "Started installing", "A", "Exact A version" }); VerifyLoggedOnce(new[] { "has been installed", "A", "Exact A version" }); VerifyLoggedOnce(new[] { "Started installing", "B", "Exact B version" }); VerifyLoggedOnce(new[] { "has been installed", "B", "Exact B version" }); }
public void InstallSnapshot( IEnumerable <DependencyManifestEntry> dependencies, string targetPath, PowerShell pwsh, DependencySnapshotInstallationMode installationMode, ILogger logger) { var installingPath = CreateInstallingSnapshot(targetPath); logger.Log( isUserOnlyLog: false, LogLevel.Trace, string.Format( PowerShellWorkerStrings.InstallingFunctionAppRequiredModules, installingPath, installationMode)); try { foreach (DependencyInfo module in GetExactVersionsOfDependencies(dependencies)) { InstallModule(module, installingPath, pwsh, logger); } _snapshotContentLogger.LogDependencySnapshotContent(installingPath, logger); switch (installationMode) { case DependencySnapshotInstallationMode.Optional: // If the new snapshot turns out to be equivalent to the latest one, // removing it helps us save storage space and avoid unnecessary worker restarts. // It is ok to do that during background upgrade because the current // worker already has a good enough snapshot, and nothing depends on // the new snapshot yet. PromoteToInstalledOrRemove(installingPath, targetPath, installationMode, logger); break; case DependencySnapshotInstallationMode.Required: // Even if the new snapshot turns out to be equivalent to the latest one, // removing it would not be safe because the current worker already depends // on it, as it has the path to this snapshot already added to PSModulePath. // As opposed to the background upgrade case, this snapshot is *required* for // this worker to run, even though it occupies some space (until the workers // restart and the redundant snapshots are purged). PromoteToInstalled(installingPath, targetPath, installationMode, logger); break; default: throw new ArgumentException($"Unexpected installation mode: {installationMode}", nameof(installationMode)); } } catch (Exception e) { var message = string.Format( PowerShellWorkerStrings.FailedToInstallDependenciesSnapshot, targetPath, installationMode); logger.Log(isUserOnlyLog: false, LogLevel.Warning, message, e); _storage.RemoveSnapshot(installingPath); throw; } finally { _moduleProvider.Cleanup(pwsh); } }