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); } } }
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")); }); }
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)); }); }
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; } }
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"); }); }
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); } } }
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(); }
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()); })); }
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); } }); }
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)); }); }
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); }); }
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; }
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); } }
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"); }
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); } }); } }
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)); } }
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(); } }); }
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); }); }
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 }); }
[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); }); }
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); } }); }
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); } }
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; } }
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); }); }
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); }); }
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); }); }
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 }); }
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())); }); }
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)); }); }
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); } }); }