public async Task TestInstallApplication()
        {
            _applicationPool = new ApplicationPoolStub();
            IApplicationFactory applicationFactory = new ApplicationFactoryStub();
            _applicationInstaller = new ApplicationInstaller(_applicationsRoot, null, applicationFactory, _applicationPool);

            AppIdentity appIdentity = new AppIdentity("test.app", new SemVersion(1,0,0));
            await _applicationInstaller.Install(new AppInstallConfig(appIdentity));

            Assert.True(_applicationPool.HasApplicationBeenAdded(appIdentity));
        }
        public async Task TestUpdateApplication()
        {
            string updateSessionId = null;
            IUpdateSessionManager updateSessionManager = new StubIUpdateSessionManager()
            {
                TryStartUpdateSessionString = id =>
                {
                    updateSessionId = id;
                    return Task.FromResult(true);
                },
                EndUpdateSessionString = id => Task.FromResult(true)
            };

            IApplicationPool applicationPool = new ApplicationPoolStub();
            IApplicationInstaller applicationInstaller = new ApplicationInstaller(_applicationsRoot, updateSessionManager, new ApplicationFactoryStub(), applicationPool);

            const string appId = "test.app";
            AppIdentity[] existingApps = { new AppIdentity(appId, new Version(1, 0, 0)), new AppIdentity(appId, new Version(1, 0, 1)) };
            AppIdentity[] newApps = { new AppIdentity(appId, new Version(1, 0, 2)), new AppIdentity(appId, new Version(2, 0, 0)) };

            foreach (var existingApp in existingApps)
            {
                string appPath = Path.Combine(_applicationsRoot, existingApp.Id, existingApp.Version.ToString());
                if (!Directory.Exists(appPath))
                {
                    Directory.CreateDirectory(appPath);
                }
                await applicationInstaller.Install(existingApp);
                Assert.IsTrue(applicationPool.HasApplication(existingApp));
            }

            await applicationInstaller.Update(appId, existingApps.Select(app => app.Version), newApps.Select(app => app.Version));

            foreach (AppIdentity app in existingApps)
            {
                Assert.IsFalse(applicationPool.HasApplication(app));
            }

            foreach (AppIdentity app in newApps)
            {
                Assert.IsTrue(applicationPool.HasApplication(app));   
            }
            
            Assert.AreEqual(appId, updateSessionId);
        }
        public async Task TestRemoveApplication()
        {
            _applicationPool = new ApplicationPoolStub();
            IApplicationFactory applicationFactory = new ApplicationFactoryStub();
            _applicationInstaller = new ApplicationInstaller(_applicationsRoot, null, applicationFactory, _applicationPool);

            AppIdentity appIdentity = new AppIdentity("test.app", new SemVersion(1, 0, 0));
            _applicationInstaller.Install(new AppInstallConfig(appIdentity)).Wait();

            // make sure the app directory exists because uninstall will try to delete it
            string appPath = Path.Combine(_applicationsRoot, "test.app", "1.0.0");
            if (!Directory.Exists(appPath))
            {
                Directory.CreateDirectory(appPath);
            }
            await _applicationInstaller.UnInstall(appIdentity);

            Assert.False(_applicationPool.HasApplication(appIdentity));
            Assert.False(Directory.Exists(appPath));
        }
        public async Task TestMultipleUpdates()
        {
            string id1 = "appId1";
            var v1 = SemVersion.Parse("1.0.0");
            var v2 = SemVersion.Parse("2.0.0");
            var v3 = SemVersion.Parse("3.0.0");
            var v4 = SemVersion.Parse("4.0.0");
            var v5 = SemVersion.Parse("5.0.0");

            AppIdentity app1v1 = new AppIdentity(id1, v1);
            AppIdentity app1v2 = new AppIdentity(id1, v2);
            AppIdentity app1v3 = new AppIdentity(id1, v3);
            AppIdentity app1v4 = new AppIdentity(id1, v4);
            AppIdentity app1v5 = new AppIdentity(id1, v5);

            IEnumerable<AppIdentity> appsToDeploy = new[] {app1v3, app1v4, app1v5};
            IEnumerable<string> clusters = new[] {"clusterId1"};

	        IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory()
		        .FetchDeployments(() => Task.FromResult(appsToDeploy.Select(identity => new AppDeploymentConfig(identity, clusters))));

            IApplicationPool applicationPool = new ApplicationPoolStub();
            string path = Path.GetTempPath();
            await applicationPool.AddApplication(new ApplicationStub(app1v1, path));
            await applicationPool.AddApplication(new ApplicationStub(app1v2, path));
            await applicationPool.AddApplication(new ApplicationStub(app1v3, path));

            var downloadedApps = new List<AppIdentity>();
            IApplicationDownloader applicationDownloader = new StubIApplicationDownloader()
                .DownloadApplication(appIdentity =>
                {
                    downloadedApps.Add(appIdentity);
                    return Task.FromResult(true);
                }
            );

            var installedApps = new List<AppIdentity>();
            var uninstalledApps = new List<AppIdentity>();
            string updatedAppId = null;
            IEnumerable<SemVersion> versionsRemoved = null;
            IEnumerable<SemVersion> versionsAdded = null;
            IApplicationInstaller applicationInstaller = new StubIApplicationInstaller()
                .Install(config => 
                {
                    installedApps.Add(config.AppIdentity);
                    return Task.FromResult(true);
                })
                .UnInstall(appIdentity =>
                {
                    uninstalledApps.Add(appIdentity);
                    return Task.FromResult(true);
                })
                .Update((applicationsToRemove, applicationsToInstall) => 
                {
	                updatedAppId = applicationsToInstall.First().AppIdentity.Id;
	                versionsRemoved = applicationsToRemove.Select(identity => identity.Version);
	                versionsAdded = applicationsToInstall.Select(config => config.AppIdentity.Version);
	                return Task.FromResult(true);
                }
            );

            ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager("clusterId", applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller);
            await applicationUpdateManager.CheckForUpdates();

            Assert.Equal(2, downloadedApps.Count);
            Assert.True(downloadedApps.Contains(app1v4));
            Assert.True(downloadedApps.Contains(app1v5));

            Assert.False(installedApps.Any());
            Assert.False(uninstalledApps.Any());

            Assert.Equal(id1, updatedAppId);
            Assert.Equal(new [] { v1, v2 }, versionsRemoved.ToList());
            Assert.Equal(new[] { v4, v5 }, versionsAdded.ToList());
        }
        public async Task TestThatUpdateReturnsIfCannotStartUpdateSession()
        {
	        IUpdateSessionManager updateSessionManager = new StubIUpdateSessionManager()
		        .TryStartUpdateSession(id => Task.FromResult(false));

            IApplicationPool applicationPool = new ApplicationPoolStub();
            IApplicationInstaller applicationInstaller = new ApplicationInstaller(_applicationsRoot, updateSessionManager, new ApplicationFactoryStub(), applicationPool);

            AppIdentity existingApp = new AppIdentity("test.app", new SemVersion(1, 0, 0));
            await applicationInstaller.Install(new AppInstallConfig(existingApp));

            AppIdentity newApp = new AppIdentity(existingApp.Id, new SemVersion(1, 1, 0));
            await applicationInstaller.Update(new[] {existingApp}, new[] {new AppInstallConfig(newApp), });

            Assert.True(applicationPool.HasApplication(existingApp));
            Assert.False(applicationPool.HasApplication(newApp));
        }
        public async Task TestMultipleUpdates()
        {
            string id1 = "appId1";
            var v1 = new Version("1.0.0");
            var v2 = new Version("2.0.0");
            var v3 = new Version("3.0.0");
            var v4 = new Version("4.0.0");
            var v5 = new Version("5.0.0");

            AppIdentity app1v1 = new AppIdentity(id1, v1);
            AppIdentity app1v2 = new AppIdentity(id1, v2);
            AppIdentity app1v3 = new AppIdentity(id1, v3);
            AppIdentity app1v4 = new AppIdentity(id1, v4);
            AppIdentity app1v5 = new AppIdentity(id1, v5);

            IEnumerable<AppIdentity> appsToDeploy = new[] {app1v3, app1v4, app1v5};

            IApplicationDeploymentDirectory applicationDeploymentDirectory = new StubIApplicationDeploymentDirectory
            {
                FetchDeploymentsString = (deploymentId) => Task.FromResult(appsToDeploy)
            };

            IApplicationPool applicationPool = new ApplicationPoolStub();
            string path = Path.GetTempPath();
            await applicationPool.AddApplication(new ApplicationStub(app1v1, path));
            await applicationPool.AddApplication(new ApplicationStub(app1v2, path));
            await applicationPool.AddApplication(new ApplicationStub(app1v3, path));

            var downloadedApps = new List<AppIdentity>();
            IApplicationDownloader applicationDownloader = new StubIApplicationDownloader
            {
                DownloadApplicationAppIdentity = (appIdentity) =>
                {
                    downloadedApps.Add(appIdentity);
                    return Task.FromResult(true);
                }
            };

            var installedApps = new List<AppIdentity>();
            var uninstalledApps = new List<AppIdentity>();
            string updatedAppId = null;
            IEnumerable<Version> versionsRemoved = null;
            IEnumerable<Version> versionsAdded = null;
            IApplicationInstaller applicationInstaller = new StubIApplicationInstaller
            {
                InstallAppIdentity = (appIdentity) =>
                {
                    installedApps.Add(appIdentity);
                    return Task.FromResult(true);
                },
                UnInstallAppIdentity = (appIdentity) =>
                {
                    uninstalledApps.Add(appIdentity);
                    return Task.FromResult(true);
                },
                UpdateStringIEnumerableOfVersionIEnumerableOfVersion = (appId, versionsToRemove, versionToDeploy) =>
                {
                    updatedAppId = appId;
                    versionsRemoved = versionsToRemove;
                    versionsAdded = versionToDeploy;
                    return Task.FromResult(true);
                }
            };

            ApplicationUpdateManager applicationUpdateManager = new ApplicationUpdateManager("deploymentId", applicationDeploymentDirectory, applicationPool, applicationDownloader, applicationInstaller);
            await applicationUpdateManager.CheckForUpdates();

            Assert.AreEqual(2, downloadedApps.Count);
            Assert.IsTrue(downloadedApps.Contains(app1v4));
            Assert.IsTrue(downloadedApps.Contains(app1v5));

            Assert.IsFalse(installedApps.Any());
            Assert.IsFalse(uninstalledApps.Any());

            Assert.AreEqual(id1, updatedAppId);
            CollectionAssert.AreEqual(new []{ v1, v2 }, versionsRemoved.ToList());
            CollectionAssert.AreEqual(new[] { v4, v5 }, versionsAdded.ToList());
        }