blob: 1949ace343c2328d99a7ee6a2451a90c480b7861 [file]
// <copyright file="EnvironmentManager.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 System.IO;
using System.Runtime.InteropServices;
using System.Text.Json;
using Bazel;
namespace OpenQA.Selenium.Tests.Infrastructure.Environment;
public class EnvironmentManager
{
private static EnvironmentManager instance;
private readonly Type driverType;
private IWebDriver driver;
private readonly DriverFactory driverFactory;
private EnvironmentManager()
{
string dataFilePath;
Runfiles runfiles = null;
try
{
runfiles = Runfiles.Create();
dataFilePath = runfiles.Rlocation("_main/dotnet/test/webdriver/appconfig.json");
}
catch (FileNotFoundException)
{
dataFilePath = "appconfig.json";
}
string currentDirectory = this.CurrentDirectory;
string content = File.ReadAllText(dataFilePath);
TestEnvironment env = JsonSerializer.Deserialize<TestEnvironment>(content, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
string activeDriverConfig = System.Environment.GetEnvironmentVariable("ACTIVE_DRIVER_CONFIG") ?? TestContext.Parameters.Get("ActiveDriverConfig", env.ActiveDriverConfig);
string driverServiceLocation = System.Environment.GetEnvironmentVariable("DRIVER_SERVICE_LOCATION") ?? TestContext.Parameters.Get("DriverServiceLocation", env.DriverServiceLocation);
string browserLocation = System.Environment.GetEnvironmentVariable("BROWSER_LOCATION") ?? TestContext.Parameters.Get("BrowserLocation", string.Empty);
// Bazel's $(location ...) expands to a runfiles-relative path (e.g.
// "../+pin_browsers_extension+mac_chrome/Chrome.app/Contents/MacOS/Chrome")
// which is relative to <runfiles>/_main. The driver process runs from a
// different cwd and cannot resolve that, so absolutize through TEST_SRCDIR.
driverServiceLocation = ResolveRunfilesPath(driverServiceLocation);
browserLocation = ResolveRunfilesPath(browserLocation);
DriverConfig driverConfig = env.DriverConfigs[activeDriverConfig];
this.driverFactory = new DriverFactory(driverServiceLocation, browserLocation);
this.driverFactory.DriverStarting += OnDriverStarting;
// Search for the driver type in the all assemblies,
// bazel uses unpredictable assembly names to execute tests
driverType = AppDomain.CurrentDomain.GetAssemblies()
.AsEnumerable()
.Reverse()
.Select(assembly => assembly.GetType(driverConfig.DriverTypeName))
.FirstOrDefault(t => t != null);
if (driverType == null)
{
throw new ArgumentOutOfRangeException($"Unable to find driver type {driverConfig.DriverTypeName}");
}
Browser = driverConfig.BrowserValue;
RemoteCapabilities = driverConfig.RemoteCapabilities;
WebServer = new AppServer();
WebServer.StartAsync().GetAwaiter().GetResult();
// Find selenium-manager binary.
try
{
string managerFilePath = "";
runfiles ??= Runfiles.Create();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
managerFilePath = runfiles.Rlocation("_main/dotnet/src/webdriver/manager/windows/selenium-manager.exe");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var linuxArch = RuntimeInformation.ProcessArchitecture == Architecture.Arm64 ? "arm64" : "x86_64";
managerFilePath = runfiles.Rlocation($"_main/dotnet/src/webdriver/manager/linux-{linuxArch}/selenium-manager");
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
managerFilePath = runfiles.Rlocation("_main/dotnet/src/webdriver/manager/macos/selenium-manager");
}
System.Environment.SetEnvironmentVariable("SE_MANAGER_PATH", managerFilePath);
}
catch (FileNotFoundException)
{
// Use the default one.
}
string projectRoot = System.Environment.GetEnvironmentVariable("TEST_SRCDIR");
if (!string.IsNullOrEmpty(projectRoot))
{
projectRoot += "/_main";
}
else
{
projectRoot = FindProjectRoot(currentDirectory);
}
bool autoStartRemoteServer = false;
if (Browser == Browser.Remote)
{
autoStartRemoteServer = driverConfig.AutoStartRemoteServer;
}
RemoteServer = new RemoteSeleniumServer(projectRoot, autoStartRemoteServer);
}
~EnvironmentManager()
{
RemoteServer?.StopAsync().Wait();
WebServer?.StopAsync().Wait();
CloseCurrentDriver();
}
public event EventHandler<DriverStartingEventArgs> DriverStarting;
public static EnvironmentManager Instance => instance ??= new EnvironmentManager();
public Browser Browser { get; }
public string CurrentDirectory
{
get
{
string assemblyLocation = Path.GetDirectoryName(typeof(EnvironmentManager).Assembly.Location);
string testDirectory = TestContext.CurrentContext.TestDirectory;
if (assemblyLocation != testDirectory)
{
return assemblyLocation;
}
return testDirectory;
}
}
public AppServer WebServer { get; }
public RemoteSeleniumServer RemoteServer { get; }
public string RemoteCapabilities { get; }
public IWebDriver GetCurrentDriver()
{
return driver ?? CreateFreshDriver();
}
public IWebDriver CreateDriverInstance()
{
return driverFactory.CreateDriver(driverType);
}
public IWebDriver CreateDriverInstance(DriverOptions options)
{
return driverFactory.CreateDriverWithOptions(driverType, options);
}
public IWebDriver CreateFreshDriver()
{
CloseCurrentDriver();
driver = CreateDriverInstance();
return driver;
}
public void CloseCurrentDriver()
{
driver?.Quit();
driver = null;
}
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;
}
private static string ResolveRunfilesPath(string path)
{
if (string.IsNullOrEmpty(path) || Path.IsPathRooted(path))
{
return path;
}
string srcdir = System.Environment.GetEnvironmentVariable("TEST_SRCDIR");
if (string.IsNullOrEmpty(srcdir))
{
return path;
}
// Bazel $(location ...) emits paths relative to <runfiles>/_main.
return Path.GetFullPath(Path.Combine(srcdir, "_main", path));
}
}