public void CorruptedReleaseFileMeansWeStartFromScratch()
        {
            string localPackagesDir = Path.Combine(".", "theApp", "packages");
            string localReleasesFile = Path.Combine(localPackagesDir, "RELEASES");

            var fileInfo = new Mock<FileInfoBase>();
            fileInfo.Setup(x => x.Exists).Returns(true);
            fileInfo.Setup(x => x.OpenRead())
                .Returns(new MemoryStream(Encoding.UTF8.GetBytes("lol this isn't right")));

            var dirInfo = new Mock<DirectoryInfoBase>();
            dirInfo.Setup(x => x.Exists).Returns(true);

            var fs = new Mock<IFileSystemFactory>();
            fs.Setup(x => x.GetFileInfo(localReleasesFile)).Returns(fileInfo.Object);
            fs.Setup(x => x.CreateDirectoryRecursive(localPackagesDir)).Verifiable();
            fs.Setup(x => x.DeleteDirectoryRecursive(localPackagesDir)).Verifiable();
            fs.Setup(x => x.GetDirectoryInfo(localPackagesDir)).Returns(dirInfo.Object);

            var urlDownloader = new Mock<IUrlDownloader>();
            var dlPath = IntegrationTestHelper.GetPath("fixtures", "RELEASES-OnePointOne");
            urlDownloader.Setup(x => x.DownloadUrl(It.IsAny<string>()))
                .Returns(Observable.Return(File.ReadAllText(dlPath, Encoding.UTF8)));

            var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net40, ".", fs.Object, urlDownloader.Object);
            using (fixture.AcquireUpdateLock()) {
                fixture.CheckForUpdate().First();
            }

            fs.Verify(x => x.CreateDirectoryRecursive(localPackagesDir), Times.Once());
            fs.Verify(x => x.DeleteDirectoryRecursive(localPackagesDir), Times.Once());
        }
            public void UpdateLocalReleasesSmokeTest()
            {
                string tempDir;
                using (Utility.WithTempDirectory(out tempDir)) {
                    var packageDir = Directory.CreateDirectory(Path.Combine(tempDir, "theApp", "packages"));

                    new[] {
                        "Shimmer.Core.1.0.0.0-full.nupkg",
                        "Shimmer.Core.1.1.0.0-delta.nupkg",
                        "Shimmer.Core.1.1.0.0-full.nupkg",
                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(tempDir, "theApp", "packages", x)));

                    var urlDownloader = new Mock<IUrlDownloader>();
                    var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net40, tempDir, null, urlDownloader.Object);

                    using (fixture.AcquireUpdateLock()) {
                        fixture.UpdateLocalReleasesFile().Last();
                    }

                    var releasePath = Path.Combine(packageDir.FullName, "RELEASES");
                    File.Exists(releasePath).ShouldBeTrue();

                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));
                    entries.Count().ShouldEqual(3);
                }
            }
Example #3
0
        public void ApplyReleasesWithDeltaReleases()
        {
            string tempDir;

            using (Utility.WithTempDirectory(out tempDir)) {
                Directory.CreateDirectory(Path.Combine(tempDir, "theApp", "packages"));

                new[] {
                    "Shimmer.Core.1.0.0.0-full.nupkg",
                    "Shimmer.Core.1.1.0.0-delta.nupkg",
                    "Shimmer.Core.1.1.0.0-full.nupkg",
                }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(tempDir, "theApp", "packages", x)));

                var fixture = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net40, tempDir, null, new FakeUrlDownloader());

                var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Shimmer.Core.1.0.0.0-full.nupkg"));
                var deltaEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Shimmer.Core.1.1.0.0-delta.nupkg"));
                var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Shimmer.Core.1.1.0.0-full.nupkg"));

                var updateInfo = UpdateInfo.Create(baseEntry, new[] { deltaEntry, latestFullEntry }, "dontcare", FrameworkVersion.Net40);
                updateInfo.ReleasesToApply.Contains(deltaEntry).ShouldBeTrue();

                using (fixture.AcquireUpdateLock()) {
                    var progress = fixture.ApplyReleases(updateInfo).ToList().First();
                    this.Log().Info("Progress: [{0}]", String.Join(",", progress));
                    progress.Buffer(2,1).All(x => x.Count != 2 || x[1] > x[0]).ShouldBeTrue();
                    progress.Last().ShouldEqual(100);
                }

                var filesToFind = new[] {
                    new {Name = "NLog.dll", Version = new Version("2.0.0.0")},
                    new {Name = "NSync.Core.dll", Version = new Version("1.1.0.0")},
                    new {Name = "Ionic.Zip.dll", Version = new Version("1.9.1.8")},
                };

                filesToFind.ForEach(x => {
                    var path = Path.Combine(tempDir, "theApp", "app-1.1.0.0", x.Name);
                    this.Log().Info("Looking for {0}", path);
                    File.Exists(path).ShouldBeTrue();

                    var vi = FileVersionInfo.GetVersionInfo(path);
                    var verInfo = new Version(vi.FileVersion ?? "1.0.0.0");
                    x.Version.ShouldEqual(verInfo);
                });
            }
        }
Example #4
0
            public void ApplyReleasesWithOneReleaseFile()
            {
                string tempDir;

                using (Utility.WithTempDirectory(out tempDir)) {
                    Directory.CreateDirectory(Path.Combine(tempDir, "theApp"));
                    Directory.CreateDirectory(Path.Combine(tempDir, "theApp", "packages"));

                    new[] {
                        "Shimmer.Core.1.0.0.0-full.nupkg",
                        "Shimmer.Core.1.1.0.0-full.nupkg",
                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(tempDir, "theApp", "packages", x)));

                    var urlDownloader = new Mock<IUrlDownloader>();
                    var fixture = new UpdateManager("http://lol", "theApp", tempDir, null, urlDownloader.Object);

                    var baseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Shimmer.Core.1.0.0.0-full.nupkg"));
                    var latestFullEntry = ReleaseEntry.GenerateFromFile(Path.Combine(tempDir, "theApp", "packages", "Shimmer.Core.1.1.0.0-full.nupkg"));

                    var updateInfo = UpdateInfo.Create(baseEntry, new[] { latestFullEntry }, "dontcare");
                    updateInfo.ReleasesToApply.Contains(latestFullEntry).ShouldBeTrue();

                    using (fixture.AcquireUpdateLock()) {
                        fixture.ApplyReleases(updateInfo).First();
                    }

                    var filesToFind = new[] {
                        new {Name = "NLog.dll", Version = new Version("2.0.0.0")},
                        new {Name = "NSync.Core.dll", Version = new Version("1.1.0.0")},
                        new {Name = "Ionic.Zip.dll", Version = new Version("1.9.1.8")},
                    };

                    filesToFind.ForEach(x => {
                        var path = Path.Combine(tempDir, "theApp", "app-1.1.0.0", x.Name);
                        this.Log().Info("Looking for {0}", path);
                        File.Exists(path).ShouldBeTrue();

                        var vi = FileVersionInfo.GetVersionInfo(path);
                        var verInfo = new Version(vi.FileVersion ?? "1.0.0.0");
                        x.Version.ShouldEqual(verInfo);
                    });
                }
            }
Example #5
0
            public void NewReleasesShouldBeDetected()
            {
                string localReleasesFile = Path.Combine(".", "theApp", "packages", "RELEASES");

                var fileInfo = new Mock<FileInfoBase>();
                fileInfo.Setup(x => x.OpenRead())
                    .Returns(File.OpenRead(IntegrationTestHelper.GetPath("fixtures", "RELEASES-OnePointOh")));

                var fs = new Mock<IFileSystemFactory>();
                fs.Setup(x => x.GetFileInfo(localReleasesFile)).Returns(fileInfo.Object);

                var urlDownloader = new Mock<IUrlDownloader>();
                var dlPath = IntegrationTestHelper.GetPath("fixtures", "RELEASES-OnePointOne");
                urlDownloader.Setup(x => x.DownloadUrl(It.IsAny<string>()))
                    .Returns(Observable.Return(File.ReadAllText(dlPath, Encoding.UTF8)));

                var fixture = new UpdateManager("http://lol", "theApp", ".", fs.Object, urlDownloader.Object);
                var result = default(UpdateInfo);

                using (fixture.AcquireUpdateLock()) {
                    result = fixture.CheckForUpdate().First();
                }

                Assert.NotNull(result);
                Assert.Equal(1, result.ReleasesToApply.Single().Version.Major);
                Assert.Equal(1, result.ReleasesToApply.Single().Version.Minor);
            }
        public void DownloadReleasesFromHttpServerIntegrationTest()
        {
            string tempDir = null;

            var updateDir = new DirectoryInfo(IntegrationTestHelper.GetPath("..", "SampleUpdatingApp", "SampleReleasesFolder"));

            var httpServer = new StaticHttpServer(30405, updateDir.FullName);

            var entriesToDownload = updateDir.GetFiles("*.nupkg")
                .Select(x => ReleaseEntry.GenerateFromFile(x.FullName))
                .ToArray();

            entriesToDownload.Count().ShouldBeGreaterThan(0);

            using (httpServer.Start())
            using (Utility.WithTempDirectory(out tempDir)) {
                // NB: This is normally done by CheckForUpdates, but since
                // we're skipping that in the test we have to do it ourselves
                (new DirectoryInfo(Path.Combine(tempDir, "SampleUpdatingApp", "packages"))).CreateRecursive();

                var fixture = new UpdateManager("http://localhost:30405", "SampleUpdatingApp", FrameworkVersion.Net40, tempDir);
                using (fixture.AcquireUpdateLock()) {
                    var progress = fixture.DownloadReleases(entriesToDownload).ToList().First();
                    this.Log().Info("Progress: [{0}]", String.Join(",", progress));
                    progress.Buffer(2,1).All(x => x.Count != 2 || x[1] > x[0]).ShouldBeTrue();
                    progress.Last().ShouldEqual(100);
                }

                entriesToDownload.ForEach(x => {
                    this.Log().Info("Looking for {0}", x.Filename);
                    var actualFile = Path.Combine(tempDir, "SampleUpdatingApp", "packages", x.Filename);
                    File.Exists(actualFile).ShouldBeTrue();

                    var actualEntry = ReleaseEntry.GenerateFromFile(actualFile);
                    actualEntry.SHA1.ShouldEqual(x.SHA1);
                    actualEntry.Version.ShouldEqual(x.Version);
                });
            }
        }
Example #7
0
        public WixUiBootstrapper(IWiXEvents wixEvents, TinyIoCContainer testKernel = null, IRoutingState router = null)
        {
            Kernel = testKernel ?? createDefaultKernel();
            Kernel.Register<IWixUiBootstrapper>(this).AsSingleton();
            Kernel.Register<IScreen>(this);
            Kernel.Register(wixEvents);

            Router = router ?? new RoutingState();
            WiXEvents = wixEvents;

            _BundledRelease = new Lazy<ReleaseEntry>(readBundledReleasesFile);

            registerExtensionDlls(Kernel);

            RxApp.ConfigureServiceLocator(
                (type, contract) => Kernel.Resolve(type, contract),
                (type, contract) => Kernel.ResolveAll(type),
                (c, t, s) => Kernel.Register(t, c, s));

            UserError.RegisterHandler(ex => {
                if (wixEvents.Command.Display != Display.Full) {
                    this.Log().Error(ex.ErrorMessage);
                    wixEvents.ShouldQuit();
                }

                var errorVm = RxApp.GetService<IErrorViewModel>();
                errorVm.Error = ex;
                Router.Navigate.Execute(errorVm);

                return Observable.Return(RecoveryOptionResult.CancelOperation);
            });

            var bundledPackageMetadata = openBundledPackage();

            wixEvents.DetectPackageCompleteObs.Subscribe(eventArgs => {
                var error = convertHResultToError(eventArgs.Status);
                if (error != null) {
                    UserError.Throw(error);
                    return;
                }

                // TODO: If the app is already installed, run it and bail

                if (wixEvents.Command.Action == LaunchAction.Uninstall) {
                    var updateManager = new UpdateManager("http://lol", BundledRelease.PackageName, FrameworkVersion.Net40);

                    var updateLock = updateManager.AcquireUpdateLock();
                    updateManager.FullUninstall()
                        .ObserveOn(RxApp.DeferredScheduler)
                        .Log(this, "Failed uninstall")
                        .Finally(updateLock.Dispose)
                        .Subscribe(
                            _ => wixEvents.Engine.Plan(LaunchAction.Uninstall),
                            ex => UserError.Throw("Failed to uninstall application", ex),
                            () => wixEvents.ShouldQuit());

                    return;
                }

                if (wixEvents.Command.Action == LaunchAction.Install) {
                    if (wixEvents.Command.Display != Display.Full) {
                        wixEvents.Engine.Plan(LaunchAction.Install);
                        return;
                    }

                    var welcomeVm = RxApp.GetService<IWelcomeViewModel>();
                    welcomeVm.PackageMetadata = bundledPackageMetadata;
                    welcomeVm.ShouldProceed.Subscribe(_ => wixEvents.Engine.Plan(LaunchAction.Install));

                    Router.Navigate.Execute(welcomeVm);
                }
            });

            wixEvents.PlanCompleteObs.Subscribe(eventArgs => {
                var error = convertHResultToError(eventArgs.Status);
                if (error != null) {
                    UserError.Throw(error);
                    return;
                }

                if (wixEvents.Command.Action != LaunchAction.Install) {
                    wixEvents.Engine.Apply(wixEvents.MainWindowHwnd);
                    return;
                }

                // NB: Create a dummy subject to receive progress if we're in silent mode
                IObserver<int> progress = new Subject<int>();
                if (wixEvents.Command.Display == Display.Full) {
                    var installingVm = RxApp.GetService<IInstallingViewModel>();
                    progress = installingVm.ProgressValue;
                    installingVm.PackageMetadata = bundledPackageMetadata;
                    Router.Navigate.Execute(installingVm);
                }

                // NB: This bit of code is a bit clever. The binaries that WiX
                // has installed *itself* meets the qualifications for being a
                // Shimmer update directory (a RELEASES file and the corresponding
                // NuGet packages).
                //
                // So, in order to reuse some code and not write the same things
                // twice we're going to "Eigenupdate" from our own directory;
                // UpdateManager will operate in bootstrap mode and create a
                // local directory for us.
                //
                // Then, we create a *new* UpdateManager whose target is the normal
                // update URL - we can then apply delta updates against the bundled
                // NuGet package to get up to vCurrent. The reason we go through
                // this rigamarole is so that developers don't have to rebuild the
                // installer as often (never, technically).

                var fxVersion = determineFxVersionFromPackage(bundledPackageMetadata);
                var eigenUpdater = new UpdateManager(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundledRelease.PackageName, fxVersion);

                var eigenLock = eigenUpdater.AcquireUpdateLock();

                var eigenUpdateProgress = eigenUpdater.CheckForUpdate()
                    .SelectMany(x => eigenUpdater.DownloadReleases(x.ReleasesToApply))
                    .Finally(eigenLock.Dispose)
                    .Select(x => x / 2)
                    .Multicast(new Subject<int>());

                eigenUpdateProgress.Subscribe(progress);
                eigenUpdateProgress.Connect();

                var realUpdateProgress = eigenUpdateProgress.TakeLast(1)
                    .SelectMany(_ => {
                        var realUpdateManager = new UpdateManager(bundledPackageMetadata.ProjectUrl.ToString(), BundledRelease.PackageName, fxVersion);

                        return realUpdateManager.CheckForUpdate()
                            .SelectMany(updateInfo => {
                                return Observable.Concat(
                                    realUpdateManager.DownloadReleases(updateInfo.ReleasesToApply).Select(x => x * 0.75),
                                    realUpdateManager.ApplyReleases(updateInfo).Select(x => x * 0.25 + 75))
                                        .Select(x => (int)x);
                            }).LoggedCatch(this, Observable.Return(100), "Failed to update to latest remote version");
                    })
                    .Select(x => x / 2 + 50)
                    .Multicast(new Subject<int>());

                realUpdateProgress.Subscribe(progress);
                realUpdateProgress.Connect();

                realUpdateProgress
                    .TakeLast(1)
                    .ObserveOn(RxApp.DeferredScheduler)
                    .Subscribe(
                        _ => wixEvents.Engine.Apply(wixEvents.MainWindowHwnd),
                        ex => UserError.Throw("Failed to install application", ex));
            });

            wixEvents.ApplyCompleteObs.Subscribe(eventArgs => {
                var error = convertHResultToError(eventArgs.Status);
                if (error != null) {
                    UserError.Throw(error);
                    return;
                }

                if (wixEvents.Command.Display != Display.Full) {
                    wixEvents.ShouldQuit();
                }

                // TODO: Figure out what the "main app" is and run it
            });

            wixEvents.ErrorObs.Subscribe(eventArgs => UserError.Throw("An installation error has occurred: " + eventArgs.ErrorMessage));
        }