Fix all CreateInstance overloads for void
[mcs.git] / nunit24 / ClientUtilities / util / Services / DomainManager.cs
blob481579d6ee99b454be3de78f7a5894d622cdb190
1 // ****************************************************************
2 // Copyright 2007, Charlie Poole
3 // This is free software licensed under the NUnit license. You may
4 // obtain a copy of the license at http://nunit.org/?p=license&r=2.4
5 // ****************************************************************
7 using System;
8 using System.IO;
9 using System.Collections;
10 using System.Text;
11 using System.Configuration;
12 using System.Diagnostics;
13 using System.Security.Policy;
14 using NUnit.Core;
16 namespace NUnit.Util
18 /// <summary>
19 /// The DomainManager class handles the creation and unloading
20 /// of domains as needed and keeps track of all existing domains.
21 /// </summary>
22 public class DomainManager : IService
24 #region Properties
25 private static string shadowCopyPath;
26 public static string ShadowCopyPath
28 get
30 if ( shadowCopyPath == null )
32 shadowCopyPath = ConfigurationSettings.AppSettings["shadowfiles.path"];
33 if ( shadowCopyPath == "" || shadowCopyPath== null )
34 shadowCopyPath = Path.Combine( Path.GetTempPath(), @"nunit20\ShadowCopyCache" );
35 else
36 shadowCopyPath = Environment.ExpandEnvironmentVariables(shadowCopyPath);
38 // FIXME: we know that in the config file we have %temp%...
39 if( shadowCopyPath.IndexOf ( "%temp%\\" ) != -1) {
40 shadowCopyPath = shadowCopyPath.Replace( "%temp%\\", Path.GetTempPath() );
41 if ( Path.DirectorySeparatorChar == '/' )
42 shadowCopyPath = shadowCopyPath.Replace ( '\\', '/' );
46 return shadowCopyPath;
49 #endregion
51 #region Create and Unload Domains
52 /// <summary>
53 /// Construct an application domain for running a test package
54 /// </summary>
55 /// <param name="package">The TestPackage to be run</param>
56 public AppDomain CreateDomain( TestPackage package )
58 FileInfo testFile = new FileInfo( package.FullName );
60 AppDomainSetup setup = new AppDomainSetup();
62 // We always use the same application name
63 setup.ApplicationName = "Tests";
65 string appBase = package.BasePath;
66 if ( appBase == null || appBase == string.Empty )
67 appBase = testFile.DirectoryName;
68 setup.ApplicationBase = appBase;
70 string configFile = package.ConfigurationFile;
71 if ( configFile == null || configFile == string.Empty )
72 configFile = NUnitProject.IsProjectFile(testFile.Name)
73 ? Path.GetFileNameWithoutExtension( testFile.Name ) + ".config"
74 : testFile.Name + ".config";
75 // Note: Mono needs full path to config file...
76 setup.ConfigurationFile = Path.Combine( appBase, configFile );
78 string binPath = package.PrivateBinPath;
79 if ( package.AutoBinPath )
80 binPath = GetPrivateBinPath( appBase, package.Assemblies );
81 setup.PrivateBinPath = binPath;
83 if ( package.GetSetting( "ShadowCopyFiles", true ) )
85 setup.ShadowCopyFiles = "true";
86 setup.ShadowCopyDirectories = appBase;
87 setup.CachePath = GetCachePath();
90 string domainName = "domain-" + package.Name;
91 Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
92 Evidence evidence = new Evidence(baseEvidence);
93 AppDomain runnerDomain = AppDomain.CreateDomain(domainName, evidence, setup);
95 // Inject assembly resolver into remote domain to help locate our assemblies
96 AssemblyResolver assemblyResolver = (AssemblyResolver)runnerDomain.CreateInstanceFromAndUnwrap(
97 typeof(AssemblyResolver).Assembly.CodeBase,
98 typeof(AssemblyResolver).FullName);
100 // Tell resolver to use our core assemblies in the test domain
101 assemblyResolver.AddFile( typeof( NUnit.Core.RemoteTestRunner ).Assembly.Location );
102 assemblyResolver.AddFile( typeof( NUnit.Core.ITest ).Assembly.Location );
104 // No reference to extensions, so we do it a different way
105 string moduleName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
106 string nunitDirPath = Path.GetDirectoryName(moduleName);
107 // string coreExtensions = Path.Combine(nunitDirPath, "nunit.core.extensions.dll");
108 // assemblyResolver.AddFile( coreExtensions );
109 //assemblyResolver.AddFiles( nunitDirPath, "*.dll" );
111 string addinsDirPath = Path.Combine(nunitDirPath, "addins");
112 assemblyResolver.AddDirectory( addinsDirPath );
114 // HACK: Only pass down our AddinRegistry one level so that tests of NUnit
115 // itself start without any addins defined.
116 if ( !IsTestDomain( AppDomain.CurrentDomain ) )
117 runnerDomain.SetData("AddinRegistry", Services.AddinRegistry);
119 return runnerDomain;
122 public void Unload( AppDomain domain )
124 bool shadowCopy = domain.ShadowCopyFiles;
125 string cachePath = domain.SetupInformation.CachePath;
126 string domainName = domain.FriendlyName;
130 AppDomain.Unload(domain);
132 catch (Exception ex)
134 // We assume that the tests did something bad and just leave
135 // the orphaned AppDomain "out there".
136 // TODO: Something useful.
137 Trace.WriteLine("Unable to unload AppDomain {0}", domainName);
138 Trace.WriteLine(ex.ToString());
140 finally
142 if (shadowCopy)
143 DeleteCacheDir(new DirectoryInfo(cachePath));
146 #endregion
148 #region Helper Methods
149 /// <summary>
150 /// Get the location for caching and delete any old cache info
151 /// </summary>
152 private string GetCachePath()
154 int processId = Process.GetCurrentProcess().Id;
155 long ticks = DateTime.Now.Ticks;
156 string cachePath = Path.Combine( ShadowCopyPath, processId.ToString() + "_" + ticks.ToString() );
158 try
160 DirectoryInfo dir = new DirectoryInfo(cachePath);
161 if(dir.Exists) dir.Delete(true);
163 catch( Exception ex)
165 throw new ApplicationException(
166 string.Format( "Invalid cache path: {0}",cachePath ),
167 ex );
170 return cachePath;
173 /// <summary>
174 /// Helper method to delete the cache dir. This method deals
175 /// with a bug that occurs when files are marked read-only
176 /// and deletes each file separately in order to give better
177 /// exception information when problems occur.
178 ///
179 /// TODO: This entire method is problematic. Should we be doing it?
180 /// </summary>
181 /// <param name="cacheDir"></param>
182 private void DeleteCacheDir( DirectoryInfo cacheDir )
184 // Debug.WriteLine( "Modules:");
185 // foreach( ProcessModule module in Process.GetCurrentProcess().Modules )
186 // Debug.WriteLine( module.ModuleName );
189 if(cacheDir.Exists)
191 foreach( DirectoryInfo dirInfo in cacheDir.GetDirectories() )
192 DeleteCacheDir( dirInfo );
194 foreach( FileInfo fileInfo in cacheDir.GetFiles() )
196 fileInfo.Attributes = FileAttributes.Normal;
197 try
199 fileInfo.Delete();
201 catch( Exception ex )
203 Debug.WriteLine( string.Format(
204 "Error deleting {0}, {1}", fileInfo.Name, ex.Message ) );
208 cacheDir.Attributes = FileAttributes.Normal;
212 cacheDir.Delete();
214 catch( Exception ex )
216 Debug.WriteLine( string.Format(
217 "Error deleting {0}, {1}", cacheDir.Name, ex.Message ) );
222 private bool IsTestDomain(AppDomain domain)
224 return domain.FriendlyName.StartsWith( "domain-" );
227 public static string GetPrivateBinPath( string basePath, IList assemblies )
229 StringBuilder sb = new StringBuilder(200);
230 ArrayList dirList = new ArrayList();
232 foreach( string assembly in assemblies )
234 string dir = PathUtils.RelativePath( basePath, Path.GetDirectoryName( assembly ) );
235 if ( dir != null && dir != "." && !dirList.Contains( dir ) )
237 dirList.Add( dir );
238 if ( sb.Length > 0 )
239 sb.Append( Path.PathSeparator );
240 sb.Append( dir );
244 return sb.Length == 0 ? null : sb.ToString();
247 public static void DeleteShadowCopyPath()
249 if ( Directory.Exists( ShadowCopyPath ) )
250 Directory.Delete( ShadowCopyPath, true );
252 #endregion
254 #region IService Members
256 public void UnloadService()
258 // TODO: Add DomainManager.UnloadService implementation
261 public void InitializeService()
263 // TODO: Add DomainManager.InitializeService implementation
266 #endregion