Skip to content

Commit

Permalink
Refactoring usage of command executors in .NET.
Browse files Browse the repository at this point in the history
We now use the same algorithm for creating and using a "command executor"
for all current driver implementations. This removes some of the
differences between Firefox and other implementations. It also prepares
the way for unifying the construction of drivers using a common base Options
class.
  • Loading branch information
jimevans committed Feb 23, 2014
1 parent 0785d10 commit 34a63e4
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 283 deletions.
3 changes: 2 additions & 1 deletion dotnet/src/webdriver/DriverService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
using System.Security.Permissions;
using System.Text;
using OpenQA.Selenium.Internal;
using OpenQA.Selenium.Remote;

namespace OpenQA.Selenium
{
/// <summary>
/// Exposes the service provided by a native WebDriver server executable.
/// </summary>
public abstract class DriverService : IDisposable
public abstract class DriverService : ICommandServer
{
private string driverServicePath;
private string driverServiceExecutableName;
Expand Down
31 changes: 3 additions & 28 deletions dotnet/src/webdriver/Firefox/FirefoxDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,31 +225,6 @@ public Screenshot GetScreenshot()
#endregion

#region Support methods
/// <summary>
/// Starts the command executor, enabling communication with the browser.
/// </summary>
protected override void StartClient()
{
try
{
ExtensionConnection connection = (ExtensionConnection)this.CommandExecutor;
connection.Profile.AddWebDriverExtension();
((ExtensionConnection)this.CommandExecutor).Start();
}
catch (IOException e)
{
throw new WebDriverException("An error occurred while connecting to Firefox", e);
}
}

/// <summary>
/// Stops the command executor, ending further communication with the browser.
/// </summary>
protected override void StopClient()
{
((ExtensionConnection)this.CommandExecutor).Quit();
}

/// <summary>
/// In derived classes, the <see cref="PrepareEnvironment"/> method prepares the environment for test execution.
/// </summary>
Expand Down Expand Up @@ -333,7 +308,7 @@ private static FirefoxProfile ExtractProfile(ICapabilities capabilities)
return profile;
}

private static ExtensionConnection CreateExtensionConnection(FirefoxBinary binary, FirefoxProfile profile, TimeSpan commandTimeout)
private static ICommandExecutor CreateExtensionConnection(FirefoxBinary binary, FirefoxProfile profile, TimeSpan commandTimeout)
{
FirefoxProfile profileToUse = profile;

Expand All @@ -347,8 +322,8 @@ private static ExtensionConnection CreateExtensionConnection(FirefoxBinary binar
profileToUse = new FirefoxProfile();
}

ExtensionConnection extension = new ExtensionConnection(binary, profileToUse, "localhost", commandTimeout);
return extension;
FirefoxDriverCommandExecutor executor = new FirefoxDriverCommandExecutor(binary, profileToUse, "localhost", commandTimeout);
return executor;
}

private static ICapabilities RemoveUnneededCapabilities(ICapabilities capabilities)
Expand Down
79 changes: 79 additions & 0 deletions dotnet/src/webdriver/Firefox/FirefoxDriverCommandExecutor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// <copyright file="FirefoxDriverCommandExecutor.cs" company="WebDriver Committers">
// Copyright 2014 Software Freedom Conservancy
//
// Licensed 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;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Firefox.Internal;

namespace OpenQA.Selenium.Firefox
{
/// <summary>
/// Provides a way of executing Commands using the FirefoxDriver.
/// </summary>
public class FirefoxDriverCommandExecutor : ICommandExecutor
{
private FirefoxDriverServer server;
private HttpCommandExecutor internalExecutor;
private TimeSpan commandTimeout;

/// <summary>
/// Initializes a new instance of the <see cref="FirefoxDriverCommandExecutor"/> class.
/// </summary>
/// <param name="binary">The <see cref="FirefoxBinary"/> on which to make the connection.</param>
/// <param name="profile">The <see cref="FirefoxProfile"/> creating the connection.</param>
/// <param name="host">The name of the host on which to connect to the Firefox extension (usually "localhost").</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public FirefoxDriverCommandExecutor(FirefoxBinary binary, FirefoxProfile profile, string host, TimeSpan commandTimeout)
{
this.server = new FirefoxDriverServer(binary, profile, host);
this.commandTimeout = commandTimeout;
}

/// <summary>
/// Executes a command
/// </summary>
/// <param name="commandToExecute">The command you wish to execute</param>
/// <returns>A response from the browser</returns>
public Response Execute(Command commandToExecute)
{
Response toReturn = null;
if (commandToExecute.Name == DriverCommand.NewSession)
{
this.server.Start();
this.internalExecutor = new HttpCommandExecutor(this.server.ExtensionUri, this.commandTimeout);
}

// Use a try-catch block to catch exceptions for the Quit
// command, so that we can get the finally block.
try
{
toReturn = this.internalExecutor.Execute(commandToExecute);
}
finally
{
if (commandToExecute.Name == DriverCommand.Quit)
{
this.server.Dispose();
}
}

return toReturn;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// <copyright file="ExtensionConnection.cs" company="WebDriver Committers">
// Copyright 2007-2011 WebDriver committers
// Copyright 2007-2011 Google Inc.
// Portions copyright 2011 Software Freedom Conservancy
// <copyright file="FirefoxDriverServer.cs" company="WebDriver Committers">
// Copyright 2014 Software Freedom Conservancy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -18,43 +16,46 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Linq;
using System.Text;
using OpenQA.Selenium.Remote;
using OpenQA.Selenium.Firefox.Internal;
using System.Net.Sockets;
using System.Net;
using System.Net.NetworkInformation;
using System.Globalization;

namespace OpenQA.Selenium.Firefox.Internal
namespace OpenQA.Selenium.Firefox
{
/// <summary>
/// Represents the connection to the WebDriver Firefox extension.
/// Provides methods for launching Firefox with the WebDriver extension installed.
/// </summary>
internal class ExtensionConnection : IExtensionConnection
public class FirefoxDriverServer : ICommandServer
{
#region Private members
private string host;
private List<IPEndPoint> addresses = new List<IPEndPoint>();
private FirefoxProfile profile;
private FirefoxBinary process;
private HttpCommandExecutor executor;
private string host;
private TimeSpan timeout;
#endregion
private Uri extensionUri;

#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="ExtensionConnection"/> class.
/// Initializes a new instance of the <see cref="FirefoxDriverServer"/> class.
/// </summary>
/// <param name="binary">The <see cref="FirefoxBinary"/> on which to make the connection.</param>
/// <param name="profile">The <see cref="FirefoxProfile"/> creating the connection.</param>
/// <param name="host">The name of the host on which to connect to the Firefox extension (usually "localhost").</param>
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
public ExtensionConnection(FirefoxBinary binary, FirefoxProfile profile, string host, TimeSpan commandTimeout)
public FirefoxDriverServer(FirefoxBinary binary, FirefoxProfile profile, string host)
{
this.host = host;
this.timeout = commandTimeout;
this.profile = profile;
if (profile == null)
{
this.profile = new FirefoxProfile();
}
else
{
this.profile = profile;
}

if (binary == null)
{
this.process = new FirefoxBinary();
Expand All @@ -63,20 +64,18 @@ public ExtensionConnection(FirefoxBinary binary, FirefoxProfile profile, string
{
this.process = binary;
}
}
#endregion
}

/// <summary>
/// Gets the <see cref="FirefoxProfile"/> associated with this connection.
/// Gets the <see cref="Uri"/> for communicating with this server.
/// </summary>
public FirefoxProfile Profile
public Uri ExtensionUri
{
get { return this.profile; }
get { return this.extensionUri; }
}

#region IExtensionConnection Members
/// <summary>
/// Starts the connection to the extension.
/// Starts the server.
/// </summary>
public void Start()
{
Expand All @@ -94,7 +93,7 @@ public void Start()
this.SetAddress(portToUse);

// TODO (JimEvans): Get a better url algorithm.
this.executor = new HttpCommandExecutor(new Uri(string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}/hub/", this.host, portToUse)), this.timeout);
this.extensionUri = new Uri(string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}/hub/", this.host, portToUse));
this.ConnectToBrowser(this.process.Timeout);
}
finally
Expand All @@ -105,30 +104,33 @@ public void Start()
}

/// <summary>
/// Closes the connection to the extension.
/// Releases all resources used by the <see cref="FirefoxDriverServer"/>.
/// </summary>
public void Quit()
public void Dispose()
{
// This should only be called after the QUIT command has been sent,
// so go ahead and clean up our process and profile.
this.process.Quit();
this.profile.Clean();
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion

#region ICommandExecutor Members
/// <summary>
/// Executes a command
/// Releases the unmanaged resources used by the <see cref="FirefoxDriverServer"/> and optionally
/// releases the managed resources.
/// </summary>
/// <param name="commandToExecute">The command you wish to execute</param>
/// <returns>A response from the browser</returns>
public Response Execute(Command commandToExecute)
/// <param name="disposing"><see langword="true"/> to release managed and resources;
/// <see langword="false"/> to only release unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
return this.executor.Execute(commandToExecute);
if (disposing)
{
// This should only be called after the QUIT command has been sent,
// so go ahead and clean up our process and profile.
this.process.Quit();
this.profile.Clean();
}

GC.SuppressFinalize(this);
}
#endregion

#region Support methods
private static int DetermineNextFreePort(string host, int port)
{
// Attempt to connect to the given port on the host
Expand Down Expand Up @@ -259,7 +261,18 @@ private void ConnectToBrowser(TimeSpan timeToWait)
{
if (extensionSocket == null || extensionSocket.RemoteEndPoint == null)
{
throw new WebDriverException(string.Format(CultureInfo.InvariantCulture, "Failed to start up socket within {0} ms", timeToWait.TotalMilliseconds));
StringBuilder addressBuilder = new StringBuilder();
foreach (IPEndPoint address in this.addresses)
{
if (addressBuilder.Length > 0)
{
addressBuilder.Append(", ");
}

addressBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}:{1}", address.Address.ToString(), address.Port.ToString(CultureInfo.InvariantCulture));
}

throw new WebDriverException(string.Format(CultureInfo.InvariantCulture, "Failed to start up socket within {0} ms. Attempted to connect to the following addresses: {1}", timeToWait.TotalMilliseconds, addressBuilder.ToString()));
}
else
{
Expand All @@ -274,6 +287,5 @@ private void ConnectToBrowser(TimeSpan timeToWait)
extensionSocket.Close();
}
}
#endregion
}
}
1 change: 1 addition & 0 deletions dotnet/src/webdriver/Firefox/FirefoxProfile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ public FirefoxProfile(string profileDirectory, bool deleteSourceOnClean)
this.deleteSource = deleteSourceOnClean;
this.ReadDefaultPreferences();
this.profilePreferences.AppendPreferences(this.ReadExistingPreferences());
this.AddWebDriverExtension();
}
#endregion

Expand Down
Loading

0 comments on commit 34a63e4

Please sign in to comment.