PageRenderTime 111ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/Trunk/NSsh/Dependencies/NUnit 2.4.6/src/ClientUtilities/util/Services/TestAgency.cs

#
C# | 356 lines | 280 code | 54 blank | 22 comment | 32 complexity | 4cc01bb1075d6d3884a61a3219717f4b MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, GPL-2.0, GPL-3.0, LGPL-3.0
  1. using System;
  2. using System.IO;
  3. using System.Threading;
  4. using System.Diagnostics;
  5. using System.Collections;
  6. using System.Collections.Specialized;
  7. using System.Runtime.Remoting;
  8. using System.Runtime.Remoting.Services;
  9. using System.Runtime.Remoting.Channels;
  10. using System.Runtime.Remoting.Channels.Tcp;
  11. using NUnit.Core;
  12. namespace NUnit.Util
  13. {
  14. /// <summary>
  15. /// Enumeration of agent types used to request agents
  16. /// </summary>
  17. [Flags]
  18. public enum AgentType
  19. {
  20. Default = 0,
  21. DomainAgent = 1, // NYI
  22. ProcessAgent = 2
  23. }
  24. /// <summary>
  25. /// Enumeration used to report AgentStatus
  26. /// </summary>
  27. public enum AgentStatus
  28. {
  29. Unknown,
  30. Starting,
  31. Ready,
  32. Busy,
  33. Stopping
  34. }
  35. /// <summary>
  36. /// The TestAgency class provides RemoteTestAgents
  37. /// on request and tracks their status. Agents
  38. /// are wrapped in an instance of the TestAgent
  39. /// class. Multiple agent types are supported
  40. /// but only one, ProcessAgent is implemented
  41. /// at this time.
  42. /// </summary>
  43. public class TestAgency : ServerBase, IService
  44. {
  45. private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
  46. System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  47. #region Private Fields
  48. private AgentDataBase agentData = new AgentDataBase();
  49. private AgentType supportedAgentTypes = AgentType.ProcessAgent;
  50. private AgentType defaultAgentType = AgentType.ProcessAgent;
  51. #endregion
  52. #region Constructors
  53. public TestAgency() : this( "TestAgency", 9100 ) { }
  54. public TestAgency( string uri, int port ) : base( uri, port ) { }
  55. #endregion
  56. #region Static Property - TestAgentExePath
  57. public static string TestAgentExePath
  58. {
  59. get
  60. {
  61. string agentPath = "nunit-agent.exe";
  62. if ( !File.Exists(agentPath) )
  63. {
  64. DirectoryInfo dir = new DirectoryInfo( Environment.CurrentDirectory );
  65. if ( dir.Parent.Name == "bin" )
  66. dir = dir.Parent.Parent.Parent.Parent;
  67. string path = PathUtils.Combine( dir.FullName, "NUnitTestServer", "nunit-agent-exe",
  68. "bin", NUnitFramework.BuildConfiguration, "nunit-agent.exe" );
  69. if( File.Exists( path ) )
  70. agentPath = path;
  71. }
  72. return agentPath;
  73. }
  74. }
  75. #endregion
  76. #region ServerBase Overrides
  77. public override void Stop()
  78. {
  79. foreach( AgentRecord r in agentData )
  80. {
  81. if ( !r.Process.HasExited )
  82. {
  83. if ( r.Agent != null )
  84. r.Agent.Stop();
  85. //r.Process.Kill();
  86. }
  87. }
  88. agentData.Clear();
  89. base.Stop ();
  90. }
  91. #endregion
  92. #region Public Methods - Called by Agents
  93. public void Register( RemoteTestAgent agent, int pid )
  94. {
  95. AgentRecord r = agentData[pid];
  96. if ( r == null )
  97. throw new ArgumentException( "Specified process is not in the agency database", "pid" );
  98. r.Agent = agent;
  99. }
  100. public void ReportStatus( int pid, AgentStatus status )
  101. {
  102. AgentRecord r = agentData[pid];
  103. if ( r == null )
  104. throw new ArgumentException( "Specified process is not in the agency database", "pid" );
  105. r.Status = status;
  106. }
  107. #endregion
  108. #region Public Methods - Called by Clients
  109. public TestAgent GetAgent()
  110. {
  111. return GetAgent( AgentType.Default, 5000 );
  112. }
  113. public TestAgent GetAgent( AgentType type )
  114. {
  115. return GetAgent( type, 5000 );
  116. }
  117. public TestAgent GetAgent(AgentType type, int waitTime)
  118. {
  119. if ( type == AgentType.Default )
  120. type = defaultAgentType;
  121. if ( (type & supportedAgentTypes) == 0 )
  122. throw new ArgumentException(
  123. string.Format( "AgentType {0} is not supported by this agency", type ),
  124. "type" );
  125. AgentRecord r = FindAvailableRemoteAgent(type);
  126. if ( r == null )
  127. r = CreateRemoteAgent(type, waitTime);
  128. return new TestAgent( this, r.Process.Id, r.Agent );
  129. }
  130. public void ReleaseAgent( TestAgent agent )
  131. {
  132. AgentRecord r = agentData[agent.Id];
  133. if ( r == null )
  134. log.ErrorFormat( "Unable to release agent {0} - not in database", agent.Id );
  135. else
  136. {
  137. r.Status = AgentStatus.Ready;
  138. log.DebugFormat( "Releasing agent {0}", agent.Id );
  139. }
  140. }
  141. public void DestroyAgent( TestAgent agent )
  142. {
  143. AgentRecord r = agentData[agent.Id];
  144. if ( r != null )
  145. {
  146. if( !r.Process.HasExited )
  147. r.Agent.Stop();
  148. agentData[r.Process.Id] = null;
  149. }
  150. }
  151. #endregion
  152. #region Helper Methods
  153. private int LaunchAgentProcess()
  154. {
  155. //ProcessStartInfo startInfo = new ProcessStartInfo( TestAgentExePath, ServerUtilities.MakeUrl( this.uri, this.port ) );
  156. //startInfo.CreateNoWindow = true;
  157. Process p = new Process();
  158. if ( Type.GetType( "Mono.Runtime", false ) != null )
  159. {
  160. p.StartInfo.FileName = @"C:\Program Files\mono-1.2.5\bin\mono.exe";
  161. p.StartInfo.Arguments = TestAgentExePath + " " + ServerUtilities.MakeUrl( this.uri, this.port );
  162. }
  163. else
  164. {
  165. p.StartInfo.FileName = TestAgentExePath;
  166. p.StartInfo.Arguments = ServerUtilities.MakeUrl( this.uri, this.port );
  167. }
  168. //Process p = Process.Start( startInfo );
  169. log.DebugFormat( "Launching {0}", p.StartInfo.FileName );
  170. p.Start();
  171. agentData.Add( new AgentRecord( p.Id, p, null, AgentStatus.Starting ) );
  172. return p.Id;
  173. }
  174. private AgentRecord FindAvailableRemoteAgent(AgentType type)
  175. {
  176. foreach( AgentRecord r in agentData )
  177. if ( r.Status == AgentStatus.Ready )
  178. {
  179. log.DebugFormat( "Reusing agent {0}", r.Id );
  180. r.Status = AgentStatus.Busy;
  181. return r;
  182. }
  183. return null;
  184. }
  185. private AgentRecord CreateRemoteAgent(AgentType type, int waitTime)
  186. {
  187. int pid = LaunchAgentProcess();
  188. log.DebugFormat( "Waiting for agent {0} to register", pid );
  189. while( waitTime > 0 )
  190. {
  191. int pollTime = Math.Min( 200, waitTime );
  192. Thread.Sleep( pollTime );
  193. waitTime -= pollTime;
  194. if ( agentData[pid].Agent != null )
  195. {
  196. log.DebugFormat( "Returning new agent record {0}", pid );
  197. return agentData[pid];
  198. }
  199. }
  200. return null;
  201. }
  202. #endregion
  203. #region IService Members
  204. public void UnloadService()
  205. {
  206. this.Stop();
  207. }
  208. public void InitializeService()
  209. {
  210. this.Start();
  211. }
  212. #endregion
  213. #region Nested Class - AgentRecord
  214. private class AgentRecord
  215. {
  216. public int Id;
  217. public Process Process;
  218. public RemoteTestAgent Agent;
  219. public AgentStatus Status;
  220. public AgentRecord( int id, Process p, RemoteTestAgent a, AgentStatus s )
  221. {
  222. this.Id = id;
  223. this.Process = p;
  224. this.Agent = a;
  225. this.Status = s;
  226. }
  227. }
  228. #endregion
  229. #region Nested Class - AgentDataBase
  230. /// <summary>
  231. /// A simple class that tracks data about this
  232. /// agencies active and available agents
  233. /// </summary>
  234. private class AgentDataBase : IEnumerable
  235. {
  236. private ListDictionary agentData = new ListDictionary();
  237. public AgentRecord this[int id]
  238. {
  239. get { return (AgentRecord)agentData[id]; }
  240. set
  241. {
  242. if ( value == null )
  243. agentData.Remove( id );
  244. else
  245. agentData[id] = value;
  246. }
  247. }
  248. public AgentRecord this[RemoteTestAgent agent]
  249. {
  250. get
  251. {
  252. foreach( System.Collections.DictionaryEntry entry in agentData )
  253. {
  254. AgentRecord r = (AgentRecord)entry.Value;
  255. if ( r.Agent == agent )
  256. return r;
  257. }
  258. return null;
  259. }
  260. }
  261. public void Add( AgentRecord r )
  262. {
  263. agentData[r.Id] = r;
  264. }
  265. public void Clear()
  266. {
  267. agentData.Clear();
  268. }
  269. #region IEnumerable Members
  270. public IEnumerator GetEnumerator()
  271. {
  272. return new AgentDataEnumerator( agentData );
  273. }
  274. #endregion
  275. #region Nested Class - AgentDataEnumerator
  276. public class AgentDataEnumerator : IEnumerator
  277. {
  278. IEnumerator innerEnum;
  279. public AgentDataEnumerator( IDictionary list )
  280. {
  281. innerEnum = list.GetEnumerator();
  282. }
  283. #region IEnumerator Members
  284. public void Reset()
  285. {
  286. innerEnum.Reset();
  287. }
  288. public object Current
  289. {
  290. get { return ((DictionaryEntry)innerEnum.Current).Value; }
  291. }
  292. public bool MoveNext()
  293. {
  294. return innerEnum.MoveNext();
  295. }
  296. #endregion
  297. }
  298. #endregion
  299. }
  300. #endregion
  301. }
  302. }