Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for chrome for testing apis #254

Merged
merged 5 commits into from
Jul 30, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion WebDriverManager.Tests/ChromeConfigTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,19 @@ public void VersionTest()
}

[Fact]
public void DriverDownloadTest()
public void DriverDownloadLatestTest()
{
new DriverManager().SetUpDriver(new ChromeConfig());
Assert.NotEmpty(WebDriverFinder.FindFile(GetBinaryName()));
}

[Fact]
public void DriverDownloadFromChromeStorageTest()
{
// Oldest stored version from https://chromedriver.storage.googleapis.com/index.html?path=73.0.3683.68/
var oldVersion = "73.0.3683.68";
new DriverManager().SetUpDriver(new ChromeConfig(), oldVersion);
Assert.NotEmpty(WebDriverFinder.FindFile(GetBinaryName()));
}
}
}
164 changes: 138 additions & 26 deletions WebDriverManager/DriverConfigs/Impl/ChromeConfig.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,36 @@
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using WebDriverManager.Helpers;
using WebDriverManager.Models.Chrome;

namespace WebDriverManager.DriverConfigs.Impl
{
public class ChromeConfig : IDriverConfig
{
private const string BaseVersionPatternUrl = "https://chromedriver.storage.googleapis.com/<version>/";
private const string LatestReleaseVersionUrl = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE";
private const string ExactReleaseVersionPatternUrl = "https://chromedriver.storage.googleapis.com/LATEST_RELEASE_<version>";

private const string ExactReleaseVersionPatternUrl =
"https://chromedriver.storage.googleapis.com/LATEST_RELEASE_<version>";
/// <summary>
/// The minimum version required to download chrome drivers from Chrome for Testing API's
/// </summary>
private static readonly Version MinChromeForTestingDriverVersion = new Version("115.0.5763.0");

/// <summary>
/// The minimum version of chrome driver required to reference download URLs via the "arm64" extension
/// </summary>
private static readonly Version MinArm64ExtensionVersion = new Version("106.0.5249.61");

private readonly ChromeForTestingClient _chromeForTestingClient;
private ChromeVersionInfo _chromeVersionInfo;
private string _chromeVersion;

public ChromeConfig()
{
_chromeForTestingClient = new ChromeForTestingClient();
}

public virtual string GetName()
{
Expand All @@ -31,23 +49,14 @@ public virtual string GetUrl64()

private string GetUrl()
{
#if NETSTANDARD
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
// Handle newer versions of chrome driver only being available for download via the Chrome for Testing API's
// whilst retaining backwards compatibility for older versions of chrome/chrome driver.
if (_chromeVersionInfo != null)
{
var architectureExtension =
RuntimeInformation.ProcessArchitecture == System.Runtime.InteropServices.Architecture.Arm64
? "_arm64"
: "64";
return $"{BaseVersionPatternUrl}chromedriver_mac{architectureExtension}.zip";
return GetUrlFromChromeForTestingApi();
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return $"{BaseVersionPatternUrl}chromedriver_linux64.zip";
}
#endif

return $"{BaseVersionPatternUrl}chromedriver_win32.zip";
return GetUrlFromChromeStorage();
}

public virtual string GetBinaryName()
Expand All @@ -63,10 +72,49 @@ public virtual string GetBinaryName()

public virtual string GetLatestVersion()
{
return GetLatestVersion(LatestReleaseVersionUrl);
var chromeReleases = _chromeForTestingClient.GetLastKnownGoodVersions().Result;
var chromeStable = chromeReleases.Channels.Stable;

_chromeVersionInfo = new ChromeVersionInfo
{
Downloads = chromeStable.Downloads
};

return chromeStable.Version;
}

public virtual string GetMatchingBrowserVersion()
{
var rawChromeBrowserVersion = GetRawBrowserVersion();
if (string.IsNullOrEmpty(rawChromeBrowserVersion))
{
throw new Exception("Not able to get chrome version or not installed");
}

var chromeVersion = VersionHelper.GetVersionWithoutRevision(rawChromeBrowserVersion);

// Handle downloading versions of the chrome webdriver less than what's supported by the Chrome for Testing known good versions API
// See https://googlechromelabs.github.io/chrome-for-testing for more info
var matchedVersion = new Version(chromeVersion);
if (matchedVersion < MinChromeForTestingDriverVersion)
{
var url = ExactReleaseVersionPatternUrl.Replace("<version>", chromeVersion);
_chromeVersion = GetVersionFromChromeStorage(url);
}
else
{
_chromeVersion = GetVersionFromChromeForTestingApi(chromeVersion).Version;
iouym marked this conversation as resolved.
Show resolved Hide resolved
}

return _chromeVersion;
}

private static string GetLatestVersion(string url)
/// <summary>
/// Retrieves a chrome driver version string from https://chromedriver.storage.googleapis.com
/// </summary>
/// <param name="url">The request URL</param>
/// <returns>A chrome driver version string</returns>
private static string GetVersionFromChromeStorage(string url)
{
var uri = new Uri(url);
var webRequest = WebRequest.Create(uri);
Expand All @@ -84,17 +132,81 @@ private static string GetLatestVersion(string url)
}
}

public virtual string GetMatchingBrowserVersion()
/// <summary>
/// Retrieves a download URL for a chrome driver from the https://chromedriver.storage.googleapis.com API's
/// </summary>
/// <returns>A chrome driver download URL</returns>
private string GetUrlFromChromeStorage()
{
var rawChromeBrowserVersion = GetRawBrowserVersion();
if (string.IsNullOrEmpty(rawChromeBrowserVersion))
#if NETSTANDARD
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
throw new Exception("Not able to get chrome version or not installed");
// Handle older versions of chrome driver arm64 builds that are tagged with 64_m1 instead of arm64.
// See: https://chromedriver.storage.googleapis.com/index.html?path=106.0.5249.21/
var useM1Prefix = new Version(_chromeVersion) < MinArm64ExtensionVersion;
var armArchitectureExtension = useM1Prefix
? "64_m1"
: "_arm64";

var architectureExtension = RuntimeInformation.ProcessArchitecture == System.Runtime.InteropServices.Architecture.Arm64
? armArchitectureExtension
: "64";

return $"{BaseVersionPatternUrl}chromedriver_mac{architectureExtension}.zip";
}

if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return $"{BaseVersionPatternUrl}chromedriver_linux64.zip";
}
#endif

return $"{BaseVersionPatternUrl}chromedriver_win32.zip";
}

/// <summary>
/// Retrieves a chrome driver version string from https://googlechromelabs.github.io/chrome-for-testing
/// </summary>
/// <param name="version">The desired version to download</param>
/// <returns>Chrome driver version info (version number, revision number, download URLs)</returns>
private ChromeVersionInfo GetVersionFromChromeForTestingApi(string version)
{
var knownGoodVersions = _chromeForTestingClient.GetKnownGoodVersionsWithDownloads().Result;
_chromeVersionInfo = knownGoodVersions.Versions.FirstOrDefault(cV => cV.Version == version);

return _chromeVersionInfo;
}

/// <summary>
/// Retrieves a chrome driver download URL from Chrome for Testing API's
/// </summary>
/// <returns>A chrome driver download URL</returns>
private string GetUrlFromChromeForTestingApi()
{
var platform = "win32";

#if NETSTANDARD
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
platform = RuntimeInformation.ProcessArchitecture == System.Runtime.InteropServices.Architecture.Arm64
? "mac-arm64"
: "mac-x64";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
platform = "linux64";
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
platform = RuntimeInformation.ProcessArchitecture == System.Runtime.InteropServices.Architecture.X64
? "win64"
: "win32";
}
#endif
var result = _chromeVersionInfo.Downloads.ChromeDriver
.FirstOrDefault(driver => driver.Platform == platform);

var chromeBrowserVersion = VersionHelper.GetVersionWithoutRevision(rawChromeBrowserVersion);
var url = ExactReleaseVersionPatternUrl.Replace("<version>", chromeBrowserVersion);
return GetLatestVersion(url);
return result.Url;
}

private string GetRawBrowserVersion()
Expand Down
43 changes: 43 additions & 0 deletions WebDriverManager/Helpers/ChromeForTestingClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using WebDriverManager.Models.Chrome;

namespace WebDriverManager.Helpers
{
public class ChromeForTestingClient
{
private static readonly string BaseUrl = "https://googlechromelabs.github.io/chrome-for-testing/";
private static readonly JsonSerializerOptions JsonSerializerOptions = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
};

private readonly HttpClient _httpClient;

public ChromeForTestingClient()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri(BaseUrl)
};
}

public async Task<ChromeVersions> GetKnownGoodVersionsWithDownloads()
{
var response = await _httpClient.GetAsync("known-good-versions-with-downloads.json");
var jsonString = await response.Content.ReadAsStringAsync();

return JsonSerializer.Deserialize<ChromeVersions>(jsonString, JsonSerializerOptions);
}

public async Task<ChromeVersions> GetLastKnownGoodVersions()
{
var response = await _httpClient.GetAsync("last-known-good-versions-with-downloads.json");
var jsonString = await response.Content.ReadAsStringAsync();

return JsonSerializer.Deserialize<ChromeVersions>(jsonString, JsonSerializerOptions);
}
}
}
9 changes: 9 additions & 0 deletions WebDriverManager/Models/Chrome/ChromeDownload.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Collections.Generic;

namespace WebDriverManager.Models.Chrome
{
public class ChromeDownload
{
public IEnumerable<ChromePlatformInfo> ChromeDriver { get; set; }
}
}
9 changes: 9 additions & 0 deletions WebDriverManager/Models/Chrome/ChromePlatformInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace WebDriverManager.Models.Chrome
{
public class ChromePlatformInfo
{
public string Platform { get; set; }

public string Url { get; set; }
}
}
13 changes: 13 additions & 0 deletions WebDriverManager/Models/Chrome/ChromeReleaseChannels.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace WebDriverManager.Models.Chrome
{
public class ChromeReleaseChannels
{
public ChromeReleaseTrack Stable { get; set; }

public ChromeReleaseTrack Beta { get; set; }

public ChromeReleaseTrack Dev { get; set; }

public ChromeReleaseTrack Canary { get; set; }
}
}
13 changes: 13 additions & 0 deletions WebDriverManager/Models/Chrome/ChromeReleaseTrack.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace WebDriverManager.Models.Chrome
{
public class ChromeReleaseTrack
{
public string Channel { get; set; }

public string Version { get; set; }

public string Revision { get; set; }

public ChromeDownload Downloads { get; set; }
}
}
11 changes: 11 additions & 0 deletions WebDriverManager/Models/Chrome/ChromeVersionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace WebDriverManager.Models.Chrome
{
public class ChromeVersionInfo
{
public string Version { get; set; }

public string Revision { get; set; }

public ChromeDownload Downloads { get; set; }
}
}
13 changes: 13 additions & 0 deletions WebDriverManager/Models/Chrome/ChromeVersions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Collections.Generic;

namespace WebDriverManager.Models.Chrome
{
public class ChromeVersions
{
public string Timestamp { get; set; }

public ChromeReleaseChannels Channels { get; set; }

public IEnumerable<ChromeVersionInfo> Versions { get; set; }
}
}
1 change: 1 addition & 0 deletions WebDriverManager/WebDriverManager.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<PackageReference Include="AngleSharp" Version="1.0.4" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="SharpZipLib" Version="1.4.2" />
<PackageReference Include="System.Text.Json" Version="7.0.3" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'net462'">
Expand Down