I am a novice developer trying to develop framework and some internal tools for UI automation.
I have some code in Helpers class which basically provides functionality to check and prepare expected directory structure, copy some files from a network folder, start a couple of Java applications (Selenium hub and node, for those interested) etc. All these methods accept an IProgress in order to be able to report back the progress, exceptions, errors etc.
I have written one console application and one Windows Forms application doing exactly the same thing but to suit different audience (Devs vs BAs). However, the behaviour and output from the Helpers class methods is different when invoked from Console app vs Windows Forms app. My question is whether this is expected. If so, how do I resolve this issue? If not, any pointers to what I am doing wrong would be greatly appreciated. Code below.
public class Helpers
{
public static void StartHub(string[] hubParams, IProgress<string> progress)
{
try
{
string hubParameters;
if (hubParams == null)
{
hubParameters = String.Empty;
}
else
{
hubParameters = String.Join(" ", hubParams);
hubParameters = hubParameters.Replace("/", "-");
}
var hubCommand =
String.Format(
@"-Xmx1024m -jar C:\Selenium\ServerExecutable\selenium-server-standalone.jar -role hub -log C:\Selenium\_Logs\hub_{0}.log {1}",
DateTime.Now.ToString("ddMMMyyyy-HHmmss"), hubParameters).Trim();
ExecuteCommand(String.Format(@"{0}\java.exe", GetJavaPath(progress)), progress, hubCommand, false);
ExecuteCommand(String.Format("http://{0}:4444/grid/console", Environment.MachineName), progress, hideWindow: false);
progress.Report(
"Hub started. Please check the opened command window and/or browser window to ensure it started successfully. For logs look in C:\\Selenium\\_Logs folder.");
}
catch (Exception e)
{
progress.Report(string.Format("Could not start hub. {0}{1}", e, Environment.NewLine));
}
}
public static void StartNode(NodeOptions nodeParams, IProgress<string> progress)
{
try
{
var ieVersion = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Internet Explorer").GetValue("svcVersion").ToString().Split('.')[0];
var defaultNodeCommand = String.Format(
@"-Xmx512m -jar C:\Selenium\ServerExecutable\selenium-server-standalone.jar -role wd -hub http://{1}/grid/register -log C:\Selenium\_Logs\node_{0}.log -Dwebdriver.chrome.driver=C:\Selenium\chromedriver_win32\chromedriver.exe -Dwebdriver.ie.driver=C:\Selenium\IEDriver_Win32\IEDriverServer.exe",
DateTime.Now.ToString("ddMMMyyyy-HHmmss"), nodeParams.Hub);
var nodeBrowsers = _BuildBrowsersNodeCommand(nodeParams, ieVersion);
string nodeCommand = String.Format("{0}{1}", defaultNodeCommand, nodeBrowsers);
ExecuteCommand(String.Format(@"{0}\java.exe", GetJavaPath(progress)), progress, nodeCommand, false);
progress.Report(
"Node started. Please check the opened command window and/or browser window to ensure it started successfully. For logs look in C:\\Selenium\\_Logs folder." +
Environment.NewLine);
}
catch (Exception e)
{
progress.Report(string.Format("Could not start node. {0}{1}", e, Environment.NewLine));
}
}
private static string _BuildBrowsersNodeCommand(NodeOptions nodeParams, string ieVersion)
{
var nodeBrowsers = new StringBuilder();
foreach (var browser in nodeParams.BrowsersList)
{
if (browser.ToUpperInvariant() == "IE" || browser.ToUpperInvariant() == "INTERNETEXPLORER")
{
nodeBrowsers.Append(String.Format(
" -browser \"platform=WINDOWS,version={0}Windows7,browserName=internet explorer,maxInstances=1\"",
ieVersion));
}
else
{
nodeBrowsers.Append(String.Format(
" -browser \"platform=WINDOWS,version=Windows7,browserName={0},maxInstances={1}\"",
browser, nodeParams.MaxSessions));
}
}
return nodeBrowsers.ToString();
}
public static Process ExecuteCommand(string fileName, IProgress<string> progress, string command = null, bool hideWindow = true)
{
if (hideWindow)
{
var processInfo = new ProcessStartInfo(fileName, command)
{
CreateNoWindow = true,
UseShellExecute = false,
//WorkingDirectory = "\\",
// *** Redirect the output ***
RedirectStandardError = true,
RedirectStandardOutput = true
};
var process = new Process { StartInfo = processInfo, EnableRaisingEvents = true };
process.ErrorDataReceived += (sender, args) => progress.Report(args.Data);
process.OutputDataReceived += (sender, args) => progress.Report(args.Data);
var started = process.Start();
progress.Report(string.Format("process started: {0}", started));
progress.Report(string.Format("process id: {0}", process.Id));
progress.Report(string.Format("process start info: {0} {1}", process.StartInfo.FileName, process.StartInfo.UserName));
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
int ExitCode = process.ExitCode;
progress.Report(string.Format("ExitCode: {0}{1}", ExitCode, Environment.NewLine));
process.Close();
return null;
}
else
{
var process = Process.Start(fileName, command);
//process.WaitForExit();
return process;
}
}
public static string GetJavaPath(IProgress<string> progress)
{
var javaPath = Environment.GetEnvironmentVariable("path").Split(';').FirstOrDefault(s => s.Contains("javapath"));
if (javaPath == default(string))
{
progress.Report(string.Format(@"{0}Java is either not installed on this machine or its path is not set in System environment variable 'Path'. Cannot proceed without Java.{0}", Environment.NewLine));
throw new ApplicationException(
@"Java is either not installed on this machine or its path is not set in System environment variable 'Path'. Cannot proceed without Java.");
}
return javaPath;
}
public static void CreateRequiredDirectories(IProgress<string> progress)
{
progress.Report(string.Format(@"Checking required folder structure exists...{0}", Environment.NewLine));
if (!Directory.Exists(@"C:\Selenium"))
{
progress.Report(string.Format(@"C:\Selenium folder doesn't exist on your machine. Creating it now...{0}", Environment.NewLine));
Directory.CreateDirectory(@"C:\Selenium");
progress.Report(string.Format(@"C:\Selenium folder created successfully{0}", Environment.NewLine));
}
if (!Directory.Exists(@"C:\Selenium\_Logs"))
{
progress.Report(string.Format(@"C:\Selenium\_Logs folder doesn't exist on your machine. Creating it now...{0}", Environment.NewLine));
Directory.CreateDirectory(@"C:\Selenium\_Logs");
progress.Report(string.Format(@"C:\Selenium\_Logs folder created successfully{0}", Environment.NewLine));
}
progress.Report(string.Format(@"Required folder structure checked successfully{0}", Environment.NewLine));
}
public static void CopyRequiredFiles(IProgress<string> progress, bool hideWindow = false)
{
progress.Report(string.Format("Copying latest version of executables...{0}", Environment.NewLine));
var currentDirectory = Directory.GetCurrentDirectory();
ExecuteCommand(String.Format(@"{0}\Copy latest Selenium files.bat", currentDirectory), progress, hideWindow: hideWindow);
progress.Report(string.Format("\r\nLatest version of executables copied successfully{0}", Environment.NewLine));
}
public static IEnumerable<string> ParseArguments(string commandLine)
{
if (string.IsNullOrWhiteSpace(commandLine))
yield break;
var sb = new StringBuilder();
bool inQuote = false;
foreach (char c in commandLine)
{
if (c == '"' && !inQuote)
{
inQuote = true;
continue;
}
if (c != '"' && !(char.IsWhiteSpace(c) && !inQuote))
{
sb.Append(c);
continue;
}
if (sb.Length > 0)
{
var result = sb.ToString();
sb.Clear();
inQuote = false;
yield return result;
}
}
if (sb.Length > 0)
yield return sb.ToString();
}
}
My Console App:
public class Program
{
private static readonly LauncherOptions Options = new LauncherOptions();
private static bool _startHub;
private static bool _startNode;
private static StringBuilder sb = new StringBuilder();
private static readonly Action<string> OutputAction = s => Console.WriteLine(s);
private static readonly Action<string> OutputActionAlter = s => sb.AppendLine(s);
private static readonly IProgress<string> Progress = new Progress<string>(OutputActionAlter);
public static void Main(string[] args)
{
if (Parser.Default.ParseArguments(args, Options))
{
_AcknowledgeAndCheckArguments();
Helpers.CreateRequiredDirectories(Progress);
Helpers.CopyRequiredFiles(Progress, true);
if (_startHub)
{
Helpers.StartHub(Options.HubParams, Progress);
}
if (_startNode)
{
var nodeOptions = new NodeOptions();
Console.WriteLine(nodeOptions.GetUsage());
Console.WriteLine("Please use above parameters to customise your node. For default node, just press the enter key.");
var userInput = Console.ReadLine();
var userInputArgs = Helpers.ParseArguments(userInput);
Parser.Default.ParseArguments(userInputArgs.ToArray(), nodeOptions);
Helpers.StartNode(nodeOptions, Progress);
}
Console.WriteLine("\r\nPress any key to close the Launcher. For hub and node logs look in C:\\Selenium\\_Logs folder.\r\n");
var output = sb.ToString();
Console.ReadKey();
}
}
}
My Windows Forms app:
public partial class frmLauncherMain : Form
{
private readonly LauncherOptions _options = new LauncherOptions();
private readonly NodeOptions _nodeOptions = new NodeOptions();
private readonly List<string> _selectedBrowsers = new List<string>();
private StringBuilder sb = new StringBuilder();
private readonly IProgress<string> _progress;
public frmLauncherMain()
{
InitializeComponent();
cboMaxSessions.SelectedItem = "5";
chkStartHub.Checked = true;
chkStartNode.Checked = true;
_nodeOptions.BrowsersList = new[] { "chrome", "firefox", "ie" };
_nodeOptions.Hub = "localhost:4444";
_nodeOptions.MaxSessions = "5";
txtOutput.Clear();
Action<string> outputAction = s => txtOutput.InvokeEx(t => t.Text += s);
Action<string> outputActionAlter = s => sb.AppendLine(s);
_progress = new Progress<string>(outputActionAlter);
}
private void btnGo_Click(object sender, EventArgs e)
{
txtOutput.Clear();
//sb.Clear();
if (txtHubParams.TextLength != 0)
{
_options.HubParams = Helpers.ParseArguments(txtHubParams.Text).ToArray();
}
if (chkCustomNode.Checked)
{
if (_selectedBrowsers.Any())
{
_nodeOptions.BrowsersList = _selectedBrowsers.ToArray();
}
else
{
MessageBox.Show("Please select at least one browser.");
}
_nodeOptions.Hub = txtHub.Text.Trim();
_nodeOptions.MaxSessions = string.IsNullOrEmpty(cboMaxSessions.SelectedText) ? "5" : cboMaxSessions.SelectedText;
}
Helpers.CreateRequiredDirectories(_progress);
Helpers.CopyRequiredFiles(_progress, true);
if (chkStartHub.Checked)
{
Helpers.StartHub(_options.HubParams, _progress);
}
if (chkStartNode.Checked)
{
Helpers.StartNode(_nodeOptions, _progress);
}
var output = sb.ToString();
/* trying another method
var createDirectoriesTask = new Task(() => Helpers.CreateRequiredDirectories(progress));
var copyFilesTask = new Task(() => Helpers.CopyRequiredFiles(progress, true));
var startHubTask = new Task(() => Helpers.StartHub(_options.HubParams, progress));
var startNodeTask = new Task(() => Helpers.StartNode(_nodeOptions, progress));
createDirectoriesTask.Start();
createDirectoriesTask.ContinueWith(delegate { copyFilesTask.Start(); });
if (chkStartHub.Checked)
{
copyFilesTask.ContinueWith(delegate { startHubTask.Start(); });
}
if (chkStartNode.Checked)
{
startHubTask.ContinueWith(delegate { startNodeTask.Start(); });
}
*/
//txtOutput.Text = sb.ToString();
}
private void chkChrome_CheckedChanged(object sender, EventArgs e)
{
if (chkChrome.Checked)
{
_selectedBrowsers.Add("chrome");
}
}
private void chkFirefox_CheckedChanged(object sender, EventArgs e)
{
if (chkFirefox.Checked)
{
_selectedBrowsers.Add("firefox");
}
}
private void chkIE_CheckedChanged(object sender, EventArgs e)
{
if (chkIE.Checked)
{
_selectedBrowsers.Add("internet explorer");
}
}
private void chkStartHub_CheckedChanged(object sender, EventArgs e)
{
_options.StartHub = chkStartHub.Checked ? "yes" : "no";
}
private void chkStartNode_CheckedChanged(object sender, EventArgs e)
{
_options.StartNode = chkStartHub.Checked ? "yes" : "no";
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
Environment.Exit(0);
}
}
Output from Console app:
Checking required folder structure exists...
Required folder structure checked successfully
Copying latest version of executables...
process started: True process id: 1196 process start info: D:\Managed\RUN\Source\Main\Automation\Selenium\HubNodeLauncher\SeleniumHubNodeLauncher\bin\Debug\Copy latest Selenium files.bat Deleting existing mappings... z: was deleted successfully.
Mapping network drives... The command completed successfully.
Copying latest Selenium jars... Z:\Hub and Node Executables\Launch Selenium 2 Node.bat Z:\Hub and Node Executables\lessons.txt Z:\Hub and Node Executables__hub parameters.txt Z:\Hub and Node Executables\Launch Selenium 2 Hub.bat Z:\Hub and Node Executables\chromedriver_win32\chromedriver.exe Z:\Hub and Node Executables\chromedriver_win32\chromedriver_win32_2.12.zip Z:\Hub and Node Executables\chromedriver_win32\chromedriver_win32_2.14.zip Z:\Hub and Node Executables\chromedriver_win32\chromedriver_win32_2.9.zip Z:\Hub and Node Executables\chromedriver_win32\current version is 2.14.txt Z:\Hub and Node Executables\IEDriver_Win32\current version is Win32_2.45.0.txt > Z:\Hub and Node Executables\IEDriver_Win32\IEDriverServer.exe Z:\Hub and Node Executables\IEDriver_Win32\IEDriverServer_Win32_2.41.0.exe Z:\Hub and Node Executables\IEDriver_Win32\IEDriverServer_Win32_2.44.0.exe Z:\Hub and Node Executables\IEDriver_x64\Current version is _x64_2.45.0.txt Z:\Hub and Node Executables\IEDriver_x64\IEDriverServer.exe Z:\Hub and Node Executables\IEDriver_x64\IEDriverServer_x64_2.44.0.exe Z:\Hub and Node Executables\NodeConfigs\nodeconfig.json Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Custom Node v2.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Custom Node v3.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Custom Node.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Default Node Using json.bat > Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Default Node.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Win 7 Chrome Firefox Node.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Win 7 IE 11 Node.bat Z:\Hub and Node Executables\NodeConfigs\Selenium 2 Win 8.1 IE 11 Node.bat Z:\Hub and Node Executables\ServerExecutable\current version is -2.45.0.txt Z:\Hub and Node Executables\ServerExecutable\selenium-server-standalone-2.41.0.jar Z:\Hub and Node Executables\ServerExecutable\selenium-server-standalone-2.43.1.jar Z:\Hub and Node Executables\ServerExecutable\selenium-server-standalone-2.44.0.jar Z:\Hub and Node Executables\ServerExecutable\selenium-server-standalone.jar 30 File(s) copied Finished copying latest Selenium jars... All done
ExitCode: 0
Latest version of executables copied successfully
Hub started. Please check the opened command window and/or browser window to ensure it started successfully. For logs look in C:\Selenium_Logs folder.
Node started. Please check the opened command window and/or browser window to ensure it started successfully. For logs look in C:\Selenium_Logs folder.
Output from Windows Forms app:
Checking required folder structure exists...
Required folder structure checked successfully
Copying latest version of executables...
process started: True process id: 13200 process start info: D:\Managed\RUN\Source\Main\Automation\Selenium\HubNodeLauncher\SeleniumHubNodeLauncherUI\bin\Debug\Copy latest Selenium files.bat Deleting existing mappings... z: was deleted successfully.
Mapping network drives... The command completed successfully.
Copying latest Selenium jars... Finished copying latest Selenium jars... All done
ExitCode: 0
Latest version of executables copied successfully