public async Task TestSha256_PackageArchiveReader_Central_Directory_Corrupt() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixture.BuildSnapApp(); using var testDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapOs.Filesystem); using var genesisSnapReleaseBuilder = _baseFixture .WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext) .AddNuspecItem(_baseFixture.BuildSnapExecutable(genesisSnapApp)) .AddSnapDll(); using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder); Checksum(genesisPackageContext.FullPackageSnapRelease); Checksum(genesisPackageContext.FullPackageSnapRelease); void Checksum(SnapRelease snapRelease) { if (snapRelease == null) { throw new ArgumentNullException(nameof(snapRelease)); } using var asyncPackageCoreReader = new PackageArchiveReader(genesisPackageContext.FullPackageMemoryStream, true); var checksum1 = _snapCryptoProvider.Sha256(snapRelease, asyncPackageCoreReader, _snapPack); var checksum2 = _snapCryptoProvider.Sha256(snapRelease, asyncPackageCoreReader, _snapPack); Assert.NotNull(checksum1); Assert.True(checksum1.Length == 64); Assert.Equal(checksum1, checksum2); } }
public SnapReleaseBuilder([NotNull] DisposableDirectory disposableDirectory, SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapReleaseBuilderContext builderContext) { if (builderContext == null) { throw new ArgumentNullException(nameof(builderContext)); } _nuspec = new Dictionary <string, IDisposable>(); SnapFilesystem = builderContext.SnapFilesystem ?? throw new ArgumentNullException(nameof(builderContext.SnapFilesystem)); SnapAppsReleases = snapAppsReleases ?? throw new ArgumentNullException(nameof(snapAppsReleases)); SnapApp = snapApp ?? throw new ArgumentNullException(nameof(snapApp)); CoreRunLib = builderContext.CoreRunLib ?? throw new ArgumentNullException(nameof(builderContext.CoreRunLib)); SnapCryptoProvider = builderContext.SnapCryptoProvider ?? throw new ArgumentNullException(nameof(builderContext.SnapCryptoProvider)); SnapEmbeddedResources = builderContext.SnapEmbeddedResources ?? throw new ArgumentNullException(nameof(builderContext.SnapEmbeddedResources)); SnapPack = builderContext.SnapPack ?? throw new ArgumentNullException(nameof(builderContext.SnapPack)); BaseDirectory = disposableDirectory ?? throw new ArgumentNullException(nameof(disposableDirectory)); NugetPackagingDirectory = SnapFilesystem.PathCombine(BaseDirectory.WorkingDirectory, "nuget", $"app-{snapApp.Version}"); SnapAppBaseDirectory = SnapFilesystem.PathCombine(BaseDirectory.WorkingDirectory, snapApp.Id); SnapAppInstallDirectory = SnapFilesystem.PathCombine(SnapAppBaseDirectory, $"app-{snapApp.Version}"); SnapAppPackagesDirectory = SnapFilesystem.PathCombine(SnapAppBaseDirectory, "packages"); SnapFilesystem.DirectoryCreateIfNotExists(NugetPackagingDirectory); SnapFilesystem.DirectoryCreateIfNotExists(SnapAppPackagesDirectory); SnapFilesystem.DirectoryCreateIfNotExists(SnapAppInstallDirectory); }
public byte[] ToSnapAppsReleases([NotNull] SnapAppsReleases snapAppsApps) { if (snapAppsApps == null) { throw new ArgumentNullException(nameof(snapAppsApps)); } return(MessagePackSerializer.Serialize(snapAppsApps, MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray))); }
public async Task TestInstallAsync() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixture.BuildSnapApp(); Assert.True(genesisSnapApp.Channels.Count >= 2); using var testDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem); using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext); var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp); genesisSnapReleaseBuilder .AddNuspecItem(mainAssemblyDefinition) .AddNuspecItem(mainAssemblyDefinition.BuildRuntimeConfigFilename(_snapFilesystem), mainAssemblyDefinition.BuildRuntimeConfig()) .AddNuspecItem(_baseFixture.BuildLibrary("test1")) .AddSnapDll(); using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder); var anyOs = SnapOs.AnyOs; Assert.NotNull(anyOs); var loggerMock = new Mock <ILog>(); var progressSource = new Mock <ISnapProgressSource>(); progressSource. Setup(x => x.Raise(It.IsAny <int>())); var failedRunAsyncReturnValues = new List <(int exitCode, string stdOut)>(); var snapOsProcessManager = new Mock <ISnapOsProcessManager>(); snapOsProcessManager .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>())) .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) => { var result = _snapOsProcessManager.RunAsync(builder, cancellationToken).GetAwaiter().GetResult(); if (result.exitCode != 0) { failedRunAsyncReturnValues.Add(result); } return(result); }); snapOsProcessManager .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>())) .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder)); snapOsProcessManager .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken)); _snapOsMock .Setup(x => x.Filesystem) .Returns(_snapFilesystem); _snapOsMock .Setup(x => x.ProcessManager) .Returns(snapOsProcessManager.Object); _snapOsMock .Setup(x => x.CreateShortcutsForExecutableAsync( It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(), It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem); using var installCts = new CancellationTokenSource(); var snapCurrentChannel = genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(); await _snapInstaller.InstallAsync( genesisPackageContext.FullPackageAbsolutePath, baseDirectory.WorkingDirectory, genesisPackageContext.FullPackageSnapRelease, snapCurrentChannel, progressSource.Object, loggerMock.Object, installCts.Token); var appDirectory = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}"); var snapAppUpdated = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader); var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow(); Assert.Equal(snapCurrentChannel.Name, snapAppUpdatedChannel.Name); #if !PLATFORM_WINDOWS || NETFULLFRAMEWORK // TODO: ENABLE ME! Unable to run a dotnet 2.2 (shared) executable on Windows. Assert.Empty(failedRunAsyncReturnValues); #endif var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, _snapEmbeddedResources.GetCoreRunExeFilenameForSnapApp(genesisPackageContext.FullPackageSnapApp)); var appExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisSnapReleaseBuilder.SnapApp.Version}", genesisSnapReleaseBuilder.CoreRunExe); var snapInstalledArguments = $"--snapx-installed {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}"; var snapFirstRunArguments = $"--snapx-first-run {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}"; progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once); } _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory( It.Is <string>(v => v == baseDirectory.WorkingDirectory)), Times.Once); _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync( It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(), It.IsAny <CancellationToken>()), Times.Once); _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync( It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe), It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.RunAsync( It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()), Times.Once); snapOsProcessManager.Verify(x => x.RunAsync( It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe && v.Arguments == snapInstalledArguments), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.StartNonBlocking( It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe & v.Arguments == snapFirstRunArguments)), Times.Once); snapOsProcessManager.Verify(x => x.StartNonBlocking( It.IsAny <ProcessStartInfoBuilder>()), Times.Once); }
public async Task TestInstallAsync_Different_Channel() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixture.BuildSnapApp(); Assert.True(genesisSnapApp.Channels.Count >= 2); using var testDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem); using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext); var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp); genesisSnapReleaseBuilder .AddNuspecItem(mainAssemblyDefinition) .AddSnapDll(); using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder); var loggerMock = new Mock <ILog>(); var snapOsProcessManager = new Mock <ISnapOsProcessManager>(); snapOsProcessManager .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>())) .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) => { var result = _snapOsProcessManager.RunAsync(builder, cancellationToken).GetAwaiter().GetResult(); return(result); }); snapOsProcessManager .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>())) .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder)); snapOsProcessManager .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken)); _snapOsMock .Setup(x => x.Filesystem) .Returns(_snapFilesystem); _snapOsMock .Setup(x => x.ProcessManager) .Returns(snapOsProcessManager.Object); _snapOsMock .Setup(x => x.CreateShortcutsForExecutableAsync( It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(), It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem); using var installCts = new CancellationTokenSource(); var nextSnapChannel = genesisSnapApp.GetNextChannel(); await _snapInstaller.InstallAsync( genesisPackageContext.FullPackageAbsolutePath, baseDirectory.WorkingDirectory, genesisPackageContext.FullPackageSnapRelease, nextSnapChannel, null, loggerMock.Object, installCts.Token); var appDirectory = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}"); var snapAppUpdated = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader); var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow(); Assert.Equal(nextSnapChannel.Name, snapAppUpdatedChannel.Name); }
public async Task TestRestoreAsync_Checksums_Genesis() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixturePackaging.BuildSnapApp(); var snapAppChannel = genesisSnapApp.GetDefaultChannelOrThrow(); using var rootDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem); using var restoreDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem); using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory); using var genesisReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext); var packagesDirectory = _snapFilesystem.PathCombine(restoreDirectory.WorkingDirectory, "packages"); _snapFilesystem.DirectoryCreate(packagesDirectory); var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory); var packageSource = nugetPackageSources.Items.Single(); genesisReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp)) .AddSnapDll(); using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder); var snapAppChannelReleases = snapAppsReleases.GetReleases(genesisSnapApp, snapAppChannel); var progressSourceMock = new Mock <ISnapPackageManagerProgressSource>(); progressSourceMock.Setup(x => x.RaiseChecksumProgress( It.IsAny <int>(), It.IsAny <long>(), It.IsAny <long>(), It.IsAny <long>())); var genesisPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, genesisPackageContext.FullPackageSnapRelease.Filename); await _snapFilesystem.FileCopyAsync(genesisPackageContext.FullPackageAbsolutePath, genesisPackageAbsolutePath, default); var restoreSummary = await _snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases, packageSource, SnapPackageManagerRestoreType.Default, progressSourceMock.Object); progressSourceMock.Verify(x => x.RaiseChecksumProgress( It.Is <int>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 1)), Times.Once); progressSourceMock.Verify(x => x.RaiseChecksumProgress( It.Is <int>(v => v == 100), It.Is <long>(v => v == 1), It.Is <long>(v => v == 1), It.Is <long>(v => v == 1)), Times.Once); Assert.Equal(SnapPackageManagerRestoreType.Default, restoreSummary.RestoreType); Assert.Single(restoreSummary.ChecksumSummary); Assert.True(restoreSummary.ChecksumSummary[0].Ok); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[0].SnapRelease.Filename); Assert.Empty(restoreSummary.DownloadSummary); Assert.Empty(restoreSummary.ReassembleSummary); Assert.True(restoreSummary.Success); using var packageArchiveReader = new PackageArchiveReader(genesisPackageAbsolutePath); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity()); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.FullSha256Checksum, _snapCryptoProvider.Sha256(genesisPackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack)); }
public async Task TestRestoreAsync_Downloads_Genesis_Delta_Consecutive_And_Reassembles_Full_From_Newest_Delta_Only() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixturePackaging.BuildSnapApp(); var update1SnapApp = _baseFixturePackaging.Bump(genesisSnapApp); var update2SnapApp = _baseFixturePackaging.Bump(update1SnapApp); var snapAppChannel = genesisSnapApp.GetDefaultChannelOrThrow(); using var rootDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem); using var restoreDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem); using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory); using var genesisReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext); using var update1ReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update1SnapApp, _releaseBuilderContext); using var update2ReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update2SnapApp, _releaseBuilderContext); var packagesDirectory = _snapFilesystem.PathCombine(restoreDirectory.WorkingDirectory, "packages"); var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory); var packageSource = nugetPackageSources.Items.Single(); genesisReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp)) .AddSnapDll(); update1ReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update1SnapApp)) .AddSnapDll(); update2ReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update2SnapApp)) .AddSnapDll(); using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder); using var update1PackageContext = await _baseFixturePackaging.BuildPackageAsync(update1ReleaseBuilder); using var update2PackageContext = await _baseFixturePackaging.BuildPackageAsync(update2ReleaseBuilder); _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock, genesisPackageContext.FullPackageSnapApp, genesisPackageContext.FullPackageMemoryStream, nugetPackageSources ); _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock, update1PackageContext.DeltaPackageSnapApp, update1PackageContext.DeltaPackageMemoryStream, nugetPackageSources ); _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock, update2PackageContext.DeltaPackageSnapApp, update2PackageContext.DeltaPackageMemoryStream, nugetPackageSources ); var snapAppChannelReleases = snapAppsReleases.GetReleases(genesisSnapApp, snapAppChannel); var progressSourceMock = new Mock <ISnapPackageManagerProgressSource>(); progressSourceMock.Setup(x => x.RaiseChecksumProgress( It.IsAny <int>(), It.IsAny <long>(), It.IsAny <long>(), It.IsAny <long>())); progressSourceMock.Setup(x => x.RaiseDownloadProgress( It.IsAny <int>(), It.IsAny <long>(), It.IsAny <long>(), It.IsAny <long>(), It.IsAny <long>())); progressSourceMock.Setup(x => x.RaiseRestoreProgress( It.IsAny <int>(), It.IsAny <long>(), It.IsAny <long>())); var restoreSummary = await _snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases, packageSource, SnapPackageManagerRestoreType.Default, progressSourceMock.Object); progressSourceMock.Verify(x => x.RaiseChecksumProgress( It.Is <int>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 4)), Times.Once); progressSourceMock.Verify(x => x.RaiseChecksumProgress( It.Is <int>(v => v == 100), It.Is <long>(v => v == 0), It.Is <long>(v => v == 4), It.Is <long>(v => v == 4)), Times.Once); var totalBytesToDownload = genesisPackageContext.FullPackageSnapRelease.FullFilesize + update1PackageContext.DeltaPackageSnapRelease.DeltaFilesize + update2PackageContext.DeltaPackageSnapRelease.DeltaFilesize; progressSourceMock.Verify(x => x.RaiseDownloadProgress( It.Is <int>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 3), It.Is <long>(v => v == 0), It.Is <long>(v => v == totalBytesToDownload))); progressSourceMock.Verify(x => x.RaiseRestoreProgress( It.Is <int>(v => v == 0), It.Is <long>(v => v == 0), It.Is <long>(v => v == 8)), Times.Once); progressSourceMock.Verify(x => x.RaiseRestoreProgress( It.Is <int>(v => v == 100), It.Is <long>(v => v == 8), It.Is <long>(v => v == 8)), Times.Once); Assert.Equal(SnapPackageManagerRestoreType.Default, restoreSummary.RestoreType); Assert.Equal(4, restoreSummary.ChecksumSummary.Count); Assert.False(restoreSummary.ChecksumSummary[0].Ok); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[0].SnapRelease.Filename); Assert.False(restoreSummary.ChecksumSummary[1].Ok); Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[1].SnapRelease.Filename); Assert.False(restoreSummary.ChecksumSummary[2].Ok); Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[2].SnapRelease.Filename); Assert.False(restoreSummary.ChecksumSummary[3].Ok); Assert.Equal(update2PackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[3].SnapRelease.Filename); Assert.Equal(3, restoreSummary.DownloadSummary.Count); Assert.True(restoreSummary.DownloadSummary[0].Ok); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.DownloadSummary[0].SnapRelease.Filename); Assert.True(restoreSummary.DownloadSummary[1].Ok); Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.DownloadSummary[1].SnapRelease.Filename); Assert.True(restoreSummary.DownloadSummary[2].Ok); Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.DownloadSummary[2].SnapRelease.Filename); _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync( It.IsAny <PackageSource>(), It.Is <DownloadContext>(v => v.PackageIdentity.Equals(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity())), It.IsAny <INugetServiceProgressSource>(), It.IsAny <CancellationToken>()), Times.Once); _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync( It.IsAny <PackageSource>(), It.Is <DownloadContext>(v => v.PackageIdentity.Equals(update1PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity())), It.IsAny <INugetServiceProgressSource>(), It.IsAny <CancellationToken>()), Times.Once); _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync( It.IsAny <PackageSource>(), It.Is <DownloadContext>(v => v.PackageIdentity.Equals(update2PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity())), It.IsAny <INugetServiceProgressSource>(), It.IsAny <CancellationToken>()), Times.Once); Assert.Single(restoreSummary.ReassembleSummary); Assert.True(restoreSummary.ReassembleSummary[0].Ok); Assert.Equal(update2PackageContext.FullPackageSnapRelease.Filename, restoreSummary.ReassembleSummary[0].SnapRelease.Filename); Assert.True(restoreSummary.Success); var genesisPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[0].SnapRelease.Filename); var update1FullPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, update1PackageContext.FullPackageSnapRelease.Filename); var update1DeltaPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[1].SnapRelease.Filename); var update2FullPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.ReassembleSummary[0].SnapRelease.Filename); var update2DeltaPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[2].SnapRelease.Filename); using (var packageArchiveReader = new PackageArchiveReader(genesisPackageAbsolutePath)) { Assert.Equal(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity()); Assert.Equal(genesisPackageContext.FullPackageSnapRelease.FullSha256Checksum, _snapCryptoProvider.Sha256(genesisPackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack)); } Assert.False(_snapFilesystem.FileExists(update1FullPackageAbsolutePath)); using (var packageArchiveReader = new PackageArchiveReader(update1DeltaPackageAbsolutePath)) { Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity()); Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.DeltaSha256Checksum, _snapCryptoProvider.Sha256(update1PackageContext.DeltaPackageSnapRelease, packageArchiveReader, _snapPack)); } using (var packageArchiveReader = new PackageArchiveReader(update2FullPackageAbsolutePath)) { Assert.Equal(update2PackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity()); Assert.Equal(update2PackageContext.FullPackageSnapRelease.FullSha256Checksum, _snapCryptoProvider.Sha256(update2PackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack)); } using (var packageArchiveReader = new PackageArchiveReader(update2DeltaPackageAbsolutePath)) { Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity()); Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.DeltaSha256Checksum, _snapCryptoProvider.Sha256(update2PackageContext.DeltaPackageSnapRelease, packageArchiveReader, _snapPack)); } }
internal SnapReleaseBuilder WithSnapReleaseBuilder(DisposableDirectory disposableDirectory, [NotNull] SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapReleaseBuilderContext builderContext) { if (snapAppsReleases == null) { throw new ArgumentNullException(nameof(snapAppsReleases)); } if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (builderContext == null) { throw new ArgumentNullException(nameof(builderContext)); } return(new SnapReleaseBuilder(disposableDirectory, snapAppsReleases, snapApp, builderContext)); }
static async Task PushPackagesAsync([NotNull] PackOptions packOptions, [NotNull] ILog logger, [NotNull] ISnapFilesystem filesystem, [NotNull] INugetService nugetService, [NotNull] ISnapPackageManager snapPackageManager, [NotNull] IDistributedMutex distributedMutex, [NotNull] SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapChannel snapChannel, [NotNull] List <string> packages, CancellationToken cancellationToken) { if (packOptions == null) { throw new ArgumentNullException(nameof(packOptions)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (filesystem == null) { throw new ArgumentNullException(nameof(filesystem)); } if (nugetService == null) { throw new ArgumentNullException(nameof(nugetService)); } if (snapPackageManager == null) { throw new ArgumentNullException(nameof(snapPackageManager)); } if (distributedMutex == null) { throw new ArgumentNullException(nameof(distributedMutex)); } if (snapAppsReleases == null) { throw new ArgumentNullException(nameof(snapAppsReleases)); } if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (snapChannel == null) { throw new ArgumentNullException(nameof(snapChannel)); } if (packages == null) { throw new ArgumentNullException(nameof(packages)); } if (packages.Count == 0) { throw new ArgumentException("Value cannot be an empty collection.", nameof(packages)); } logger.Info('-'.Repeat(TerminalBufferWidth)); var pushDegreeOfParallelism = Math.Min(Environment.ProcessorCount, packages.Count); var nugetSources = snapApp.BuildNugetSources(filesystem.PathGetTempPath()); var pushFeedPackageSource = nugetSources.Items.Single(x => x.Name == snapChannel.PushFeed.Name); if (pushFeedPackageSource.IsLocalOrUncPath()) { filesystem.DirectoryCreateIfNotExists(pushFeedPackageSource.SourceUri.AbsolutePath); } if (snapChannel.UpdateFeed.HasCredentials()) { if (!logger.Prompt("y|yes", "Update feed contains credentials. Do you want to continue? [y|n]", infoOnly: packOptions.YesToAllPrompts)) { logger.Error("Publish aborted."); return; } } logger.Info("Ready to publish application!"); logger.Info($"Id: {snapApp.Id}"); logger.Info($"Rid: {snapApp.Target.Rid}"); logger.Info($"Channel: {snapChannel.Name}"); logger.Info($"Version: {snapApp.Version}"); logger.Info($"Feed name: {snapChannel.PushFeed.Name}"); if (!logger.Prompt("y|yes", "Are you ready to push release upstream? [y|n]", infoOnly: packOptions.YesToAllPrompts)) { logger.Error("Publish aborted."); return; } var stopwatch = new Stopwatch(); stopwatch.Restart(); logger.Info($"Pushing packages to default channel: {snapChannel.Name}. Feed: {snapChannel.PushFeed.Name}."); await packages.ForEachAsync(async packageAbsolutePath => await PushPackageAsync(nugetService, filesystem, distributedMutex, nugetSources, pushFeedPackageSource, snapChannel, packageAbsolutePath, logger, cancellationToken), pushDegreeOfParallelism); logger.Info($"Successfully pushed {packages.Count} packages in {stopwatch.Elapsed.TotalSeconds:F1}s."); var skipInitialBlock = pushFeedPackageSource.IsLocalOrUncPath(); await BlockUntilSnapUpdatedReleasesNupkgAsync(logger, snapPackageManager, snapAppsReleases, snapApp, snapChannel, TimeSpan.FromSeconds(15), cancellationToken, skipInitialBlock, packOptions.SkipAwaitUpdate); }
static async Task <int> CommandPackAsync([NotNull] PackOptions packOptions, [NotNull] ISnapFilesystem filesystem, [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources, [NotNull] ISnapPack snapPack, [NotNull] INugetService nugetService, [NotNull] ISnapOs snapOs, [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ISnapExtractor snapExtractor, [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ICoreRunLib coreRunLib, [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider, [NotNull] ILog logger, [NotNull] IDistributedMutexClient distributedMutexClient, [NotNull] string workingDirectory, CancellationToken cancellationToken) { if (packOptions == null) { throw new ArgumentNullException(nameof(packOptions)); } if (filesystem == null) { throw new ArgumentNullException(nameof(filesystem)); } if (snapAppReader == null) { throw new ArgumentNullException(nameof(snapAppReader)); } if (snapAppWriter == null) { throw new ArgumentNullException(nameof(snapAppWriter)); } if (nuGetPackageSources == null) { throw new ArgumentNullException(nameof(nuGetPackageSources)); } if (snapPack == null) { throw new ArgumentNullException(nameof(snapPack)); } if (nugetService == null) { throw new ArgumentNullException(nameof(nugetService)); } if (snapOs == null) { throw new ArgumentNullException(nameof(snapOs)); } if (snapxEmbeddedResources == null) { throw new ArgumentNullException(nameof(snapxEmbeddedResources)); } if (snapExtractor == null) { throw new ArgumentNullException(nameof(snapExtractor)); } if (snapPackageManager == null) { throw new ArgumentNullException(nameof(snapPackageManager)); } if (coreRunLib == null) { throw new ArgumentNullException(nameof(coreRunLib)); } if (snapNetworkTimeProvider == null) { throw new ArgumentNullException(nameof(snapNetworkTimeProvider)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (distributedMutexClient == null) { throw new ArgumentNullException(nameof(distributedMutexClient)); } if (workingDirectory == null) { throw new ArgumentNullException(nameof(workingDirectory)); } var stopwatch = new Stopwatch(); stopwatch.Restart(); var(snapApps, snapApp, error, snapsManifestAbsoluteFilename) = BuildSnapAppFromDirectory(filesystem, snapAppReader, nuGetPackageSources, packOptions.Id, packOptions.Rid, workingDirectory); if (snapApp == null) { if (!error) { logger.Error($"Snap with id {packOptions.Id} was not found in manifest: {snapsManifestAbsoluteFilename}"); } return(1); } if (!SemanticVersion.TryParse(packOptions.Version, out var semanticVersion)) { logger.Error($"Unable to parse semantic version (v2): {packOptions.Version}"); return(1); } snapApp.Version = semanticVersion; if (packOptions.ReleasesNotes != null) { snapApp.ReleaseNotes = packOptions.ReleasesNotes; } var artifactsDirectory = BuildArtifactsDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp); var installersDirectory = BuildInstallersDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp); var packagesDirectory = BuildPackagesDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp); filesystem.DirectoryCreateIfNotExists(installersDirectory); filesystem.DirectoryCreateIfNotExists(packagesDirectory); var snapAppChannel = snapApp.GetDefaultChannelOrThrow(); MaybeOverrideLockToken(snapApps, logger, packOptions.Id, packOptions.LockToken); if (string.IsNullOrWhiteSpace(snapApps.Generic.Token)) { logger.Error("Please specify a token in your snapx.yml file. A random UUID is sufficient."); return(1); } await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger, snapApps.BuildLockKey(snapApp), cancellationToken); logger.Info($"Schema version: {snapApps.Schema}"); logger.Info($"Packages directory: {packagesDirectory}"); logger.Info($"Artifacts directory: {artifactsDirectory}"); logger.Info($"Installers directory: {installersDirectory}"); logger.Info($"Pack strategy: {snapApps.Generic.PackStrategy}"); logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Info($"Id: {snapApp.Id}"); logger.Info($"Version: {snapApp.Version}"); logger.Info($"Channel: {snapAppChannel.Name}"); logger.Info($"Rid: {snapApp.Target.Rid}"); logger.Info($"OS: {snapApp.Target.Os.ToString().ToLowerInvariant()}"); var installersStr = !snapApp.Target.Installers.Any() ? "None" : string.Join(", ", snapApp.Target.Installers); logger.Info($"Installers: {installersStr}"); var shortcutsStr = !snapApp.Target.Shortcuts.Any() ? "None" : string.Join(", ", snapApp.Target.Shortcuts); logger.Info($"Shortcuts: {shortcutsStr}"); logger.Info('-'.Repeat(TerminalBufferWidth)); var tryAcquireRetries = packOptions.LockRetries == -1 ? int.MaxValue : packOptions.LockRetries; if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries)) { logger.Info('-'.Repeat(TerminalBufferWidth)); return(1); } logger.Info('-'.Repeat(TerminalBufferWidth)); var updateFeedPackageSource = await snapPackageManager.GetPackageSourceAsync(snapApp); logger.Info("Downloading releases nupkg."); var snapReleasesPackageDirectory = filesystem.DirectoryGetParent(packagesDirectory); filesystem.DirectoryCreateIfNotExists(snapReleasesPackageDirectory); var(snapAppsReleases, _, currentReleasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken); if (currentReleasesMemoryStream != null) { await currentReleasesMemoryStream.DisposeAsync(); } if (snapAppsReleases == null) { if (!logger.Prompt("y|yes", "Unable to find a previous release in any of your NuGet package sources. " + "Is this the first time you are publishing this application? " + "NB! The package may not yet be visible to due to upstream caching. [y/n]", infoOnly: packOptions.YesToAllPrompts) ) { return(1); } snapAppsReleases = new SnapAppsReleases(); } else { logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}."); if (packOptions.Gc) { var releasesRemoved = snapAppsReleases.Gc(snapApp); logger.Info($"Garbage collected (removed) {releasesRemoved} releases."); } var snapAppChannelReleases = snapAppsReleases.GetReleases(snapApp, snapAppChannel); var restoreSummary = await snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases, updateFeedPackageSource, SnapPackageManagerRestoreType.Pack, logger : logger, cancellationToken : cancellationToken); if (!restoreSummary.Success) { return(1); } if (snapAppChannelReleases.Any(x => x.Version >= snapApp.Version)) { logger.Error($"Version {snapApp.Version} is already published to feed: {updateFeedPackageSource.Name}."); return(1); } } var snapPackageDetails = new SnapPackageDetails { SnapApp = snapApp, NuspecBaseDirectory = artifactsDirectory, PackagesDirectory = packagesDirectory, SnapAppsReleases = snapAppsReleases }; logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Info($"Building nupkg: {snapApp.Version}."); var pushPackages = new List <string>(); var(fullNupkgMemoryStream, fullSnapApp, fullSnapRelease, deltaNupkgMemorystream, deltaSnapApp, deltaSnapRelease) = await snapPack.BuildPackageAsync(snapPackageDetails, coreRunLib, cancellationToken); var fullNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullSnapRelease.Filename); await using (fullNupkgMemoryStream) await using (deltaNupkgMemorystream) { logger.Info($"Writing full nupkg to disk: {fullSnapRelease.Filename}. File size: {fullSnapRelease.FullFilesize.BytesAsHumanReadable()}"); await filesystem.FileWriteAsync(fullNupkgMemoryStream, fullNupkgAbsolutePath, default); if (!fullSnapRelease.IsGenesis) { var deltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, deltaSnapRelease.Filename); logger.Info( $"Writing delta nupkg to disk: {deltaSnapRelease.Filename}. File size: {deltaSnapRelease.DeltaFilesize.BytesAsHumanReadable()}"); await filesystem.FileWriteAsync(deltaNupkgMemorystream, deltaNupkgAbsolutePath, default); } } var fullOrDeltaSnapApp = deltaSnapApp ?? fullSnapApp; var fullOrDeltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullOrDeltaSnapApp.BuildNugetFilename()); pushPackages.Add(fullOrDeltaNupkgAbsolutePath); logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Info($"Retrieving network time from: {snapNetworkTimeProvider}."); var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3); if (!nowUtc.HasValue) { logger.Error($"Unknown error retrieving network time from: {snapNetworkTimeProvider}"); return(1); } var localTimeStr = TimeZoneInfo .ConvertTimeFromUtc(nowUtc.Value, TimeZoneInfo.Local) .ToString("F", CultureInfo.CurrentCulture); logger.Info($"Successfully retrieved network time. Time is now: {localTimeStr}"); logger.Info('-'.Repeat(TerminalBufferWidth)); fullSnapRelease.CreatedDateUtc = nowUtc.Value; if (deltaSnapRelease != null) { deltaSnapRelease.CreatedDateUtc = nowUtc.Value; } snapAppsReleases.LastWriteAccessUtc = nowUtc.Value; int?forcedDbVersion = null; if (packOptions.DbVersion > 0) { if (packOptions.DbVersion <= snapAppsReleases.DbVersion) { logger.Error($"Unable to force database version because version is less than or equal to current database version. \n" + $"Forced version: {packOptions.DbVersion}.\n" + $"Current database version: {snapAppsReleases.DbVersion}."); return(1); } forcedDbVersion = packOptions.DbVersion; logger.Info($"Database version is forced because of '--db-version' option. Initial database version: {forcedDbVersion}."); } else if (fullOrDeltaSnapApp.IsGenesis && fullOrDeltaSnapApp.Version.Major > snapAppsReleases.Version.Major) { forcedDbVersion = fullOrDeltaSnapApp.Version.Major; logger.Info($"Database version is forced because genesis nupkg detected. Initial database version: {forcedDbVersion}"); } logger.Info($"Building releases nupkg. Current database version: {snapAppsReleases.Version}."); var releasesMemoryStream = snapPack.BuildReleasesPackage(fullOrDeltaSnapApp, snapAppsReleases, forcedDbVersion); var releasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(snapReleasesPackageDirectory, fullOrDeltaSnapApp.BuildNugetReleasesFilename()); var releasesNupkgFilename = filesystem.PathGetFileName(releasesNupkgAbsolutePath); await snapOs.Filesystem.FileWriteAsync(releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken); pushPackages.Add(releasesNupkgAbsolutePath); logger.Info("Finished building releases nupkg.\n" + $"Filename: {releasesNupkgFilename}.\n" + $"Size: {releasesMemoryStream.Length.BytesAsHumanReadable()}.\n" + $"New database version: {snapAppsReleases.Version}.\n" + $"Pack id: {snapAppsReleases.PackId:N}."); logger.Info('-'.Repeat(TerminalBufferWidth)); await using (releasesMemoryStream) { if (!packOptions.SkipInstallers && fullOrDeltaSnapApp.Target.Installers.Any()) { var channels = fullOrDeltaSnapApp.IsGenesis ? fullOrDeltaSnapApp.Channels : new List <SnapChannel> { snapAppChannel }; foreach (var channel in channels) { var snapAppInstaller = new SnapApp(fullOrDeltaSnapApp); snapAppInstaller.SetCurrentChannel(channel.Name); if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Offline))) { logger.Info('-'.Repeat(TerminalBufferWidth)); var(installerOfflineSuccess, canContinueIfError, installerOfflineExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib, installersDirectory, fullNupkgAbsolutePath, releasesNupkgAbsolutePath, true, cancellationToken); if (!installerOfflineSuccess) { if (!canContinueIfError || !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)", infoOnly: packOptions.YesToAllPrompts)) { logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Error("Unknown error building offline installer."); return(1); } } else { var installerOfflineExeStat = snapOs.Filesystem.FileStat(installerOfflineExeAbsolutePath); logger.Info($"Successfully built offline installer. File size: {installerOfflineExeStat.Length.BytesAsHumanReadable()}."); } } if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Web))) { logger.Info('-'.Repeat(TerminalBufferWidth)); var(installerWebSuccess, canContinueIfError, installerWebExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib, installersDirectory, null, releasesNupkgAbsolutePath, false, cancellationToken); if (!installerWebSuccess) { if (!canContinueIfError || !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)", infoOnly: packOptions.YesToAllPrompts)) { logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Error("Unknown error building offline installer."); return(1); } } else { var installerWebExeStat = snapOs.Filesystem.FileStat(installerWebExeAbsolutePath); logger.Info($"Successfully built web installer. File size: {installerWebExeStat.Length.BytesAsHumanReadable()}."); } } } } } if (snapApps.Generic.PackStrategy == SnapAppsPackStrategy.push) { await PushPackagesAsync(packOptions, logger, filesystem, nugetService, snapPackageManager, distributedMutex, snapAppsReleases, fullOrDeltaSnapApp, snapAppChannel, pushPackages, cancellationToken); } logger.Info($"Fetching releases overview from feed {updateFeedPackageSource.Name}."); await CommandListAsync(new ListOptions { Id = fullOrDeltaSnapApp.Id }, filesystem, snapAppReader, nuGetPackageSources, nugetService, snapExtractor, snapPackageManager, logger, workingDirectory, cancellationToken); logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Info($"Pack completed in {stopwatch.Elapsed.TotalSeconds:F1}s."); return(0); }
public async Task TestUpdateAsync() { var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixture.BuildSnapApp(); var update1SnapApp = _baseFixture.Bump(genesisSnapApp); var update2SnapApp = _baseFixture.Bump(update1SnapApp); await using var testDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem); using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext); using var update1SnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update1SnapApp, _snapReleaseBuilderContext); using var update2SnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update2SnapApp, _snapReleaseBuilderContext); var mainExecutable = _baseFixture.BuildSnapExecutable(genesisSnapApp); genesisSnapReleaseBuilder .AddNuspecItem(mainExecutable) .AddNuspecItem(mainExecutable.BuildRuntimeConfigFilename(_snapFilesystem), mainExecutable.BuildRuntimeConfig()) .AddNuspecItem(_baseFixture.BuildLibrary("test1")) .AddSnapDll(); update1SnapReleaseBuilder .AddNuspecItem(genesisSnapReleaseBuilder, 0) .AddNuspecItem(genesisSnapReleaseBuilder, 1) .AddNuspecItem(genesisSnapReleaseBuilder, 2) .AddNuspecItem(_baseFixture.BuildLibrary("test2")) .AddSnapDll(); update2SnapReleaseBuilder .AddNuspecItem(update1SnapReleaseBuilder, 0) .AddNuspecItem(update1SnapReleaseBuilder, 1) .AddNuspecItem(update1SnapReleaseBuilder, 2) .AddNuspecItem(update1SnapReleaseBuilder, 3) .AddNuspecItem(_baseFixture.BuildLibrary("test3")) .AddSnapDll(); using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder); using (await _baseFixture.BuildPackageAsync(update1SnapReleaseBuilder)) { using var update2PackageContext = await _baseFixture.BuildPackageAsync(update2SnapReleaseBuilder); var loggerMock = new Mock <ILog>(); var progressSource = new Mock <ISnapProgressSource>(); progressSource. Setup(x => x.Raise(It.IsAny <int>())); var snapOsProcessManager = new Mock <ISnapOsProcessManager>(); snapOsProcessManager .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>())) .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) => { var result = TplHelper.RunSync(() => _snapOsProcessManager.RunAsync(builder, cancellationToken)); return(result); }); snapOsProcessManager .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>())) .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder)); snapOsProcessManager .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>())) .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken)); _snapOsMock .Setup(x => x.Filesystem) .Returns(_snapFilesystem); _snapOsMock .Setup(x => x.ProcessManager) .Returns(snapOsProcessManager.Object); _snapOsMock .Setup(x => x.CreateShortcutsForExecutableAsync( It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(), It.IsAny <CancellationToken>())) .Returns(Task.CompletedTask); await using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem); using var updateCts = new CancellationTokenSource(); await _snapInstaller.InstallAsync( genesisPackageContext.FullPackageAbsolutePath, baseDirectory.WorkingDirectory, genesisPackageContext.FullPackageSnapRelease, genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(), cancellationToken : updateCts.Token); _snapOsMock.Invocations.Clear(); snapOsProcessManager.Invocations.Clear(); var update2FullNupkgAbsolutePath = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, "packages", update2PackageContext.FullPackageSnapRelease.BuildNugetFilename()); await _snapFilesystem.FileCopyAsync(update2PackageContext.FullPackageAbsolutePath, update2FullNupkgAbsolutePath, default); await _snapInstaller.UpdateAsync( baseDirectory.WorkingDirectory, update2PackageContext.FullPackageSnapRelease, update2PackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(), progressSource.Object, loggerMock.Object, updateCts.Token); var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, update2SnapReleaseBuilder.CoreRunExe); var appExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{update2SnapReleaseBuilder.SnapApp.Version}", update2SnapReleaseBuilder.CoreRunExe); var snapUpdatedArguments = $"--snapx-updated {update2SnapReleaseBuilder.SnapApp.Version.ToNormalizedString()}"; progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once); if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2)); snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.ChmodExecuteAsync( It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once); } _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory( It.IsAny <string>()), Times.Never); _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync( It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(), It.IsAny <CancellationToken>()), Times.Once); _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync( It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe), It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.RunAsync(It.Is <ProcessStartInfoBuilder>( v => v.Filename == appExe && v.Arguments == snapUpdatedArguments), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once); snapOsProcessManager.Verify(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()), Times.Never); } }
public async Task TestGetSnapsReleasesAsync() { using var _ = LogHelper.Capture(_testOutputHelper, LogProvider.SetCurrentLogProvider); var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixturePackaging.BuildSnapApp(); var update1SnapApp = _baseFixturePackaging.Bump(genesisSnapApp); var update2SnapApp = _baseFixturePackaging.Bump(update1SnapApp); await using var rootDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem); await using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory); using var genesisReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext); using var update1ReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update1SnapApp, _releaseBuilderContext); using var update2ReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update2SnapApp, _releaseBuilderContext); var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory); genesisReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp)) .AddSnapDll(); update1ReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update1SnapApp)) .AddSnapDll(); update2ReleaseBuilder .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update2SnapApp)) .AddSnapDll(); using (await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder)) using (await _baseFixturePackaging.BuildPackageAsync(update1ReleaseBuilder)) { using var update2PackageContext = await _baseFixturePackaging.BuildPackageAsync(update2ReleaseBuilder); await using var releasesNupkgMemoryStream = _snapPack.BuildReleasesPackage(genesisSnapApp, snapAppsReleases); var expectedVersion = SemanticVersion.Parse("1.0.0"); var expectedPackageIdentity = new PackageIdentity( update2PackageContext.FullPackageSnapRelease.BuildNugetReleasesUpstreamId(), expectedVersion.ToNuGetVersion()); using (var releasesPackageArchiveReader = new PackageArchiveReader(releasesNupkgMemoryStream, true)) { Assert.Equal(expectedPackageIdentity, releasesPackageArchiveReader.GetIdentity()); } releasesNupkgMemoryStream.Seek(0, SeekOrigin.Begin); _baseFixtureNuget.SetupReleases(_nugetServiceMock, releasesNupkgMemoryStream, nugetPackageSources, genesisSnapApp); var(snapAppsReleasesAfter, packageSourceAfter, releasesMemoryStream) = await _snapPackageManager.GetSnapsReleasesAsync(genesisSnapApp); await using (releasesMemoryStream) { Assert.NotNull(releasesMemoryStream); Assert.Equal(0, releasesMemoryStream.Position); Assert.True(releasesMemoryStream.Length > 0); Assert.NotNull(snapAppsReleasesAfter); Assert.NotNull(packageSourceAfter); Assert.Equal(expectedVersion, snapAppsReleases.Version); Assert.Equal(expectedVersion, snapAppsReleasesAfter.Version); var snapAppReleases = snapAppsReleasesAfter.GetReleases(genesisSnapApp); Assert.Equal(3, snapAppReleases.Count()); } } }
public async Task TestInstall_Offline_Using_Local_PackageSource() { await using var specialFoldersAnyOs = new SnapOsSpecialFoldersUnitTest(_snapFilesystem, _baseFixturePackaging.WorkingDirectory); await using var packagesDirectory = new DisposableDirectory(specialFoldersAnyOs.WorkingDirectory, _snapFilesystem); using var cts = new CancellationTokenSource(); SetupSnapOsMock(specialFoldersAnyOs); var snapInstallerIoEnvironment = new SnapInstallerIoEnvironment { WorkingDirectory = specialFoldersAnyOs.WorkingDirectory, ThisExeWorkingDirectory = specialFoldersAnyOs.WorkingDirectory, SpecialFolders = specialFoldersAnyOs, }; var snapAppsReleases = new SnapAppsReleases(); var genesisSnapApp = _baseFixturePackaging.BuildSnapApp(localPackageSourceDirectory: packagesDirectory); Assert.True(genesisSnapApp.Channels.Count >= 2); using var genesisSnapReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(packagesDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext); var mainAssemblyDefinition = _baseFixturePackaging.BuildSnapExecutable(genesisSnapApp); genesisSnapReleaseBuilder .AddNuspecItem(mainAssemblyDefinition) .AddSnapDll(); using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisSnapReleaseBuilder, cts.Token); var releasesFilename = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, genesisPackageContext.FullPackageSnapApp.BuildNugetReleasesFilename()); var snapAppDllFilename = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, SnapConstants.SnapAppDllFilename); var setupNupkgFilename = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, SnapConstants.SetupNupkgFilename); await using var releasePackageMemoryStream = _snapPack.BuildReleasesPackage(genesisSnapApp, snapAppsReleases); await _snapFilesystem.FileWriteAsync(genesisPackageContext.FullPackageMemoryStream, setupNupkgFilename, cts.Token); await _snapFilesystem.FileWriteAsync(releasePackageMemoryStream, releasesFilename, cts.Token); using var snapAppDllAssemblyDefinition = _snapAppWriter.BuildSnapAppAssembly(genesisSnapApp); snapAppDllAssemblyDefinition.Write(snapAppDllFilename); var(exitCode, installerType) = await Program.MainImplAsync(new[] { "--headless" }, LogLevel.Info, cts, _snapOsMock.Object, x => { x.Register <ISnapInstallerIoEnvironment>(_ => snapInstallerIoEnvironment); return((ISnapInstallerEnvironment)x.GetInstance(typeof(ISnapInstallerEnvironment))); }); Assert.Equal(0, exitCode); Assert.Equal(SnapInstallerType.Offline, installerType); var appInstallDirectory = _snapInstaller.GetApplicationDirectory( _snapFilesystem.PathCombine(specialFoldersAnyOs.LocalApplicationData, genesisSnapApp.Id), genesisSnapApp.Version); var files = _snapFilesystem.DirectoryGetAllFiles(appInstallDirectory).OrderBy(x => x, new OrdinalIgnoreCaseComparer()).ToList(); Assert.Equal(3, files.Count); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { Assert.EndsWith($"{genesisSnapApp.Id}.exe", files[0]); } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { Assert.EndsWith(genesisSnapApp.Id, files[0]); } else { throw new PlatformNotSupportedException(); } Assert.EndsWith(SnapConstants.SnapAppDllFilename, files[1]); Assert.EndsWith(SnapConstants.SnapDllFilename, files[2]); }
static async Task BlockUntilSnapUpdatedReleasesNupkgAsync([NotNull] ILog logger, [NotNull] ISnapPackageManager snapPackageManager, [NotNull] SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapChannel snapChannel, TimeSpan retryInterval, CancellationToken cancellationToken) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (snapPackageManager == null) { throw new ArgumentNullException(nameof(snapPackageManager)); } if (snapAppsReleases == null) { throw new ArgumentNullException(nameof(snapAppsReleases)); } if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (snapChannel == null) { throw new ArgumentNullException(nameof(snapChannel)); } var stopwatch = new Stopwatch(); stopwatch.Restart(); logger.Info('-'.Repeat(TerminalBufferWidth)); logger.Info( $"Waiting until uploaded release nupkg is available in feed: {snapChannel.PushFeed.Name}. " + $"Retry every {retryInterval.TotalSeconds:0.0}s."); var logDashes = false; while (!cancellationToken.IsCancellationRequested) { sleep: await Task.Delay(retryInterval, cancellationToken); if (logDashes) { logger.Info('-'.Repeat(TerminalBufferWidth)); } logDashes = true; var(upstreamSnapAppsReleases, _, releasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken); if (releasesMemoryStream != null) { await releasesMemoryStream.DisposeAsync(); } if (upstreamSnapAppsReleases == null) { goto sleep; } if (upstreamSnapAppsReleases.PackId == snapAppsReleases.PackId) { logger.Info($"{snapChannel.PushFeed.Name} releases nupkg has been successfully updated to version: {upstreamSnapAppsReleases.Version}.\n" + $"Pack id: {upstreamSnapAppsReleases.PackId:N}. \n" + $"Completed in {stopwatch.Elapsed.TotalSeconds:0.0}s. "); break; } logger.Info( $"Current {snapChannel.PushFeed.Name} version: {upstreamSnapAppsReleases.Version}.\n" + $"Current pack id: {upstreamSnapAppsReleases.PackId:N}\n" + $"Local version: {snapAppsReleases.Version}. \n" + $"Local pack id: {snapAppsReleases.PackId:N} \n" + $"Retry in {retryInterval.TotalSeconds:0.0}s."); } logger.Info('-'.Repeat(TerminalBufferWidth)); }