Skip to content

Commit

Permalink
Allow user to specify DevTools Protocol verison in .NET
Browse files Browse the repository at this point in the history
This change introduces an overload to the `CreateDevToolsSession` method
that will allow a user to request a specific version of the protocol to
use instead of automatically detecting the version used by the browser
being automated. While using this overload can in theory help a user
avoid code changes with every browser update when their code relies on
the concrete, browser-specific protocol domains, using this overload is
still fraught with peril, and should be avoided in favor of the
version-independent API the Selenium library provides.

This change also cleans up some API details, removing, among other
things, the `Start` method of the DevToolsSession object from the
public-facing API. When the `CreateDevToolsSession` method is called,
there is no need to start the session, as it is already started.
  • Loading branch information
jimevans committed Nov 11, 2020
1 parent 9ca44d6 commit 36e141d
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 23 deletions.
13 changes: 12 additions & 1 deletion dotnet/src/webdriver/Chromium/ChromiumDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,19 @@ public object ExecuteChromeCommandWithResult(string commandName, Dictionary<stri
/// <summary>
/// Creates a session to communicate with a browser using the Chromium Developer Tools debugging protocol.
/// </summary>
/// <param name="devToolsProtocolVersion">The version of the Chromium Developer Tools protocol to use. Defaults to autodetect the protocol version.</param>
/// <returns>The active session to use to communicate with the Chromium Developer Tools debugging protocol.</returns>
public DevToolsSession CreateDevToolsSession()
{
return CreateDevToolsSession(DevToolsSession.AutoDetectDevToolsProtocolVersion);
}

/// <summary>
/// Creates a session to communicate with a browser using the Chromium Developer Tools debugging protocol.
/// </summary>
/// <param name="devToolsProtocolVersion">The version of the Chromium Developer Tools protocol to use. Defaults to autodetect the protocol version.</param>
/// <returns>The active session to use to communicate with the Chromium Developer Tools debugging protocol.</returns>
public DevToolsSession CreateDevToolsSession(int devToolsProtocolVersion)
{
if (!this.Capabilities.HasCapability(this.optionsCapabilityName))
{
Expand All @@ -190,7 +201,7 @@ public DevToolsSession CreateDevToolsSession()
try
{
DevToolsSession session = new DevToolsSession(debuggerAddress);
session.Start().ConfigureAwait(false).GetAwaiter().GetResult();
session.Start(devToolsProtocolVersion).ConfigureAwait(false).GetAwaiter().GetResult();
return session;
}
catch (Exception e)
Expand Down
23 changes: 9 additions & 14 deletions dotnet/src/webdriver/DevTools/DevToolsDomains.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,39 +71,34 @@ public abstract class DevToolsDomains
/// <summary>
/// Initializes the supplied DevTools session's domains for the specified browser version.
/// </summary>
/// <param name="versionInfo">The <see cref="DevToolsVersionInfo"/> object containing the browser version information.</param>
/// <param name="protocolVersion">The version of the DevTools Protocol to use.</param>
/// <param name="session">The <see cref="DevToolsSession"/> for which to initialiize the domains.</param>
/// <returns>The <see cref="DevToolsDomains"/> object containing the version-specific domains.</returns>
public static DevToolsDomains InitializeDomains(DevToolsVersionInfo versionInfo, DevToolsSession session)
public static DevToolsDomains InitializeDomains(int protocolVersion, DevToolsSession session)
{
return InitializeDomains(versionInfo, session, DefaultVersionRange);
return InitializeDomains(protocolVersion, session, DefaultVersionRange);
}

/// <summary>
/// Initializes the supplied DevTools session's domains for the specified browser version within the specified number of versions.
/// </summary>
/// <param name="versionInfo">The <see cref="DevToolsVersionInfo"/> object containing the browser version information.</param>
/// <param name="protocolVersion">The version of the DevTools Protocol to use.</param>
/// <param name="session">The <see cref="DevToolsSession"/> for which to initialiize the domains.</param>
/// <param name="versionRange">The range of versions within which to match the provided version number. Defaults to 5 versions.</param>
/// <returns>The <see cref="DevToolsDomains"/> object containing the version-specific domains.</returns>
public static DevToolsDomains InitializeDomains(DevToolsVersionInfo versionInfo, DevToolsSession session, int versionRange)
public static DevToolsDomains InitializeDomains(int protocolVersion, DevToolsSession session, int versionRange)
{
if (versionRange < 0)
{
throw new ArgumentException("Version range must be positive", "versionRange");
}

DevToolsDomains domains = null;
int browserMajorVersion = 0;
bool versionParsed = int.TryParse(versionInfo.BrowserMajorVersion, out browserMajorVersion);
if (versionParsed)
Type domainType = MatchDomainsVersion(protocolVersion, versionRange);
ConstructorInfo constructor = domainType.GetConstructor(new Type[] { typeof(DevToolsSession) });
if (constructor != null)
{
Type domainType = MatchDomainsVersion(browserMajorVersion, versionRange);
ConstructorInfo constructor = domainType.GetConstructor(new Type[] { typeof(DevToolsSession) });
if (constructor != null)
{
domains = constructor.Invoke(new object[] { session }) as DevToolsDomains;
}
domains = constructor.Invoke(new object[] { session }) as DevToolsDomains;
}

return domains;
Expand Down
17 changes: 15 additions & 2 deletions dotnet/src/webdriver/DevTools/DevToolsSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Net.Http;
Expand All @@ -36,6 +37,8 @@ namespace OpenQA.Selenium.DevTools
///</summary>
public class DevToolsSession : IDevToolsSession
{
public const int AutoDetectDevToolsProtocolVersion = 0;

private readonly string debuggerEndpoint;
private string websocketAddress;
private readonly TimeSpan closeConnectionWaitTimeSpan = TimeSpan.FromSeconds(2);
Expand Down Expand Up @@ -242,8 +245,9 @@ public T GetVersionSpecificDomains<T>() where T: DevToolsSessionDomains
/// <summary>
/// Asynchronously starts the session.
/// </summary>
/// <param name="protocolVersion">The version of the protocol to use in communicating with the browswer.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
public async Task Start()
internal async Task Start(int protocolVersion)
{
string debuggerUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}", this.debuggerEndpoint);
string rawVersionInfo = string.Empty;
Expand All @@ -256,7 +260,16 @@ public async Task Start()
var versionInfo = JsonConvert.DeserializeObject<DevToolsVersionInfo>(rawVersionInfo);
websocketAddress = versionInfo.WebSocketDebuggerUrl;

this.domains = DevToolsDomains.InitializeDomains(versionInfo, this);
if (protocolVersion == AutoDetectDevToolsProtocolVersion)
{
bool versionParsed = int.TryParse(versionInfo.BrowserMajorVersion, out protocolVersion);
if (!versionParsed)
{
throw new WebDriverException(string.Format(CultureInfo.InvariantCulture, "Unable to parse version number received from browser. Reported browser version string is '{0}'", versionInfo.Browser));
}
}

this.domains = DevToolsDomains.InitializeDomains(protocolVersion, this);

string targetId = null;
var targets = await this.domains.Target.GetTargets();
Expand Down
6 changes: 0 additions & 6 deletions dotnet/src/webdriver/DevTools/IDevToolsSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,5 @@ Task<TCommandResponse> SendCommand<TCommand, TCommandResponse>(TCommand command,
/// <param name="throwExceptionIfResponseNotReceived"><see langword="true"/> to throw an exception if a response is not received; otherwise, <see langword="false"/>.</param>
/// <returns>The command response object implementing the <see cref="ICommandResponse{T}"/> interface.</returns>
Task<JToken> SendCommand(string commandName, JToken @params, CancellationToken cancellationToken, int? millisecondsTimeout, bool throwExceptionIfResponseNotReceived);

/// <summary>
/// Asynchronously starts the session.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
Task Start();
}
}

0 comments on commit 36e141d

Please sign in to comment.