blob: 50705a076bb07e3f0d5bb023d2480c8434c0c806 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Serialization.Formatters;
using System.Text;
using System.Threading;
namespace Apache.Geode.DUnitFramework
{
using NUnit.Framework;
public class UnitProcess : ClientBase
{
#region Public constants and accessors
public const string ClientProcName = "FwkClient.exe";
public string SshArgs
{
get
{
return m_sshArgs;
}
}
public string PsexecArgs
{
get
{
return m_psexecArgs;
}
}
public override string StartDir
{
get
{
return m_startDir;
}
}
#endregion
#region Private members
private static int m_clientId = 0;
private static int m_clientPort = Util.RandPort(20000, 40000) - 1;
internal static Dictionary<string, ManualResetEvent> ProcessIDMap =
new Dictionary<string, ManualResetEvent>();
public const int MaxStartWaitMillis = 300000;
public const int MaxEndWaitMillis = 3000000;
private Process m_process;
private string m_sshPath;
private string m_sshArgs;
private string m_psexecPath;
private string m_psexecArgs;
private string m_hostName;
private string m_sharePath;
private string m_shareName;
private string m_startDir;
private Dictionary<string, string> m_envs;
private IClientComm m_clientComm;
private bool m_timeout;
private volatile bool m_exiting;
private ManualResetEvent m_clientEvent = new ManualResetEvent(false);
#endregion
// Using static constructor since it is guaranteed
// to be called on first access.
static UnitProcess()
{
// Create the server side channels (required only once)
// NOTE: This is required so that remote client receives custom exceptions
RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off;
RegisterChannel();
RemotingConfiguration.RegisterWellKnownServiceType(typeof(DriverComm),
CommConstants.DriverService, WellKnownObjectMode.SingleCall);
if (Util.ExternalBBServer == null)
{
RemotingConfiguration.RegisterWellKnownServiceType(typeof(BBComm),
CommConstants.BBService, WellKnownObjectMode.SingleCall);
Util.SetEnvironmentVariable(CommConstants.BBAddrEnvVar,
Util.IPAddressString + ':' + Util.DriverPort.ToString());
}
}
#region Private functions
private static void RegisterChannel()
{
var serverProvider = new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel = TypeFilterLevel.Full;
var clientProvider = new BinaryClientFormatterSinkProvider();
var properties = new Dictionary<string, string>();
properties["port"] = Util.DriverPort.ToString();
properties["name"] = "GFTcpChannel";
var channel = new TcpChannel(properties, clientProvider, serverProvider);
ChannelServices.RegisterChannel(channel, false);
}
private void ExitClient(int waitMillis, bool force)
{
if (m_clientComm != null)
{
Thread killThread = new Thread(ExitClient);
killThread.Start();
if (waitMillis > 0)
{
if (!killThread.Join(waitMillis))
{
Util.Log(Util.LogLevel.Error,
"Timed out waiting for client {0} to exit.", ID);
}
}
if (m_process != null && !m_process.HasExited)
{
if (waitMillis > 0)
{
m_process.WaitForExit(waitMillis);
}
}
if (m_process != null && !m_process.HasExited)
{
try
{
m_process.Kill();
}
catch
{
}
if (waitMillis > 0)
{
m_process.WaitForExit(waitMillis);
}
}
m_clientComm = null;
}
}
private void ExitClient()
{
ExitClient(false);
}
private void ExitClient(bool force)
{
try
{
m_clientComm.Exit(force);
}
catch
{
// Client cannot be reached or already forcibly closed.
// Nothing required to be done.
}
}
#endregion
#region Public non-overriding methods
public static void Init()
{
// Do nothing; just ensures that the static constructor is invoked.
}
public static int GetClientId()
{
Interlocked.Increment(ref m_clientId);
return m_clientId;
}
public static int GetClientPort()
{
Interlocked.Increment(ref m_clientPort);
return m_clientPort;
}
private UnitProcess(string clientId)
{
if (clientId == null)
{
clientId = GetClientId().ToString();
}
this.ID = clientId;
}
public UnitProcess()
: this(null, null)
{
}
public UnitProcess(string clientId, string startDir)
{
int clientPort = GetClientPort();
if (clientId == null)
{
clientId = GetClientId().ToString();
}
this.ID = clientId;
string localArgs = "--id=" + clientId + " --driver=tcp://" +
Util.IPAddressString + ':' + Util.DriverPort + '/' +
CommConstants.DriverService + " --bbServer=";
if (Util.ExternalBBServer != null)
{
localArgs += Util.ExternalBBServer + ' ' + clientPort;
}
else
{
localArgs += "tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.BBService + ' ' + clientPort;
}
lock (((ICollection)ProcessIDMap).SyncRoot)
{
ProcessIDMap[clientId] = m_clientEvent;
}
bool procStarted;
bool hasCoverage = "true".Equals(Environment.GetEnvironmentVariable(
"COVERAGE_ENABLED"));
if (hasCoverage)
{
string coveragePrefix = "coverage-" + clientId;
procStarted = Util.StartProcess("ncover.console.exe", "//x "
+ coveragePrefix + ".xml " + ClientProcName + " " + localArgs,
Util.LogFile == null, startDir, true, true, true, out m_process);
}
else
{
procStarted = Util.StartProcess(ClientProcName, localArgs,
Util.LogFile == null, startDir, false, false, false, true, out m_process);
}
if (!procStarted)
{
throw new AssertionException("FATAL: Could not start client: " +
ClientProcName);
}
m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
Util.IPAddressString + ':' + clientPort + '/' + CommConstants.ClientService);
m_timeout = false;
m_exiting = false;
m_startDir = startDir;
}
public UnitProcess(string clientId, int clientNum, string sshPath,
string sshArgs, string hostName, string sharePath, string shareName,
string startDir, Dictionary<string, string> envs)
{
string clientProcPath = ClientProcName;
string remoteArgs;
string runDir = null;
if (sharePath != null)
{
runDir = Util.AssemblyDir.Replace(sharePath.ToLower(), shareName);
clientProcPath = runDir + Path.DirectorySeparatorChar + ClientProcName;
clientProcPath = clientProcPath.Replace('\\', '/');
}
int clientPort = GetClientPort();
if (clientId == null)
{
clientId = GetClientId().ToString();
}
this.ID = clientId;
string envStr = string.Empty;
if (envs != null)
{
m_envs = envs;
foreach (KeyValuePair<string, string> envNameValue in envs)
{
string envValue = envNameValue.Value.Replace(sharePath, shareName);
envStr += " '--env:" + envNameValue.Key + '=' + envValue + '\'';
}
}
string bbServer;
if (Util.ExternalBBServer != null)
{
bbServer = Util.ExternalBBServer;
}
else
{
bbServer = "tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.BBService;
}
remoteArgs = sshArgs + ' ' + hostName + " '" + clientProcPath +
"' --id=" + clientId + " --num=" + clientNum + envStr +
" '--startdir=" + (startDir == null ? runDir : startDir) +
"' '--driver=tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.DriverService + "' '--bbServer=" + bbServer +
"' " + clientPort;
try
{
lock (((ICollection)ProcessIDMap).SyncRoot)
{
ProcessIDMap[clientId] = m_clientEvent;
}
if (!Util.StartProcess(sshPath, remoteArgs, Util.LogFile == null,
null, false, false, false, out m_process))
{
throw new AssertionException("Failed to start the client.");
}
if (!m_clientEvent.WaitOne(MaxStartWaitMillis, false))
{
throw new AssertionException("Timed out waiting for client to start.");
}
m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
hostName + ':' + clientPort + '/' + CommConstants.ClientService);
m_process = m_clientComm.GetClientProcess();
m_sshPath = sshPath;
m_sshArgs = sshArgs;
m_hostName = hostName;
m_timeout = false;
m_exiting = false;
m_sharePath = sharePath;
m_shareName = shareName;
m_startDir = startDir;
}
catch (Exception ex)
{
throw new AssertionException(string.Format("FATAL: Could not start " +
"client: {1}{0}\ton host: {2}{0}\tusing remote shell: {3}{0}" +
"\tException: {4}", Environment.NewLine, clientProcPath, hostName,
sshPath, ex));
}
}
/// <summary>
/// Create a UnitProcess object by launching a client using a launcher. The
/// launcher is launched on the remote host using psexec.
/// </summary>
public UnitProcess(string clientId, int clientNum, string psexecPath,
string psexecArgs, string hostName, string sharePath, string shareName,
string startDir, Dictionary<string, string> envs,
int launcherPort, Dictionary<string, UnitProcess> launcherProcesses, string logPath)
{
UnitProcess launcherProcess = null;
if (!launcherProcesses.ContainsKey(hostName))
{
launcherProcess = CreateLauncherUsingPsexec(GetClientId().ToString(),
psexecPath, psexecArgs, hostName, sharePath, shareName, startDir,
launcherPort, logPath);
launcherProcesses.Add(hostName, launcherProcess);
}
else
{
launcherProcess = launcherProcesses[hostName];
}
string clientProcPath = ClientProcName;
string remoteArgs;
string runDir = null;
if (sharePath != null)
{
runDir = Util.AssemblyDir.Replace(sharePath.ToLower(), shareName);
clientProcPath = runDir + Path.DirectorySeparatorChar + ClientProcName;
clientProcPath = clientProcPath.Replace('/', '\\');
}
int clientPort = GetClientPort();
if (clientId == null)
{
clientId = GetClientId().ToString();
}
this.ID = clientId;
string envStr = string.Empty;
if (envs != null)
{
m_envs = envs;
foreach (KeyValuePair<string, string> envNameValue in envs)
{
string envValue = envNameValue.Value.Replace(sharePath, shareName);
envStr += " --env:" + envNameValue.Key + "=\"" + envValue + '\"';
}
}
string bbServer;
if (Util.ExternalBBServer != null)
{
bbServer = Util.ExternalBBServer;
}
else
{
bbServer = "tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.BBService;
}
remoteArgs = " --id=" + clientId + " --num=" + clientNum + envStr +
" --startdir=\"" + (startDir == null ? runDir : startDir) +
"\" --driver=tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.DriverService + " --bbServer=\"" + bbServer +
"\" " + clientPort;
try
{
IClientCommV2 clientComm = launcherProcess.m_clientComm as IClientCommV2;
Process proc;
if (!clientComm.LaunchNewClient(clientProcPath, remoteArgs, out proc))
{
throw new AssertionException("Failed to start client: " +
clientId);
}
m_process = proc;
lock (((ICollection)ProcessIDMap).SyncRoot)
{
ProcessIDMap[clientId] = m_clientEvent;
}
if (!m_clientEvent.WaitOne(MaxStartWaitMillis, false))
{
throw new AssertionException("Timed out waiting for client to start.");
}
m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
hostName + ':' + clientPort + '/' + CommConstants.ClientService);
m_process = m_clientComm.GetClientProcess();
m_psexecPath = psexecPath;
m_psexecArgs = psexecArgs;
m_hostName = hostName;
m_timeout = false;
m_exiting = false;
m_sharePath = sharePath;
m_shareName = shareName;
m_startDir = startDir;
}
catch (Exception ex)
{
throw new AssertionException(string.Format("FATAL: Could not start " +
"client: {1}{0}\ton host: {2}{0}\tusing: FwkLauncher{0}" +
"\tException: {3}", Environment.NewLine, clientProcPath, hostName,
ex));
}
}
public static UnitProcess Create()
{
return new UnitProcess();
}
public static UnitProcess Create(string clientId, string startDir)
{
return new UnitProcess(clientId, startDir);
}
public static UnitProcess Create(string clientId, int clientNum,
string sshPath, string sshArgs, string hostName, string sharePath,
string shareName, string startDir, Dictionary<string, string> envs)
{
return new UnitProcess(clientId, clientNum, sshPath, sshArgs, hostName,
sharePath, shareName, startDir, envs);
}
public static List<UnitProcess> Create(List<string> clientIds,
int startClientNum, string sshPath, string sshArgs, string hostName,
string sharePath, string shareName, string startDir,
Dictionary<string, string> envs)
{
if (clientIds != null && clientIds.Count > 0)
{
string clientProcPath = ClientProcName;
string clientsCmd = string.Empty;
string runDir = null;
string clientId;
List<UnitProcess> unitProcs = new List<UnitProcess>();
UnitProcess unitProc;
if (sharePath != null)
{
runDir = Util.AssemblyDir.Replace(sharePath.ToLower(), shareName);
clientProcPath = runDir + Path.DirectorySeparatorChar + ClientProcName;
clientProcPath = clientProcPath.Replace('\\', '/');
}
string envStr = string.Empty;
if (envs != null)
{
foreach (KeyValuePair<string, string> envNameValue in envs)
{
string envValue = envNameValue.Value.Replace(sharePath, shareName);
envStr += " '--env:" + envNameValue.Key + '=' + envValue + '\'';
}
}
List<int> clientPorts = new List<int>();
lock (((ICollection)ProcessIDMap).SyncRoot)
{
for (int i = 0; i < clientIds.Count; i++, startClientNum++)
{
int clientPort = GetClientPort();
clientId = clientIds[i];
if (clientId == null)
{
clientId = GetClientId().ToString();
clientIds[i] = clientId;
}
string bbServer;
if (Util.ExternalBBServer != null)
{
bbServer = Util.ExternalBBServer;
}
else
{
bbServer = "tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.BBService;
}
clientsCmd += '\'' + clientProcPath + "' --bg --id=" + clientId +
" --num=" + startClientNum + envStr + " '--startdir=" +
(startDir == null ? runDir : startDir) + "' '--driver=tcp://" +
Util.IPAddressString + ':' + Util.DriverPort + '/' +
CommConstants.DriverService + "' '--bbServer=" + bbServer +
"' " + clientPort + " ; ";
clientPorts.Add(clientPort);
unitProc = new UnitProcess(clientId);
ProcessIDMap[clientId] = unitProc.m_clientEvent;
unitProcs.Add(unitProc);
}
}
try
{
Process proc;
//string sshAllArgs = sshArgs + ' ' + hostName +
// " \"" + " NCover.Console.exe //x Coverage.xml //at coverage.trend " + clientsCmd + '"';
string sshAllArgs = sshArgs + ' ' + hostName +
" \"" + clientsCmd + '"';
Util.RawLog(string.Format("Running remote command: {0} {1}{2}",
sshPath, Util.HideSshPassword(sshAllArgs), Environment.NewLine));
if (!Util.StartProcess(sshPath, sshAllArgs, Util.LogFile == null, null,
false, false, false, out proc))
{
throw new AssertionException("Failed to start the clients.");
}
for (int i = 0; i < clientIds.Count; i++)
{
clientId = clientIds[i];
unitProc = (UnitProcess)unitProcs[i];
if (!unitProc.m_clientEvent.WaitOne(MaxStartWaitMillis, false))
{
throw new AssertionException("Timed out waiting for client: " +
clientId);
}
unitProc.m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
hostName + ':' + clientPorts[i] + '/' + CommConstants.ClientService);
unitProc.m_process = unitProc.m_clientComm.GetClientProcess();
unitProc.m_sshPath = sshPath;
unitProc.m_sshArgs = sshArgs;
unitProc.m_hostName = hostName;
unitProc.m_timeout = false;
unitProc.m_exiting = false;
unitProc.m_sharePath = sharePath;
unitProc.m_shareName = shareName;
unitProc.m_startDir = startDir;
unitProc.m_envs = envs;
}
}
catch (Exception ex)
{
unitProcs.Clear();
unitProcs = null;
clientPorts.Clear();
clientPorts = null;
throw new AssertionException(string.Format("FATAL: Could not start " +
"client: {1}{0}\ton host: {2}{0}\tusing remote shell: {3}{0}" +
"\tException: {4}", Environment.NewLine, clientProcPath, hostName,
sshPath, ex));
}
return unitProcs;
}
return null;
}
/// <summary>
/// Create clients on the remote host using FwkLauncher.
/// </summary>
public static List<UnitProcess> CreateClientsUsingLauncher(List<string> clientIds,
int startClientNum, string psexecPath, string psexecArgs, string hostName,
string sharePath, string shareName, string startDir,
Dictionary<string, string> envs, int launcherPort,
Dictionary<string, UnitProcess> launcherProcesses, string logPath)
{
if (clientIds != null && clientIds.Count > 0)
{
UnitProcess launcherProcess = null;
if (!launcherProcesses.ContainsKey(hostName))
{
launcherProcess = CreateLauncherUsingPsexec(GetClientId().ToString(), psexecPath, psexecArgs,
hostName, sharePath, shareName, startDir, launcherPort, logPath);
launcherProcesses.Add(hostName, launcherProcess);
}
else
{
launcherProcess = launcherProcesses[hostName];
}
string clientProcPath = ClientProcName;
string runDir = null;
string clientId;
List<UnitProcess> unitProcs = new List<UnitProcess>();
if (sharePath != null)
{
runDir = Util.AssemblyDir.Replace(sharePath.ToLower(), shareName);
clientProcPath = runDir + Path.DirectorySeparatorChar + ClientProcName;
clientProcPath = clientProcPath.Replace('\\', '/');
}
string envStr = string.Empty;
if (envs != null)
{
foreach (KeyValuePair<string, string> envNameValue in envs)
{
string envValue = envNameValue.Value.Replace(sharePath, shareName);
envStr += " --env:" + envNameValue.Key + "=\"" + envValue + '\"';
}
}
List<int> clientPorts = new List<int>();
try
{
for (int i = 0; i < clientIds.Count; i++, startClientNum++)
{
string clientsCmd = string.Empty;
int clientPort = GetClientPort();
clientId = clientIds[i];
if (clientId == null)
{
clientId = GetClientId().ToString();
clientIds[i] = clientId;
}
string bbServer;
if (Util.ExternalBBServer != null)
{
bbServer = Util.ExternalBBServer;
}
else
{
bbServer = "tcp://" + Util.IPAddressString + ':' + Util.DriverPort +
'/' + CommConstants.BBService;
}
clientsCmd = " --id=" + clientId +
" --num=" + startClientNum + envStr + " --startdir=\"" +
(startDir == null ? runDir : startDir) + "\" --driver=\"tcp://" +
Util.IPAddressString + ':' + Util.DriverPort + '/' +
CommConstants.DriverService + "\" --bbServer=\"" + bbServer +
"\" " + clientPort;
clientPorts.Add(clientPort);
IClientCommV2 clientComm = launcherProcess.m_clientComm as IClientCommV2;
Process proc;
UnitProcess unitProc;
unitProc = new UnitProcess(clientId);
lock (((ICollection)ProcessIDMap).SyncRoot)
{
ProcessIDMap[clientId] = unitProc.m_clientEvent;
unitProcs.Add(unitProc);
}
if (!clientComm.LaunchNewClient(clientProcPath, clientsCmd, out proc))
{
throw new AssertionException("Failed to start client: " +
clientId);
}
unitProc.m_process = proc;
}
for (int i = 0; i < clientIds.Count; i++)
{
clientId = clientIds[i];
UnitProcess unitProc = (UnitProcess)unitProcs[i];
if (!unitProc.m_clientEvent.WaitOne(MaxStartWaitMillis, false))
{
throw new AssertionException("Timed out waiting for client: " +
clientId);
}
unitProc.m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
hostName + ':' + clientPorts[i] + '/' + CommConstants.ClientService);
unitProc.m_process = unitProc.m_clientComm.GetClientProcess();
unitProc.m_psexecPath = psexecPath;
unitProc.m_psexecArgs = psexecArgs;
unitProc.m_hostName = hostName;
unitProc.m_timeout = false;
unitProc.m_exiting = false;
unitProc.m_sharePath = sharePath;
unitProc.m_shareName = shareName;
unitProc.m_startDir = startDir;
unitProc.m_envs = envs;
}
}
catch (Exception ex)
{
unitProcs.Clear();
unitProcs = null;
clientPorts.Clear();
clientPorts = null;
throw new AssertionException(string.Format("FATAL: Could not start " +
"client: {1}{0}\ton host: {2}{0}\tusing: FwkLauncher{0}" +
"\tException: {3}", Environment.NewLine, clientProcPath, hostName,
ex));
}
return unitProcs;
}
return null;
}
/// <summary>
/// If not already created, Create a launcher process on the remote host using
/// psexec. This launcher is used to launch the FwkClients on the host.
/// </summary>
private static UnitProcess CreateLauncherUsingPsexec(string clientId,
string psexecPath, string psexecArgs, string hostName,
string sharePath, string shareName, string startDir,
int launcherPort, string logPath)
{
if (clientId != null)
{
string clientProcPath = "FwkLauncher.exe";
string clientsCmd = string.Empty;
string runDir = null;
bool newProcCreated = false;
UnitProcess unitProc;
Process proc = null;
try
{
lock (((ICollection)ProcessIDMap).SyncRoot)
{
unitProc = new UnitProcess(clientId);
ProcessIDMap[clientId] = unitProc.m_clientEvent;
}
if (launcherPort == 0) // i.e. launcher is not running
{
launcherPort = GetClientPort();
if (sharePath != null)
{
runDir = Util.AssemblyDir.Replace(sharePath.ToLower(), shareName);
clientProcPath = runDir + Path.DirectorySeparatorChar + clientProcPath;
clientProcPath = clientProcPath.Replace('/', '\\');
}
clientsCmd = " cmd.exe /C \"\"" + clientProcPath + "\" --id=" + clientId +
" --bg --port=" + launcherPort + " --driver=\"tcp://" + Util.IPAddressString +
':' + Util.DriverPort + '/' + CommConstants.DriverService + "\"\"";
string psexecAllArgs = psexecArgs + "\\\\" + hostName +
" " + clientsCmd;
Util.Log(string.Format("Running remote command: {0} {1}{2}",
psexecPath, Util.HidePsexecPassword(psexecAllArgs), Environment.NewLine));
if (!Util.StartProcess(psexecPath, psexecAllArgs, Util.LogFile == null, null,
false, false, false, out proc))
{
throw new AssertionException("Failed to start the launcher.");
}
if (!unitProc.m_clientEvent.WaitOne(90000, false))
{
throw new AssertionException("Timed out waiting for launcher: " +
clientId);
}
newProcCreated = true;
}
unitProc.m_clientComm = (IClientComm)ServerConnection<IClientCommV2>.Connect("tcp://" +
hostName + ':' + launcherPort + '/' + CommConstants.ClientService);
unitProc.m_process = unitProc.m_clientComm.GetClientProcess();
unitProc.m_psexecPath = psexecPath;
unitProc.m_psexecArgs = psexecArgs;
unitProc.m_hostName = hostName;
unitProc.m_timeout = false;
unitProc.m_exiting = false;
unitProc.m_sharePath = sharePath;
unitProc.m_shareName = shareName;
unitProc.m_startDir = startDir;
if (newProcCreated)
{
logPath += "/" + "Launcher" + "_" + hostName + "_" + clientId + ".log";
Util.Log("Launcher log path {0}", logPath);
unitProc.SetLogLevel(Util.CurrentLogLevel);
unitProc.SetLogFile(logPath);
}
}
catch (Exception ex)
{
throw new AssertionException(string.Format("FATAL: Could not start " +
"launcher: {1}{0}\ton host: {2}{0}" +
"\tException: {3}", Environment.NewLine, clientProcPath, hostName,
ex));
}
return unitProc;
}
return null;
}
#endregion
#region ClientBase Members
public override void RemoveObjectID(int objectID)
{
if (m_clientComm != null)
{
m_clientComm.RemoveObjectID(objectID);
}
}
public override void CallFn(Delegate deleg, object[] paramList)
{
string assemblyName, typeName, methodName;
int objectId;
ClientBase.GetDelegateInfo(deleg, out assemblyName,
out typeName, out methodName, out objectId);
Exception callEx = null;
for (int numTries = 1; numTries <= 5; numTries++)
{
if (m_clientComm != null)
{
try
{
m_clientComm.Call(objectId,
assemblyName, typeName, methodName, paramList);
return;
}
catch (Exception ex)
{
callEx = ex;
if (m_exiting)
{
throw new ClientExitedException("Process exited while calling '." +
deleg.Method.ToString() + '\'');
}
else if (m_timeout)
{
throw new ClientTimeoutException("Timeout occured while calling '" +
deleg.Method.ToString() + '\'');
}
else if (ex is RemotingException ||
ex is System.Net.Sockets.SocketException)
{
Thread.Sleep(numTries * 1000);
}
else
{
break;
}
}
}
}
if (callEx != null)
{
throw callEx;
}
}
public override object CallFnR(Delegate deleg, object[] paramList)
{
string assemblyName, typeName, methodName;
int objectId;
ClientBase.GetDelegateInfo(deleg, out assemblyName,
out typeName, out methodName, out objectId);
Exception callEx = null;
for (int numTries = 1; numTries <= 5; numTries++)
{
if (m_clientComm != null)
{
try
{
return m_clientComm.CallR(objectId,
assemblyName, typeName, methodName, paramList);
}
catch (Exception ex)
{
callEx = ex;
if (m_exiting)
{
throw new ClientExitedException("Process exited while calling '." +
deleg.Method.ToString() + '\'');
}
else if (m_timeout)
{
throw new ClientTimeoutException("Timeout occured while calling '" +
deleg.Method.ToString() + '\'');
}
else if (ex is RemotingException ||
ex is System.Net.Sockets.SocketException)
{
Thread.Sleep(numTries * 1000);
}
else
{
break;
}
}
}
}
if (callEx != null)
{
throw callEx;
}
return null;
}
public override string HostName
{
get
{
return (m_hostName == null ? "localhost" : m_hostName);
}
}
/// <summary>
/// Set the log file for the client.
/// </summary>
/// <param name="logPath">The path of the log file.</param>
public override void SetLogFile(string logPath)
{
if (m_clientComm != null)
{
m_clientComm.SetLogFile(logPath);
}
}
/// <summary>
/// Set logging level for the client.
/// </summary>
/// <param name="logLevel">The logging level to set.</param>
public override void SetLogLevel(Util.LogLevel logLevel)
{
if (m_clientComm != null)
{
m_clientComm.SetLogLevel(logLevel);
}
}
public override void DumpStackTrace()
{
if (m_clientComm != null)
{
m_clientComm.DumpStackTrace();
}
}
public override void ForceKill(int waitMillis)
{
if (m_clientComm != null)
{
m_timeout = true;
Util.Log("Forcing kill for client {0}", this.ID);
ExitClient(waitMillis, true);
Util.Log("Done kill for client {0}", this.ID);
}
}
public override ClientBase CreateNew(string clientId)
{
UnitProcess newProc;
if (clientId == null)
{
clientId = GetClientId().ToString();
}
if (m_sshPath != null)
{
int clientPort = GetClientPort();
m_clientEvent.Reset();
lock (((ICollection)ProcessIDMap).SyncRoot)
{
ProcessIDMap[clientId] = m_clientEvent;
}
if (!m_clientComm.CreateNew(clientId, clientPort))
{
throw new AssertionException("FATAL: Could not start client: " +
ClientProcName);
}
if (!m_clientEvent.WaitOne(MaxStartWaitMillis, false))
{
throw new AssertionException("FATAL: Timed out waiting for client to start: " +
ClientProcName);
}
newProc = new UnitProcess(clientId);
newProc.m_sshPath = m_sshPath;
newProc.m_sshArgs = m_sshArgs;
newProc.m_hostName = m_hostName;
newProc.m_clientComm = ServerConnection<IClientComm>.Connect("tcp://" +
m_hostName + ':' + clientPort + '/' + CommConstants.ClientService);
newProc.m_process = newProc.m_clientComm.GetClientProcess();
newProc.m_timeout = false;
newProc.m_exiting = false;
newProc.m_sharePath = m_sharePath;
newProc.m_shareName = m_shareName;
newProc.m_startDir = m_startDir;
newProc.m_envs = m_envs;
}
else
{
newProc = new UnitProcess(clientId, m_startDir);
}
return newProc;
}
public override void TestCleanup()
{
if (m_clientComm != null)
{
m_clientComm.TestCleanup();
}
}
public override void Exit()
{
if (m_clientComm != null)
{
m_exiting = true;
ExitClient(MaxEndWaitMillis, false);
}
}
#endregion
}
}