Imported Upstream version 3.6.0

Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
This commit is contained in:
Jo Shields
2014-08-13 10:39:27 +01:00
commit a575963da9
50588 changed files with 8155799 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Reflection;
using NUnit.Core;
using NUnit.Core.Extensibility;
namespace NUnit.Util
{
public class AddinManager : IService
{
#region Instance Fields
IAddinRegistry addinRegistry;
#endregion
#region Constructor
public AddinManager()
{
}
#endregion
#region Addin Registration
public void RegisterAddins()
{
//Figure out the directory from which NUnit is executing
string moduleName = TestFixtureBuilder.GetAssemblyPath( GetType().Assembly );
//string moduleName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
string nunitDirPath = Path.GetDirectoryName( moduleName );
string coreExtensions = Path.Combine( nunitDirPath, "nunit.core.extensions.dll" );
string addinsDirPath = Path.Combine( nunitDirPath, "addins" );
// Load nunit.core.extensions if available
if ( File.Exists( coreExtensions ) )
Register( coreExtensions );
// Load any extensions in the addins directory
DirectoryInfo dir = new DirectoryInfo( addinsDirPath );
if ( dir.Exists )
foreach( FileInfo file in dir.GetFiles( "*.dll" ) )
Register( file.FullName );
}
public void Register( string path )
{
try
{
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = Path.GetFileNameWithoutExtension(path);
assemblyName.CodeBase = path;
Assembly assembly = Assembly.Load(assemblyName);
NTrace.Debug( "Loaded " + Path.GetFileName(path) );
foreach ( Type type in assembly.GetExportedTypes() )
{
if ( type.GetCustomAttributes(typeof(NUnitAddinAttribute), false).Length == 1 )
{
Addin addin = new Addin( type );
addinRegistry.Register( addin );
NTrace.Debug( "Registered addin: " + addin.Name );
}
}
}
catch( Exception ex )
{
// NOTE: Since the gui isn't loaded at this point,
// the trace output will only show up in Visual Studio
NTrace.Error( "Failed to load" + path, ex );
}
}
#endregion
#region IService Members
public void InitializeService()
{
addinRegistry = Services.AddinRegistry;
RegisterAddins();
}
public void UnloadService()
{
}
#endregion
}
}

View File

@@ -0,0 +1,60 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using System.Reflection;
using NUnit.Core;
using NUnit.Core.Extensibility;
namespace NUnit.Util
{
/// <summary>
/// Summary description for AddinRegistry.
/// </summary>
public class AddinRegistry : MarshalByRefObject, IAddinRegistry, IService
{
#region Instance Fields
private ArrayList addins = new ArrayList();
#endregion
#region IAddinRegistry Members
public void Register(Addin addin)
{
addins.Add( addin );
}
public IList Addins
{
get
{
return addins;
}
}
public void SetStatus( string name, AddinStatus status, string message )
{
foreach( Addin addin in addins )
if ( addin.Name == name )
{
addin.Status = status;
addin.Message = message;
}
}
#endregion
#region IService Members
public void InitializeService()
{
}
public void UnloadService()
{
}
#endregion
}
}

View File

@@ -0,0 +1,298 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using System.Collections;
using System.Text;
using System.Threading;
using System.Configuration;
using System.Diagnostics;
using System.Security.Policy;
using NUnit.Core;
namespace NUnit.Util
{
/// <summary>
/// The DomainManager class handles the creation and unloading
/// of domains as needed and keeps track of all existing domains.
/// </summary>
public class DomainManager : IService
{
#region Properties
private static string shadowCopyPath;
public static string ShadowCopyPath
{
get
{
if ( shadowCopyPath == null )
{
shadowCopyPath = ConfigurationSettings.AppSettings["shadowfiles.path"];
if ( shadowCopyPath == "" || shadowCopyPath== null )
shadowCopyPath = Path.Combine( Path.GetTempPath(), @"nunit20\ShadowCopyCache" );
else
shadowCopyPath = Environment.ExpandEnvironmentVariables(shadowCopyPath);
// FIXME: we know that in the config file we have %temp%...
if( shadowCopyPath.IndexOf ( "%temp%\\" ) != -1) {
shadowCopyPath = shadowCopyPath.Replace( "%temp%\\", Path.GetTempPath() );
if ( Path.DirectorySeparatorChar == '/' )
shadowCopyPath = shadowCopyPath.Replace ( '\\', '/' );
}
}
return shadowCopyPath;
}
}
#endregion
#region Create and Unload Domains
/// <summary>
/// Construct an application domain for running a test package
/// </summary>
/// <param name="package">The TestPackage to be run</param>
public AppDomain CreateDomain( TestPackage package )
{
FileInfo testFile = new FileInfo( package.FullName );
AppDomainSetup setup = new AppDomainSetup();
// We always use the same application name
setup.ApplicationName = "Tests";
string appBase = package.BasePath;
if ( appBase == null || appBase == string.Empty )
appBase = testFile.DirectoryName;
setup.ApplicationBase = appBase;
string configFile = package.ConfigurationFile;
if ( configFile == null || configFile == string.Empty )
configFile = NUnitProject.IsProjectFile(testFile.Name)
? Path.GetFileNameWithoutExtension( testFile.Name ) + ".config"
: testFile.Name + ".config";
// Note: Mono needs full path to config file...
setup.ConfigurationFile = Path.Combine( appBase, configFile );
string binPath = package.PrivateBinPath;
if ( package.AutoBinPath )
binPath = GetPrivateBinPath( appBase, package.Assemblies );
setup.PrivateBinPath = binPath;
if ( package.GetSetting( "ShadowCopyFiles", true ) )
{
setup.ShadowCopyFiles = "true";
setup.ShadowCopyDirectories = appBase;
setup.CachePath = GetCachePath();
}
string domainName = "domain-" + package.Name;
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence evidence = new Evidence(baseEvidence);
AppDomain runnerDomain = AppDomain.CreateDomain(domainName, evidence, setup);
// Inject assembly resolver into remote domain to help locate our assemblies
AssemblyResolver assemblyResolver = (AssemblyResolver)runnerDomain.CreateInstanceFromAndUnwrap(
typeof(AssemblyResolver).Assembly.CodeBase,
typeof(AssemblyResolver).FullName);
// Tell resolver to use our core assemblies in the test domain
assemblyResolver.AddFile( typeof( NUnit.Core.RemoteTestRunner ).Assembly.Location );
assemblyResolver.AddFile( typeof( NUnit.Core.ITest ).Assembly.Location );
// No reference to extensions, so we do it a different way
string moduleName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
string nunitDirPath = Path.GetDirectoryName(moduleName);
// string coreExtensions = Path.Combine(nunitDirPath, "nunit.core.extensions.dll");
// assemblyResolver.AddFile( coreExtensions );
//assemblyResolver.AddFiles( nunitDirPath, "*.dll" );
string addinsDirPath = Path.Combine(nunitDirPath, "addins");
assemblyResolver.AddDirectory( addinsDirPath );
// HACK: Only pass down our AddinRegistry one level so that tests of NUnit
// itself start without any addins defined.
if ( !IsTestDomain( AppDomain.CurrentDomain ) )
runnerDomain.SetData("AddinRegistry", Services.AddinRegistry);
return runnerDomain;
}
public void Unload( AppDomain domain )
{
new DomainUnloader(domain).Unload();
}
#endregion
#region Nested DomainUnloader Class
class DomainUnloader
{
private Thread thread;
private AppDomain domain;
public DomainUnloader(AppDomain domain)
{
this.domain = domain;
}
public void Unload()
{
thread = new Thread(new ThreadStart(UnloadOnThread));
thread.Start();
if (!thread.Join(20000))
{
Trace.WriteLine("Unable to unload AppDomain {0}", domain.FriendlyName);
Trace.WriteLine("Unload thread timed out");
}
}
private void UnloadOnThread()
{
bool shadowCopy = domain.ShadowCopyFiles;
string cachePath = domain.SetupInformation.CachePath;
string domainName = domain.FriendlyName;
try
{
AppDomain.Unload(domain);
}
catch (Exception ex)
{
// We assume that the tests did something bad and just leave
// the orphaned AppDomain "out there".
// TODO: Something useful.
Trace.WriteLine("Unable to unload AppDomain {0}", domainName);
Trace.WriteLine(ex.ToString());
}
finally
{
if (shadowCopy)
DeleteCacheDir(new DirectoryInfo(cachePath));
}
}
}
#endregion
#region Helper Methods
/// <summary>
/// Get the location for caching and delete any old cache info
/// </summary>
private string GetCachePath()
{
int processId = Process.GetCurrentProcess().Id;
long ticks = DateTime.Now.Ticks;
string cachePath = Path.Combine( ShadowCopyPath, processId.ToString() + "_" + ticks.ToString() );
try
{
DirectoryInfo dir = new DirectoryInfo(cachePath);
if(dir.Exists) dir.Delete(true);
}
catch( Exception ex)
{
throw new ApplicationException(
string.Format( "Invalid cache path: {0}",cachePath ),
ex );
}
return cachePath;
}
/// <summary>
/// Helper method to delete the cache dir. This method deals
/// with a bug that occurs when files are marked read-only
/// and deletes each file separately in order to give better
/// exception information when problems occur.
///
/// TODO: This entire method is problematic. Should we be doing it?
/// </summary>
/// <param name="cacheDir"></param>
private static void DeleteCacheDir( DirectoryInfo cacheDir )
{
// Debug.WriteLine( "Modules:");
// foreach( ProcessModule module in Process.GetCurrentProcess().Modules )
// Debug.WriteLine( module.ModuleName );
if(cacheDir.Exists)
{
foreach( DirectoryInfo dirInfo in cacheDir.GetDirectories() )
DeleteCacheDir( dirInfo );
foreach( FileInfo fileInfo in cacheDir.GetFiles() )
{
fileInfo.Attributes = FileAttributes.Normal;
try
{
fileInfo.Delete();
}
catch( Exception ex )
{
Debug.WriteLine( string.Format(
"Error deleting {0}, {1}", fileInfo.Name, ex.Message ) );
}
}
cacheDir.Attributes = FileAttributes.Normal;
try
{
cacheDir.Delete();
}
catch( Exception ex )
{
Debug.WriteLine( string.Format(
"Error deleting {0}, {1}", cacheDir.Name, ex.Message ) );
}
}
}
private bool IsTestDomain(AppDomain domain)
{
return domain.FriendlyName.StartsWith( "domain-" );
}
public static string GetPrivateBinPath( string basePath, IList assemblies )
{
StringBuilder sb = new StringBuilder(200);
ArrayList dirList = new ArrayList();
foreach( string assembly in assemblies )
{
string dir = PathUtils.RelativePath( basePath, Path.GetDirectoryName( assembly ) );
if ( dir != null && dir != "." && !dirList.Contains( dir ) )
{
dirList.Add( dir );
if ( sb.Length > 0 )
sb.Append( Path.PathSeparator );
sb.Append( dir );
}
}
return sb.Length == 0 ? null : sb.ToString();
}
public static void DeleteShadowCopyPath()
{
if ( Directory.Exists( ShadowCopyPath ) )
Directory.Delete( ShadowCopyPath, true );
}
#endregion
#region IService Members
public void UnloadService()
{
// TODO: Add DomainManager.UnloadService implementation
}
public void InitializeService()
{
// TODO: Add DomainManager.InitializeService implementation
}
#endregion
}
}

View File

@@ -0,0 +1,169 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
namespace NUnit.Util
{
/// <summary>
/// Summary description for RecentFilesService.
/// </summary>
public class RecentFilesService : RecentFiles, NUnit.Core.IService
{
private RecentFilesCollection fileEntries = new RecentFilesCollection();
private ISettings settings;
public static readonly int MinSize = 1;
public static readonly int MaxSize = 24;
public static readonly int DefaultSize = 5;
#region Constructor
public RecentFilesService()
: this( Services.UserSettings ) { }
public RecentFilesService( ISettings settings )
{
this.settings = settings;
}
#endregion
#region Properties
public int Count
{
get { return fileEntries.Count; }
}
public int MaxFiles
{
get
{
int size = settings.GetSetting( "RecentProjects.MaxFiles", DefaultSize );
if ( size < MinSize ) size = MinSize;
if ( size > MaxSize ) size = MaxSize;
return size;
}
set
{
int oldSize = MaxFiles;
int newSize = value;
if ( newSize < MinSize ) newSize = MinSize;
if ( newSize > MaxSize ) newSize = MaxSize;
settings.SaveSetting( "RecentProjects.MaxFiles", newSize );
if ( newSize < oldSize ) SaveEntriesToSettings( this. settings );
}
}
#endregion
#region Public Methods
public RecentFilesCollection Entries
{
get
{
return fileEntries;
}
}
public void Remove( string fileName )
{
fileEntries.Remove( fileName );
}
public void SetMostRecent( string fileName )
{
SetMostRecent( new RecentFileEntry( fileName ) );
}
public void SetMostRecent( RecentFileEntry entry )
{
int index = fileEntries.IndexOf(entry.Path);
if(index != -1)
fileEntries.RemoveAt(index);
fileEntries.Insert( 0, entry );
if( fileEntries.Count > MaxFiles )
fileEntries.RemoveAt( MaxFiles );
}
#endregion
#region Helper Methods for saving and restoring the settings
private void LoadEntriesFromSettings( ISettings settings )
{
fileEntries.Clear();
string prefix = Environment.Version.Major >= 2
? "RecentProjects.V2"
: "RecentProjects.V1";
for ( int index = 1; index <= MaxFiles; index++ )
{
string fileSpec = settings.GetSetting( GetRecentFileKey( prefix, index ) ) as string;
if ( fileSpec != null ) fileEntries.Add( new RecentFileEntry( fileSpec ) );
}
// Try legacy entries if nothing was found
if ( fileEntries.Count == 0 )
{
for ( int index = 1; index <= MaxFiles; index++ )
{
string fileSpec = settings.GetSetting( GetRecentFileKey( "RecentProjects", index ) ) as string;
if ( fileSpec != null )
{
RecentFileEntry entry = RecentFileEntry.Parse( fileSpec );
if ( entry.CLRVersion.Major <= Environment.Version.Major )
fileEntries.Add( entry );
}
}
};
}
private void SaveEntriesToSettings( ISettings settings )
{
string prefix = Environment.Version.Major >= 2
? "RecentProjects.V2"
: "RecentProjects.V1";
while( fileEntries.Count > MaxFiles )
fileEntries.RemoveAt( fileEntries.Count - 1 );
for( int index = 0; index < MaxSize; index++ )
{
string keyName = GetRecentFileKey( prefix, index + 1 );
if ( index < fileEntries.Count )
settings.SaveSetting( keyName, fileEntries[index].Path );
else
settings.RemoveSetting( keyName );
}
}
private string GetRecentFileKey( string prefix, int index )
{
return string.Format( "{0}.File{1}", prefix, index );
}
#endregion
#region IService Members
public void UnloadService()
{
SaveEntriesToSettings( this.settings );
}
public void InitializeService()
{
LoadEntriesFromSettings( this.settings );
}
#endregion
}
}

View File

@@ -0,0 +1,82 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.Collections;
using NUnit.Core;
namespace NUnit.Util
{
/// <summary>
/// Summary description for ServiceManger.
/// </summary>
public class ServiceManager
{
private ArrayList services = new ArrayList();
private Hashtable serviceIndex = new Hashtable();
private static ServiceManager defaultServiceManager = new ServiceManager();
public static ServiceManager Services
{
get { return defaultServiceManager; }
}
public void AddService( IService service )
{
services.Add( service );
NTrace.Debug( "Added " + service.GetType().Name );
}
public IService GetService( Type serviceType )
{
IService theService = (IService)serviceIndex[serviceType];
if ( theService == null )
foreach( IService service in services )
{
// TODO: Does this work on Mono?
if( serviceType.IsInstanceOfType( service ) )
{
serviceIndex[serviceType] = service;
theService = service;
break;
}
}
if ( theService == null )
NTrace.Error( string.Format( "Requested service {0} was not found", serviceType.FullName ) );
else
NTrace.Info( string.Format( "Request for service {0} satisfied by {1}", serviceType.Name, theService.GetType().Name ) );
return theService;
}
public void InitializeServices()
{
foreach( IService service in services )
{
NTrace.Info( "Initializing " + service.GetType().Name );
service.InitializeService();
}
}
public void StopAllServices()
{
// Stop services in reverse of initialization order
// TODO: Deal with dependencies explicitly
int index = services.Count;
while( --index >= 0 )
((IService)services[index]).UnloadService();
}
public void ClearServices()
{
services.Clear();
}
private ServiceManager() { }
}
}

View File

@@ -0,0 +1,140 @@
// ****************************************************************
// Copyright 2007, Charlie Poole
// This is free software licensed under the NUnit license. You may
// obtain a copy of the license at http://nunit.org/?p=license&r=2.4
// ****************************************************************
using System;
using System.IO;
using Microsoft.Win32;
namespace NUnit.Util
{
/// <summary>
/// Summary description for UserSettingsService.
/// </summary>
public class SettingsService : SettingsGroup, NUnit.Core.IService
{
static readonly string applicationDirectory =
Environment.GetFolderPath( Environment.SpecialFolder.ApplicationData )
+ Path.DirectorySeparatorChar + "NUnit" + Path.DirectorySeparatorChar;
static readonly string settingsFileName = "NUnitSettings.xml";
public SettingsService()
{
string settingsFile = System.Configuration.ConfigurationSettings.AppSettings["settingsFile"];
if ( settingsFile == null )
settingsFile = applicationDirectory + settingsFileName;
this.storage = new XmlSettingsStorage( settingsFile );
if ( File.Exists( settingsFile ) )
storage.LoadSettings();
else
ConvertLegacySettings();
}
#region IService Implementation
public void InitializeService()
{
}
public void UnloadService()
{
storage.SaveSettings();
this.Dispose();
}
#endregion
#region ConvertLegacySettings
void ConvertLegacySettings()
{
RegistryKey key = Registry.CurrentUser.OpenSubKey( NUnitRegistry.KEY );
if ( key == null )
key = Registry.CurrentUser.OpenSubKey( NUnitRegistry.LEGACY_KEY );
if ( key != null )
{
using( ISettingsStorage legacyStorage = new RegistrySettingsStorage( key ) )
{
new LegacySettingsConverter( legacyStorage, storage ).Convert();
}
storage.SaveSettings();
}
}
private class LegacySettingsConverter : SettingsGroup
{
private ISettingsStorage legacy;
private ISettingsStorage current;
public LegacySettingsConverter( ISettingsStorage legacy, ISettingsStorage current )
: base( current )
{
this.legacy = legacy;
this.current = current;
}
public void Convert()
{
Convert( "Form.x-location", "Gui.MainForm.Left" );
Convert( "Form.x-location", "Gui.MiniForm.Left" );
Convert( "Form.y-location", "Gui.MainForm.Top" );
Convert( "Form.y-location", "Gui.MiniForm.Top" );
Convert( "Form.width", "Gui.MainForm.Width" );
Convert( "Form.width", "Gui.MiniForm.Width" );
Convert( "Form.height", "Gui.MainForm.Height" );
Convert( "Form.height", "Gui.MiniForm.Height" );
Convert( "Form.maximized", "Gui.MainForm.Maximized", "False", "True" );
Convert( "Form.maximized", "Gui.MiniForm.Maximized", "False", "True" );
Convert( "Form.font", "Gui.MainForm.Font" );
Convert( "Form.font", "Gui.MiniForm.Font" );
Convert( "Form.tree-splitter-position", "Gui.MainForm.SplitPosition");
Convert( "Form.tab-splitter-position", "Gui.ResultTabs.ErrorsTabSplitterPosition");
Convert( "Options.TestLabels", "Gui.ResultTabs.DisplayTestLabels", "False", "True" );
Convert( "Options.FailureToolTips", "Gui.ResultTabs.ErrorTab.ToolTipsEnabled", "False", "True" );
Convert( "Options.EnableWordWrapForFailures", "Gui.ResultTabs.ErrorTab.WordWrapEnabled", "False", "True" );
Convert( "Options.InitialTreeDisplay", "Gui.TestTree.InitialTreeDisplay", "Auto", "Expand", "Collapse", "HideTests" );
Convert( "Options.ShowCheckBoxes", "Gui.TestTree.ShowCheckBoxes", "False", "True" );
Convert( "Options.LoadLastProject", "Options.LoadLastProject", "False", "True" );
Convert( "Options.ClearResults", "Options.TestLoader.ClearResultsOnReload", "False", "True" );
Convert( "Options.ReloadOnChange", "Options.TestLoader.ReloadOnChange", "False", "True" );
Convert( "Options.RerunOnChange", "Options.TestLoader.RerunOnChange", "False", "True" );
Convert( "Options.ReloadOnRun", "Options.TestLoader.ReloadOnRun", "False", "True" );
Convert( "Options.MergeAssemblies", "Options.TestLoader.MergeAssemblies", "False", "True" );
Convert( "Options.MultiDomain", "Options.TestLoader.MultiDomain", "False", "True" );
Convert( "Options.AutoNamespaceSuites", "Options.TestLoader.AutoNamespaceSuites", "False", "True" );
Convert( "Options.VisualStudioSupport", "Options.TestLoader.VisualStudioSupport", "False", "True" );
Convert( "Recent-Projects.MaxFiles", "RecentProjects.MaxFiles" );
int maxFiles = this.GetSetting( "RecentProjects.MaxFiles", 5 );
for( int i = 1; i <= maxFiles; i++ )
{
string fileKey = string.Format( "File{0}", i );
object fileEntry = legacy.GetSetting( "Recent-Projects." + fileKey );
if ( fileEntry != null )
this.SaveSetting( "RecentProjects." + fileKey, fileEntry );
}
}
private void Convert( string legacyName, string currentName, params string[]values )
{
object val = legacy.GetSetting( legacyName );
if ( val != null )
{
if ( val is int && values != null )
{
int ival = (int)val;
if ( ival >= 0 && ival < values.Length )
val = values[(int)val];
}
this.SaveSetting( currentName, val );
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,353 @@
using System;
using System.IO;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using NUnit.Core;
namespace NUnit.Util
{
/// <summary>
/// Enumeration of agent types used to request agents
/// </summary>
[Flags]
public enum AgentType
{
Default = 0,
DomainAgent = 1, // NYI
ProcessAgent = 2
}
/// <summary>
/// Enumeration used to report AgentStatus
/// </summary>
public enum AgentStatus
{
Unknown,
Starting,
Ready,
Busy,
Stopping
}
/// <summary>
/// The TestAgency class provides RemoteTestAgents
/// on request and tracks their status. Agents
/// are wrapped in an instance of the TestAgent
/// class. Multiple agent types are supported
/// but only one, ProcessAgent is implemented
/// at this time.
/// </summary>
public class TestAgency : ServerBase, IService
{
#region Private Fields
private AgentDataBase agentData = new AgentDataBase();
private AgentType supportedAgentTypes = AgentType.ProcessAgent;
private AgentType defaultAgentType = AgentType.ProcessAgent;
#endregion
#region Constructors
public TestAgency() : this( "TestAgency", 9100 ) { }
public TestAgency( string uri, int port ) : base( uri, port ) { }
#endregion
#region Static Property - TestAgentExePath
public static string TestAgentExePath
{
get
{
string agentPath = "nunit-agent.exe";
if ( !File.Exists(agentPath) )
{
DirectoryInfo dir = new DirectoryInfo( Environment.CurrentDirectory );
if ( dir.Parent.Name == "bin" )
dir = dir.Parent.Parent.Parent.Parent;
string path = PathUtils.Combine( dir.FullName, "NUnitTestServer", "nunit-agent-exe",
"bin", NUnitFramework.BuildConfiguration, "nunit-agent.exe" );
if( File.Exists( path ) )
agentPath = path;
}
return agentPath;
}
}
#endregion
#region ServerBase Overrides
public override void Stop()
{
foreach( AgentRecord r in agentData )
{
if ( !r.Process.HasExited )
{
if ( r.Agent != null )
r.Agent.Stop();
//r.Process.Kill();
}
}
agentData.Clear();
base.Stop ();
}
#endregion
#region Public Methods - Called by Agents
public void Register( RemoteTestAgent agent, int pid )
{
AgentRecord r = agentData[pid];
if ( r == null )
throw new ArgumentException( "Specified process is not in the agency database", "pid" );
r.Agent = agent;
}
public void ReportStatus( int pid, AgentStatus status )
{
AgentRecord r = agentData[pid];
if ( r == null )
throw new ArgumentException( "Specified process is not in the agency database", "pid" );
r.Status = status;
}
#endregion
#region Public Methods - Called by Clients
public TestAgent GetAgent()
{
return GetAgent( AgentType.Default, 5000 );
}
public TestAgent GetAgent( AgentType type )
{
return GetAgent( type, 5000 );
}
public TestAgent GetAgent(AgentType type, int waitTime)
{
if ( type == AgentType.Default )
type = defaultAgentType;
if ( (type & supportedAgentTypes) == 0 )
throw new ArgumentException(
string.Format( "AgentType {0} is not supported by this agency", type ),
"type" );
AgentRecord r = FindAvailableRemoteAgent(type);
if ( r == null )
r = CreateRemoteAgent(type, waitTime);
return new TestAgent( this, r.Process.Id, r.Agent );
}
public void ReleaseAgent( TestAgent agent )
{
AgentRecord r = agentData[agent.Id];
if ( r == null )
NTrace.Error( string.Format( "Unable to release agent {0} - not in database", agent.Id ) );
else
{
r.Status = AgentStatus.Ready;
NTrace.Debug( "Releasing agent " + agent.Id.ToString() );
}
}
public void DestroyAgent( TestAgent agent )
{
AgentRecord r = agentData[agent.Id];
if ( r != null )
{
if( !r.Process.HasExited )
r.Agent.Stop();
agentData[r.Process.Id] = null;
}
}
#endregion
#region Helper Methods
private int LaunchAgentProcess()
{
//ProcessStartInfo startInfo = new ProcessStartInfo( TestAgentExePath, ServerUtilities.MakeUrl( this.uri, this.port ) );
//startInfo.CreateNoWindow = true;
Process p = new Process();
if ( Type.GetType( "Mono.Runtime", false ) != null )
{
p.StartInfo.FileName = @"C:\Program Files\mono-1.2.5\bin\mono.exe";
p.StartInfo.Arguments = TestAgentExePath + " " + ServerUtilities.MakeUrl( this.uri, this.port );
}
else
{
p.StartInfo.FileName = TestAgentExePath;
p.StartInfo.Arguments = ServerUtilities.MakeUrl( this.uri, this.port );
}
//NTrace.Debug( "Launching {0}" p.StartInfo.FileName );
p.Start();
agentData.Add( new AgentRecord( p.Id, p, null, AgentStatus.Starting ) );
return p.Id;
}
private AgentRecord FindAvailableRemoteAgent(AgentType type)
{
foreach( AgentRecord r in agentData )
if ( r.Status == AgentStatus.Ready )
{
NTrace.DebugFormat( "Reusing agent {0}", r.Id );
r.Status = AgentStatus.Busy;
return r;
}
return null;
}
private AgentRecord CreateRemoteAgent(AgentType type, int waitTime)
{
int pid = LaunchAgentProcess();
NTrace.DebugFormat( "Waiting for agent {0} to register", pid );
while( waitTime > 0 )
{
int pollTime = Math.Min( 200, waitTime );
Thread.Sleep( pollTime );
waitTime -= pollTime;
if ( agentData[pid].Agent != null )
{
NTrace.DebugFormat( "Returning new agent record {0}", pid );
return agentData[pid];
}
}
return null;
}
#endregion
#region IService Members
public void UnloadService()
{
this.Stop();
}
public void InitializeService()
{
this.Start();
}
#endregion
#region Nested Class - AgentRecord
private class AgentRecord
{
public int Id;
public Process Process;
public RemoteTestAgent Agent;
public AgentStatus Status;
public AgentRecord( int id, Process p, RemoteTestAgent a, AgentStatus s )
{
this.Id = id;
this.Process = p;
this.Agent = a;
this.Status = s;
}
}
#endregion
#region Nested Class - AgentDataBase
/// <summary>
/// A simple class that tracks data about this
/// agencies active and available agents
/// </summary>
private class AgentDataBase : IEnumerable
{
private ListDictionary agentData = new ListDictionary();
public AgentRecord this[int id]
{
get { return (AgentRecord)agentData[id]; }
set
{
if ( value == null )
agentData.Remove( id );
else
agentData[id] = value;
}
}
public AgentRecord this[RemoteTestAgent agent]
{
get
{
foreach( System.Collections.DictionaryEntry entry in agentData )
{
AgentRecord r = (AgentRecord)entry.Value;
if ( r.Agent == agent )
return r;
}
return null;
}
}
public void Add( AgentRecord r )
{
agentData[r.Id] = r;
}
public void Clear()
{
agentData.Clear();
}
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return new AgentDataEnumerator( agentData );
}
#endregion
#region Nested Class - AgentDataEnumerator
public class AgentDataEnumerator : IEnumerator
{
IEnumerator innerEnum;
public AgentDataEnumerator( IDictionary list )
{
innerEnum = list.GetEnumerator();
}
#region IEnumerator Members
public void Reset()
{
innerEnum.Reset();
}
public object Current
{
get { return ((DictionaryEntry)innerEnum.Current).Value; }
}
public bool MoveNext()
{
return innerEnum.MoveNext();
}
#endregion
}
#endregion
}
#endregion
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.Threading;
using System.Collections.Specialized;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Services;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using NUnit.Core;
namespace NUnit.Util
{
/// <summary>
/// Summary description for TestAgentManager.
/// </summary>
public class TestAgentManager : ServerBase, IService
{
private ListDictionary agents = new ListDictionary();
public TestAgentManager( string uri, int port ) : base( uri, port ) { }
public void Register( object obj, int id )
{
agents[id] = obj;
}
public object GetTestRunner( int id )
{
return agents[id];
}
#region IService Members
public void UnloadService()
{
// TODO: Add TestAgentManager.UnloadService implementation
}
public void InitializeService()
{
this.Start();
}
#endregion
}
}