public async Task TestDropboxBasic() { OAuthInfo oauth = GetOAuthInfo(); if (oauth == null) { // only run in private kudu return; } AccountInfo account = GetAccountInfo(oauth); DropboxDeployInfo deploy = GetDeployInfo("/BasicTest", oauth, account); string appName = "DropboxTest"; await ApplicationManager.RunAsync(appName, async appManager => { HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); var result = await client.PostAsJsonAsync("deploy?scmType=Dropbox", deploy); result.EnsureSuccessful(); await Task.WhenAll( KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/default.html", "Hello Default!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/temp/temp.html", "Hello Temp!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/New Folder/New File.html", "Hello New File!") ); }); }
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/Git/trace/trace.xml"); Assert.Contains(path, trace, StringComparison.OrdinalIgnoreCase); }); }
private void VerifyValues(ApplicationManager appManager, params KeyValuePair <string, string>[] values) { using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { HttpResponseMessage response = client.GetAsync("diagnostics/settings").Result.EnsureSuccessful(); using (var reader = new JsonTextReader(new StreamReader(response.Content.ReadAsStreamAsync().Result))) { JObject json = (JObject)JToken.ReadFrom(reader); Assert.Equal(values.Length + 6, json.Count); foreach (KeyValuePair <string, string> value in values) { Assert.Equal(value.Value, json[value.Key].Value <string>()); } } } foreach (KeyValuePair <string, string> value in values) { using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { if (value.Value != null) { HttpResponseMessage response = client.GetAsync("diagnostics/settings/" + value.Key).Result.EnsureSuccessful(); var result = response.Content.ReadAsStringAsync().Result; Assert.Equal(value.Value, result.Trim('\"')); } else { var ex = Assert.Throws <HttpUnsuccessfulRequestException>(() => client.GetAsync("diagnostics/settings/" + value.Key).Result.EnsureSuccessful()); Assert.Equal(HttpStatusCode.NotFound, ex.ResponseMessage.StatusCode); } } } }
public void ConstructorTest() { string repositoryName = "Mvc3Application"; string appName = "ConstructorTest"; using (var repo = Git.CreateLocalRepository(repositoryName)) { ApplicationManager.Run(appName, appManager => { using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { HttpResponseMessage response = client.GetAsync("diagnostics/settings").Result.EnsureSuccessful(); using (var reader = new JsonTextReader(new StreamReader(response.Content.ReadAsStreamAsync().Result))) { JObject json = (JObject)JToken.ReadFrom(reader); Assert.Equal(6, json.Count); } } using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { var ex = Assert.Throws <HttpUnsuccessfulRequestException>(() => client.GetAsync("diagnostics/settings/trace_level").Result.EnsureSuccessful()); Assert.Equal(HttpStatusCode.NotFound, ex.ResponseMessage.StatusCode); } }); } }
public async Task TestDropboxBasicForBasicScenarioWithOAuthV2() { if (String.IsNullOrEmpty(OAuth20Token)) { // only run in private kudu return; } object payload = new { scmType = "DropboxV2", dropbox_token = OAuth20Token, dropbox_path = "/Basictest" }; await ApplicationManager.RunAsync("TestDropboxBasicForBasicScenarioWithOAuthV2", async appManager => { HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); var result = await client.PostAsJsonAsync("deploy?scmType=Dropbox", payload); result.EnsureSuccessful(); await Task.WhenAll( KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/default.html", "Hello Default!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/temp/temp.html", "Hello Temp!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/New Folder/New File.html", "Hello New File!") ); }); }
private HttpClient CreateDeploymentHttpClient(string websiteName) { Repository repository; ICredentials credentials; websiteName = GetWebsiteDeploymentHttpConfiguration(websiteName, out repository, out credentials); return(HttpClientHelper.CreateClient(repository.RepositoryUri, credentials)); }
public async Task TestDropboxBasicForBasicScenario(Scenario scenario) { OAuthInfo oauth = GetOAuthInfo(); if (oauth == null) { // only run in private kudu return; } AccountInfo account = GetAccountInfo(oauth); Assert.Equal(oauth.Account, account.email); var deploy = GetDeployInfo("/BasicTest", oauth, account); string appName = "DropboxTest"; await ApplicationManager.RunAsync(appName, async appManager => { if (scenario == Scenario.NoRepository) { await appManager.SettingsManager.SetValue(SettingsKeys.NoRepository, "1"); } else if (scenario == Scenario.InPlace) { await appManager.SettingsManager.SetValue(SettingsKeys.RepositoryPath, "wwwroot"); } HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); var result = await client.PostAsJsonAsync("deploy?scmType=Dropbox", deploy); result.EnsureSuccessful(); await Task.WhenAll( KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/default.html", "Hello Default!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/temp/temp.html", "Hello Temp!"), KuduAssert.VerifyUrlAsync(appManager.SiteUrl + "/New Folder/New File.html", "Hello New File!") ); var repositoryGit = appManager.VfsManager.Exists(@"site\repository\.git"); var wwwrootGit = appManager.VfsManager.Exists(@"site\wwwroot\.git"); if (scenario == Scenario.NoRepository) { Assert.False(repositoryGit, @"site\repository\.git should not exist for " + scenario); Assert.False(wwwrootGit, @"site\wwwroot\.git should not exist for " + scenario); } else if (scenario == Scenario.InPlace) { Assert.False(repositoryGit, @"site\repository\.git should not exist for " + scenario); Assert.True(wwwrootGit, @"site\wwwroot\.git should exist for " + scenario); } else if (scenario == Scenario.Default) { Assert.True(repositoryGit, @"site\repository\.git should exist for " + scenario); Assert.False(wwwrootGit, @"site\wwwroot\.git should not exist for " + scenario); } }); }
public void DeployLargeRepoFromDropbox(string repoPath, string appName, string verificationText, string resourcePath) { if (!shouldRunLargeRepoTests) { return; } using (new LatencyLogger("PushAndDeployApps - " + appName)) { var db = new DropboxTests(); { DropboxTests.OAuthInfo oauth = db.GetOAuthInfo(appName); if (oauth == null) { // only run in private kudu return; } JObject deploy; DropboxTests.AccountInfo account = db.GetAccountInfo(oauth); using (new LatencyLogger("DropboxGetDeployInfo - " + appName)) { deploy = db.GetDeployInfo(repoPath, oauth, account); } ApplicationManager.Run(appName, appManager => { const int timeoutInMinutes = 100; DateTime stopTime = DateTime.Now.AddMinutes(timeoutInMinutes); var client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); using (new LatencyLogger("DropboxDeploy - " + appName)) { client.PostAsJsonAsync("deploy?scmType=Dropbox", deploy); List <DeployResult> results; do { Thread.Sleep(5000); if (DateTime.Now > stopTime) { throw new TimeoutException("Terminating test. Current test took too long."); } results = appManager.DeploymentManager.GetResultsAsync().Result.ToList(); TestTracer.Trace(results[0].Progress); } while ((results[0]).Status != DeployStatus.Success && (results[0]).Status != DeployStatus.Failed); } KuduAssert.VerifyUrl(appManager.SiteUrl + resourcePath, verificationText); using (new LatencyLogger("DropboxScmDelete - " + appName)) { appManager.RepositoryManager.Delete(deleteWebRoot: false, ignoreErrors: false).Wait(); } }); } } }
private static async Task WaitForSiteAsync(string serviceUrl, ICredentials credentials) { using (var client = HttpClientHelper.CreateClient(serviceUrl, credentials)) { using (var response = await client.GetAsync("")) { response.EnsureSuccessStatusCode(); } } }
public IEnumerable <T> SearchFTS <T>(string query, int start = 0, int limit = 0) where T : BaseE3SEntity { HttpClient client = HttpClientHelper.CreateClient(UserName, Password); var requestGenerator = new FTSRequestGenerator(_basedAddress); Uri request = requestGenerator.GenerateRequestUrl <T>(query, start, limit); string resultString = client.GetStringAsync(request).Result; return(JsonConvert.DeserializeObject <FTSResponse <T> >(resultString).Items.Select(t => t.Data)); }
private async Task WaitForSiteAsync(string serviceUrl) { var credentials = _context.Configuration.BasicAuthCredential.GetCredentials(); using (var client = HttpClientHelper.CreateClient(serviceUrl, credentials)) { using (var response = await client.GetAsync(serviceUrl)) { response.EnsureSuccessStatusCode(); } } }
public void SetGetDeleteValue() { var values = new[] { new KeyValuePair <string, string>(Guid.NewGuid().ToString(), Guid.NewGuid().ToString()), new KeyValuePair <string, string>(Guid.NewGuid().ToString(), String.Empty), new KeyValuePair <string, string>(Guid.NewGuid().ToString(), null) }; string repositoryName = "Mvc3Application"; string appName = "SetGetDeleteValue"; using (var repo = Git.CreateLocalRepository(repositoryName)) { ApplicationManager.Run(appName, appManager => { // set values using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { JObject json = new JObject(); foreach (KeyValuePair <string, string> value in values) { json[value.Key] = value.Value; } client.PostAsJsonAsync("diagnostics/settings", json).Result.EnsureSuccessful(); } // verify values VerifyValues(appManager, values); // delete value using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { KeyValuePair <string, string> deleted = values[1]; client.DeleteAsync("diagnostics/settings/" + deleted.Key).Result.EnsureSuccessful(); values = values.Where(p => p.Key != deleted.Key).ToArray(); } // update value using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { KeyValuePair <string, string> updated = values[0] = new KeyValuePair <string, string>(values[0].Key, Guid.NewGuid().ToString()); JObject json = new JObject(); json[updated.Key] = updated.Value; client.PostAsJsonAsync("diagnostics/settings", json).Result.EnsureSuccessful(); } // verify values VerifyValues(appManager, values); }); } }
protected KuduRemoteClientBase( string serviceUrl, ICredentials credentials = null, HttpMessageHandler handler = null) { if (serviceUrl == null) { throw new ArgumentNullException("serviceUrl"); } ServiceUrl = GeneralUtilities.EnsureTrailingSlash(serviceUrl); Credentials = credentials; Client = HttpClientHelper.CreateClient(ServiceUrl, credentials, handler); }
private HttpClient CreateWebsitesHttpClient() { WebRequestHandler requestHandler = new WebRequestHandler(); requestHandler.ClientCertificates.Add(Subscription.Certificate); StringBuilder endpoint = new StringBuilder(General.EnsureTrailingSlash(Subscription.ServiceEndpoint)); endpoint.Append(subscriptionId); endpoint.Append("/services/"); HttpClient client = HttpClientHelper.CreateClient(endpoint.ToString(), handler: requestHandler); client.DefaultRequestHeaders.Add(ServiceManagement.Constants.VersionHeaderName, WebsitesServiceVersion); return(client); }
public void DiagnosticsSettingsExpectedValuesReturned() { const string expectedEmptyResponse = "{\"AzureDriveEnabled\":false,\"AzureDriveTraceLevel\":\"Error\"," + "\"AzureTableEnabled\":false,\"AzureTableTraceLevel\":\"Error\"," + "\"AzureBlobEnabled\":false,\"AzureBlobTraceLevel\":\"Error\"}"; const string settingsContentWithNumbers = "{AzureDriveEnabled: true,AzureDriveTraceLevel: \"4\"}"; const string settingsContentWithNulls = "{AzureDriveEnabled: null,AzureDriveTraceLevel: \"4\"}"; const string settingsContentWithString = "{AzureDriveEnabled: true,AzureDriveTraceLevel: \"Warning\"}"; const string expectedResponse = "{\"AzureDriveEnabled\":true,\"AzureDriveTraceLevel\":\"Warning\"," + "\"AzureTableEnabled\":false,\"AzureTableTraceLevel\":\"Error\"," + "\"AzureBlobEnabled\":false,\"AzureBlobTraceLevel\":\"Error\"}"; const string repositoryName = "Mvc3Application"; const string appName = "DiagnosticsSettingsExpectedValuesReturned"; using (var repo = Git.Clone(repositoryName)) { ApplicationManager.Run(appName, appManager => { // verify values using (HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { // Empty settings.json should return default values string responseContent = DownloadDiagnosticsSettings(client); Assert.Equal(expectedEmptyResponse, responseContent); // Expecting value will be reset appManager.VfsManager.WriteAllText("site/diagnostics/settings.json", settingsContentWithNumbers); responseContent = DownloadDiagnosticsSettings(client); Assert.Equal(expectedEmptyResponse, responseContent); // Invalid json we expect default values appManager.VfsManager.WriteAllText("site/diagnostics/settings.json", settingsContentWithNulls); responseContent = DownloadDiagnosticsSettings(client); Assert.Equal(expectedEmptyResponse, responseContent); // Expecting AzureDriveEnabled to be true appManager.VfsManager.WriteAllText("site/diagnostics/settings.json", settingsContentWithString); responseContent = DownloadDiagnosticsSettings(client); Assert.Equal(expectedResponse, responseContent); } }); } }
public static void VerifyUrl(string url, ICredentials cred, params string[] contents) { HttpClient client = HttpClientHelper.CreateClient(url, cred); client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Kudu-Test", "1.0")); var response = client.GetAsync(url).Result.EnsureSuccessful(); if (contents.Length > 0) { var responseBody = response.Content.ReadAsStringAsync().Result; foreach (var content in contents) { Assert.Contains(content, responseBody, StringComparison.Ordinal); } } }
public async Task KuduVersionTest() { string appName = "KuduVersionTest"; await ApplicationManager.RunAsync(appName, async appManager => { // Arrange var id = Git.Id(Directory.GetCurrentDirectory()); var client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.SettingsManager.Credentials); client.DefaultRequestHeaders.Accept.Clear(); // Act string clientId = await client.GetStringAsync("commit.txt"); // Assert Assert.Equal(id, clientId.TrimEnd()); }); }
private HttpClient CreateServiceBusHttpClient() { WebRequestHandler requestHandler = new WebRequestHandler() { ClientCertificateOptions = ClientCertificateOption.Manual }; requestHandler.ClientCertificates.Add(Subscription.Certificate); StringBuilder endpoint = new StringBuilder(General.EnsureTrailingSlash(Subscription.ServiceEndpoint)); endpoint.Append(subscriptionId); endpoint.Append("/services/servicebus/namespaces/"); HttpClient client = HttpClientHelper.CreateClient(endpoint.ToString(), handler: requestHandler); client.DefaultRequestHeaders.Add(ApiConstants.VersionHeaderName, "2012-03-01"); return(client); }
/// <summary> /// Creates and initialise instance of HttpClient /// </summary> /// <returns></returns> private static HttpClient CreateIMediaServicesHttpClient(SubscriptionData subscription) { var requestHandler = new WebRequestHandler(); requestHandler.ClientCertificates.Add(subscription.Certificate); var endpoint = new StringBuilder(General.EnsureTrailingSlash(subscription.ServiceEndpoint)); endpoint.Append(subscription.SubscriptionId); //Please note that / is nessesary here endpoint.Append("/services/mediaservices/"); HttpClient client = HttpClientHelper.CreateClient(endpoint.ToString(), handler: requestHandler); client.DefaultRequestHeaders.Add(Constants.VersionHeaderName, MediaServiceVersion); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); return(client); }
public void TestDropboxConcurrent() { OAuthInfo oauth = GetOAuthInfo(); if (oauth == null) { // only run in private kudu return; } AccountInfo account = GetAccountInfo(oauth); DropboxDeployInfo deploy = GetDeployInfo("/BasicTest", oauth, account); string appName = "DropboxTest"; ApplicationManager.Run(appName, appManager => { HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); var tasks = new Task <HttpResponseMessage>[] { client.PostAsJsonAsync("deploy", deploy), client.PostAsJsonAsync("deploy", deploy) }; Task.WaitAll(tasks); // both 200 and 202 is success tasks[0].Result.EnsureSuccessful(); tasks[1].Result.EnsureSuccessful(); var success = (tasks[0].Result.StatusCode == HttpStatusCode.OK) ? tasks[0].Result : tasks[1].Result; var failure = !Object.ReferenceEquals(success, tasks[0].Result) ? tasks[0].Result : tasks[1].Result; success.EnsureSuccessful(); Assert.Equal(HttpStatusCode.Accepted, failure.StatusCode); var results = appManager.DeploymentManager.GetResultsAsync().Result.ToList(); Assert.Equal(1, results.Count); Assert.Equal(DeployStatus.Success, results[0].Status); Assert.Equal("Dropbox", results[0].Deployer); }); }
public IEnumerable SearchFTS(Type type, IList <string> queries, int start = 0, int limit = 0) { HttpClient client = HttpClientHelper.CreateClient(UserName, Password); var requestGenerator = new FTSRequestGenerator(_basedAddress); Uri request = requestGenerator.GenerateRequestUrl(type, queries, start, limit); var resultString = client.GetStringAsync(request).Result; var endType = typeof(FTSResponse <>).MakeGenericType(type); var result = JsonConvert.DeserializeObject(resultString, endType); var list = Activator.CreateInstance(typeof(List <>).MakeGenericType(type)) as IList; foreach (object item in (IEnumerable)endType.GetProperty("items").GetValue(result)) { list.Add(item.GetType().GetProperty("data").GetValue(item)); } return(list); }
public string GetKuduUpTime() { const string pattern = @"<div class=""col-xs-2"">\s*<strong>Site up time</strong>\s*</div>\s*<div>([^<]*)</div>"; string content = OperationManager.Attempt <string>(() => { using (HttpClient client = HttpClientHelper.CreateClient(this.ServiceUrl, this.DeploymentManager.Credentials)) { using (HttpResponseMessage response = client.GetAsync(String.Empty).Result.EnsureSuccessStatusCode()) { return(response.Content.ReadAsStringAsync().Result); } } }, 3, 1000); MatchCollection matches = Regex.Matches(content, pattern); Debug.Assert(matches.Count == 1, "Could not find Up Time section!"); Debug.Assert(matches[0].Groups.Count == 2, "Could not find Up Time value!"); return(matches[0].Groups[1].Value); }
public void TestDropboxSpecialFolderChars() { OAuthInfo oauth = GetOAuthInfo(); if (oauth == null) { // only run in private kudu return; } AccountInfo account = GetAccountInfo(oauth); DropboxDeployInfo deploy = GetDeployInfo("/!@#$faiztest$#!@", oauth, account); string appName = "SpecialCharsTest"; ApplicationManager.Run(appName, appManager => { HttpClient client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials); client.PostAsJsonAsync("deploy?scmType=Dropbox", deploy).Result.EnsureSuccessful(); }); }
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")); }); }
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); } } }
public async Task Error404UnknownRouteTests() { string appName = "Error404UnknownRouteTests"; await ApplicationManager.RunAsync(appName, async appManager => { using (var client = HttpClientHelper.CreateClient(appManager.ServiceUrl, appManager.DeploymentManager.Credentials)) { var path = "/api/badroute"; using (var response = await client.GetAsync(path)) { Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); var content = await response.Content.ReadAsStringAsync(); // assert Assert.True(content.Contains("No route registered for")); Assert.True(content.Contains(path)); } } }); }
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 RunIntegrationTest() { string dir = Guid.NewGuid().ToString("N"); string dirAddress = BaseAddress + _segmentDelimiter + dir; string dirAddressWithTerminatingSlash = dirAddress + _segmentDelimiter; string file = Guid.NewGuid().ToString("N") + ".txt"; string fileAddress = dirAddressWithTerminatingSlash + file; string fileAddressWithTerminatingSlash = fileAddress + _segmentDelimiter; 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 VerifyDeployment(deploymentFileAddress, HttpStatusCode.OK, _fileContent0); Assert.Equal(HttpStatusCode.Created, response.StatusCode); EntityTagHeaderValue originalEtag = response.Headers.ETag; Assert.NotNull(originalEtag); // 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(_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 VerifyDeployment(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 VerifyDeployment(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 VerifyDeployment(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 VerifyDeployment(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(content.StartsWith(_conflict)); } // The previous conflict results in a git cleanup which at times takes time. During this interval the server responds with ServerUnavailable. // To work aroudn this, we'll simply add a bit of sleep timing. Thread.Sleep(TimeSpan.FromSeconds(3)); // 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 VerifyDeployment(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 VerifyDeployment(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; } // 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 VerifyDeployment(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 VerifyDeployment(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 VerifyDeployment(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 VerifyDeployment(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 VerifyDeployment(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); } }
/// <summary> /// 发送请求 /// </summary> /// <param name="request">请求的参数</param> /// <param name="completionOption"></param> /// <param name="token"></param> /// <param name="sourceName"></param> /// <returns>自定义的Response结果</returns> public static Task <HttpResponseMessage> RestSend(this OssHttpRequest request, HttpCompletionOption completionOption, CancellationToken token, string sourceName = null) { return(HttpClientHelper.CreateClient(sourceName).RestSend(request, completionOption, token)); }
/// <summary> /// Creates and initialise instance of HttpClient /// </summary> /// <returns></returns> public HttpClient CreateIMediaServicesHttpClient() { return(HttpClientHelper.CreateClient("http://test/services/mediaservices/", handler: this)); }