diff --git a/dotnet/Selenium.slnx b/dotnet/Selenium.slnx index 20a3c052efdc7..f713133ccbc86 100644 --- a/dotnet/Selenium.slnx +++ b/dotnet/Selenium.slnx @@ -7,5 +7,6 @@ + diff --git a/dotnet/private/dotnet_nunit_test_suite.bzl b/dotnet/private/dotnet_nunit_test_suite.bzl index 74e0e96977720..cd18905c88234 100644 --- a/dotnet/private/dotnet_nunit_test_suite.bzl +++ b/dotnet/private/dotnet_nunit_test_suite.bzl @@ -20,10 +20,7 @@ _BROWSERS = { "--params=DriverServiceLocation=$(location @mac_chromedriver//:chromedriver)", "--params=BrowserLocation=$(location @mac_chrome//:Chrome.app)/Contents/MacOS/Chrome", ], - "@selenium//common:use_local_chromedriver": [], - "//conditions:default": [ - "--where=SkipTest==True", - ], + "//conditions:default": [], }), "data": chrome_data, "tags": [], @@ -40,10 +37,7 @@ _BROWSERS = { "--params=DriverServiceLocation=$(location @mac_edgedriver//:msedgedriver)", "\"--params=BrowserLocation=$(location @mac_edge//:Edge.app)/Contents/MacOS/Microsoft Edge\"", ], - "@selenium//common:use_local_msedgedriver": [], - "//conditions:default": [ - "--where=SkipTest==True", - ], + "//conditions:default": [], }), "data": edge_data, "tags": [], @@ -60,10 +54,7 @@ _BROWSERS = { "--params=DriverServiceLocation=$(location @mac_geckodriver//:geckodriver)", "--params=BrowserLocation=$(location @mac_firefox//:Firefox.app)/Contents/MacOS/firefox", ], - "@selenium//common:use_local_geckodriver": [], - "//conditions:default": [ - "--where=SkipTest==True", - ], + "//conditions:default": [], }), "data": firefox_data, "tags": [], diff --git a/dotnet/test/remote/BUILD.bazel b/dotnet/test/remote/BUILD.bazel index cf9e0b47d4895..750de342e00c6 100644 --- a/dotnet/test/remote/BUILD.bazel +++ b/dotnet/test/remote/BUILD.bazel @@ -10,9 +10,11 @@ dotnet_nunit_test_suite( "//dotnet/test/webdriver:test-data", ], flaky = True, + project_sdk = "web", target_frameworks = ["net8.0"], deps = [ "//dotnet/src/webdriver:webdriver-net8.0", + "//dotnet/test/testing.webserver", "//dotnet/test/webdriver", nuget_package("NUnit"), nuget_package("Runfiles"), diff --git a/dotnet/test/support/BUILD.bazel b/dotnet/test/support/BUILD.bazel index 2a9f6b9edc7fb..8d14af1c92633 100644 --- a/dotnet/test/support/BUILD.bazel +++ b/dotnet/test/support/BUILD.bazel @@ -10,10 +10,12 @@ dotnet_nunit_test_suite( data = [ "//dotnet/test/webdriver:test-data", ], + project_sdk = "web", target_frameworks = ["net8.0"], deps = [ "//dotnet/src/support", "//dotnet/src/webdriver:webdriver-net8.0", + "//dotnet/test/testing.webserver", "//dotnet/test/webdriver", nuget_package("Microsoft.Bcl.AsyncInterfaces"), nuget_package("Moq"), diff --git a/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj b/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj index 81683d3ca8d9c..b5546e6a0bce0 100644 --- a/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj +++ b/dotnet/test/support/Selenium.WebDriver.Support.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/dotnet/test/testing.webserver/AppServer.cs b/dotnet/test/testing.webserver/AppServer.cs new file mode 100644 index 0000000000000..2b5a54aa2910f --- /dev/null +++ b/dotnet/test/testing.webserver/AppServer.cs @@ -0,0 +1,159 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Linq; +using System.Net; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; +using OpenQA.Selenium.Testing.WebServer.Handlers; + +namespace OpenQA.Selenium.Testing.WebServer; + +public class AppServer : IAsyncDisposable +{ + private WebApplication? _app; + private readonly string _webContentRoot = FindWebContentRoot(); + private readonly ConcurrentDictionary _pages = new(); + + public async Task<(string HttpUrl, string HttpsUrl)> StartAsync() + { + var builder = WebApplication.CreateSlimBuilder(); + + var certificate = GenerateSelfSignedCertificate(); + + builder.WebHost.ConfigureKestrel(options => + { + options.Listen(IPAddress.Loopback, 0); + options.Listen(IPAddress.Loopback, 0, listenOptions => + { + listenOptions.UseHttps(certificate); + }); + }); + builder.Services.AddDirectoryBrowser(); + + _app = builder.Build(); + + MapEndpoints(_app); + MapEndpoints(_app.MapGroup("/common")); + + if (Directory.Exists(_webContentRoot)) + { + var fileProvider = new PhysicalFileProvider(_webContentRoot); + + _app.UseStaticFiles(new StaticFileOptions + { + FileProvider = fileProvider, + ServeUnknownFileTypes = true + }); + + _app.UseStaticFiles(new StaticFileOptions + { + FileProvider = fileProvider, + RequestPath = "/common", + ServeUnknownFileTypes = true + }); + + _app.UseDirectoryBrowser(new DirectoryBrowserOptions + { + FileProvider = fileProvider + }); + + _app.UseDirectoryBrowser(new DirectoryBrowserOptions + { + FileProvider = fileProvider, + RequestPath = "/common" + }); + } + + await _app.StartAsync(); + + int httpPort = new Uri(_app.Urls.First(u => u.StartsWith("http://"))).Port; + int httpsPort = new Uri(_app.Urls.First(u => u.StartsWith("https://"))).Port; + + return ($"http://localhost:{httpPort}", $"https://localhost:{httpsPort}"); + } + + public async Task StopAsync() + { + if (_app is not null) + { + await _app.StopAsync(); + await _app.DisposeAsync(); + _app = null; + } + } + + public async ValueTask DisposeAsync() + { + await StopAsync(); + } + + private void MapEndpoints(IEndpointRouteBuilder endpoints) + { + endpoints.MapGet("/basicAuth", BasicAuthHandler.Handle); + endpoints.MapGet("/echo", (Delegate)EchoHandler.Handle); + endpoints.MapGet("/cookie", CookieHandler.Handle); + endpoints.MapGet("/encoding", EncodingHandler.Handle); + endpoints.MapGet("/sleep", (Delegate)SleepHandler.Handle); + endpoints.MapGet("/redirect", RedirectHandler.Handle); + endpoints.MapGet("/page/{pageNumber}", PageHandler.Handle); + endpoints.MapGet("/utf8/{*path}", (HttpContext context, string path) => Utf8Handler.Handle(context, path, _webContentRoot)); + endpoints.MapPost("/createPage", (Delegate)((HttpContext context) => CreatePageHandler.Handle(context, _pages))); + endpoints.MapPost("/upload", (Delegate)UploadHandler.Handle); + + endpoints.MapGet("/.well-known/web-identity", (HttpContext context) => FedCmHandler.HandleWebIdentity(context)); + endpoints.MapGet("/fedcm/config.json", (HttpContext context) => FedCmHandler.HandleConfig(context)); + endpoints.MapPost("/fedcm/id_assertion.json", (HttpContext context) => FedCmHandler.HandleIdAssertion(context)); + + endpoints.MapGet("/temp/{fileName}", (string fileName) => CreatePageHandler.ServePage(fileName, _pages)); + } + + private static X509Certificate2 GenerateSelfSignedCertificate() + { + using var ecdsa = ECDsa.Create(); + var request = new CertificateRequest("CN=localhost", ecdsa, HashAlgorithmName.SHA256); + return request.CreateSelfSigned(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddYears(1)); + } + + private static string FindWebContentRoot() + { + var info = new DirectoryInfo(AppContext.BaseDirectory); + while (info is not null && info != info.Root) + { + string webPath = Path.Combine(info.FullName, "common", "src", "web"); + if (Directory.Exists(webPath)) + { + return webPath; + } + info = info.Parent; + } + + return string.Empty; + } +} diff --git a/dotnet/test/testing.webserver/BUILD.bazel b/dotnet/test/testing.webserver/BUILD.bazel new file mode 100644 index 0000000000000..efb1d5b61a358 --- /dev/null +++ b/dotnet/test/testing.webserver/BUILD.bazel @@ -0,0 +1,18 @@ +load("//dotnet:defs.bzl", "csharp_library") + +csharp_library( + name = "testing.webserver", + testonly = True, + srcs = glob(["**/*.cs"]), + out = "Testing.WebServer", + data = [ + "//common/src/web", + ], + nullable = "enable", + project_sdk = "web", + run_analyzers = False, + target_frameworks = ["net8.0"], + visibility = [ + "//dotnet/test:__subpackages__", + ], +) diff --git a/dotnet/test/testing.webserver/Handlers/BasicAuthHandler.cs b/dotnet/test/testing.webserver/Handlers/BasicAuthHandler.cs new file mode 100644 index 0000000000000..d145b3707f9fa --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/BasicAuthHandler.cs @@ -0,0 +1,52 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Net; +using System.Text; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class BasicAuthHandler +{ + private const string ExpectedUser = "test"; + private const string ExpectedPassword = "test"; + + public static IResult Handle(HttpContext context) + { + string? authorization = context.Request.Headers.Authorization; + + if (authorization is not null && authorization.StartsWith("Basic ")) + { + string encoded = authorization["Basic ".Length..]; + string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded)); + string[] parts = decoded.Split(':', 2); + + if (parts.Length == 2 && parts[0] == ExpectedUser && parts[1] == ExpectedPassword) + { + return Results.Content("

authorized

", "text/html; charset=utf-8"); + } + } + + context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"selenium-server\""; + return Results.Text(string.Empty, statusCode: (int)HttpStatusCode.Unauthorized, + contentType: "text/html; charset=utf-8"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/CookieHandler.cs b/dotnet/test/testing.webserver/Handlers/CookieHandler.cs new file mode 100644 index 0000000000000..d599ede273bc1 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/CookieHandler.cs @@ -0,0 +1,93 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class CookieHandler +{ + private const string ResponseFormat = "Done{0} : {1}"; + + public static IResult Handle(HttpContext context) + { + var request = context.Request; + var response = context.Response; + + response.Headers.ContentType = "text/html"; + response.Headers.CacheControl = "no-cache"; + response.Headers.Pragma = "no-cache"; + response.Headers.Expires = "0"; + + string? action = request.Query["action"]; + + string html; + + if (action == "add") + { + string? name = request.Query["name"]; + string? value = request.Query["value"]; + string? domain = request.Query["domain"]; + string? path = request.Query["path"]; + string? expiry = request.Query["expiry"]; + string? secure = request.Query["secure"]; + string? httpOnly = request.Query["httpOnly"]; + + var cookie = $"{name}={value}; "; + + if (!string.IsNullOrEmpty(domain)) cookie += $"Domain={domain}; "; + if (!string.IsNullOrEmpty(path)) cookie += $"Path={path}; "; + if (!string.IsNullOrEmpty(expiry)) cookie += $"Max-Age={expiry}; "; + if (!string.IsNullOrEmpty(secure)) cookie += "Secure; "; + if (!string.IsNullOrEmpty(httpOnly)) cookie += "HttpOnly; "; + + response.Headers.Append("Set-Cookie", cookie); + + html = string.Format(ResponseFormat, "Cookie added", name); + } + else if (action == "delete") + { + string? name = request.Query["name"]; + + foreach (var cookiePair in request.Cookies) + { + if (cookiePair.Key != name) continue; + + response.Headers.Append("Set-Cookie", $"{name}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"); + } + + html = string.Format(ResponseFormat, "Cookie deleted", name); + } + else if (action == "deleteAll") + { + foreach (var cookiePair in request.Cookies) + { + response.Headers.Append("Set-Cookie", $"{cookiePair.Key}=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT"); + } + + html = string.Format(ResponseFormat, "All cookies deleted", ""); + } + else + { + html = string.Format(ResponseFormat, "Unrecognized action", action); + } + + return Results.Content(html, "text/html; charset=utf-8"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/CreatePageHandler.cs b/dotnet/test/testing.webserver/Handlers/CreatePageHandler.cs new file mode 100644 index 0000000000000..cc0e178dafe77 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/CreatePageHandler.cs @@ -0,0 +1,60 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class CreatePageHandler +{ + public static async Task Handle(HttpContext context, ConcurrentDictionary pages) + { + string body; + using (var reader = new StreamReader(context.Request.Body)) + { + body = await reader.ReadToEndAsync(); + } + + var json = JsonSerializer.Deserialize>(body); + string content = json!["content"]; + + string fileName = $"page{Guid.NewGuid():N}.html"; + pages[fileName] = content; + + string url = $"{context.Request.Scheme}://{context.Request.Host}/temp/{fileName}"; + + return Results.Text(url, "text/plain"); + } + + public static IResult ServePage(string fileName, ConcurrentDictionary pages) + { + if (pages.TryGetValue(fileName, out string? content)) + { + return Results.Content(content, "text/html; charset=utf-8"); + } + + return Results.NotFound(); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/EchoHandler.cs b/dotnet/test/testing.webserver/Handlers/EchoHandler.cs new file mode 100644 index 0000000000000..cdd38945e4af0 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/EchoHandler.cs @@ -0,0 +1,64 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.IO; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class EchoHandler +{ + public static async Task Handle(HttpContext context) + { + var request = context.Request; + + string method = request.Method; + + var headersBuilder = new StringBuilder(); + foreach (var header in request.Headers) + { + foreach (var value in header.Value) + { + headersBuilder.AppendFormat("{0}{1}", header.Key, value); + } + } + + string body = string.Empty; + using (var reader = new StreamReader(request.Body, Encoding.UTF8)) + { + body = await reader.ReadToEndAsync(); + } + + string html = $""" + Done +

Method: {method}

+

Headers

{headersBuilder}
+

Body:

{body}
+ + """; + + context.Response.Headers.CacheControl = "no-cache"; + context.Response.Headers.Pragma = "no-cache"; + context.Response.Headers.Expires = "0"; + + return Results.Content(html, "text/html; charset=utf-8"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/EncodingHandler.cs b/dotnet/test/testing.webserver/Handlers/EncodingHandler.cs new file mode 100644 index 0000000000000..179465ebbd005 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/EncodingHandler.cs @@ -0,0 +1,39 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.Text; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class EncodingHandler +{ + public static IResult Handle() + { + string text = + "Character encoding (UTF 16)" + + "

" + + "\u05E9\u05DC\u05D5\u05DD" // "Shalom" + + "

"; + + byte[] bytes = Encoding.Unicode.GetBytes(text); // UTF-16LE + + return Results.Bytes(bytes, "text/html;charset=UTF-16LE"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/FedCmHandler.cs b/dotnet/test/testing.webserver/Handlers/FedCmHandler.cs new file mode 100644 index 0000000000000..f10892b6b5300 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/FedCmHandler.cs @@ -0,0 +1,53 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class FedCmHandler +{ + public static IResult HandleWebIdentity(HttpContext context) + { + context.Response.Headers.CacheControl = "no-store"; + + return Results.Json(new { provider_urls = new[] { "https://idp.com" } }); + } + + public static IResult HandleConfig(HttpContext context) + { + context.Response.Headers.CacheControl = "no-store"; + + return Results.Json(new + { + accounts_endpoint = "accounts.json", + client_metadata_endpoint = "client_metadata.json", + id_assertion_endpoint = "id_assertion.json", + signin_url = "signin", + login_url = "login" + }); + } + + public static IResult HandleIdAssertion(HttpContext context) + { + context.Response.Headers.CacheControl = "no-store"; + + return Results.Json(new { token = "a token" }); + } +} diff --git a/dotnet/test/webdriver/Infrastructure/Environment/WebsiteConfig.cs b/dotnet/test/testing.webserver/Handlers/PageHandler.cs similarity index 58% rename from dotnet/test/webdriver/Infrastructure/Environment/WebsiteConfig.cs rename to dotnet/test/testing.webserver/Handlers/PageHandler.cs index 25142e8277530..7a213beb40230 100644 --- a/dotnet/test/webdriver/Infrastructure/Environment/WebsiteConfig.cs +++ b/dotnet/test/testing.webserver/Handlers/PageHandler.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,17 +17,21 @@ // under the License. // -namespace OpenQA.Selenium.Tests.Infrastructure.Environment; +using Microsoft.AspNetCore.Http; -public class WebsiteConfig -{ - public string Protocol { get; set; } - - public string HostName { get; set; } +namespace OpenQA.Selenium.Testing.WebServer.Handlers; - public string Port { get; set; } - - public string SecurePort { get; set; } +public static class PageHandler +{ + public static IResult Handle(string pageNumber) + { + string html = $""" + Page{pageNumber} + Page number {pageNumber} +

top + + """; - public string Folder { get; set; } + return Results.Content(html, "text/html; charset=utf-8"); + } } diff --git a/dotnet/test/webdriver/Infrastructure/Environment/TestWebServerConfig.cs b/dotnet/test/testing.webserver/Handlers/RedirectHandler.cs similarity index 60% rename from dotnet/test/webdriver/Infrastructure/Environment/TestWebServerConfig.cs rename to dotnet/test/testing.webserver/Handlers/RedirectHandler.cs index 03368d0098924..a89852c925eae 100644 --- a/dotnet/test/webdriver/Infrastructure/Environment/TestWebServerConfig.cs +++ b/dotnet/test/testing.webserver/Handlers/RedirectHandler.cs @@ -1,4 +1,4 @@ -// +// // Licensed to the Software Freedom Conservancy (SFC) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information @@ -17,18 +17,20 @@ // under the License. // -using System.Text.Json.Serialization; +using Microsoft.AspNetCore.Http; -namespace OpenQA.Selenium.Tests.Infrastructure.Environment; +namespace OpenQA.Selenium.Testing.WebServer.Handlers; -public class TestWebServerConfig +public static class RedirectHandler { - public bool CaptureConsoleOutput { get; set; } + public static IResult Handle(HttpContext context) + { + string path = context.Request.Path.Value ?? "/"; + string basePath = path.Contains("/redirect") + ? path[..path.IndexOf("/redirect")] + : ""; + string targetLocation = $"{basePath}/resultPage.html"; - public bool HideCommandPromptWindow { get; set; } - - public string JavaHomeDirectory { get; set; } - - [JsonIgnore] - public string Port { get; set; } + return Results.Redirect(targetLocation); + } } diff --git a/dotnet/test/testing.webserver/Handlers/SleepHandler.cs b/dotnet/test/testing.webserver/Handlers/SleepHandler.cs new file mode 100644 index 0000000000000..216af9b6175fa --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/SleepHandler.cs @@ -0,0 +1,42 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class SleepHandler +{ + public static async Task Handle(HttpContext context) + { + string? duration = context.Request.Query["time"]; + int seconds = int.Parse(duration!); + + await Task.Delay(seconds * 1000); + + string html = $"DoneSlept for {duration}s"; + + context.Response.Headers.CacheControl = "no-cache"; + context.Response.Headers.Pragma = "no-cache"; + context.Response.Headers.Expires = "0"; + + return Results.Content(html, "text/html; charset=utf-8"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/UploadHandler.cs b/dotnet/test/testing.webserver/Handlers/UploadHandler.cs new file mode 100644 index 0000000000000..d4daee22f1785 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/UploadHandler.cs @@ -0,0 +1,47 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class UploadHandler +{ + public static async Task Handle(HttpContext context) + { + var form = await context.Request.ReadFormAsync(); + string content = string.Empty; + + var uploadFile = form.Files["upload"]; + if (uploadFile is not null) + { + using var reader = new StreamReader(uploadFile.OpenReadStream()); + content = await reader.ReadToEndAsync(); + } + + // Slow down the upload so we can verify WebDriver waits. + await Task.Delay(2500); + + string html = content + ""; + + return Results.Content(html, "text/html; charset=utf-8"); + } +} diff --git a/dotnet/test/testing.webserver/Handlers/Utf8Handler.cs b/dotnet/test/testing.webserver/Handlers/Utf8Handler.cs new file mode 100644 index 0000000000000..ddc41c76691a0 --- /dev/null +++ b/dotnet/test/testing.webserver/Handlers/Utf8Handler.cs @@ -0,0 +1,41 @@ +// +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; + +namespace OpenQA.Selenium.Testing.WebServer.Handlers; + +public static class Utf8Handler +{ + public static async Task Handle(HttpContext context, string path, string webContentRoot) + { + string filePath = Path.Combine(webContentRoot, path); + + if (!File.Exists(filePath)) + { + return Results.NotFound(); + } + + string content = await File.ReadAllTextAsync(filePath); + + return Results.Content(content, "text/html; charset=UTF-8"); + } +} diff --git a/dotnet/test/testing.webserver/Selenium.Testing.WebServer.csproj b/dotnet/test/testing.webserver/Selenium.Testing.WebServer.csproj new file mode 100644 index 0000000000000..99aaf96fd6708 --- /dev/null +++ b/dotnet/test/testing.webserver/Selenium.Testing.WebServer.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + Testing.WebServer + OpenQA.Selenium.Testing.WebServer + enable + + + + + + + diff --git a/dotnet/test/webdriver/BUILD.bazel b/dotnet/test/webdriver/BUILD.bazel index 7c56eaa6a6947..735af168a2cb9 100644 --- a/dotnet/test/webdriver/BUILD.bazel +++ b/dotnet/test/webdriver/BUILD.bazel @@ -11,8 +11,6 @@ filegroup( "//dotnet/src/webdriver:manager-linux", "//dotnet/src/webdriver:manager-macos", "//dotnet/src/webdriver:manager-windows", - "//java/test/org/openqa/selenium/environment:appserver", - "//java/test/org/openqa/selenium/environment:keystore", "//javascript/atoms", "//third_party/closure/goog", "//third_party/js/selenium:webdriver_json", @@ -39,10 +37,12 @@ dotnet_nunit_test_suite( data = [ ":test-data", ], + project_sdk = "web", target_frameworks = ["net8.0"], visibility = ["//dotnet/test:__subpackages__"], deps = [ "//dotnet/src/webdriver:webdriver-net8.0", + "//dotnet/test/testing.webserver", nuget_package("BenderProxy"), nuget_package("NUnit"), nuget_package("Runfiles"), diff --git a/dotnet/test/webdriver/CookieImplementationTests.cs b/dotnet/test/webdriver/CookieImplementationTests.cs index 4a6165e1221be..29127b9f47454 100644 --- a/dotnet/test/webdriver/CookieImplementationTests.cs +++ b/dotnet/test/webdriver/CookieImplementationTests.cs @@ -35,7 +35,7 @@ public class CookieImplementationTests : DriverTestFixture [SetUp] public void GoToSimplePageAndDeleteCookies() { - GotoValidDomainAndClearCookies("animals"); + GotoValidDomainAndClearCookies("simpleTest.html"); AssertNoCookiesArePresent(); } @@ -176,10 +176,8 @@ public void AddCookiesWithDifferentPathsThatAreRelatedToOurs() return; } - string basePath = EnvironmentManager.Instance.UrlBuilder.Path; - - Cookie cookie1 = new Cookie("fish", "cod", "/" + basePath + "/animals"); - Cookie cookie2 = new Cookie("planet", "earth", "/" + basePath + "/"); + Cookie cookie1 = new Cookie("fish", "cod", "/common/animals"); + Cookie cookie2 = new Cookie("planet", "earth", "/common/"); IOptions options = driver.Manage(); options.Cookies.AddCookie(cookie1); options.Cookies.AddCookie(cookie2); @@ -361,19 +359,17 @@ public void ShouldWalkThePathToDeleteACookie() return; } - string basePath = EnvironmentManager.Instance.UrlBuilder.Path; - Cookie cookie1 = new Cookie("fish", "cod"); driver.Manage().Cookies.AddCookie(cookie1); int count = driver.Manage().Cookies.AllCookies.Count; driver.Url = childPage; - Cookie cookie2 = new Cookie("rodent", "hamster", "/" + basePath + "/child"); + Cookie cookie2 = new Cookie("rodent", "hamster", "/common/child"); driver.Manage().Cookies.AddCookie(cookie2); count = driver.Manage().Cookies.AllCookies.Count; driver.Url = grandchildPage; - Cookie cookie3 = new Cookie("dog", "dalmatian", "/" + basePath + "/child/grandchild/"); + Cookie cookie3 = new Cookie("dog", "dalmatian", "/common/child/grandchild/"); driver.Manage().Cookies.AddCookie(cookie3); count = driver.Manage().Cookies.AllCookies.Count; @@ -648,9 +644,8 @@ public void CanSetCookiesOnADifferentPathOfTheSameHost() return; } - string basePath = EnvironmentManager.Instance.UrlBuilder.Path; - Cookie cookie1 = new Cookie("fish", "cod", "/" + basePath + "/animals"); - Cookie cookie2 = new Cookie("planet", "earth", "/" + basePath + "/galaxy"); + Cookie cookie1 = new Cookie("fish", "cod", "/common/animals"); + Cookie cookie2 = new Cookie("planet", "earth", "/common/galaxy"); IOptions options = driver.Manage(); ReadOnlyCollection count = options.Cookies.AllCookies; @@ -727,7 +722,7 @@ public void ShouldAddCookieToCurrentDomainAndPath() driver.Url = macbethPage; IOptions options = driver.Manage(); - Cookie cookie = new Cookie("Homer", "Simpson", this.hostname, "/" + EnvironmentManager.Instance.UrlBuilder.Path, null); + Cookie cookie = new Cookie("Homer", "Simpson", this.hostname, "/common", null); options.Cookies.AddCookie(cookie); ReadOnlyCollection cookies = options.Cookies.AllCookies; Assert.That(cookies, Does.Contain(cookie), "Valid cookie was not returned"); @@ -743,7 +738,7 @@ public void ShouldNotShowCookieAddedToDifferentDomain() driver.Url = macbethPage; IOptions options = driver.Manage(); - Cookie cookie = new Cookie("Bart", "Simpson", EnvironmentManager.Instance.UrlBuilder.HostName + ".com", EnvironmentManager.Instance.UrlBuilder.Path, null); + Cookie cookie = new Cookie("Bart", "Simpson", EnvironmentManager.Instance.UrlBuilder.HostName + ".com", "/common", null); Assert.That( () => options.Cookies.AddCookie(cookie), Throws.InstanceOf().Or.InstanceOf()); @@ -771,7 +766,7 @@ public void ShouldNotShowCookieAddedToDifferentPath() driver.Url = macbethPage; IOptions options = driver.Manage(); - Cookie cookie = new Cookie("Lisa", "Simpson", EnvironmentManager.Instance.UrlBuilder.HostName, "/" + EnvironmentManager.Instance.UrlBuilder.Path + "IDoNotExist", null); + Cookie cookie = new Cookie("Lisa", "Simpson", EnvironmentManager.Instance.UrlBuilder.HostName, "/commonIDoNotExist", null); options.Cookies.AddCookie(cookie); ReadOnlyCollection cookies = options.Cookies.AllCookies; Assert.That(cookies, Does.Not.Contain(cookie), "Invalid cookie was returned"); diff --git a/dotnet/test/webdriver/Infrastructure/Environment/EnvironmentManager.cs b/dotnet/test/webdriver/Infrastructure/Environment/EnvironmentManager.cs index a1dc5a2c11d23..15b14ffd21ce8 100644 --- a/dotnet/test/webdriver/Infrastructure/Environment/EnvironmentManager.cs +++ b/dotnet/test/webdriver/Infrastructure/Environment/EnvironmentManager.cs @@ -21,7 +21,7 @@ using System.Runtime.InteropServices; using System.Text.Json; using Bazel; -using OpenQA.Selenium.Internal; +using OpenQA.Selenium.Testing.WebServer; namespace OpenQA.Selenium.Tests.Infrastructure.Environment; @@ -58,18 +58,7 @@ private EnvironmentManager() string browserLocation = System.Environment.GetEnvironmentVariable("BROWSER_LOCATION") ?? TestContext.Parameters.Get("BrowserLocation", string.Empty); - string activeWebsiteConfig = TestContext.Parameters.Get("ActiveWebsiteConfig", env.ActiveWebsiteConfig); DriverConfig driverConfig = env.DriverConfigs[activeDriverConfig]; - WebsiteConfig websiteConfig = env.WebSiteConfigs[activeWebsiteConfig]; - - int port = PortUtilities.FindFreePort(); - websiteConfig.Port = port.ToString(); - - TestWebServerConfig webServerConfig = env.TestWebServerConfig; - webServerConfig.CaptureConsoleOutput = TestContext.Parameters.Get("CaptureWebServerOutput", env.TestWebServerConfig.CaptureConsoleOutput); - webServerConfig.HideCommandPromptWindow = TestContext.Parameters.Get("HideWebServerCommandPrompt", env.TestWebServerConfig.HideCommandPromptWindow); - webServerConfig.JavaHomeDirectory = TestContext.Parameters.Get("WebServerJavaHome", env.TestWebServerConfig.JavaHomeDirectory); - webServerConfig.Port = websiteConfig.Port; this.driverFactory = new DriverFactory(driverServiceLocation, browserLocation); this.driverFactory.DriverStarting += OnDriverStarting; @@ -90,70 +79,10 @@ private EnvironmentManager() Browser = driverConfig.BrowserValue; RemoteCapabilities = driverConfig.RemoteCapabilities; - UrlBuilder = new UrlBuilder(websiteConfig); - - // When run using the `bazel test` command, the following environment - // variable will be set. If not set, we're running from a build system - // outside Bazel, and need to locate the directory containing the jar. - string projectRoot = System.Environment.GetEnvironmentVariable("TEST_SRCDIR"); - if (string.IsNullOrEmpty(projectRoot)) - { - // Walk up the directory tree until we find ourselves in a directory - // where the path to the Java web server can be determined. - bool continueTraversal = true; - DirectoryInfo info = new DirectoryInfo(currentDirectory); - while (continueTraversal) - { - if (info == info.Root) - { - break; - } - - foreach (var childDir in info.EnumerateDirectories()) - { - // Case 1: The current directory of this assembly is in the - // same direct sub-tree as the Java targets (usually meaning - // executing tests from the same build system as that which - // builds the Java targets). - // If we find a child directory named "java", then the web - // server should be able to be found under there. - if (string.Compare(childDir.Name, "java", StringComparison.OrdinalIgnoreCase) == 0) - { - continueTraversal = false; - break; - } - - // Case 2: The current directory of this assembly is a different - // sub-tree as the Java targets (usually meaning executing tests - // from a different build system as that which builds the Java - // targets). - // If we travel to a place in the tree where there is a child - // directory named "bazel-bin", the web server should be found - // in the "java" subdirectory of that directory. - if (string.Compare(childDir.Name, "bazel-bin", StringComparison.OrdinalIgnoreCase) == 0) - { - string javaOutDirectory = Path.Combine(childDir.FullName, "java"); - if (Directory.Exists(javaOutDirectory)) - { - info = childDir; - continueTraversal = false; - break; - } - } - } - - if (continueTraversal) - { - info = info.Parent; - } - } + WebServer = new AppServer(); + var (httpUrl, httpsUrl) = WebServer.StartAsync().Result; - projectRoot = info.FullName; - } - else - { - projectRoot += "/_main"; - } + UrlBuilder = new UrlBuilder(httpUrl, httpsUrl); // Find selenium-manager binary. try @@ -181,7 +110,16 @@ private EnvironmentManager() // Use the default one. } - WebServer = new TestWebServer(projectRoot, webServerConfig); + string projectRoot = System.Environment.GetEnvironmentVariable("TEST_SRCDIR"); + if (!string.IsNullOrEmpty(projectRoot)) + { + projectRoot += "/_main"; + } + else + { + projectRoot = FindProjectRoot(currentDirectory); + } + bool autoStartRemoteServer = false; if (Browser == Browser.Remote) { @@ -218,7 +156,7 @@ public string CurrentDirectory } } - public TestWebServer WebServer { get; } + public AppServer WebServer { get; } public RemoteSeleniumServer RemoteServer { get; } @@ -258,4 +196,21 @@ protected void OnDriverStarting(object sender, DriverStartingEventArgs e) { this.DriverStarting?.Invoke(sender, e); } + + private static string FindProjectRoot(string startDirectory) + { + // Walk up until we find a directory containing common/ and dotnet/ + DirectoryInfo info = new DirectoryInfo(startDirectory); + while (info is not null && info != info.Root) + { + if (Directory.Exists(Path.Combine(info.FullName, "common")) + && Directory.Exists(Path.Combine(info.FullName, "dotnet"))) + { + return info.FullName; + } + info = info.Parent; + } + + return startDirectory; + } } diff --git a/dotnet/test/webdriver/Infrastructure/Environment/TestEnvironment.cs b/dotnet/test/webdriver/Infrastructure/Environment/TestEnvironment.cs index fa54224fbb506..672d80fe07e59 100644 --- a/dotnet/test/webdriver/Infrastructure/Environment/TestEnvironment.cs +++ b/dotnet/test/webdriver/Infrastructure/Environment/TestEnvironment.cs @@ -29,11 +29,5 @@ internal class TestEnvironment public string ActiveDriverConfig { get; set; } - public string ActiveWebsiteConfig { get; set; } - - public Dictionary WebSiteConfigs { get; set; } - public Dictionary DriverConfigs { get; set; } - - public TestWebServerConfig TestWebServerConfig { get; set; } } diff --git a/dotnet/test/webdriver/Infrastructure/Environment/TestWebServer.cs b/dotnet/test/webdriver/Infrastructure/Environment/TestWebServer.cs deleted file mode 100644 index dab321883df44..0000000000000 --- a/dotnet/test/webdriver/Infrastructure/Environment/TestWebServer.cs +++ /dev/null @@ -1,164 +0,0 @@ -// -// Licensed to the Software Freedom Conservancy (SFC) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The SFC licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// - -using System.Diagnostics; -using System.IO; -using System.Net; -using System.Net.Http; -using Bazel; - -namespace OpenQA.Selenium.Tests.Infrastructure.Environment; - -public class TestWebServer(string projectRoot, TestWebServerConfig config) -{ - private Process webserverProcess; - - private string standaloneAppserverPath; - private bool captureWebServerOutput = config.CaptureConsoleOutput; - private readonly bool hideCommandPrompt = config.HideCommandPromptWindow; - private readonly string port = config.Port; - - public async Task StartAsync() - { - if (webserverProcess == null || webserverProcess.HasExited) - { - try - { - var runfiles = Runfiles.Create(); - - var standaloneAppserverProbingPath = @"_main/java/test/org/openqa/selenium/environment/appserver"; - - if (OperatingSystem.IsWindows()) - { - standaloneAppserverProbingPath += ".exe"; - } - - standaloneAppserverPath = runfiles.Rlocation(standaloneAppserverProbingPath); - } - catch (FileNotFoundException) - { - // means we are NOT running under bazel runtime - // most likely in IDE - } - - var processFileName = standaloneAppserverPath ?? "bazel"; - - string processArguments = $"{port}"; - - if (standaloneAppserverPath is null) - { - processArguments = $"run //java/test/org/openqa/selenium/environment:appserver {processArguments}"; - - // Override project root path to be exact selenium repo path, not 'bazel-bin' - projectRoot = Path.Combine(AppContext.BaseDirectory, "../../../../../.."); - } - - webserverProcess = new Process(); - - webserverProcess.StartInfo.FileName = processFileName; - webserverProcess.StartInfo.Arguments = processArguments; - webserverProcess.StartInfo.WorkingDirectory = projectRoot; - webserverProcess.StartInfo.UseShellExecute = !(hideCommandPrompt || captureWebServerOutput); - webserverProcess.StartInfo.CreateNoWindow = hideCommandPrompt; - - captureWebServerOutput = true; - - if (captureWebServerOutput) - { - webserverProcess.StartInfo.RedirectStandardOutput = true; - webserverProcess.StartInfo.RedirectStandardError = true; - } - - webserverProcess.Start(); - - TimeSpan timeout = TimeSpan.FromSeconds(30); - DateTime endTime = DateTime.Now.Add(TimeSpan.FromSeconds(30)); - bool isRunning = false; - - // Poll until the webserver is correctly serving pages. - using var httpClient = new HttpClient(); - - while (!isRunning && DateTime.Now < endTime) - { - try - { - using var response = await httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("simpleTest.html")); - - if (response.StatusCode == HttpStatusCode.OK) - { - isRunning = true; - } - } - catch (Exception ex) when (ex is HttpRequestException || ex is TimeoutException) - { - } - } - - if (!isRunning) - { - string output = "'CaptureWebServerOutput' parameter is false. Web server output not captured"; - string error = "'CaptureWebServerOutput' parameter is false. Web server output not being captured."; - if (captureWebServerOutput) - { - error = webserverProcess.StandardError.ReadToEnd(); - output = webserverProcess.StandardOutput.ReadToEnd(); - } - - string errorMessage = string.Format("Could not start the test web server in {0} seconds.\nWorking directory: {1}\nProcess Args: {2}\nstdout: {3}\nstderr: {4}", timeout.TotalSeconds, projectRoot, processArguments, output, error); - - throw new TimeoutException(errorMessage); - } - } - } - - public async Task StopAsync() - { - if (webserverProcess != null) - { - using (var httpClient = new HttpClient()) - { - try - { - using (await httpClient.GetAsync(EnvironmentManager.Instance.UrlBuilder.LocalWhereIs("quitquitquit"))) - { - - } - } - catch (HttpRequestException) - { - - } - } - - try - { - webserverProcess.WaitForExit(10000); - if (!webserverProcess.HasExited) - { - webserverProcess.Kill(entireProcessTree: true); - } - } - finally - { - webserverProcess.Dispose(); - webserverProcess = null; - } - } - } -} diff --git a/dotnet/test/webdriver/Infrastructure/Environment/UrlBuilder.cs b/dotnet/test/webdriver/Infrastructure/Environment/UrlBuilder.cs index 45087694dd10b..4add226e07704 100644 --- a/dotnet/test/webdriver/Infrastructure/Environment/UrlBuilder.cs +++ b/dotnet/test/webdriver/Infrastructure/Environment/UrlBuilder.cs @@ -27,23 +27,18 @@ namespace OpenQA.Selenium.Tests.Infrastructure.Environment; public class UrlBuilder { - private readonly string protocol; - private readonly string port; - private readonly string securePort; + private readonly Uri _httpBaseUrl; + private readonly Uri _httpsBaseUrl; - public string AlternateHostName { get; } - - public string HostName { get; } + public string HostName => _httpBaseUrl.Host; - public string Path { get; } + public string AlternateHostName { get; } - public UrlBuilder(WebsiteConfig config) + public UrlBuilder(string httpUrl, string httpsUrl) { - protocol = config.Protocol; - HostName = config.HostName; - port = config.Port; - securePort = config.SecurePort; - Path = config.Folder; + _httpBaseUrl = new Uri(httpUrl); + _httpsBaseUrl = new Uri(httpsUrl); + //Use the first IPv4 address that we find IPAddress ipAddress = IPAddress.Parse("127.0.0.1"); foreach (IPAddress ip in Dns.GetHostEntry(HostName).AddressList) @@ -57,25 +52,14 @@ public UrlBuilder(WebsiteConfig config) AlternateHostName = ipAddress.ToString(); } - public string LocalWhereIs(string page) - { - string location = "http://localhost:" + port + "/" + Path + "/" + page; - - return location; - } - public string WhereIs(string page) { - string location = "http://" + HostName + ":" + port + "/" + Path + "/" + page; - - return location; + return _httpBaseUrl + "common/" + page; } public string WhereElseIs(string page) { - string location = "http://" + AlternateHostName + ":" + port + "/" + Path + "/" + page; - - return location; + return new UriBuilder(_httpBaseUrl) { Host = AlternateHostName } + "common/" + page; } public string WhereIsViaNonLoopbackAddress(string page) @@ -90,16 +74,12 @@ public string WhereIsViaNonLoopbackAddress(string page) break; } } - string location = "http://" + hostNameAsIPAddress + ":" + port + "/" + Path + "/" + page; - - return location; + return new UriBuilder(_httpBaseUrl) { Host = hostNameAsIPAddress } + "common/" + page; } public string WhereIsSecure(string page) { - string location = "https://" + HostName + ":" + securePort + "/" + Path + "/" + page; - - return location; + return _httpsBaseUrl + "common/" + page; } public string CreateInlinePage(InlinePage page) { diff --git a/dotnet/test/webdriver/PositionAndSizeTests.cs b/dotnet/test/webdriver/PositionAndSizeTests.cs index 0f8b4b703936c..7946fdaf453bb 100644 --- a/dotnet/test/webdriver/PositionAndSizeTests.cs +++ b/dotnet/test/webdriver/PositionAndSizeTests.cs @@ -154,14 +154,14 @@ public void ShouldHandleNonIntegerPositionAndSize() IWebElement r2 = driver.FindElement(By.Id("r2")); string left = r2.GetCssValue("left"); - Assert.That(Math.Round(Convert.ToDecimal(left.Replace("px", "")), 1), Is.EqualTo(10.9)); + Assert.That(Math.Round(decimal.Parse(left.Replace("px", ""), System.Globalization.CultureInfo.InvariantCulture), 1), Is.EqualTo(10.9)); string top = r2.GetCssValue("top"); - Assert.That(Math.Round(Convert.ToDecimal(top.Replace("px", "")), 1), Is.EqualTo(10.1)); + Assert.That(Math.Round(decimal.Parse(top.Replace("px", ""), System.Globalization.CultureInfo.InvariantCulture), 1), Is.EqualTo(10.1)); Assert.That(r2.Location, Is.EqualTo(new Point(11, 10))); string width = r2.GetCssValue("width"); - Assert.That(Math.Round(Convert.ToDecimal(width.Replace("px", "")), 1), Is.EqualTo(48.7)); + Assert.That(Math.Round(decimal.Parse(width.Replace("px", ""), System.Globalization.CultureInfo.InvariantCulture), 1), Is.EqualTo(48.7)); string height = r2.GetCssValue("height"); - Assert.That(Math.Round(Convert.ToDecimal(height.Replace("px", "")), 1), Is.EqualTo(49.3)); + Assert.That(Math.Round(decimal.Parse(height.Replace("px", ""), System.Globalization.CultureInfo.InvariantCulture), 1), Is.EqualTo(49.3)); Assert.That(r2.Size, Is.EqualTo(new Size(49, 49))); } diff --git a/dotnet/test/webdriver/Selenium.WebDriver.Tests.csproj b/dotnet/test/webdriver/Selenium.WebDriver.Tests.csproj index a6b48b81cc7c5..20a80804aa44d 100644 --- a/dotnet/test/webdriver/Selenium.WebDriver.Tests.csproj +++ b/dotnet/test/webdriver/Selenium.WebDriver.Tests.csproj @@ -20,6 +20,7 @@ + @@ -32,8 +33,4 @@ - - - - diff --git a/dotnet/test/webdriver/appconfig.json b/dotnet/test/webdriver/appconfig.json index 3edf07a838bdf..52cc39c0d1d8e 100644 --- a/dotnet/test/webdriver/appconfig.json +++ b/dotnet/test/webdriver/appconfig.json @@ -1,28 +1,6 @@ { "DriverServiceLocation": "", "ActiveDriverConfig": "Chrome", - "ActiveWebsiteConfig": "Default", - "TestWebServerConfig": { - "CaptureConsoleOutput": false, - "HideCommandPromptWindow": true, - "JavaHomeDirectory": "" - }, - "WebsiteConfigs": { - "Default": { - "Protocol": "http", - "HostName": "localhost", - "Port": "2310", - "SecurePort": "2410", - "Folder": "common" - }, - "HostsFileRedirect": { - "Protocol": "http", - "HostName": "www.seleniumhq-test.test", - "Port": "2310", - "SecurePort": "2410", - "Folder": "common" - } - }, "DriverConfigs": { "Chrome": { "DriverTypeName": "OpenQA.Selenium.Tests.Infrastructure.DriverConfigs.StableChannelChromeDriver",