blob: 51e2070688b5364ea5c6d08090ffc920f12b0aa1 [file] [log] [blame] [edit]
// <copyright file="TestWebServer.cs" company="Selenium Committers">
// 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.
// </copyright>
using Bazel;
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace OpenQA.Selenium.Environment;
public class TestWebServer
{
private Process webserverProcess;
private string standaloneAppserverPath;
private string projectRootPath;
private bool captureWebServerOutput;
private bool hideCommandPrompt;
private string port;
public TestWebServer(string projectRoot, TestWebServerConfig config)
{
this.projectRootPath = projectRoot;
this.captureWebServerOutput = config.CaptureConsoleOutput;
this.hideCommandPrompt = config.HideCommandPromptWindow;
this.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'
projectRootPath = Path.Combine(AppContext.BaseDirectory, "../../../../../..");
}
webserverProcess = new Process();
webserverProcess.StartInfo.FileName = processFileName;
webserverProcess.StartInfo.Arguments = processArguments;
webserverProcess.StartInfo.WorkingDirectory = projectRootPath;
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, projectRootPath, 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;
}
}
}
}