I have a Selenium Test.DLL that loads using NUnit.
I run the required Selenium Java Server silently hidden in the process when starting the test.
However, currently start the server when the test starts and it when the test stops . Kill()
This causes the selenium server to start / stop for each test .
I want the Selenium Server process:
- Run either in the loading / initialization of the DLL , or the first time you run the test
- Be ed on Death DLL or Garbage Collection
Kill()
I read that C # does not support the DLL initialization trap and call code. (I am wrong?)
My idea was to host the Selenium server in a singleton class and initialize it the first time the test is run. Then I left it in the garbage collector to call the Dispose method through the deconstructor. I currently have the following code for hosting a selenium server:
namespace Tests.Server
{
using System;
using System.Diagnostics;
using System.IO;
using System.Security;
using System.Windows.Forms;
using Microsoft.Win32;
public class SeleniumServer : IDisposable
{
#region Fields
private static volatile SeleniumServer instance;
private static object syncRoot = new Object();
private Process seleniumServer = null;
private bool isDisposed = false;
#endregion
#region Constructor
private SeleniumServer()
{
string javaFileLocation = this.GetJavaFileLocation();
string jarFileLocation = '"' + Directory.GetCurrentDirectory() + @"\SeleniumServer\selenium-server.jar""";
seleniumServer = new Process();
seleniumServer.StartInfo.FileName = javaFileLocation;
seleniumServer.StartInfo.Arguments = " -jar " + jarFileLocation + " -browserSessionReuse -trustAllSSLCertification";
seleniumServer.StartInfo.WorkingDirectory = jarFileLocation.Substring(0, jarFileLocation.LastIndexOf("\\"));
seleniumServer.StartInfo.UseShellExecute = true;
seleniumServer.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
seleniumServer.Start();
}
#endregion
#region Deconstructor
~SeleniumServer()
{
Dispose(false);
}
#endregion
#region Properties
public static SeleniumServer Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new SeleniumServer();
}
}
}
return instance;
}
}
#endregion
#region Methods
protected void Dispose(bool disposing)
{
if (disposing)
{
}
Instance.seleniumServer.Kill();
isDisposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Stop()
{
this.Dispose();
}
private string GetJavaFileLocation()
{
string javaFileLocation = string.Empty;
RegistryKey regKey = Registry.LocalMachine;
RegistryKey subKey = null;
try
{
string javaRegistryLocation = @"SOFTWARE\JavaSoft\Java Runtime Environment\";
subKey = regKey.OpenSubKey(javaRegistryLocation);
if (subKey == null)
{
javaRegistryLocation = @"SOFTWARE\Wow6432Node\JavaSoft\Java Runtime Environment\";
subKey = regKey.OpenSubKey(javaRegistryLocation);
}
if (subKey == null)
{
MessageBox.Show(
"You must have Java installed to run the commands server. This allows browser commands to be routed to the browser window.\n\nPlease visit: http://www.java.com/ to download.",
"Please Install Java",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
throw new Exception("No installation of Java was detected to run the selenium server.");
}
string[] subKeyNames = subKey.GetSubKeyNames();
subKey = regKey.OpenSubKey(javaRegistryLocation + subKeyNames[subKeyNames.Length - 1]);
javaFileLocation = subKey.GetValue("JavaHome").ToString() + @"\bin\java.exe";
}
catch (SecurityException e)
{
javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
if (!File.Exists(javaFileLocation))
{
MessageBox.Show(
"The program did not have permission to access the registry to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
"Java Executable Not Found",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
throw new Exception("The program did not have permission to access the registry to obtain the installation folder of Java.", e);
}
}
catch (UnauthorizedAccessException e)
{
javaFileLocation = @"C:\Program Files\Java\jre6\bin\java.exe";
if (!File.Exists(javaFileLocation))
{
MessageBox.Show(
"The user does not have the necessary registry rights to obtain the installation folder of Java.\n\nThe default location (" + javaFileLocation + ") of Java was used and the Java executable was not found.\n\nPlease install Java in this folder or see the help under the RegistryKey.OpenSubKey method on MSDN.",
"Java Executable Not Found",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
throw new Exception("The user does not have the necessary registry rights to obtain the installation folder of Java.", e);
}
}
catch (ObjectDisposedException e)
{
MessageBox.Show(
"The Java registry object was closed, resulting in the Java server not being started. Please report this error.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
throw new ObjectDisposedException("The Java registry object was closed. Please report this error.", e);
}
catch (IOException e)
{
MessageBox.Show(
"The Java registry object was marked for deletion, resulting in the Java server not being started. Please report this error.",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
throw new ObjectDisposedException("The Java registry object was marked for deletion. Please report this error.", e);
}
return javaFileLocation;
}
#endregion
}
}
My questions:
- Is this a smart way to host a process for a DLL's life?
- How do I configure this class from my code? Does it need static / global? Any good singleton usage examples you know about?
- Will garbage collection recycle this singleton when unloading a DLL?
- DLL, DLL , NUnit DLL ?