diff --git a/src/.nuget/NuGet.Config b/src/.nuget/NuGet.Config
index 67f8ea0..1a2e3dc 100644
--- a/src/.nuget/NuGet.Config
+++ b/src/.nuget/NuGet.Config
@@ -1,6 +1,9 @@
-
+
+
+
+
-
\ No newline at end of file
+
diff --git a/src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.Tests.csproj b/src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.Tests.csproj
index c709295..76d2c9e 100644
--- a/src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.Tests.csproj
+++ b/src/TestApps.Tests/WindowsFormsTestApplication.Tests/WindowsFormsTestApplication.Tests.csproj
@@ -41,8 +41,8 @@
-
- ..\..\packages\Selenium.WebDriver.2.53.1\lib\net40\WebDriver.dll
+
+ ..\..\packages\Selenium.WebDriver.3.3.0\lib\net40\WebDriver.dll
True
@@ -92,4 +92,4 @@
-->
-
\ No newline at end of file
+
diff --git a/src/TestApps.Tests/WindowsFormsTestApplication.Tests/packages.config b/src/TestApps.Tests/WindowsFormsTestApplication.Tests/packages.config
index c5c2577..7518043 100644
--- a/src/TestApps.Tests/WindowsFormsTestApplication.Tests/packages.config
+++ b/src/TestApps.Tests/WindowsFormsTestApplication.Tests/packages.config
@@ -1,5 +1,5 @@
-
-
\ No newline at end of file
+
+
diff --git a/src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.Tests.csproj b/src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.Tests.csproj
index a7ee778..9d48552 100644
--- a/src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.Tests.csproj
+++ b/src/TestApps.Tests/WpfTestApplication.Tests/WpfTestApplication.Tests.csproj
@@ -40,8 +40,8 @@
-
- ..\..\packages\Selenium.WebDriver.2.53.1\lib\net40\WebDriver.dll
+
+ ..\..\packages\Selenium.WebDriver.3.3.0\lib\net40\WebDriver.dll
True
@@ -96,4 +96,4 @@
-->
-
\ No newline at end of file
+
diff --git a/src/TestApps.Tests/WpfTestApplication.Tests/packages.config b/src/TestApps.Tests/WpfTestApplication.Tests/packages.config
index c5c2577..7518043 100644
--- a/src/TestApps.Tests/WpfTestApplication.Tests/packages.config
+++ b/src/TestApps.Tests/WpfTestApplication.Tests/packages.config
@@ -1,5 +1,5 @@
-
-
\ No newline at end of file
+
+
diff --git a/src/Winium.Desktop.Driver/Automator/Automator.cs b/src/Winium.Desktop.Driver/Automator/Automator.cs
index 88f8d25..03371cc 100644
--- a/src/Winium.Desktop.Driver/Automator/Automator.cs
+++ b/src/Winium.Desktop.Driver/Automator/Automator.cs
@@ -21,9 +21,8 @@ internal class Automator
#region Constructors and Destructors
- public Automator(string session)
+ public Automator()
{
- this.Session = session;
this.ElementsRegistry = new ElementsRegistry();
}
@@ -37,7 +36,7 @@ public Automator(string session)
public ElementsRegistry ElementsRegistry { get; private set; }
- public string Session { get; private set; }
+ public string Session { get; set; }
public WiniumKeyboard WiniumKeyboard { get; set; }
@@ -61,13 +60,8 @@ public static Automator InstanceForSession(string sessionId)
{
if (instance == null)
{
- if (sessionId == null)
- {
- sessionId = "AwesomeSession";
- }
-
// TODO: Add actual support for sessions. Temporary return single Automator for any season
- instance = new Automator(sessionId);
+ instance = new Automator();
}
}
}
diff --git a/src/Winium.Desktop.Driver/Automator/Capabilities.cs b/src/Winium.Desktop.Driver/Automator/Capabilities.cs
index 8a6b2d7..554d125 100644
--- a/src/Winium.Desktop.Driver/Automator/Capabilities.cs
+++ b/src/Winium.Desktop.Driver/Automator/Capabilities.cs
@@ -17,6 +17,8 @@ internal Capabilities()
{
this.App = string.Empty;
this.Arguments = string.Empty;
+ this.ResetDirectory = string.Empty;
+ this.ResetProcesses = false;
this.LaunchDelay = 0;
this.DebugConnectToRunningApp = false;
this.InnerPort = 9998;
@@ -27,12 +29,27 @@ internal Capabilities()
#region Public Properties
+ [JsonProperty("platformName")]
+ public static string PlatformName
+ {
+ get
+ {
+ return "Windows";
+ }
+ }
+
[JsonProperty("app")]
public string App { get; set; }
[JsonProperty("args")]
public string Arguments { get; set; }
+ [JsonProperty("resetDirectory")]
+ public string ResetDirectory { get; set; }
+
+ [JsonProperty("resetProcesses")]
+ public bool ResetProcesses { get; set; }
+
[JsonProperty("debugConnectToRunningApp")]
public bool DebugConnectToRunningApp { get; set; }
diff --git a/src/Winium.Desktop.Driver/CommandExecutors/CommandExecutorBase.cs b/src/Winium.Desktop.Driver/CommandExecutors/CommandExecutorBase.cs
index caa8503..83d926e 100644
--- a/src/Winium.Desktop.Driver/CommandExecutors/CommandExecutorBase.cs
+++ b/src/Winium.Desktop.Driver/CommandExecutors/CommandExecutorBase.cs
@@ -8,6 +8,7 @@
using Newtonsoft.Json;
using Winium.Desktop.Driver.Automator;
+ using Winium.Desktop.Driver.Exceptions;
using Winium.StoreApps.Common;
using Winium.StoreApps.Common.Exceptions;
@@ -52,6 +53,12 @@ public CommandResponse Do()
HttpStatusCode.NotImplemented,
this.JsonResponse(ResponseStatus.UnknownCommand, exception));
}
+ catch (SessionNotCreatedException exception)
+ {
+ return CommandResponse.Create(
+ HttpStatusCode.InternalServerError,
+ this.JsonResponse(ResponseStatus.SessionNotCreatedException, exception.GetBaseException()));
+ }
catch (Exception exception)
{
return CommandResponse.Create(
@@ -76,8 +83,13 @@ protected string JsonResponse()
protected string JsonResponse(ResponseStatus status, object value)
{
+ var session = this.Automator.Session;
+ if (status == ResponseStatus.SessionNotCreatedException)
+ {
+ this.Automator.Session = null;
+ }
return JsonConvert.SerializeObject(
- new JsonResponse(this.Automator.Session, status, value),
+ new JsonResponse(session, status, value),
Formatting.Indented);
}
diff --git a/src/Winium.Desktop.Driver/CommandExecutors/GetSessionCapabilitiesExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/GetSessionCapabilitiesExecutor.cs
new file mode 100644
index 0000000..09a7756
--- /dev/null
+++ b/src/Winium.Desktop.Driver/CommandExecutors/GetSessionCapabilitiesExecutor.cs
@@ -0,0 +1,20 @@
+namespace Winium.Desktop.Driver.CommandExecutors
+{
+ #region using
+
+ using Winium.StoreApps.Common;
+
+ #endregion
+
+ internal class GetSessionCapabilitiesExecutor : CommandExecutorBase
+ {
+ #region Methods
+
+ protected override string DoImpl()
+ {
+ return this.JsonResponse(ResponseStatus.Success, this.Automator.ActualCapabilities);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Winium.Desktop.Driver/CommandExecutors/NewSessionExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/NewSessionExecutor.cs
index e9b448a..bf172c3 100644
--- a/src/Winium.Desktop.Driver/CommandExecutors/NewSessionExecutor.cs
+++ b/src/Winium.Desktop.Driver/CommandExecutors/NewSessionExecutor.cs
@@ -2,6 +2,9 @@
{
#region using
+ using System;
+ using System.IO;
+ using System.Diagnostics;
using System.Threading;
using Newtonsoft.Json;
@@ -9,6 +12,7 @@
using Winium.Cruciatus;
using Winium.Cruciatus.Settings;
using Winium.Desktop.Driver.Automator;
+ using Winium.Desktop.Driver.Exceptions;
using Winium.Desktop.Driver.Input;
using Winium.StoreApps.Common;
@@ -20,21 +24,81 @@ internal class NewSessionExecutor : CommandExecutorBase
protected override string DoImpl()
{
- // It is easier to reparse desired capabilities as JSON instead of re-mapping keys to attributes and calling type conversions,
- // so we will take possible one time performance hit by serializing Dictionary and deserializing it as Capabilities object
- var serializedCapability =
- JsonConvert.SerializeObject(this.ExecutedCommand.Parameters["desiredCapabilities"]);
- this.Automator.ActualCapabilities = Capabilities.CapabilitiesFromJsonString(serializedCapability);
+ try
+ {
+ this.Automator.Session = Guid.NewGuid().ToString();
+ Logger.Debug("session for command: " + this.Automator.Session);
- this.InitializeApplication(this.Automator.ActualCapabilities.DebugConnectToRunningApp);
- this.InitializeKeyboardEmulator(this.Automator.ActualCapabilities.KeyboardSimulator);
+ // It is easier to reparse desired capabilities as JSON instead of re-mapping keys to attributes and calling type conversions,
+ // so we will take possible one time performance hit by serializing Dictionary and deserializing it as Capabilities object
+ var serializedCapability =
+ JsonConvert.SerializeObject(this.ExecutedCommand.Parameters["desiredCapabilities"]);
+ this.Automator.ActualCapabilities = Capabilities.CapabilitiesFromJsonString(serializedCapability);
- // Gives sometime to load visuals (needed only in case of slow emulation)
- Thread.Sleep(this.Automator.ActualCapabilities.LaunchDelay);
+ if (this.Automator.ActualCapabilities.ResetProcesses)
+ {
+ this.ResetProcesses(this.Automator.ActualCapabilities.App);
+ }
+ this.ResetDirectory(this.Automator.ActualCapabilities.ResetDirectory);
+ this.InitializeApplication(this.Automator.ActualCapabilities.DebugConnectToRunningApp);
+ this.InitializeKeyboardEmulator(this.Automator.ActualCapabilities.KeyboardSimulator);
+
+ // Gives sometime to load visuals (needed only in case of slow emulation)
+ Thread.Sleep(this.Automator.ActualCapabilities.LaunchDelay);
+ } catch(Exception e)
+ {
+ throw new SessionNotCreatedException(e.Message, e);
+ }
return this.JsonResponse(ResponseStatus.Success, this.Automator.ActualCapabilities);
}
+ private void ResetProcesses(string app)
+ {
+ string executable = app.Substring(app.LastIndexOf("\\") + 1);
+ string processName = executable.Substring(0, executable.LastIndexOf("."));
+ foreach (Process process in Process.GetProcesses())
+ {
+ Logger.Debug("Running process: " + process.ProcessName);
+ }
+ foreach (Process process in Process.GetProcessesByName(processName))
+ {
+ Logger.Debug("Killing process: " + process.ProcessName);
+ try
+ {
+ process.Kill();
+ }
+ catch (Exception e)
+ {
+ Logger.Info("Could not kill process: " + e.Message);
+ }
+ try
+ {
+ process.WaitForExit(10000);
+ } catch(Exception e)
+ {
+ Logger.Info("Could not wait for process to exit: " + e.Message);
+ }
+ }
+ }
+
+ private void ResetDirectory(string resetDirectory)
+ {
+ if (!string.IsNullOrEmpty(resetDirectory))
+ {
+ DirectoryInfo directory = new DirectoryInfo(resetDirectory);
+
+ foreach (FileInfo file in directory.GetFiles())
+ {
+ file.Delete();
+ }
+ foreach (DirectoryInfo subDirectory in directory.GetDirectories())
+ {
+ subDirectory.Delete(true);
+ }
+ }
+ }
+
private void InitializeApplication(bool debugDoNotDeploy = false)
{
var appPath = this.Automator.ActualCapabilities.App;
diff --git a/src/Winium.Desktop.Driver/CommandExecutors/SetTimeoutExecutor.cs b/src/Winium.Desktop.Driver/CommandExecutors/SetTimeoutExecutor.cs
new file mode 100644
index 0000000..cf6209e
--- /dev/null
+++ b/src/Winium.Desktop.Driver/CommandExecutors/SetTimeoutExecutor.cs
@@ -0,0 +1,20 @@
+namespace Winium.Desktop.Driver.CommandExecutors
+{
+ #region using
+
+ using Winium.StoreApps.Common;
+
+ #endregion
+
+ internal class SetTimeoutExecutor : CommandExecutorBase
+ {
+ #region Methods
+
+ protected override string DoImpl()
+ {
+ return this.JsonResponse(ResponseStatus.Success, null);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/Winium.Desktop.Driver/CommandLineOptions.cs b/src/Winium.Desktop.Driver/CommandLineOptions.cs
index 666ae9d..840db8c 100644
--- a/src/Winium.Desktop.Driver/CommandLineOptions.cs
+++ b/src/Winium.Desktop.Driver/CommandLineOptions.cs
@@ -15,8 +15,8 @@ internal class CommandLineOptions
HelpText = "write server log to file instead of stdout, increases log level to INFO")]
public string LogPath { get; set; }
- [Option("port", Required = false, HelpText = "port to listen on")]
- public int? Port { get; set; }
+ [Option("port", Required = false, DefaultValue = 9999, HelpText = "port to listen on")]
+ public int Port { get; set; }
[Option("url-base", Required = false, HelpText = "base URL path prefix for commands, e.g. wd/url")]
public string UrlBase { get; set; }
@@ -24,6 +24,12 @@ internal class CommandLineOptions
[Option("verbose", Required = false, HelpText = "log verbosely")]
public bool Verbose { get; set; }
+ [Option("version", Required = false, HelpText = "print version number and exit")]
+ public bool Version { get; set; }
+
+ [Option("nodeconfig", Required = false, HelpText = "configuration JSON file to register driver with selenium grid")]
+ public string NodeConfig { get; set; }
+
[Option("silent", Required = false, HelpText = "log nothing")]
public bool Silent { get; set; }
diff --git a/src/Winium.Desktop.Driver/Exceptions/SessionNotCreatedException.cs b/src/Winium.Desktop.Driver/Exceptions/SessionNotCreatedException.cs
new file mode 100644
index 0000000..52177d9
--- /dev/null
+++ b/src/Winium.Desktop.Driver/Exceptions/SessionNotCreatedException.cs
@@ -0,0 +1,35 @@
+namespace Winium.Desktop.Driver.Exceptions
+{
+ #region
+
+ using System;
+
+ #endregion
+
+ public class SessionNotCreatedException : Exception
+ {
+
+ #region Constructors and Destructors
+
+ public SessionNotCreatedException()
+ {
+ }
+
+ public SessionNotCreatedException(string message)
+ : base(message)
+ {
+ }
+
+ public SessionNotCreatedException(string message, params object[] args)
+ : base(string.Format(message, args))
+ {
+ }
+
+ public SessionNotCreatedException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Winium.Desktop.Driver/Listener.cs b/src/Winium.Desktop.Driver/Listener.cs
index c628dfb..561607e 100644
--- a/src/Winium.Desktop.Driver/Listener.cs
+++ b/src/Winium.Desktop.Driver/Listener.cs
@@ -16,7 +16,9 @@ public class Listener
{
#region Static Fields
- private static string urnPrefix;
+ private readonly Uri baseAddress;
+
+ private readonly NodeRegistrar nodeRegistrar;
#endregion
@@ -32,35 +34,33 @@ public class Listener
#region Constructors and Destructors
- public Listener(int listenerPort)
+ public Listener(int listenerPort, string urlBase, string nodeConfigFile)
{
+ urlBase = NormalizePrefix(urlBase);
this.Port = listenerPort;
- }
-
- #endregion
-
- #region Public Properties
-
- public static string UrnPrefix
- {
- get
- {
- return urnPrefix;
- }
- set
+ if (!string.IsNullOrWhiteSpace(nodeConfigFile))
{
- if (!string.IsNullOrEmpty(value))
+ if (!urlBase.Equals("wd/hub"))
{
- // Normalize prefix
- urnPrefix = "/" + value.Trim('/');
+ Logger.Warn(
+ "--url-base '{0}' will be overriden and set to 'wd/hub' because --nodeconfig option was specified",
+ urlBase);
}
+
+ urlBase = "wd/hub";
+
+ this.nodeRegistrar = new NodeRegistrar(nodeConfigFile, "localhost", this.Port);
}
+
+ this.baseAddress = new UriBuilder("http", "localhost", this.Port, urlBase).Uri;
}
- public int Port { get; private set; }
+ #endregion
+
+ #region Public Properties
- public Uri Prefix { get; private set; }
+ public int Port { get; private set; }
#endregion
@@ -71,13 +71,17 @@ public void StartListening()
try
{
this.listener = new TcpListener(IPAddress.Any, this.Port);
-
- this.Prefix = new Uri(string.Format(CultureInfo.InvariantCulture, "http://localhost:{0}", this.Port));
- this.dispatcher = new UriDispatchTables(new Uri(this.Prefix, UrnPrefix));
+ this.dispatcher = new UriDispatchTables(this.baseAddress);
this.executorDispatcher = new CommandExecutorDispatchTable();
// Start listening for client requests.
this.listener.Start();
+ Logger.Info("RemoteWebDriver instances should connect to: {0}", this.baseAddress);
+
+ if (this.nodeRegistrar != null)
+ {
+ this.nodeRegistrar.Register();
+ }
// Enter the listening loop
while (true)
@@ -125,12 +129,12 @@ public void StartListening()
}
catch (SocketException ex)
{
- Logger.Error("SocketException occurred while trying to start listner: {0}", ex);
+ Logger.Error("SocketException occurred while trying to start listener: {0}", ex);
throw;
}
catch (ArgumentException ex)
{
- Logger.Error("ArgumentException occurred while trying to start listner: {0}", ex);
+ Logger.Error("ArgumentException occurred while trying to start listener: {0}", ex);
throw;
}
finally
@@ -149,13 +153,18 @@ public void StopListening()
#region Methods
+ private static string NormalizePrefix(string prefix)
+ {
+ return string.IsNullOrWhiteSpace(prefix) ? string.Empty : prefix.Trim('/');
+ }
+
private string HandleRequest(HttpRequest acceptedRequest)
{
var firstHeaderTokens = acceptedRequest.StartingLine.Split(' ');
var method = firstHeaderTokens[0];
var resourcePath = firstHeaderTokens[1];
- var uriToMatch = new Uri(this.Prefix, resourcePath);
+ var uriToMatch = new Uri(this.baseAddress, resourcePath);
var matched = this.dispatcher.Match(method, uriToMatch);
if (matched == null)
@@ -165,14 +174,22 @@ private string HandleRequest(HttpRequest acceptedRequest)
}
var commandName = matched.Data.ToString();
- var commandToExecute = new Command(commandName, acceptedRequest.MessageBody);
- foreach (string variableName in matched.BoundVariables.Keys)
+ try
{
- commandToExecute.Parameters[variableName] = matched.BoundVariables[variableName];
- }
+ var commandToExecute = new Command(commandName, acceptedRequest.MessageBody);
+ foreach (string variableName in matched.BoundVariables.Keys)
+ {
+ commandToExecute.Parameters[variableName] = matched.BoundVariables[variableName];
+ }
- var commandResponse = this.ProcessCommand(commandToExecute);
- return HttpResponseHelper.ResponseString(commandResponse.HttpStatusCode, commandResponse.Content);
+ var commandResponse = this.ProcessCommand(commandToExecute);
+ return HttpResponseHelper.ResponseString(commandResponse.HttpStatusCode, commandResponse.Content);
+ }
+ catch (Newtonsoft.Json.JsonReaderException exception)
+ {
+ Logger.Error("{0}\r\nRAW REQUEST BODY:\r\n{1}", exception.ToString(), acceptedRequest.MessageBody);
+ return HttpResponseHelper.ResponseString(HttpStatusCode.BadRequest, exception.ToString());
+ }
}
private CommandResponse ProcessCommand(Command command)
@@ -180,10 +197,10 @@ private CommandResponse ProcessCommand(Command command)
Logger.Info("COMMAND {0}\r\n{1}", command.Name, command.Parameters.ToString());
var executor = this.executorDispatcher.GetExecutor(command.Name);
executor.ExecutedCommand = command;
- var respnose = executor.Do();
- Logger.Debug("RESPONSE:\r\n{0}", respnose);
+ var response = executor.Do();
+ Logger.Debug("RESPONSE:\r\n{0}", response);
- return respnose;
+ return response;
}
#endregion
diff --git a/src/Winium.Desktop.Driver/NodeRegistrar.cs b/src/Winium.Desktop.Driver/NodeRegistrar.cs
new file mode 100644
index 0000000..c71072d
--- /dev/null
+++ b/src/Winium.Desktop.Driver/NodeRegistrar.cs
@@ -0,0 +1,243 @@
+namespace Winium.Desktop.Driver
+{
+ #region
+
+ using System;
+ using System.IO;
+ using System.Net;
+ using System.Threading;
+ using System.Timers;
+
+ using Newtonsoft.Json;
+ using Newtonsoft.Json.Linq;
+
+ using Timer = System.Timers.Timer;
+
+ #endregion
+
+ public class NodeRegistrar
+ {
+ #region Fields
+
+ private readonly string configFilePath;
+
+ private readonly string defaultHost;
+
+ private readonly int defaultPort;
+
+ private Timer autoRegisterTimer;
+
+ private string data;
+
+ private NodeRegistrarConfiguration registrarConfiguration;
+
+ #endregion
+
+ #region Constructors and Destructors
+
+ public NodeRegistrar(string configFilePath, string defaultHost, int defaultPort)
+ {
+ this.configFilePath = configFilePath;
+ this.defaultHost = defaultHost;
+ this.defaultPort = defaultPort;
+ }
+
+ #endregion
+
+ #region Public Methods and Operators
+
+ public void Register()
+ {
+ new Thread(
+ () =>
+ {
+ Thread.CurrentThread.IsBackground = true;
+ this.RegisterNode();
+ }).Start();
+ }
+
+ #endregion
+
+ #region Methods
+
+ private void AutoRegisterEvent(object source, ElapsedEventArgs e)
+ {
+ if (!this.IsAlreadyRegistered())
+ {
+ this.PostData();
+ }
+ }
+
+ private bool IsAlreadyRegistered()
+ {
+ try
+ {
+ using (var client = new WebClient())
+ {
+ client.Headers[HttpRequestHeader.ContentType] = "application/json";
+ var uri = new Uri(this.registrarConfiguration.HubUri, "/grid/api/proxy");
+ client.QueryString.Add("id", this.registrarConfiguration.Id);
+ dynamic jo = JObject.Parse(client.DownloadString(uri));
+ return jo.success;
+ }
+ }
+ catch (WebException webException)
+ {
+ Logger.Error("Selenium Grid hub down or not responding: {0}.", webException.Message);
+ }
+
+ return false;
+ }
+
+ private bool LoadConfiguration()
+ {
+ try
+ {
+ dynamic jo = JObject.Parse(File.ReadAllText(this.configFilePath));
+
+ if (jo.configuration.host == null || jo.configuration.port == null || jo.configuration.url == null)
+ {
+ jo.configuration.host = this.defaultHost;
+ jo.configuration.port = this.defaultPort;
+ jo.configuration.url = new UriBuilder("http", this.defaultHost, this.defaultPort).ToString();
+ Logger.Warn(
+ "Some of required node options (host, port or url) are not set, Winium set them to: host={0}, port={1}, url={2}."
+ + " Note that this will not work if your node and grid aren't in the same place.",
+ jo.configuration.host,
+ jo.configuration.port,
+ jo.configuration.url);
+ }
+
+ this.registrarConfiguration = jo.configuration.ToObject();
+
+ this.data = JsonConvert.SerializeObject(jo, Formatting.Indented);
+
+ return true;
+ }
+ catch (JsonReaderException ex)
+ {
+ Logger.Error("Syntax error in node configuration file: {0}", ex.Message);
+ return false;
+ }
+ catch (Exception ex)
+ {
+ Logger.Error("Error reading node configuration: {0}", ex.Message);
+ return false;
+ }
+ }
+
+ private void PostData()
+ {
+ try
+ {
+ using (var client = new WebClient())
+ {
+ client.Headers[HttpRequestHeader.ContentType] = "application/json";
+ var uri = new Uri(this.registrarConfiguration.HubUri, "grid/register/");
+ var response = client.UploadString(uri, this.data);
+
+ Logger.Debug(
+ "Winium successfully registered with the grid on {0}, grid responded with: '{1}'.",
+ this.registrarConfiguration.HubUri,
+ response);
+ }
+ }
+ catch (WebException webException)
+ {
+ var webResponse = webException.Response as HttpWebResponse;
+ if (webResponse != null)
+ {
+ Logger.Error("Selenium Grid refused to register hub. {0}", webResponse.StatusDescription);
+ }
+ else
+ {
+ Logger.Error("Selenium Grid hub down or not responding: {0}.", webException.Message);
+ }
+ }
+ }
+
+ private void RegisterNode()
+ {
+ if (!this.LoadConfiguration())
+ {
+ return;
+ }
+
+ if (!this.registrarConfiguration.Register)
+ {
+ Logger.Debug("Node registration data was not send to Selenium Grid.");
+ return;
+ }
+
+ this.PostData();
+
+ if (!(this.registrarConfiguration.RegisterCycle > 0))
+ {
+ return;
+ }
+
+ Logger.Debug(
+ "Starting auto register for grid. Will try to register every {0} ms",
+ this.registrarConfiguration.RegisterCycle);
+ this.autoRegisterTimer = new Timer();
+ this.autoRegisterTimer.Elapsed += this.AutoRegisterEvent;
+ this.autoRegisterTimer.Interval = this.registrarConfiguration.RegisterCycle;
+ this.autoRegisterTimer.Enabled = true;
+ }
+
+ #endregion
+
+ private class NodeRegistrarConfiguration
+ {
+ #region Fields
+
+ private Uri hubUri;
+
+ private string id;
+
+ #endregion
+
+ #region Public Properties
+
+ public Uri HubUri
+ {
+ get
+ {
+ return this.hubUri ?? (this.hubUri = new UriBuilder("http", this.HubHost, this.HubPort).Uri);
+ }
+ }
+
+ public string Id
+ {
+ get
+ {
+ return this.id ?? (this.id = new UriBuilder("http", this.Host, this.Port).ToString());
+ }
+ }
+
+ [JsonProperty("register")]
+ public bool Register { get; set; }
+
+ [JsonProperty("registerCycle")]
+ public double RegisterCycle { get; set; }
+
+ #endregion
+
+ #region Properties
+
+ [JsonProperty("host")]
+ private string Host { get; set; }
+
+ [JsonProperty("hubHost")]
+ private string HubHost { get; set; }
+
+ [JsonProperty("hubPort")]
+ private int HubPort { get; set; }
+
+ [JsonProperty("port")]
+ private int Port { get; set; }
+
+ #endregion
+ }
+ }
+}
diff --git a/src/Winium.Desktop.Driver/Program.cs b/src/Winium.Desktop.Driver/Program.cs
index 4dd5bf5..a343750 100644
--- a/src/Winium.Desktop.Driver/Program.cs
+++ b/src/Winium.Desktop.Driver/Program.cs
@@ -3,6 +3,7 @@
#region using
using System;
+ using Winium.Desktop.Driver.CommandHelpers;
#endregion
@@ -13,15 +14,16 @@ internal class Program
[STAThread]
private static void Main(string[] args)
{
- var listeningPort = 9999;
-
var options = new CommandLineOptions();
- if (CommandLine.Parser.Default.ParseArguments(args, options))
+ CommandLine.Parser.Default.ParseArgumentsStrict(args, options);
+
+ var appName = typeof(Program).Assembly.GetName().Name;
+ var versionInfo = string.Format("{0}, {1}", appName, new BuildInfo());
+
+ if (options.Version)
{
- if (options.Port.HasValue)
- {
- listeningPort = options.Port.Value;
- }
+ Console.WriteLine(versionInfo);
+ Environment.Exit(0);
}
if (options.LogPath != null)
@@ -37,12 +39,13 @@ private static void Main(string[] args)
Logger.TargetNull();
}
+ Logger.Info(versionInfo);
+
try
{
- var listener = new Listener(listeningPort);
- Listener.UrnPrefix = options.UrlBase;
+ var listener = new Listener(options.Port, options.UrlBase, options.NodeConfig);
- Console.WriteLine("Starting Windows Desktop Driver on port {0}\n", listeningPort);
+ Console.WriteLine("Starting {0} on port {1}\n", appName, listener.Port);
listener.StartListening();
}
diff --git a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj
index 1ad8823..500e741 100644
--- a/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj
+++ b/src/Winium.Desktop.Driver/Winium.Desktop.Driver.csproj
@@ -38,6 +38,7 @@
..\packages\CommandLineParser.1.9.71\lib\net45\CommandLine.dll
+
..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
@@ -52,8 +53,8 @@
-
- ..\packages\Selenium.WebDriver.2.53.1\lib\net40\WebDriver.dll
+
+ ..\packages\Selenium.WebDriver.3.3.0\lib\net40\WebDriver.dll
True
@@ -72,6 +73,7 @@
+
@@ -85,6 +87,7 @@
+
@@ -117,6 +120,7 @@
+
@@ -126,6 +130,7 @@
+
diff --git a/src/Winium.Desktop.Driver/packages.config b/src/Winium.Desktop.Driver/packages.config
index 0486d04..9b60155 100644
--- a/src/Winium.Desktop.Driver/packages.config
+++ b/src/Winium.Desktop.Driver/packages.config
@@ -5,6 +5,6 @@
-
+
\ No newline at end of file