Skip to content

Commit 357a6cc

Browse files
committed
Initial work making .NET bindings understand W3C dialect of wire protocol
1 parent 7c2b517 commit 357a6cc

24 files changed

+969
-162
lines changed

dotnet/src/webdriver/DriverService.cs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ protected virtual string CommandLineArguments
157157
get { return string.Format(CultureInfo.InvariantCulture, "--port={0}", this.driverServicePort); }
158158
}
159159

160+
protected virtual TimeSpan InitialConnectionTimeout
161+
{
162+
get { return TimeSpan.FromSeconds(20); }
163+
}
164+
165+
protected virtual bool IgnoreMissingStatusEndPoint
166+
{
167+
get { return false; }
168+
}
169+
160170
/// <summary>
161171
/// Releases all resources associated with this <see cref="DriverService"/>.
162172
/// </summary>
@@ -180,7 +190,7 @@ public void Start()
180190
this.driverServiceProcess.Start();
181191
Uri serviceHealthUri = new Uri(this.ServiceUrl, new Uri(DriverCommand.Status, UriKind.Relative));
182192
bool processStarted = false;
183-
DateTime timeout = DateTime.Now.Add(TimeSpan.FromSeconds(20));
193+
DateTime timeout = DateTime.Now.Add(this.InitialConnectionTimeout);
184194
while (!processStarted && DateTime.Now < timeout)
185195
{
186196
try
@@ -193,6 +203,7 @@ public void Start()
193203

194204
HttpWebRequest request = HttpWebRequest.Create(serviceHealthUri) as HttpWebRequest;
195205
request.KeepAlive = false;
206+
request.Timeout = 5000;
196207
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
197208

198209
// Checking the response from the 'status' end point. Note that we are simply checking
@@ -202,12 +213,13 @@ public void Start()
202213
processStarted = response.StatusCode == HttpStatusCode.OK && response.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase);
203214
response.Close();
204215
}
205-
catch (WebException)
216+
catch (WebException ex)
206217
{
218+
Console.WriteLine(ex.Message);
207219
}
208220
}
209221

210-
if (!processStarted)
222+
if (!this.IgnoreMissingStatusEndPoint && !processStarted)
211223
{
212224
string msg = "Cannot start the driver service on " + this.ServiceUrl;
213225
throw new WebDriverException(msg);

dotnet/src/webdriver/Firefox/FirefoxDriver.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,13 +166,42 @@ public FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile, TimeSpan comm
166166
{
167167
}
168168

169+
/// <summary>
170+
/// Initializes a new instance of the <see cref="FirefoxDriver"/> class using the specified options. Uses the Mozilla-provided Marionette driver implementation.
171+
/// </summary>
172+
/// <param name="options">The <see cref="FirefoxOptions"/> to be used with the Firefox driver.</param>
173+
public FirefoxDriver(FirefoxOptions options)
174+
: this(FirefoxDriverService.CreateDefaultService(), options, RemoteWebDriver.DefaultCommandTimeout)
175+
{
176+
}
177+
178+
/// <summary>
179+
/// Initializes a new instance of the <see cref="FirefoxDriver"/> class using the specified driver service. Uses the Mozilla-provided Marionette driver implementation.
180+
/// </summary>
181+
/// <param name="service">The <see cref="FirefoxDriverService"/> used to initialize the driver.</param>
182+
public FirefoxDriver(FirefoxDriverService service)
183+
: this(service, new FirefoxOptions(), RemoteWebDriver.DefaultCommandTimeout)
184+
{
185+
}
186+
187+
/// <summary>
188+
/// Initializes a new instance of the <see cref="FirefoxDriver"/> class using the specified options, driver service, and timeout. Uses the Mozilla-provided Marionette driver implementation.
189+
/// </summary>
190+
/// <param name="service">The <see cref="FirefoxDriverService"/> to use.</param>
191+
/// <param name="options">The <see cref="FirefoxOptions"/> to be used with the Firefox driver.</param>
192+
/// <param name="commandTimeout">The maximum amount of time to wait for each command.</param>
193+
public FirefoxDriver(FirefoxDriverService service, FirefoxOptions options, TimeSpan commandTimeout)
194+
: base(new DriverServiceCommandExecutor(service, commandTimeout), options.ToCapabilities())
195+
{
196+
}
197+
#endregion
198+
169199
private FirefoxDriver(FirefoxBinary binary, FirefoxProfile profile, ICapabilities capabilities, TimeSpan commandTimeout)
170200
: base(CreateExtensionConnection(binary, profile, commandTimeout), RemoveUnneededCapabilities(capabilities))
171201
{
172202
this.binary = binary;
173203
this.profile = profile;
174204
}
175-
#endregion
176205

177206
#region Properties
178207
/// <summary>

dotnet/src/webdriver/Firefox/FirefoxDriverCommandExecutor.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ public FirefoxDriverCommandExecutor(FirefoxBinary binary, FirefoxProfile profile
4747
this.commandTimeout = commandTimeout;
4848
}
4949

50+
/// <summary>
51+
/// Gets the repository of objects containin information about commands.
52+
/// </summary>
53+
public CommandInfoRepository CommandInfoRepository
54+
{
55+
get { return this.internalExecutor.CommandInfoRepository; }
56+
}
57+
5058
/// <summary>
5159
/// Executes a command
5260
/// </summary>
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// <copyright file="FirefoxDriverService.cs" company="WebDriver Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
// </copyright>
18+
19+
using System;
20+
using System.Collections.Generic;
21+
using System.Globalization;
22+
using System.IO;
23+
using System.Text;
24+
using OpenQA.Selenium.Internal;
25+
26+
namespace OpenQA.Selenium.Firefox
27+
{
28+
/// <summary>
29+
/// Exposes the service provided by the native FirefoxDriver executable.
30+
/// </summary>
31+
public sealed class FirefoxDriverService : DriverService
32+
{
33+
private const string FirefoxDriverServiceFileName = "wires.exe";
34+
private static readonly Uri FirefoxDriverDownloadUrl = new Uri("https://github.com/jgraham/wires/releases");
35+
private string browserBinaryPath = @"C:\Program Files (x86)\Nightly\firefox.exe";
36+
private int browserCommunicationPort = -1;
37+
38+
/// <summary>
39+
/// Initializes a new instance of the FirefoxDriverService class.
40+
/// </summary>
41+
/// <param name="executablePath">The full path to the Firefox driver executable.</param>
42+
/// <param name="executableFileName">The file name of the Firefox driver executable.</param>
43+
/// <param name="port">The port on which the Firefox driver executable should listen.</param>
44+
private FirefoxDriverService(string executablePath, string executableFileName, int port)
45+
: base(executablePath, port, executableFileName, FirefoxDriverDownloadUrl)
46+
{
47+
}
48+
49+
/// <summary>
50+
/// Gets or sets the location of the Firefox binary executable.
51+
/// </summary>
52+
public string FirefoxBinaryPath
53+
{
54+
get { return this.browserBinaryPath; }
55+
set { this.browserBinaryPath = value; }
56+
}
57+
58+
/// <summary>
59+
/// Gets or sets the port used by the driver executable to communicate with the browser.
60+
/// </summary>
61+
public int BrowserCommunicationPort
62+
{
63+
get { return this.browserCommunicationPort; }
64+
set { this.browserCommunicationPort = value; }
65+
}
66+
67+
/// <summary>
68+
/// Gets a value indicating whether to ignore the absence of a status end point.
69+
/// </summary>
70+
protected override bool IgnoreMissingStatusEndPoint
71+
{
72+
get { return true; }
73+
}
74+
75+
/// <summary>
76+
/// Gets a value indicating the time to wait for an initial connection before timing out.
77+
/// </summary>
78+
protected override TimeSpan InitialConnectionTimeout
79+
{
80+
get { return TimeSpan.FromSeconds(2); }
81+
}
82+
83+
/// <summary>
84+
/// Gets the command-line arguments for the driver service.
85+
/// </summary>
86+
protected override string CommandLineArguments
87+
{
88+
get
89+
{
90+
StringBuilder argsBuilder = new StringBuilder();
91+
if (this.browserCommunicationPort > 0)
92+
{
93+
argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --marionette-port {0}", this.browserCommunicationPort);
94+
}
95+
96+
if (this.Port > 0)
97+
{
98+
argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --webdriver-port {0}", this.Port);
99+
}
100+
101+
if (!string.IsNullOrEmpty(this.browserBinaryPath))
102+
{
103+
argsBuilder.AppendFormat(CultureInfo.InvariantCulture, " --binary \"{0}\"", this.browserBinaryPath);
104+
}
105+
106+
return argsBuilder.ToString().Trim();
107+
}
108+
}
109+
110+
/// <summary>
111+
/// Creates a default instance of the FirefoxDriverService.
112+
/// </summary>
113+
/// <returns>A FirefoxDriverService that implements default settings.</returns>
114+
public static FirefoxDriverService CreateDefaultService()
115+
{
116+
string serviceDirectory = DriverService.FindDriverServiceExecutable(FirefoxDriverServiceFileName, FirefoxDriverDownloadUrl);
117+
return CreateDefaultService(serviceDirectory);
118+
}
119+
120+
/// <summary>
121+
/// Creates a default instance of the FirefoxDriverService using a specified path to the Firefox driver executable.
122+
/// </summary>
123+
/// <param name="driverPath">The directory containing the Firefox driver executable.</param>
124+
/// <returns>A FirefoxDriverService using a random port.</returns>
125+
public static FirefoxDriverService CreateDefaultService(string driverPath)
126+
{
127+
return CreateDefaultService(driverPath, FirefoxDriverServiceFileName);
128+
}
129+
130+
/// <summary>
131+
/// Creates a default instance of the FirefoxDriverService using a specified path to the ChromeDriver executable with the given name.
132+
/// </summary>
133+
/// <param name="driverPath">The directory containing the Firefox driver executable.</param>
134+
/// <param name="driverExecutableFileName">The name of th Firefox driver executable file.</param>
135+
/// <returns>A FirefoxDriverService using a random port.</returns>
136+
public static FirefoxDriverService CreateDefaultService(string driverPath, string driverExecutableFileName)
137+
{
138+
return new FirefoxDriverService(driverPath, driverExecutableFileName, PortUtilities.FindFreePort());
139+
}
140+
}
141+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// <copyright file="FirefoxOptions.cs" company="WebDriver Committers">
2+
// Licensed to the Software Freedom Conservancy (SFC) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The SFC licenses this file
6+
// to you under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
// </copyright>
18+
19+
using System;
20+
using System.Collections.Generic;
21+
using System.Linq;
22+
using System.Text;
23+
using OpenQA.Selenium.Remote;
24+
25+
namespace OpenQA.Selenium.Firefox
26+
{
27+
/// <summary>
28+
/// Class to manage options specific to <see cref="FirefoxDriver"/>
29+
/// </summary>
30+
/// <remarks>
31+
/// Used with the marionette executable wires.exe.
32+
/// </remarks>
33+
/// <example>
34+
/// <code>
35+
/// FirefoxOptions options = new FirefoxOptions();
36+
/// </code>
37+
/// <para></para>
38+
/// <para>For use with FirefoxDriver:</para>
39+
/// <para></para>
40+
/// <code>
41+
/// FirefoxDriver driver = new FirefoxDriver(options);
42+
/// </code>
43+
/// <para></para>
44+
/// <para>For use with RemoteWebDriver:</para>
45+
/// <para></para>
46+
/// <code>
47+
/// RemoteWebDriver driver = new RemoteWebDriver(new Uri("http://localhost:4444/wd/hub"), options.ToCapabilities());
48+
/// </code>
49+
/// </example>
50+
public class FirefoxOptions
51+
{
52+
private bool isMarionette = true;
53+
54+
/// <summary>
55+
/// Gets or sets a value indicating whether or not to use the Mozilla-provided Marionette implementation.
56+
/// </summary>
57+
public bool IsMarionette
58+
{
59+
get { return this.isMarionette; }
60+
set { isMarionette = value; }
61+
}
62+
63+
64+
/// <summary>
65+
/// Returns DesiredCapabilities for Firefox with these options included as
66+
/// capabilities. This does not copy the options. Further changes will be
67+
/// reflected in the returned capabilities.
68+
/// </summary>
69+
/// <returns>The DesiredCapabilities for Firefox with these options.</returns>
70+
public ICapabilities ToCapabilities()
71+
{
72+
DesiredCapabilities capabilities = DesiredCapabilities.Firefox();
73+
capabilities.SetCapability("marionette", this.isMarionette);
74+
return capabilities;
75+
}
76+
}
77+
}

dotnet/src/webdriver/PhantomJS/PhantomJSDriver.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ public PhantomJSDriver(PhantomJSDriverService service, PhantomJSOptions options,
151151
{
152152
// Add the custom commandInfo of PhantomJSDriver
153153
CommandInfo commandInfo = new CommandInfo(CommandInfo.PostCommand, "/session/{sessionId}/phantom/execute");
154-
CommandInfoRepository.Instance.TryAddCommand(CommandExecutePhantomScript, commandInfo);
154+
this.CommandExecutor.CommandInfoRepository.TryAddCommand(CommandExecutePhantomScript, commandInfo);
155155
}
156156

157157
/// <summary>

dotnet/src/webdriver/Remote/Command.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ public string ParametersAsJsonString
9797
parametersString = JsonConvert.SerializeObject(this.commandParameters);
9898
}
9999

100+
if (string.IsNullOrEmpty(parametersString))
101+
{
102+
parametersString = "{}";
103+
}
104+
100105
return parametersString;
101106
}
102107
}

0 commit comments

Comments
 (0)