Пример #1
0
        private static async Task DeployZippedArtifact(ApplicationManager applicationManager,
                                                                            RemotePushDeploymentManager deploymentManager,
                                                                            TestFile[] files,
                                                                            string type,
                                                                            string path,
                                                                            bool isAsync)
        {
            TestTracer.Trace("Deploying zip");
            using (var zipStream = DeploymentTestHelper.CreateZipStream(files))
            {
                IList<KeyValuePair<string, string>> queryParams = GetOneDeployQueryParams(type, path, isAsync);

                var response = await deploymentManager.PushDeployFromStream(zipStream, new ZipDeployMetadata(), queryParams);
                response.EnsureSuccessStatusCode();

                if (isAsync)
                {
                    await DeploymentTestHelper.WaitForDeploymentCompletionAsync(applicationManager, deployer);
                }
            }
        }
Пример #2
0
        public async Task DiagnosticsDumpTests()
        {
            string appName = "DiagnosticsDumpTests";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                string path = String.Format("dump?marker={0}", Guid.NewGuid());
                using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials))
                {
                    using (var zipStream = new MemoryStream())
                    {
                        using (var dump = await client.GetStreamAsync(path))
                        {
                            Assert.NotNull(dump);
                            await dump.CopyToAsync(zipStream);
                        }
                        TestTracer.Trace("zipStream lenth={0}", zipStream.Length);
                        Assert.True(zipStream.Length > 0);

                        zipStream.Position = 0;
                        using (var targetStream = new MemoryStream())
                        {
                            ZipUtils.Unzip(zipStream, targetStream);
                            TestTracer.Trace("targetStream lenth={0}", targetStream.Length);
                            Assert.True(targetStream.Length > 0);
                        }
                    }
                }

                // Ensure trace
                string trace = await appManager.VfsManager.ReadAllTextAsync("LogFiles/kudu/trace/");
                Assert.Contains("_GET_dump_200_", trace, StringComparison.OrdinalIgnoreCase);
                Assert.Contains("s.xml", trace, StringComparison.OrdinalIgnoreCase);
                Assert.Contains("_GET_api-vfs-LogFiles-kudu-trace_pending.xml", trace, StringComparison.OrdinalIgnoreCase);

                // Test runtime object by checking for one Node version
                RuntimeInfo runtimeInfo = await appManager.RuntimeManager.GetRuntimeInfo();
                Assert.True(runtimeInfo.NodeVersions.Any(dict => dict["version"] == "0.8.2"));
            });
        }
Пример #3
0
        public async Task SiteExtensionV2AndV3FeedTests(string feedEndpoint)
        {
            TestTracer.Trace("Testing against feed: '{0}'", feedEndpoint);

            const string appName            = "SiteExtensionV2AndV3FeedTests";
            const string testPackageId      = "bootstrap";
            const string testPackageVersion = "3.0.0";
            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;

                // list package
                TestTracer.Trace("Search extensions by id: '{0}'", testPackageId);
                IEnumerable <SiteExtensionInfo> results = await manager.GetRemoteExtensions(
                    filter: testPackageId,
                    feedUrl: feedEndpoint);
                Assert.True(results.Count() > 0, string.Format("GetRemoteExtensions for '{0}' package result should > 0", testPackageId));

                // get package
                TestTracer.Trace("Get an extension by id: '{0}'", testPackageId);
                SiteExtensionInfo result = await manager.GetRemoteExtension(testPackageId, feedUrl: feedEndpoint);
                Assert.Equal(testPackageId, result.Id);

                TestTracer.Trace("Get an extension by id: '{0}' and version: '{1}'", testPackageId, testPackageVersion);
                result = await manager.GetRemoteExtension(testPackageId, version: testPackageVersion, feedUrl: feedEndpoint);
                Assert.Equal(testPackageId, result.Id);
                Assert.Equal(testPackageVersion, result.Version);

                // install
                TestTracer.Trace("Install an extension by id: '{0}' and version: '{1}'", testPackageId, testPackageVersion);
                HttpResponseResult <SiteExtensionInfo> richResult = await manager.InstallExtension <SiteExtensionInfo>(testPackageId, version: testPackageVersion, feedUrl: feedEndpoint);
                Assert.Equal(testPackageId, richResult.Body.Id);
                Assert.Equal(testPackageVersion, richResult.Body.Version);
                Assert.False(richResult.Headers.ContainsKey(Constants.SiteOperationHeaderKey)); // only ARM request will have SiteOperation header

                // uninstall
                TestTracer.Trace("Uninstall an extension by id: '{0}'", testPackageId);
                Assert.True(await manager.UninstallExtension(testPackageId));
            });
        }
Пример #4
0
        private void VerifyTriggeredJobTriggers(ApplicationManager appManager, string jobName, int expectedNumberOfRuns, string expectedStatus, string expectedOutput = null, string expectedError = null, string arguments = null, bool scheduledTriggeredJob = false)
        {
            if (!scheduledTriggeredJob)
            {
                appManager.JobsManager.InvokeTriggeredJobAsync(jobName, arguments).Wait();
            }

            try
            {
                WaitUntilAssertVerified(
                    "verify triggered job run",
                    TimeSpan.FromSeconds(30),
                    () =>
                {
                    TriggeredJobHistory triggeredJobHistory = appManager.JobsManager.GetTriggeredJobHistoryAsync(jobName).Result;
                    Assert.NotNull(triggeredJobHistory);
                    Assert.Equal(expectedNumberOfRuns, triggeredJobHistory.TriggeredJobRuns.Count());

                    TriggeredJobRun triggeredJobRun = triggeredJobHistory.TriggeredJobRuns.FirstOrDefault();
                    AssertTriggeredJobRun(appManager, triggeredJobRun, jobName, expectedStatus, expectedOutput, expectedError);
                });
            }
            catch
            {
                // On error trace the scheduler log if it is a scheduler job
                if (scheduledTriggeredJob)
                {
                    try
                    {
                        string schedulerLog = appManager.VfsManager.ReadAllText(JobsDataPath + "/triggered/" + jobName + "/job_scheduler.log");
                        TestTracer.Trace("Scheduler log - " + schedulerLog);
                    }
                    catch
                    {
                    }
                }

                throw;
            }
        }
Пример #5
0
        public void TriggeredJobAcceptsArguments()
        {
            RunScenario("TriggeredJobAcceptsArguments", appManager =>
            {
                const string jobName = "job1";

                TestTracer.Trace("Copying the script to the triggered job directory");

                appManager.JobsManager.CreateTriggeredJobAsync(jobName, "run.cmd", "echo %*").Wait();

                var expectedTriggeredJob = new TriggeredJob()
                {
                    Name       = jobName,
                    JobType    = "triggered",
                    RunCommand = "run.cmd"
                };

                TestTracer.Trace("Trigger the job");

                VerifyTriggeredJobTriggers(appManager, jobName, 1, "Success", "echo test arguments", expectedError: null, arguments: "test arguments");
            });
        }
Пример #6
0
        private async Task AssertUrlContentAsync(ApplicationManager appManager, Uri requestUrl, string expectedContent)
        {
            if (expectedContent == null)
            {
                Assert.Null(requestUrl);
                return;
            }

            string address = requestUrl.ToString();

            using (var httpClient = HttpClientHelper.CreateClient(address, appManager.JobsManager.Credentials))
            {
                using (var response = await httpClient.GetAsync(String.Empty))
                {
                    var content = await response.Content.ReadAsStringAsync();

                    TestTracer.Trace("Request to: {0}\nStatus code: {1}\nContent: {2}", address, response.StatusCode, content);

                    Assert.True(content.IndexOf(expectedContent, StringComparison.OrdinalIgnoreCase) >= 0, "Expected content: " + expectedContent);
                }
            }
        }
Пример #7
0
        private void WaitUntilAssertVerified(string description, TimeSpan maxWaitTime, Action assertAction)
        {
            TestTracer.Trace("Waiting for " + description);

            Stopwatch waitTime = Stopwatch.StartNew();

            while (waitTime.Elapsed < maxWaitTime)
            {
                try
                {
                    assertAction();
                    return;
                }
                catch
                {
                }

                Thread.Sleep(1000);
            }

            assertAction();
        }
Пример #8
0
        public Task TestAsyncZipDeployment()
        {
            return(ApplicationManager.RunAsync("TestAsyncZipDeployment", async appManager =>
            {
                // Big enough to require at least a couple polls for status until success
                var files = CreateRandomFilesForZip(1000);
                var response = await DeployZip(appManager, files, doAsync: true);
                response.EnsureSuccessStatusCode();

                TestTracer.Trace("Confirming deployment is in progress");

                DeployResult result;
                do
                {
                    result = await appManager.DeploymentManager.GetResultAsync("latest");
                    Assert.Equal("Zip-Push", result.Deployer);
                    await Task.Delay(TimeSpan.FromSeconds(2));
                } while (!new[] { DeployStatus.Failed, DeployStatus.Success }.Contains(result.Status));

                await AssertSuccessfulDeploymentByFilenames(appManager, files.Select(f => f.Filename).ToArray());
            }));
        }
Пример #9
0
        public void ContinuousJobStopsWhenDisabledStartsWhenEnabled()
        {
            RunScenario("ContinuousJobStopsWhenDisabledStartsWhenEnabled", appManager =>
            {
                using (TestRepository testRepository = Git.Clone("ConsoleWorker"))
                {
                    TestTracer.Trace("Starting ConsoleWorker test, deploying the worker");

                    PushAndVerifyConsoleWorker(appManager, testRepository, new string[] { ExpectedVerificationFileContent });

                    TestTracer.Trace("Make sure process is up");
                    var processes     = appManager.ProcessManager.GetProcessesAsync().Result;
                    var workerProcess = processes.FirstOrDefault(p => String.Equals("ConsoleWorker", p.Name, StringComparison.OrdinalIgnoreCase));
                    Assert.NotNull(workerProcess);

                    TestTracer.Trace("Disable this job");
                    appManager.JobsManager.DisableContinuousJobAsync("deployedJob").Wait();

                    VerifyContinuousJobDisabled(appManager);

                    TestTracer.Trace("Enable this job");
                    appManager.JobsManager.EnableContinuousJobAsync("deployedJob").Wait();

                    VerifyContinuousJobEnabled(appManager);

                    TestTracer.Trace("Disable all WebJobs");
                    appManager.SettingsManager.SetValue(SettingsKeys.WebJobsStopped, "1").Wait();
                    RestartServiceSite(appManager);

                    VerifyContinuousJobDisabled(appManager);

                    TestTracer.Trace("Enable all WebJobs");
                    appManager.SettingsManager.SetValue(SettingsKeys.WebJobsStopped, "0").Wait();
                    RestartServiceSite(appManager);

                    VerifyContinuousJobEnabled(appManager);
                }
            });
        }
Пример #10
0
        public void JobsSettingsSetSuccessfully()
        {
            RunScenario("JobsSettingsSetSuccessfully", appManager =>
            {
                const string triggeredJobName  = "triggeredJob";
                const string continuousJobName = "continuousJob";

                const string settingKey   = "mysetting";
                const string settingValue = "myvalue";

                TestTracer.Trace("Creating a triggered job and creating a continuous job");

                appManager.JobsManager.CreateTriggeredJobAsync(triggeredJobName, "run.cmd", JobScript).Wait();
                appManager.JobsManager.CreateContinuousJobAsync(continuousJobName, "run.cmd", JobScript).Wait();

                TestTracer.Trace("Test update of continuous job settings");

                JobSettings continuousJobSettings = appManager.JobsManager.GetContinuousJobSettingsAsync(continuousJobName).Result;
                Assert.Equal(null, continuousJobSettings.GetSetting <string>(settingKey));

                continuousJobSettings.SetSetting(settingKey, settingValue);
                appManager.JobsManager.SetContinuousJobSettingsAsync(continuousJobName, continuousJobSettings).Wait();

                continuousJobSettings = appManager.JobsManager.GetContinuousJobSettingsAsync(continuousJobName).Result;
                Assert.Equal(settingValue, continuousJobSettings.GetSetting <string>(settingKey));

                TestTracer.Trace("Test update of triggered job settings");

                JobSettings triggeredJobSettings = appManager.JobsManager.GetTriggeredJobSettingsAsync(triggeredJobName).Result;
                Assert.Equal(null, triggeredJobSettings.GetSetting <string>(settingKey));

                triggeredJobSettings.SetSetting(settingKey, settingValue);
                appManager.JobsManager.SetTriggeredJobSettingsAsync(triggeredJobName, triggeredJobSettings).Wait();

                triggeredJobSettings = appManager.JobsManager.GetTriggeredJobSettingsAsync(triggeredJobName).Result;
                Assert.Equal(settingValue, triggeredJobSettings.GetSetting <string>(settingKey));
            });
        }
Пример #11
0
        public async Task SiteExtensionShouldDeployWebJobs()
        {
            const string appName = "SiteExtensionShouldDeployWebJobs";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                TestTracer.Trace("Install site extension with jobs");
                await manager.InstallExtension("filecounterwithwebjobs", null, "https://www.myget.org/F/amitaptest/");

                TestTracer.Trace("Verify jobs were deployed");
                await OperationManager.AttemptAsync(async() =>
                {
                    var continuousJobs = (await appManager.JobsManager.ListContinuousJobsAsync()).ToArray();
                    Assert.Equal(1, continuousJobs.Length);
                    Assert.Equal("filecounterwithwebjobs(cjoba)", continuousJobs[0].Name);
                    TestTracer.Trace("Job status - {0}", continuousJobs[0].Status);
                    Assert.Equal("PendingRestart", continuousJobs[0].Status);
                }, 100, 500);

                var triggeredJobs = (await appManager.JobsManager.ListTriggeredJobsAsync()).ToArray();
                Assert.Equal(2, triggeredJobs.Length);
                Assert.Equal("filecounterwithwebjobs(tjoba)", triggeredJobs[0].Name);
                Assert.Equal("filecounterwithwebjobs(tjobb)", triggeredJobs[1].Name);

                TestTracer.Trace("Uninstall site extension with jobs");
                await manager.UninstallExtension("filecounterwithwebjobs");

                TestTracer.Trace("Verify jobs removed");
                var continuousJobs2 = (await appManager.JobsManager.ListContinuousJobsAsync()).ToArray();
                Assert.Equal(0, continuousJobs2.Length);

                triggeredJobs = (await appManager.JobsManager.ListTriggeredJobsAsync()).ToArray();
                Assert.Equal(0, triggeredJobs.Length);
            });
        }
Пример #12
0
        private static async Task<string> DeployNonZippedArtifact(
            ApplicationManager appManager,
            string type,
            string path,
            bool isAsync)
        {
            TestTracer.Trace("Deploying file");

            var testFile = DeploymentTestHelper.CreateRandomTestFile();
            using (var fileStream = DeploymentTestHelper.CreateFileStream(testFile))
            {
                IList<KeyValuePair<string, string>> queryParams = GetOneDeployQueryParams(type, path, isAsync);

                var response = await appManager.OneDeployManager.PushDeployFromStream(fileStream, new ZipDeployMetadata(), queryParams);
                response.EnsureSuccessStatusCode();

                if (isAsync)
                {
                    await DeploymentTestHelper.WaitForDeploymentCompletionAsync(appManager, deployer);
                }
            }

            return testFile.Content;
        }
Пример #13
0
        private static async Task AssertSuccessfulDeploymentByContent(ApplicationManager appManager, FileForZip[] files)
        {
            TestTracer.Trace("Verifying files are deployed and deployment record created.");

            var deployment = await appManager.DeploymentManager.GetResultAsync("latest");

            Assert.Equal(DeployStatus.Success, deployment.Status);
            Assert.Equal(ZipDeployer, deployment.Deployer);

            var entries = await appManager.VfsWebRootManager.ListAsync(null);

            var deployedFilenames = entries.Select(e => e.Name);

            var filenameSet = new HashSet <string>(files.Select(f => f.Filename));

            Assert.True(filenameSet.SetEquals(entries.Select(e => e.Name)));

            foreach (var file in files)
            {
                var deployedContent = await appManager.VfsWebRootManager.ReadAllTextAsync(file.Filename);

                Assert.Equal(file.Content, deployedContent);
            }
        }
Пример #14
0
        private async Task VerifyWebHooksCall(IEnumerable <string> hookAddresses, ApplicationManager hookAppManager, params string[] expectedContents)
        {
            TestTracer.Trace("Verify web hook was called {0} times".FormatCurrentCulture(hookAddresses.Count()));

            string webHookCallResponse = await GetWebHookResponseAsync(hookAppManager.SiteUrl);

            string[] webHookResults = webHookCallResponse.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);

            Assert.Equal(hookAddresses.Count(), webHookResults.Count());

            foreach (var hookAddress in hookAddresses)
            {
                bool found = false;

                foreach (var webHookResult in webHookResults)
                {
                    dynamic webHookResultObject = JsonConvert.DeserializeObject(webHookResult);
                    if (("/" + hookAddress) == (string)webHookResultObject.url)
                    {
                        var body = (string)webHookResultObject.body;
                        found = true;

                        // Make sure body json
                        JsonConvert.DeserializeObject(body);
                        foreach (var expectedContent in expectedContents)
                        {
                            Assert.Contains(expectedContent, body, StringComparison.OrdinalIgnoreCase);
                        }
                    }
                }

                Assert.True(found, "Web hook address {0} was not called".FormatCurrentCulture(hookAddress));
            }

            hookAppManager.VfsWebRootManager.Delete("result.txt");
        }
Пример #15
0
        public void PostDeploymentActionsShouldNotBeCalledOnFailedDeployment()
        {
            string testName  = "PostDeploymentActionsShouldNotBeCalledOnFailedDeployment";
            string testLine1 = "test script 1 is running";
            string testLine2 = "test script 2 is running too";

            using (new LatencyLogger(testName))
            {
                ApplicationManager.Run(testName, appManager =>
                {
                    using (var appRepository = Git.Clone("WarningsAsErrors"))
                    {
                        TestTracer.Trace("Add action scripts");
                        appManager.VfsManager.WriteAllText(
                            @"site\deployments\tools\PostDeploymentActions\test_script_1.cmd",
                            @"@echo off
                              echo " + testLine1);

                        appManager.VfsManager.WriteAllText(
                            @"site\deployments\tools\PostDeploymentActions\test_script_2.bat",
                            @"@echo off
                              echo " + testLine2);

                        TestTracer.Trace("Deploy test app");
                        appManager.GitDeploy(appRepository.PhysicalPath);

                        TestTracer.Trace("Verify results");
                        var deploymentResults = appManager.DeploymentManager.GetResultsAsync().Result.ToList();
                        Assert.Equal(1, deploymentResults.Count);
                        Assert.Equal(DeployStatus.Failed, deploymentResults[0].Status);

                        KuduAssert.VerifyLogOutputWithUnexpected(appManager, deploymentResults[0].Id, testLine1, testLine2);
                    }
                });
            }
        }
Пример #16
0
        private static async Task <HttpResponseMessage> DeployWar(
            ApplicationManager appManager,
            FileForZip[] files,
            ZipDeployMetadata metadata,
            string appName = null)
        {
            TestTracer.Trace("Push-deploying war");
            using (var zipStream = CreateZipStream(files))
            {
                IList <KeyValuePair <string, string> > queryParams = null;
                if (!string.IsNullOrWhiteSpace(appName))
                {
                    queryParams = new List <KeyValuePair <string, string> >()
                    {
                        new KeyValuePair <string, string>("name", appName)
                    };
                }

                return(await appManager.WarDeploymentManager.PushDeployFromStream(
                           zipStream,
                           metadata,
                           queryParams));
            }
        }
Пример #17
0
        private void CleanupTest(ApplicationManager appManager)
        {
            WaitUntilAssertVerified(
                "clean site for jobs",
                TimeSpan.FromSeconds(60),
                () =>
            {
                TestTracer.Trace($"CleanupTest: Delete {JobsBinPath}");
                appManager.VfsManager.Delete(JobsBinPath, recursive: true);
                TestTracer.Trace($"CleanupTest: Delete {JobsDataPath}");
                appManager.VfsManager.Delete(JobsDataPath, recursive: true);

                var logFiles = appManager.VfsManager.ListAsync("LogFiles").Result;
                foreach (var logFile in logFiles)
                {
                    if (logFile.Name.StartsWith("appSettings.txt", StringComparison.OrdinalIgnoreCase) ||
                        logFile.Name.StartsWith("verification.txt", StringComparison.OrdinalIgnoreCase))
                    {
                        TestTracer.Trace($"CleanupTest: Delete LogFiles/{logFile.Name}");
                        appManager.VfsManager.Delete("LogFiles/" + logFile.Name);
                    }
                }

                foreach (var job in appManager.JobsManager.ListTriggeredJobsAsync().Result)
                {
                    TestTracer.Trace($"CleanupTest: DeleteTriggeredJobAsync {job.Name}");
                    appManager.JobsManager.DeleteTriggeredJobAsync(job.Name).Wait();
                }

                foreach (var job in appManager.JobsManager.ListContinuousJobsAsync().Result)
                {
                    TestTracer.Trace($"CleanupTest: DeleteContinuousJobAsync {job.Name}");
                    appManager.JobsManager.DeleteContinuousJobAsync(job.Name).Wait();
                }
            });
        }
Пример #18
0
        public async Task SiteExtensionShouldNotSeeButAbleToInstallUnlistedPackage()
        {
            const string appName             = "SiteExtensionShouldNotSeeUnlistPackage";
            const string externalPackageId   = "SimpleSite";
            const string unlistedVersion     = "3.0.0";
            const string latestListedVersion = "2.0.0";
            const string externalFeed        = "https://www.myget.org/F/simplesvc/";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                HttpResponseMessage response = await manager.GetRemoteExtension(externalPackageId, feedUrl: externalFeed);
                SiteExtensionInfo info       = await response.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.NotEqual(unlistedVersion, info.Version);

                response = await manager.GetRemoteExtension(externalPackageId, version: unlistedVersion, feedUrl: externalFeed);
                info     = await response.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(unlistedVersion, info.Version);

                response = await manager.GetRemoteExtensions(externalPackageId, allowPrereleaseVersions: true, feedUrl: externalFeed);
                List <SiteExtensionInfo> infos = await response.Content.ReadAsAsync <List <SiteExtensionInfo> >();
                Assert.NotEmpty(infos);
                foreach (var item in infos)
                {
                    Assert.NotEqual(unlistedVersion, item.Version);
                }

                response = await manager.InstallExtension(externalPackageId, feedUrl: externalFeed);
                info     = await response.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(externalPackageId, info.Id);
                Assert.Equal(latestListedVersion, info.Version);
                Assert.Equal(externalFeed, info.FeedUrl);

                TestTracer.Trace("Should able to installed unlisted package if specify version");
                response = await manager.InstallExtension(externalPackageId, version: unlistedVersion, feedUrl: externalFeed);
                info     = await response.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(externalPackageId, info.Id);
                Assert.Equal(unlistedVersion, info.Version);
                Assert.Equal(externalFeed, info.FeedUrl);

                UpdateHeaderIfGoingToBeArmRequest(manager.Client, isArmRequest: true);
                response = await manager.GetRemoteExtension(externalPackageId, feedUrl: externalFeed);
                ArmEntry <SiteExtensionInfo> armInfo = await response.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.NotEqual(unlistedVersion, armInfo.Properties.Version);

                response = await manager.GetRemoteExtensions(externalPackageId, allowPrereleaseVersions: true, feedUrl: externalFeed);
                ArmListEntry <SiteExtensionInfo> armInfos = await response.Content.ReadAsAsync <ArmListEntry <SiteExtensionInfo> >();
                Assert.NotEmpty(armInfos.Value);
                foreach (var item in armInfos.Value)
                {
                    Assert.NotEqual(unlistedVersion, item.Properties.Version);
                }

                response = await manager.InstallExtension(externalPackageId, feedUrl: externalFeed);
                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                await PollAndVerifyAfterArmInstallation(manager, externalPackageId);
                response = await manager.GetLocalExtension(externalPackageId);
                armInfo  = await response.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(externalPackageId, armInfo.Properties.Id);
                Assert.Equal(latestListedVersion, armInfo.Properties.Version);
                Assert.Equal(externalFeed, armInfo.Properties.FeedUrl);

                response = await manager.InstallExtension(externalPackageId, version: unlistedVersion, feedUrl: externalFeed);
                Assert.Equal(HttpStatusCode.Created, response.StatusCode);
                await PollAndVerifyAfterArmInstallation(manager, externalPackageId);
                response = await manager.GetLocalExtension(externalPackageId);
                armInfo  = await response.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(externalPackageId, armInfo.Properties.Id);
                Assert.Equal(unlistedVersion, armInfo.Properties.Version);
                Assert.Equal(externalFeed, armInfo.Properties.FeedUrl);
            });
        }
Пример #19
0
        public async Task SiteExtensionInstallPackageToWebRootTests()
        {
            const string appName                = "SiteExtensionInstallPackageToWebRootTests";
            const string externalPackageId      = "SimpleSvc";
            const string externalPackageVersion = "1.0.0";
            const string externalFeed           = "https://www.myget.org/F/simplesvc/";

            // site extension 'webrootxdttest' search for xdt files under site extension 'webrootxdttest' folder, and print out xdt content onto page
            const string externalPackageWithXdtId = "webrootxdttest";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                // install/update
                TestTracer.Trace("Perform InstallExtension with id '{0}', version '{1}' from '{2}'", externalPackageId, externalPackageVersion, externalFeed);
                HttpResponseMessage responseMessage = await manager.InstallExtension(externalPackageId, externalPackageVersion, externalFeed, SiteExtensionInfo.SiteExtensionType.WebRoot);
                SiteExtensionInfo result            = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(externalPackageId, result.Id);
                Assert.Equal(externalPackageVersion, result.Version);
                Assert.Equal(externalFeed, result.FeedUrl);

                TestTracer.Trace("GET request to verify package content has been copied to wwwroot");
                HttpClient client      = new HttpClient();
                responseMessage        = await client.GetAsync(appManager.SiteUrl);
                string responseContent = await responseMessage.Content.ReadAsStringAsync();
                Assert.NotNull(responseContent);
                Assert.True(responseContent.Contains(@"<h3>Site for testing</h3>"));

                TestTracer.Trace("GetLocalExtension should return WebRoot type SiteExtensionInfo");
                responseMessage = await manager.GetLocalExtension(externalPackageId);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(SiteExtensionInfo.SiteExtensionType.WebRoot, result.Type);

                responseMessage = await manager.GetLocalExtensions(externalPackageId);
                var results     = await responseMessage.Content.ReadAsAsync <List <SiteExtensionInfo> >();
                foreach (var item in results)
                {
                    if (string.Equals(externalPackageId, item.Id, StringComparison.OrdinalIgnoreCase))
                    {
                        Assert.Equal(SiteExtensionInfo.SiteExtensionType.WebRoot, item.Type);
                    }
                }

                // delete
                TestTracer.Trace("Perform UninstallExtension with id '{0}' only.", externalPackageId);
                responseMessage   = await manager.UninstallExtension(externalPackageId);
                bool deleteResult = await responseMessage.Content.ReadAsAsync <bool>();
                Assert.True(deleteResult, "Delete must return true");

                TestTracer.Trace("GET request to verify package content has been removed wwwroot");
                responseMessage = await client.GetAsync(appManager.SiteUrl);
                Assert.Equal(HttpStatusCode.Forbidden, responseMessage.StatusCode);

                // install package that with xdt file
                TestTracer.Trace("Perform InstallExtension with id '{0}' from '{1}'", externalPackageWithXdtId, externalFeed);
                responseMessage = await manager.InstallExtension(externalPackageWithXdtId, feedUrl: externalFeed, type: SiteExtensionInfo.SiteExtensionType.WebRoot);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(externalPackageWithXdtId, result.Id);
                Assert.Equal(externalFeed, result.FeedUrl);

                TestTracer.Trace("GET request to verify package content has been copied to wwwroot");
                responseMessage = await client.GetAsync(appManager.SiteUrl);
                responseContent = await responseMessage.Content.ReadAsStringAsync();
                Assert.NotNull(responseContent);
                Assert.True(responseContent.Contains(@"1 files"));
                Assert.True(responseContent.Contains(@"site\path\shall\not\be\found")); // xdt content
            });
        }
Пример #20
0
        [InlineData("https://api.nuget.org/v3/index.json", "filecounter")] // v3 endpoint
        public async Task SiteExtensionInstallUninstallAsyncTest(string feedEndpoint, string testPackageId)
        {
            TestTracer.Trace("Testing against feed: '{0}'", feedEndpoint);

            const string appName = "SiteExtensionInstallUninstallAsyncTest";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                // Get the latest package, make sure that call will return right away when we try to update
                TestTracer.Trace("Get latest package '{0}' from '{1}'", testPackageId, feedEndpoint);
                SiteExtensionInfo latestPackage = await(await manager.GetRemoteExtension(testPackageId, feedUrl: feedEndpoint)).Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(testPackageId, latestPackage.Id);

                // install from non-default endpoint
                UpdateHeaderIfGoingToBeArmRequest(manager.Client, true);
                TestTracer.Trace("Install package '{0}'-'{1}' fresh from '{2}' async", testPackageId, latestPackage.Version, feedEndpoint);
                HttpResponseMessage responseMessage    = await manager.InstallExtension(id: testPackageId, version: latestPackage.Version, feedUrl: feedEndpoint);
                ArmEntry <SiteExtensionInfo> armResult = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(string.Empty, armResult.Location);   // test "x-ms-geo-location" header is empty, same value should be assign to "Location"
                Assert.Equal(HttpStatusCode.Created, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                TestTracer.Trace("Poll for status. Expecting 200 response eventually with site operation header.");
                responseMessage = await PollAndVerifyAfterArmInstallation(manager, testPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                // after successfully installed, should return SiteOperationHeader to notify GEO to restart website
                Assert.True(responseMessage.Headers.Contains(Constants.SiteOperationHeaderKey));
                Assert.Equal(feedEndpoint, armResult.Properties.FeedUrl);
                Assert.Equal(latestPackage.Version, armResult.Properties.Version);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                TestTracer.Trace("Get '{0}' again. Expecting 200 response without site operation header", testPackageId);
                responseMessage = await manager.GetLocalExtension(testPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                // get again shouldn`t see SiteOperationHeader anymore
                Assert.False(responseMessage.Headers.Contains(Constants.SiteOperationHeaderKey));
                Assert.Equal(feedEndpoint, armResult.Properties.FeedUrl);
                Assert.Equal(latestPackage.Version, armResult.Properties.Version);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                TestTracer.Trace("Try to update package '{0}' without given a feed", testPackageId);
                // Not passing feed endpoint will default to feed endpoint from installed package
                // Update should return right away, expecting code to look up from feed that store in local package
                // since we had installed the latest package, there is nothing to update.
                // We shouldn`t see any site operation header value
                // And there is no polling, since it finished within 15 seconds
                responseMessage = await manager.InstallExtension(testPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(string.Empty, armResult.Location);   // test "x-ms-geo-location" header is empty, same value should be assign to "Location"
                Assert.Equal(latestPackage.Id, armResult.Properties.Id);
                Assert.Equal(feedEndpoint, armResult.Properties.FeedUrl);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));
                // no installation operation happened, shouldn`t see SiteOperationHeader return
                Assert.False(responseMessage.Headers.Contains(Constants.SiteOperationHeaderKey));

                TestTracer.Trace("Uninstall '{0}' async", testPackageId);
                responseMessage = await manager.UninstallExtension(testPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Null(armResult);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                TestTracer.Trace("Get '{0}' again. Expecting 404.", testPackageId);
                var ex = await KuduAssert.ThrowsUnwrappedAsync <HttpUnsuccessfulRequestException>(async() =>
                {
                    await manager.GetLocalExtension(testPackageId);
                });
                Assert.Equal(HttpStatusCode.NotFound, ex.ResponseMessage.StatusCode);
            });
        }
Пример #21
0
        public async Task SiteExtensionGetArmTest()
        {
            const string appName              = "SiteExtensionGetAsyncTest";
            const string externalPackageId    = "filecounter";
            const string externalFeed         = "https://api.nuget.org/v3/index.json";
            const string installationArgument = "arg0";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                UpdateHeaderIfGoingToBeArmRequest(manager.Client, true);
                TestTracer.Trace("GetRemoteExtensions with Arm header, expecting site extension info will be wrap inside Arm envelop");
                HttpResponseMessage responseMessage            = await manager.GetRemoteExtensions(externalPackageId, true, externalFeed);
                ArmListEntry <SiteExtensionInfo> armResultList = await responseMessage.Content.ReadAsAsync <ArmListEntry <SiteExtensionInfo> >();
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.NotNull(armResultList);
                Assert.NotEmpty(armResultList.Value);
                Assert.NotNull(armResultList.Value.Where(item => string.Equals(externalPackageId, item.Properties.Id, StringComparison.OrdinalIgnoreCase)));
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                TestTracer.Trace("GetRemoteExtension with Arm header, expecting site extension info will be wrap inside Arm envelop");
                responseMessage = await manager.GetRemoteExtension(externalPackageId, feedUrl: externalFeed);
                ArmEntry <SiteExtensionInfo> armResult = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.NotNull(armResult);
                Assert.Equal(externalPackageId, armResult.Properties.Id);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                UpdateHeaderIfGoingToBeArmRequest(manager.Client, false);
                responseMessage = await manager.InstallExtension(externalPackageId, feedUrl: externalFeed, installationArgs: installationArgument);
                SiteExtensionInfo syncResult = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(externalPackageId, syncResult.Id);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                UpdateHeaderIfGoingToBeArmRequest(manager.Client, true);
                TestTracer.Trace("GetLocalExtensions (no filter) with Arm header, expecting site extension info will be wrap inside Arm envelop");
                responseMessage = await manager.GetLocalExtensions();
                armResultList   = await responseMessage.Content.ReadAsAsync <ArmListEntry <SiteExtensionInfo> >();
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.NotNull(armResultList);
                Assert.NotEmpty(armResultList.Value);
                Assert.NotNull(armResultList.Value.Where(item => string.Equals(externalPackageId, item.Properties.Id, StringComparison.OrdinalIgnoreCase)));
                Assert.Equal(Constants.SiteExtensionProvisioningStateSucceeded, armResultList.Value.First <ArmEntry <SiteExtensionInfo> >().Properties.ProvisioningState);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));
                foreach (var item in armResultList.Value)
                {
                    Assert.Equal(Constants.SiteExtensionProvisioningStateSucceeded, item.Properties.ProvisioningState);
                    Assert.Equal(installationArgument, item.Properties.InstallationArgs);
                }

                TestTracer.Trace("GetLocalExtensions (with filter) with Arm header, expecting site extension info will be wrap inside Arm envelop");
                responseMessage = await manager.GetLocalExtensions(externalPackageId);
                armResultList   = await responseMessage.Content.ReadAsAsync <ArmListEntry <SiteExtensionInfo> >();
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);
                Assert.NotNull(armResultList);
                Assert.NotEmpty(armResultList.Value);
                Assert.NotNull(armResultList.Value.Where(item => string.Equals(externalPackageId, item.Properties.Id, StringComparison.OrdinalIgnoreCase)));
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));
                foreach (var item in armResultList.Value)
                {
                    Assert.Equal(Constants.SiteExtensionProvisioningStateSucceeded, item.Properties.ProvisioningState);
                    Assert.Equal(installationArgument, item.Properties.InstallationArgs);
                }
            });
        }
Пример #22
0
        public virtual async Task RunIntegrationTest()
        {
            string dir        = Guid.NewGuid().ToString("N");
            string dirAddress = BaseAddress + _segmentDelimiter + dir;
            string dirAddressWithTerminatingSlash = dirAddress + _segmentDelimiter;

            // The %2520 is there to test that we can accept those characters. Here, %2520 is the URL encoded form,
            // and the actual file name has %20 (and not a space character!)
            string file        = Guid.NewGuid().ToString("N") + "%2520" + ".txt";
            string fileAddress = dirAddressWithTerminatingSlash + file;
            string fileAddressWithTerminatingSlash = fileAddress + _segmentDelimiter;

            string query = "?foo=bar";
            string baseAddressWithQuery = BaseAddress + _segmentDelimiter + query;
            string dirAddressWithQuery  = dirAddressWithTerminatingSlash + query;
            string fileAddressWithQuery = fileAddress + query;

            string deploymentFileAddress       = null;
            string customDeploymentFileAddress = null;

            if (DeploymentClient != null)
            {
                deploymentFileAddress       = string.Format("{0}{1}site{1}wwwroot{1}{2}{1}{3}", DeploymentBaseAddress, _segmentDelimiter, dir, file);
                customDeploymentFileAddress = string.Format("{0}{1}site{1}wwwroot{1}test{1}{2}{1}{3}", DeploymentBaseAddress, _segmentDelimiter, dir, file);
            }

            TestTracer.Trace("Starting RunIntegrationTest");
            TestTracer.Trace("Dir - {0}", dirAddress);
            TestTracer.Trace("File - {0}", fileAddress);
            TestTracer.Trace("DeploymentFileAddress - {0}", deploymentFileAddress);

            HttpResponseMessage response;

            // Check not found file responses
            TestTracer.Trace("==== Check not found file responses");
            response = await HttpGetAsync(dirAddress);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(dirAddressWithTerminatingSlash);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(fileAddress);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(fileAddressWithTerminatingSlash);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            // Check create file results in 201 response with etag
            TestTracer.Trace("==== Check create file results in 201 response with etag");
            response = await HttpPutAsync(fileAddress, CreateUploadContent(_fileContent0));
            await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent0);

            Assert.Equal(HttpStatusCode.Created, response.StatusCode);
            EntityTagHeaderValue originalEtag = response.Headers.ETag;

            Assert.NotNull(originalEtag);

            DateTimeOffset?lastModified = response.Content.Headers.LastModified;

            if (!_isScmEditorTest)
            {
                Assert.NotNull(lastModified);
            }

            // Check query string
            TestTracer.Trace("==== Check handle query string");
            response = await HttpGetAsync(baseAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            response = await HttpGetAsync(dirAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            response = await HttpGetAsync(fileAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            // Check that we get a 200 (OK) on created file with the correct etag
            TestTracer.Trace("==== Check that we get a 200 (OK) on created file with the correct etag");
            response = await HttpGetAsync(fileAddress);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal(originalEtag, response.Headers.ETag);
            Assert.Equal(lastModified, response.Content.Headers.LastModified);
            Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);

            // Check that we get a 200 (OK) on created file using HEAD with the correct etag
            TestTracer.Trace("==== Check that we get a 200 (OK) on created file using HEAD with the correct etag");
            using (HttpRequestMessage headReq = new HttpRequestMessage())
            {
                headReq.Method     = HttpMethod.Head;
                headReq.RequestUri = new Uri(fileAddress);
                response           = await Client.SendAsync(headReq);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
                Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
            }

            // Check that we get a 304 (Not Modified) response if matching If-None-Match
            TestTracer.Trace("==== Check that we get a 304 (Not Modified) response if matching If-None-Match");
            using (HttpRequestMessage ifNoneMatchReq = new HttpRequestMessage())
            {
                ifNoneMatchReq.RequestUri = new Uri(fileAddress);
                ifNoneMatchReq.Headers.IfNoneMatch.Add(originalEtag);
                response = await HttpSendAsync(ifNoneMatchReq);

                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that we get a 200 (OK) response if not matching If-None-Match
            TestTracer.Trace("==== Check that we get a 200 (OK) response if not matching If-None-Match");
            using (HttpRequestMessage ifNoneMatchReqBadEtag = new HttpRequestMessage())
            {
                ifNoneMatchReqBadEtag.RequestUri = new Uri(fileAddress);
                ifNoneMatchReqBadEtag.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"NotMatching\""));
                response = await HttpSendAsync(ifNoneMatchReqBadEtag);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that If-Range request with range returns 206 (Partial Content)
            TestTracer.Trace("==== Check that If-Range request with range returns 206 (Partial Content)");
            using (HttpRequestMessage ifRangeReq = new HttpRequestMessage())
            {
                ifRangeReq.RequestUri      = new Uri(fileAddress);
                ifRangeReq.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                ifRangeReq.Headers.Range   = new RangeHeaderValue(0, 0)
                {
                    Unit = "bytes"
                };
                response = await HttpSendAsync(ifRangeReq);

                Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
                Assert.Equal(1, response.Content.Headers.ContentLength);
                Assert.Equal(new ContentRangeHeaderValue(0, 0, _fileContent0.Length), response.Content.Headers.ContentRange);
            }

            // Check that If-Range request with no range returns 200 (OK)
            TestTracer.Trace("==== Check that If-Range request with no range returns 200 (OK)");
            using (HttpRequestMessage ifRangeReqNoRange = new HttpRequestMessage())
            {
                ifRangeReqNoRange.RequestUri      = new Uri(fileAddress);
                ifRangeReqNoRange.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                response = await HttpSendAsync(ifRangeReqNoRange);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that If-Range request with bad range returns 416 (Requested Range Not Satisfiable)
            // including a Content-Range header
            TestTracer.Trace("==== Check that If-Range request with bad range returns 416 (Requested Range Not Satisfiable)");
            using (HttpRequestMessage ifRangeReqBadRange = new HttpRequestMessage())
            {
                ifRangeReqBadRange.RequestUri      = new Uri(fileAddress);
                ifRangeReqBadRange.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                ifRangeReqBadRange.Headers.Range   = new RangeHeaderValue(100, 100)
                {
                    Unit = "bytes"
                };
                response = await HttpSendAsync(ifRangeReqBadRange);

                Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
                Assert.Equal(_fileContentRange, response.Content.Headers.ContentRange);
            }

            // Check that we get a root directory view
            TestTracer.Trace("==== Check that we get a root directory view");
            response = await HttpGetAsync(BaseAddress);

            Assert.Equal(_dirMediaType, response.Content.Headers.ContentType);

            // Check that we get a directory view from folder
            TestTracer.Trace("==== Check that we get a directory view from folder");
            response = await HttpGetAsync(dirAddress);

            Assert.Equal(_dirMediaType, response.Content.Headers.ContentType);

            // Check various redirects between files and folders
            HttpClientHandler redirectHandler = HttpClientHelper.CreateClientHandler(BaseAddress, KuduClient.Credentials);

            redirectHandler.AllowAutoRedirect = false;
            using (HttpClient redirectClient = HttpClientHelper.CreateClient(BaseAddress, KuduClient.Credentials, redirectHandler))
            {
                // Ensure that requests to root without slash is redirected to one with slash
                TestTracer.Trace("==== Ensure that requests to root without slash is redirected to one with slash");
                response = await HttpGetAsync(BaseAddress, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(BaseAddress + _segmentDelimiter, response.Headers.Location.AbsoluteUri);

                // Ensure that requests to directory without slash is redirected to one with slash
                TestTracer.Trace("==== Ensure that requests to directory without slash is redirected to one with slash");
                response = await HttpGetAsync(dirAddress, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(dirAddressWithTerminatingSlash, response.Headers.Location.AbsoluteUri);

                // Ensure that requests to file with slash is redirected to one without slash
                TestTracer.Trace("==== Ensure that requests to file with slash is redirected to one without slash");
                response = await HttpGetAsync(fileAddressWithTerminatingSlash, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(fileAddress, response.Headers.Location.AbsoluteUri);
            }

            // Check that 2nd create attempt fails
            TestTracer.Trace("==== Check that 2nd create attempt fails");
            response = await HttpPutAsync(fileAddress, CreateUploadContent(_fileContent0));

            Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
            Assert.Equal(originalEtag, response.Headers.ETag);

            // Check that we can't update a directory
            TestTracer.Trace("==== Check that we can't update a directory");
            response = await HttpPutAsync(dirAddress, CreateUploadContent(_fileContent0));

            Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);

            // Check that we can't delete a non-empty directory
            TestTracer.Trace("==== Check that we can't delete a non-empty directory");
            response = await HttpDeleteAsync(dirAddress);

            Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);

            EntityTagHeaderValue updatedEtag;

            if (_testConflictingUpdates)
            {
                // Update file with first edit based on original etag
                TestTracer.Trace("==== Update file with first edit based on original etag");
                using (HttpRequestMessage update1 = new HttpRequestMessage())
                {
                    update1.Method     = HttpMethod.Put;
                    update1.RequestUri = new Uri(fileAddress);
                    update1.Headers.IfMatch.Add(originalEtag);
                    update1.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update1);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with second edit based on original etag (non-conflicting merge)
                TestTracer.Trace("==== Update file with second edit based on original etag (non-conflicting merge)");
                using (HttpRequestMessage update2 = new HttpRequestMessage())
                {
                    update2.Method     = HttpMethod.Put;
                    update2.RequestUri = new Uri(fileAddress);
                    update2.Headers.IfMatch.Add(originalEtag);
                    update2.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(update2);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(updatedEtag, response.Headers.ETag);
                    Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with third edit based on original etag (non-conflicting merge)
                TestTracer.Trace("==== Update file with third edit based on original etag (non-conflicting merge)");
                using (HttpRequestMessage update3 = new HttpRequestMessage())
                {
                    update3.Method     = HttpMethod.Put;
                    update3.RequestUri = new Uri(fileAddress);
                    update3.Headers.IfMatch.Add(originalEtag);
                    update3.Content = CreateUploadContent(_fileContent3);

                    response = await HttpSendAsync(update3);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                    Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with forth edit based on original etag (conflicting)
                TestTracer.Trace("==== Update file with forth edit based on original etag (conflicting)");
                using (HttpRequestMessage update4 = new HttpRequestMessage())
                {
                    update4.Method     = HttpMethod.Put;
                    update4.RequestUri = new Uri(fileAddress);
                    update4.Headers.IfMatch.Add(originalEtag);
                    update4.Content = CreateUploadContent(_fileContent4);

                    response = await HttpSendAsync(update4);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
                    Assert.Equal(_conflictMediaType, response.Content.Headers.ContentType);
                    Assert.Null(response.Headers.ETag);
                    string content = await response.Content.ReadAsStringAsync();

                    Assert.True(Regex.IsMatch(content, _conflict));
                }

                // Update file with fifth edit based on invalid etag
                TestTracer.Trace("==== Update file with fifth edit based on invalid etag");
                using (HttpRequestMessage update5 = new HttpRequestMessage())
                {
                    update5.Method     = HttpMethod.Put;
                    update5.RequestUri = new Uri(fileAddress);
                    update5.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    update5.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update5);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with wildcard etag succeeds
                TestTracer.Trace("==== Check that update with wildcard etag succeeds");
                using (HttpRequestMessage update6 = new HttpRequestMessage())
                {
                    update6.Method     = HttpMethod.Put;
                    update6.RequestUri = new Uri(fileAddress);
                    update6.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    update6.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update6);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check that concurrent updates work");
                List <Task <HttpResponseMessage> > concurrentUpdates = new List <Task <HttpResponseMessage> >();
                for (int cnt = 0; cnt < 16; cnt++)
                {
                    HttpRequestMessage concurrentRequest = new HttpRequestMessage()
                    {
                        Method     = HttpMethod.Put,
                        RequestUri = new Uri(fileAddress + "?nodeploy"),
                        Content    = CreateUploadContent(_fileContent2)
                    };

                    concurrentRequest.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    concurrentUpdates.Add(HttpSendAsync(concurrentRequest));
                }
                await Task.WhenAll(concurrentUpdates);

                IEnumerable <HttpResponseMessage> concurrentResponses = concurrentUpdates.Select(update => update.Result);
                foreach (HttpResponseMessage concurrentResponse in concurrentResponses)
                {
                    // NoContent is the expected success case.
                    // PreConditionFailed can happen due to race condition between LibGit2Sharp cleanup and lock acquisition and release.
                    // In PreConditionFailed case, nothing is written and the repo isn't updated or corrupted.
                    // This is an edge case for a legacy feature
                    Assert.True(
                        concurrentResponse.StatusCode == HttpStatusCode.NoContent ||
                        concurrentResponse.StatusCode == HttpStatusCode.PreconditionFailed,
                        $"Status code expected to be either {HttpStatusCode.NoContent} or {HttpStatusCode.PreconditionFailed} but got {concurrentResponse.StatusCode}");
                }

                TestTracer.Trace("==== Check that 'nodeploy' doesn't deploy and that the old content remains.");
                using (HttpRequestMessage request = new HttpRequestMessage())
                {
                    request.Method     = HttpMethod.Put;
                    request.RequestUri = new Uri(fileAddress + "?nodeploy");
                    request.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    request.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(request);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check passing custom commit message.");
                using (HttpRequestMessage request = new HttpRequestMessage())
                {
                    request.Method     = HttpMethod.Put;
                    request.RequestUri = new Uri(fileAddress + "?message=helloworld");
                    request.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    request.Content = CreateUploadContent(_fileContent3);

                    response = await HttpSendAsync(request);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check that custom deployment script works");
                using (HttpRequestMessage update7 = new HttpRequestMessage())
                {
                    // Upload custom deployment scripts
                    TestTracer.Trace("==== Upload custom deployment scripts");
                    updatedEtag = await UploadCustomDeploymentScripts();

                    // Upload content and validate that it gets deployed
                    TestTracer.Trace("==== Upload content and validate that it gets deployed");
                    update7.Method     = HttpMethod.Put;
                    update7.RequestUri = new Uri(fileAddress);
                    update7.Headers.IfMatch.Add(updatedEtag);
                    update7.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(update7);
                    await VerifyDeploymentAsync(customDeploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;

                    // Remove custom deployment scripts
                    TestTracer.Trace("==== Remove custom deployment scripts");
                    updatedEtag = await RemoveCustomDeploymentScripts();
                }

                // Check that delete with invalid etag fails
                TestTracer.Trace("==== Check that delete with invalid etag fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that delete with conflict fails
                TestTracer.Trace("==== Check that delete with conflict fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(originalEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
                }

                // Check that delete with valid etag succeeds
                TestTracer.Trace("==== Check that delete with valid etag succeeds");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.NotFound, null);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }

                // Check that 2nd delete attempt fails
                TestTracer.Trace("==== Check that 2nd delete attempt fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.NotFound, null);

                    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
                }
            }
            else
            {
                // Check that update with correct etag generates 204 Response with new etag
                TestTracer.Trace("==== Check that update with correct etag generates 204 Response with new etag");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(originalEtag);
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Check that 2nd create attempt fails
                TestTracer.Trace("==== Check that 2nd create attempt fails");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(originalEtag);
                    updateRequest.Content = CreateUploadContent(_fileContent2);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with invalid etag fails
                TestTracer.Trace("==== Check that update with invalid etag fails");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with wildcard etag succeeds
                TestTracer.Trace("==== Check that update with wildcard etag succeeds");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Check that delete with invalid etag fails
                TestTracer.Trace("==== Check that delete with invalid etag fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that delete with valid etag succeeds
                TestTracer.Trace("==== Check that delete with valid etag succeeds");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }

                // Check that 2nd delete attempt fails
                TestTracer.Trace("==== Check that 2nd delete attempt fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
                }

                // Check that we can delete an empty directory
                TestTracer.Trace("==== Check that we can delete an empty directory");
                response = await HttpDeleteAsync(dirAddress);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
Пример #23
0
        public async Task HandleAutoSwapTests()
        {
            string deploymentId = Guid.Empty.ToString();

            var deploymentSettingsMock      = new Mock <IDeploymentSettingsManager>();
            var enviromentMock              = new Mock <IEnvironment>();
            var deploymentStatusManagerMock = new Mock <IDeploymentStatusManager>();
            var tracerMock            = new Mock <ITracer>();
            var deploymentContextMock = new DeploymentContext()
            {
                Logger = Mock.Of <ILogger>(),
                Tracer = tracerMock.Object
            };

            enviromentMock.Setup(e => e.LocksPath).Returns(@"x:\foo");
            deploymentStatusManagerMock.Setup(d => d.ActiveDeploymentId).Returns(deploymentId);

            var handler = new AutoSwapHandler(
                deploymentStatusManagerMock.Object,
                enviromentMock.Object,
                deploymentSettingsMock.Object,
                Mock.Of <ITraceFactory>());

            TestTracer.Trace("Autoswap will not happen, since it is not enabled.");
            await handler.HandleAutoSwap(deploymentId, deploymentContextMock);

            TestTracer.Trace("Autoswap will not happen, since there is no JWT token.");
            System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, null);
            deploymentSettingsMock.Setup(
                s => s.GetValue(It.Is <string>(v => "WEBSITE_SWAP_SLOTNAME".StartsWith(v)), It.IsAny <bool>())
                ).Returns("someslot");

            handler = new AutoSwapHandler(
                deploymentStatusManagerMock.Object,
                enviromentMock.Object,
                deploymentSettingsMock.Object,
                Mock.Of <ITraceFactory>());

            var fileSystemMock   = new Mock <IFileSystem>();
            var fileInfoMock     = new Mock <IFileInfoFactory>();
            var fileInfoBaseMock = new Mock <FileInfoBase>();

            FileSystemHelpers.Instance = fileSystemMock.Object;

            fileSystemMock.Setup(f => f.FileInfo).Returns(fileInfoMock.Object);
            fileInfoMock.Setup(f => f.FromFileName(It.IsAny <string>())).Returns(fileInfoBaseMock.Object);
            fileInfoBaseMock.Setup(f => f.Exists).Returns(true);
            fileInfoBaseMock.Setup(f => f.LastWriteTimeUtc).Returns(DateTime.UtcNow);
            await handler.HandleAutoSwap(deploymentId, deploymentContextMock);

            try
            {
                string jwtToken = Guid.NewGuid().ToString();
                string hostName = "foo.scm.bar";
                System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, jwtToken);
                System.Environment.SetEnvironmentVariable(Constants.HttpHost, hostName);

                TestTracer.Trace("Autoswap will not happen, since there deploymet id not changed");
                await handler.HandleAutoSwap(deploymentId, deploymentContextMock);

                tracerMock.Verify(l => l.Trace("AutoSwap is not enabled", It.IsAny <IDictionary <string, string> >()), Times.Once);
                tracerMock.Verify(l => l.Trace("AutoSwap is not enabled", It.IsAny <IDictionary <string, string> >()), Times.Once);
                tracerMock.Verify(l =>
                                  l.Trace(string.Format(CultureInfo.InvariantCulture, "Deployment haven't changed, no need for auto swap: {0}", deploymentId),
                                          It.IsAny <IDictionary <string, string> >()),
                                  Times.Once);

                TestTracer.Trace("Autoswap will be triggered");
                string newDeploymentId = Guid.NewGuid().ToString();

                string autoSwapRequestUrl = null;
                string bearerToken        = null;
                OperationClient.ClientHandler = new TestMessageHandler((HttpRequestMessage requestMessage) =>
                {
                    autoSwapRequestUrl = requestMessage.RequestUri.AbsoluteUri;
                    bearerToken        = requestMessage.Headers.GetValues("Authorization").First();
                    return(new HttpResponseMessage(HttpStatusCode.OK));
                });

                await handler.HandleAutoSwap(newDeploymentId, deploymentContextMock);

                Assert.NotNull(autoSwapRequestUrl);
                Assert.True(autoSwapRequestUrl.StartsWith("https://foo.scm.bar/operations/autoswap?slot=someslot&operationId=AUTOSWAP"));

                Assert.NotNull(bearerToken);
                Assert.Equal("Bearer " + jwtToken, bearerToken);
            }
            finally
            {
                System.Environment.SetEnvironmentVariable(Constants.SiteRestrictedJWT, null);
                System.Environment.SetEnvironmentVariable(Constants.HttpHost, null);
                OperationClient.ClientHandler = null;
            }
        }
Пример #24
0
        public async Task ProcessApiTests()
        {
            string appName = "ProcessApiTests";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                // Test current process
                var process        = await appManager.ProcessManager.GetCurrentProcessAsync();
                int currentId      = process.Id;
                DateTime startTime = process.StartTime;
                Assert.NotNull(process);
                Assert.Contains("w3wp", process.Name);
                Assert.Contains("/diagnostics/processes/" + currentId, process.Href.AbsoluteUri);

                // Test get process by id
                process = await appManager.ProcessManager.GetProcessAsync(currentId);
                Assert.NotNull(process);
                Assert.Contains("w3wp", process.Name);
                Assert.Contains("/diagnostics/processes/" + currentId, process.Href.AbsoluteUri);

                // Test get not running process id
                var notfound = await KuduAssert.ThrowsUnwrappedAsync <HttpUnsuccessfulRequestException>(() => appManager.ProcessManager.GetProcessAsync(99999));
                Assert.Equal(HttpStatusCode.NotFound, notfound.ResponseMessage.StatusCode);
                Assert.Contains("is not running", notfound.ResponseMessage.ExceptionMessage);

                // Test process list
                var processes = await appManager.ProcessManager.GetProcessesAsync();
                Assert.True(processes.Count() >= 1);
                Assert.True(processes.Any(p => p.Id == currentId));

                // Test process dumps
                foreach (var format in new[] { "raw", "zip", "diagsession" })
                {
                    if (format != "diagsession")
                    {
                        TestTracer.Trace("Test minidump format={0}", format);
                        using (var stream = new MemoryStream())
                        {
                            using (var minidump = await appManager.ProcessManager.MiniDump(format: format))
                            {
                                Assert.NotNull(minidump);
                                await minidump.CopyToAsync(stream);
                            }
                            TestTracer.Trace("Test minidump lenth={0}", stream.Length);
                            Assert.True(stream.Length > 0);
                        }
                    }

                    if (ProcessExtensions.SupportGCDump)
                    {
                        TestTracer.Trace("Test gcdump format={0}", format);
                        using (var stream = new MemoryStream())
                        {
                            using (var gcdump = await appManager.ProcessManager.GCDump(format: format))
                            {
                                Assert.NotNull(gcdump);
                                await gcdump.CopyToAsync(stream);
                            }
                            TestTracer.Trace("Test gcdump lenth={0}", stream.Length);
                            Assert.True(stream.Length > 0);
                        }
                    }
                }

                // Test kill process
                await KuduAssert.ThrowsUnwrappedAsync <HttpRequestException>(() => appManager.ProcessManager.KillProcessAsync(currentId));
                HttpUtils.WaitForSite(appManager.SiteUrl, delayBeforeRetry: 10000);
                process = await appManager.ProcessManager.GetCurrentProcessAsync();
                Assert.NotEqual(startTime, process.StartTime);
            });
        }
Пример #25
0
        public async Task SiteExtensionBasicTests()
        {
            const string appName = "SiteExtensionBasicTests";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;

                // list
                List <SiteExtensionInfo> results = (await manager.GetRemoteExtensions()).ToList();
                Assert.True(results.Any(), "GetRemoteExtensions expects results > 0");

                // pick site extension
                var expectedId = _galleryInstalledExtensions.Keys.ToArray()[new Random().Next(_galleryInstalledExtensions.Count)];
                var expected   = results.Find(ext => String.Equals(ext.Id, expectedId, StringComparison.OrdinalIgnoreCase));
                TestTracer.Trace("Testing Against Site Extension {0}", expectedId);

                // get
                var result = await manager.GetRemoteExtension(expectedId);
                Assert.Equal(expected.Id, result.Id);
                Assert.Equal(expected.Version, result.Version);

                // clear local extensions
                results = (await manager.GetLocalExtensions()).ToList();
                foreach (var ext in results)
                {
                    Assert.True(await manager.UninstallExtension(ext.Id), "Delete must return true");
                }

                // install/update
                HttpResponseResult <SiteExtensionInfo> richResult = await manager.InstallExtension <SiteExtensionInfo>(expected.Id);
                Assert.Equal(expected.Id, richResult.Body.Id);
                Assert.Equal(expected.Version, richResult.Body.Version);

                // list
                results = (await manager.GetLocalExtensions()).ToList();
                Assert.True(results.Any(), "GetLocalExtensions expects results > 0");

                // get
                result = await manager.GetLocalExtension(expected.Id);
                Assert.Equal(expected.Id, result.Id);

                // delete
                var deleted = await manager.UninstallExtension(expected.Id);
                Assert.True(deleted, "Delete must return true");

                // list installed
                results = (await manager.GetLocalExtensions()).ToList();
                Assert.False(results.Exists(ext => ext.Id == expected.Id), "After deletion extension " + expected.Id + " should not exist.");

                // install from non-default endpoint
                richResult = await manager.InstallExtension <SiteExtensionInfo>("bootstrap", version: "3.0.0", feedUrl: "http://www.nuget.org/api/v2/");
                Assert.Equal("bootstrap", richResult.Body.Id);
                Assert.Equal("3.0.0", richResult.Body.Version);
                Assert.Equal("http://www.nuget.org/api/v2/", richResult.Body.FeedUrl);

                // update site extension installed from non-default endpoint
                richResult = await manager.InstallExtension <SiteExtensionInfo>("bootstrap");
                Assert.Equal("bootstrap", richResult.Body.Id);
                Assert.Equal("http://www.nuget.org/api/v2/", richResult.Body.FeedUrl);
            });
        }
Пример #26
0
        public async Task ProcessApiTests()
        {
            string appName = "ProcessApiTests";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                // Test current process
                var process        = await appManager.ProcessManager.GetCurrentProcessAsync();
                int currentId      = process.Id;
                var currentUser    = process.UserName;
                DateTime startTime = process.StartTime;
                Assert.NotNull(process);
                Assert.Contains("w3wp", process.Name);
                Assert.Contains("/api/processes/" + currentId, process.Href.AbsoluteUri);

                // Test get process by id
                process = await appManager.ProcessManager.GetProcessAsync(currentId);
                Assert.NotNull(process);
                Assert.Contains("w3wp", process.Name);
                Assert.Contains("/api/processes/" + currentId, process.Href.AbsoluteUri);

                // Test get not running process id
                var notfound = await KuduAssert.ThrowsUnwrappedAsync <HttpUnsuccessfulRequestException>(() => appManager.ProcessManager.GetProcessAsync(99999));
                Assert.Equal(HttpStatusCode.NotFound, notfound.ResponseMessage.StatusCode);
                Assert.Contains("is not running", notfound.ResponseMessage.ExceptionMessage);

                // Test process list
                var processes = await appManager.ProcessManager.GetProcessesAsync();
                Assert.True(processes.Count() >= 1);
                Assert.True(processes.Any(p => p.Id == currentId));
                Assert.True(processes.All(p => p.UserName == currentUser));

                // Test all-users process list
                var allProcesses = await appManager.ProcessManager.GetProcessesAsync(allUsers: true);
                Assert.True(allProcesses.Count() >= processes.Count());
                Assert.True(allProcesses.Any(p => p.Id == currentId));
                Assert.True(allProcesses.Any(p => p.UserName == currentUser));

                // Test process dumps
                foreach (var format in new[] { "raw", "zip" })
                {
                    TestTracer.Trace("Test minidump format={0}", format);
                    using (var stream = new MemoryStream())
                    {
                        using (var minidump = await appManager.ProcessManager.MiniDump(format: format))
                        {
                            Assert.NotNull(minidump);
                            await minidump.CopyToAsync(stream);
                        }
                        TestTracer.Trace("Test minidump lenth={0}", stream.Length);
                        Assert.True(stream.Length > 0);
                    }
                }

                //Test Handles
                process = await appManager.ProcessManager.GetCurrentProcessAsync();
                Assert.NotNull(process);
                Assert.True(
                    process.OpenFileHandles.Any(
                        h => h.IndexOf("kudu.core.dll", StringComparison.InvariantCultureIgnoreCase) != -1));

                //Test Modules
                process = await appManager.ProcessManager.GetCurrentProcessAsync();
                Assert.NotNull(process);
                Assert.True(
                    process.Modules.Any(h => h.FileName.Equals("ntdll.dll", StringComparison.InvariantCultureIgnoreCase)));

                // Test kill process
                await KuduAssert.ThrowsUnwrappedAsync <HttpRequestException>(() => appManager.ProcessManager.KillProcessAsync(currentId));
                HttpUtils.WaitForSite(appManager.SiteUrl, delayBeforeRetry: 10000);
                process = await appManager.ProcessManager.GetCurrentProcessAsync();
                Assert.NotEqual(startTime, process.StartTime);
            });
        }
Пример #27
0
        public async Task SiteExtensionInstallPackageToWebRootAsyncTests()
        {
            const string appName                = "SiteExtensionInstallPackageToWebRootAsyncTests";
            const string externalPackageId      = "SimpleSvc";
            const string externalPackageVersion = "1.0.0";
            const string externalFeed           = "https://www.myget.org/F/simplesvc/";

            // site extension 'webrootxdttest' search for xdt files under site extension 'webrootxdttest' folder, and print out xdt content onto page
            const string externalPackageWithXdtId = "webrootxdttest";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                // install/update
                TestTracer.Trace("Perform InstallExtension with id '{0}', version '{1}' from '{2}'", externalPackageId, externalPackageVersion, externalFeed);
                UpdateHeaderIfGoingToBeArmRequest(manager.Client, true);
                HttpResponseMessage responseMessage    = await manager.InstallExtension(externalPackageId, externalPackageVersion, externalFeed, SiteExtensionInfo.SiteExtensionType.WebRoot);
                ArmEntry <SiteExtensionInfo> armResult = null;
                if (responseMessage.StatusCode == HttpStatusCode.OK)
                {
                    TestTracer.Trace("Installation done within 15 seconds, no polling needed.");
                    armResult = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                }
                else
                {
                    Assert.Equal(HttpStatusCode.Created, responseMessage.StatusCode);
                    responseMessage = await PollAndVerifyAfterArmInstallation(manager, externalPackageId);
                    armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                }

                // shouldn`t see restart header since package doesn`t come with XDT
                Assert.False(responseMessage.Headers.Contains(Constants.SiteOperationHeaderKey), "Must not contain restart header");
                Assert.Equal(externalFeed, armResult.Properties.FeedUrl);
                Assert.Equal(externalPackageVersion, armResult.Properties.Version);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);

                TestTracer.Trace("GET request to verify package content has been copied to wwwroot");
                HttpClient client      = new HttpClient();
                responseMessage        = await client.GetAsync(appManager.SiteUrl);
                string responseContent = await responseMessage.Content.ReadAsStringAsync();
                Assert.NotNull(responseContent);
                Assert.True(responseContent.Contains(@"<h3>Site for testing</h3>"));

                TestTracer.Trace("GetLocalExtension should return WebRoot type SiteExtensionInfo");
                responseMessage = await manager.GetLocalExtension(externalPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Equal(SiteExtensionInfo.SiteExtensionType.WebRoot, armResult.Properties.Type);

                responseMessage = await manager.GetLocalExtensions(externalPackageId);
                var results     = await responseMessage.Content.ReadAsAsync <ArmListEntry <SiteExtensionInfo> >();
                foreach (var item in results.Value)
                {
                    if (string.Equals(externalPackageId, item.Properties.Id, StringComparison.OrdinalIgnoreCase))
                    {
                        Assert.Equal(SiteExtensionInfo.SiteExtensionType.WebRoot, item.Properties.Type);
                    }
                }

                // delete
                TestTracer.Trace("Perform UninstallExtension with id '{0}' only.", externalPackageId);
                responseMessage = await manager.UninstallExtension(externalPackageId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                Assert.Null(armResult);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);

                TestTracer.Trace("GET request to verify package content has been removed wwwroot");
                responseMessage = await client.GetAsync(appManager.SiteUrl);
                Assert.Equal(HttpStatusCode.Forbidden, responseMessage.StatusCode);

                // install package that with xdt file
                TestTracer.Trace("Perform InstallExtension with id '{0}' from '{1}'", externalPackageWithXdtId, externalFeed);
                responseMessage = await manager.InstallExtension(externalPackageWithXdtId, feedUrl: externalFeed, type: SiteExtensionInfo.SiteExtensionType.WebRoot);
                Assert.Equal(HttpStatusCode.Created, responseMessage.StatusCode);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));
                // package come with XDT, which would require site restart
                TestTracer.Trace("Poll for status. Expecting 200 response eventually with site operation header.");
                responseMessage = await PollAndVerifyAfterArmInstallation(manager, externalPackageWithXdtId);
                armResult       = await responseMessage.Content.ReadAsAsync <ArmEntry <SiteExtensionInfo> >();
                // after successfully installed, should return SiteOperationHeader to notify GEO to restart website
                Assert.True(responseMessage.Headers.Contains(Constants.SiteOperationHeaderKey));
                Assert.Equal(externalFeed, armResult.Properties.FeedUrl);
                Assert.Equal(HttpStatusCode.OK, responseMessage.StatusCode);

                TestTracer.Trace("GET request to verify package content has been copied to wwwroot");
                responseMessage = await client.GetAsync(appManager.SiteUrl);
                responseContent = await responseMessage.Content.ReadAsStringAsync();
                Assert.NotNull(responseContent);
                Assert.True(responseContent.Contains(@"1 files"));
                Assert.True(responseContent.Contains(@"site\path\shall\not\be\found")); // xdt content
            });
        }
Пример #28
0
        public void ContinuousJobStartsAfterGoingDown()
        {
            RunScenario("ContinuousJobStartsAfterGoingDown", appManager =>
            {
                TestTracer.Trace("Copying the script to the continuous job directory");

                appManager.JobsManager.CreateContinuousJobAsync("basicJob1", "run.cmd", JobScript).Wait();

                var expectedContinuousJob = new ContinuousJob()
                {
                    Name       = "basicJob1",
                    JobType    = "continuous",
                    Status     = "PendingRestart",
                    RunCommand = "run.cmd"
                };

                WaitUntilAssertVerified(
                    "verify continuous job",
                    TimeSpan.FromSeconds(60),
                    () =>
                {
                    ContinuousJob deployedJob = appManager.JobsManager.GetContinuousJobAsync("basicJob1").Result;
                    AssertContinuousJob(expectedContinuousJob, deployedJob);
                });

                TestTracer.Trace("Waiting for verification file to have 2 lines (which means it ran twice)");

                var expectedVerificationFileContents = new List <string>();
                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);
                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);

                WaitUntilAssertVerified(
                    "verification file",
                    TimeSpan.FromSeconds(30),
                    () => VerifyVerificationFile(appManager, expectedVerificationFileContents.ToArray()));

                TestTracer.Trace("Verify continuous job settings and set it to isSingleton: true");
                JobSettings continuousJobSettings =
                    appManager.JobsManager.GetContinuousJobSettingsAsync(expectedContinuousJob.Name).Result;

                Assert.False(continuousJobSettings.IsSingleton);

                continuousJobSettings.SetSetting("is_singleton", true);
                appManager.JobsManager.SetContinuousJobSettingsAsync(expectedContinuousJob.Name, continuousJobSettings).Wait();

                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);
                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);

                WaitUntilAssertVerified(
                    "verification file",
                    TimeSpan.FromSeconds(30),
                    () => VerifyVerificationFile(appManager, expectedVerificationFileContents.ToArray()));

                TestTracer.Trace("Verify continuous job settings and set it to isSingleton: false");
                continuousJobSettings =
                    appManager.JobsManager.GetContinuousJobSettingsAsync(expectedContinuousJob.Name).Result;

                Assert.True(continuousJobSettings.GetSetting <bool>("is_singleton"));

                continuousJobSettings.SetSetting("is_singleton", false);
                appManager.JobsManager.SetContinuousJobSettingsAsync(expectedContinuousJob.Name, continuousJobSettings).Wait();

                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);
                expectedVerificationFileContents.Add(ExpectedVerificationFileContent);

                WaitUntilAssertVerified(
                    "verification file",
                    TimeSpan.FromSeconds(30),
                    () => VerifyVerificationFile(appManager, expectedVerificationFileContents.ToArray()));
            });
        }
Пример #29
0
        public async Task SiteExtensionBasicTests()
        {
            const string appName = "SiteExtensionBasicTests";
            const string installationArgument = "arg0";

            await ApplicationManager.RunAsync(appName, async appManager =>
            {
                var manager = appManager.SiteExtensionManager;
                await CleanSiteExtensions(manager);

                // list
                List <SiteExtensionInfo> results = await(await manager.GetRemoteExtensions()).Content.ReadAsAsync <List <SiteExtensionInfo> >();
                Assert.True(results.Any(), "GetRemoteExtensions expects results > 0");

                // pick site extension
                var expectedId = _galleryInstalledExtensions.Keys.ToArray()[new Random().Next(_galleryInstalledExtensions.Count)];
                var expectedInstallationArgs = installationArgument;
                var expected = results.Find(ext => string.Equals(ext.Id, expectedId, StringComparison.OrdinalIgnoreCase));
                Assert.True(expected != null, string.Format(CultureInfo.InvariantCulture, "Should able to find {0} from search result", expectedId));
                TestTracer.Trace("Testing Against Site Extension '{0}' - '{1}'", expectedId, expected.Version);

                // get
                TestTracer.Trace("Perform GetRemoteExtension with id '{0}' only", expectedId);
                HttpResponseMessage responseMessage = await manager.GetRemoteExtension(expectedId);
                SiteExtensionInfo result            = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(expected.Id, result.Id);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // clear local extensions
                TestTracer.Trace("Clear all installed extensions.");
                results = await(await manager.GetLocalExtensions()).Content.ReadAsAsync <List <SiteExtensionInfo> >();
                HttpResponseMessage deleteResponseMessage = null;
                foreach (var ext in results)
                {
                    deleteResponseMessage = await manager.UninstallExtension(ext.Id);
                    Assert.True(await deleteResponseMessage.Content.ReadAsAsync <bool>(), "Delete must return true");
                    Assert.True(deleteResponseMessage.Headers.Contains(Constants.RequestIdHeader));
                }

                // install/update
                TestTracer.Trace("Perform InstallExtension with id '{0}' and installationArgs '{1}'", expectedId, installationArgument);
                responseMessage = await manager.InstallExtension(expected.Id, installationArgs: installationArgument);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(expected.Id, result.Id);
                Assert.Equal(expected.Version, result.Version);
                Assert.Equal(expectedInstallationArgs, result.InstallationArgs);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // list
                TestTracer.Trace("Perform GetLocalExtensions with no parameter");
                results = await(await manager.GetLocalExtensions()).Content.ReadAsAsync <List <SiteExtensionInfo> >();
                Assert.True(results.Any(), "GetLocalExtensions expects results > 0");

                // get
                TestTracer.Trace("Perform GetLocalExtension with id '{0}' only.", expectedId);
                responseMessage = await manager.GetLocalExtension(expected.Id);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal(expected.Id, result.Id);
                Assert.Equal(expectedInstallationArgs, result.InstallationArgs);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // delete
                TestTracer.Trace("Perform UninstallExtension with id '{0}' only.", expectedId);
                responseMessage   = await manager.UninstallExtension(expected.Id);
                bool deleteResult = await responseMessage.Content.ReadAsAsync <bool>();
                Assert.True(deleteResult, "Delete must return true");
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // list installed
                TestTracer.Trace("Verify only '{0}' is installed", expectedId);
                results = await(await manager.GetLocalExtensions()).Content.ReadAsAsync <List <SiteExtensionInfo> >();
                Assert.False(results.Exists(ext => ext.Id == expected.Id), "After deletion extension " + expected.Id + " should not exist.");

                // install from non-default endpoint
                responseMessage = await manager.InstallExtension("filecounter", version: "1.0.19", feedUrl: "https://www.nuget.org/api/v2/", installationArgs: installationArgument);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal("filecounter", result.Id);
                Assert.Equal("1.0.19", result.Version);
                Assert.Equal("https://www.nuget.org/api/v2/", result.FeedUrl);
                Assert.Equal(expectedInstallationArgs, result.InstallationArgs);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // update site extension installed from non-default endpoint with no installation arguments
                responseMessage = await manager.InstallExtension("filecounter");
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal("filecounter", result.Id);
                Assert.Equal("https://www.nuget.org/api/v2/", result.FeedUrl);
                Assert.True(string.IsNullOrWhiteSpace(result.InstallationArgs));
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));

                // update site extension installed using installation arguments
                responseMessage = await manager.InstallExtension("filecounter", installationArgs: installationArgument);
                result          = await responseMessage.Content.ReadAsAsync <SiteExtensionInfo>();
                Assert.Equal("filecounter", result.Id);
                Assert.Equal("https://www.nuget.org/api/v2/", result.FeedUrl);
                Assert.Equal(expectedInstallationArgs, result.InstallationArgs);
                Assert.True(responseMessage.Headers.Contains(Constants.RequestIdHeader));
            });
        }
Пример #30
0
        public void TestZipController()
        {
            ApplicationManager.Run("TestZip", appManager =>
            {
                string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                Directory.CreateDirectory(tempDirectory);
                string tempZip1Path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                string tempZip2Path = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                string foundContent;
                try
                {
                    var siteRoot           = "site";
                    var wwwRoot            = "wwwroot";
                    var testFile1Name      = "TestFile1." + System.Guid.NewGuid().ToString("N") + ".txt";
                    var testFile1Content   = "Hello World\n" + System.Guid.NewGuid().ToString("N");
                    var testFile1LocalPath = Path.Combine(tempDirectory, wwwRoot, testFile1Name);

                    TestTracer.Trace("Creating first test file {0} is on the server.", testFile1Name);
                    appManager.VfsWebRootManager.WriteAllText(testFile1Name, testFile1Content);

                    TestTracer.Trace("Verifying first file {0} is in downloaded.", testFile1Name);
                    using (var zipFile = new ZipArchive(appManager.ZipManager.GetZipStream(siteRoot)))
                    {
                        zipFile.ExtractToDirectory(tempDirectory);
                        foundContent = File.ReadAllText(testFile1LocalPath);
                        Assert.Equal(testFile1Content, foundContent);
                    }

                    var testFile2Name           = "TestFile2." + System.Guid.NewGuid().ToString("N") + ".txt";
                    var testFile2LocalPath      = Path.Combine(tempDirectory, wwwRoot, testFile2Name);
                    var testFile2InitialContent = "Hello World with a guid\n" + System.Guid.NewGuid().ToString("N");
                    var testFile2UpdatedContent = "Hello World without a guid";

                    // Make sure our second version of the file is smaller so we can see bugs in file overwrite.
                    Assert.True(testFile2UpdatedContent.Length < testFile2InitialContent.Length);

                    TestTracer.Trace("Uploading second file {0}.", testFile2Name);
                    File.WriteAllText(testFile2LocalPath, testFile2InitialContent);
                    ZipFile.CreateFromDirectory(tempDirectory, tempZip1Path);
                    appManager.ZipManager.PutZipFile(siteRoot, tempZip1Path);

                    TestTracer.Trace("Verifying second file {0} is in uploaded.", testFile2Name);
                    foundContent = appManager.VfsWebRootManager.ReadAllText(testFile2Name);
                    Assert.Equal(testFile2InitialContent, foundContent);

                    TestTracer.Trace("Uploading zip with modified second file and missing first file.", testFile2UpdatedContent);
                    File.Delete(testFile1LocalPath);
                    File.WriteAllText(testFile2LocalPath, testFile2UpdatedContent);
                    ZipFile.CreateFromDirectory(tempDirectory, tempZip2Path);
                    appManager.ZipManager.PutZipFile(siteRoot, tempZip2Path);

                    TestTracer.Trace("Verifying second file is in uploaded and modified correctly.");
                    foundContent = appManager.VfsWebRootManager.ReadAllText(testFile2Name);
                    Assert.Equal(testFile2UpdatedContent, foundContent);

                    // This is expected because our zip controller does not delete files
                    // that are missing from the zip if they are already existing on the server.
                    TestTracer.Trace("Verifying first file still on server.");
                    foundContent = appManager.VfsWebRootManager.ReadAllText(testFile1Name);
                    Assert.Equal(testFile1Content, foundContent);
                }
                finally
                {
                    Directory.Delete(tempDirectory, recursive: true);
                    File.Delete(tempZip1Path);
                    File.Delete(tempZip2Path);
                }
            });
        }