Fix unit test memory leak

Shutdown ASP.NET AppDomains after running each SpecFlow scenario.

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-05-22 17:50:18 -07:00
parent ef34e58ed5
commit 01c7e29db2
8 changed files with 57 additions and 12 deletions

View File

@@ -14,10 +14,10 @@ using HtmlAgilityPack;
using log4net.Appender; using log4net.Appender;
using log4net.Core; using log4net.Core;
using log4net.Repository; using log4net.Repository;
using NUnit.Framework;
using Orchard.Specs.Hosting; using Orchard.Specs.Hosting;
using Orchard.Specs.Util; using Orchard.Specs.Util;
using TechTalk.SpecFlow; using TechTalk.SpecFlow;
using NUnit.Framework;
namespace Orchard.Specs.Bindings { namespace Orchard.Specs.Bindings {
[Binding] [Binding]
@@ -27,6 +27,9 @@ namespace Orchard.Specs.Bindings {
private HtmlDocument _doc; private HtmlDocument _doc;
private MessageSink _messages; private MessageSink _messages;
public WebAppHosting() {
}
public WebHost Host { public WebHost Host {
get { return _webHost; } get { return _webHost; }
} }
@@ -36,6 +39,14 @@ namespace Orchard.Specs.Bindings {
set { _details = value; } set { _details = value; }
} }
[AfterScenario]
public void AfterScenario() {
if (_webHost != null) {
_webHost.Dispose();
_webHost = null;
}
}
[Given(@"I have a clean site")] [Given(@"I have a clean site")]
public void GivenIHaveACleanSite() { public void GivenIHaveACleanSite() {
GivenIHaveACleanSiteBasedOn("Orchard.Web"); GivenIHaveACleanSiteBasedOn("Orchard.Web");

View File

@@ -44,6 +44,13 @@ namespace Orchard.Specs.Hosting {
} }
public void Dispose() {
if (_webHostAgent != null) {
_webHostAgent.Shutdown();
_webHostAgent = null;
}
}
public void CopyExtension(string extensionFolder, string extensionName) { public void CopyExtension(string extensionFolder, string extensionName) {
var sourceModule = _orchardWebPath.Combine(extensionFolder).Combine(extensionName); var sourceModule = _orchardWebPath.Combine(extensionFolder).Combine(extensionName);
var targetModule = _tempSite.Combine(extensionFolder).Combine(extensionName); var targetModule = _tempSite.Combine(extensionFolder).Combine(extensionName);
@@ -73,6 +80,5 @@ namespace Orchard.Specs.Hosting {
fieldInfo.SetValue(to, value); fieldInfo.SetValue(to, value);
} }
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Web.Hosting;
namespace Orchard.Specs.Hosting { namespace Orchard.Specs.Hosting {
public class WebHostAgent : MarshalByRefObject public class WebHostAgent : MarshalByRefObject
@@ -8,5 +9,9 @@ namespace Orchard.Specs.Hosting {
shuttle.Delegate(); shuttle.Delegate();
return shuttle; return shuttle;
} }
public void Shutdown() {
HostingEnvironment.InitiateShutdown();
}
} }
} }

View File

@@ -284,9 +284,6 @@
<Name>Orchard</Name> <Name>Orchard</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Hosting\Simple.Web\Content\Static.txt"> <Content Include="Hosting\Simple.Web\Content\Static.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Orchard {
public class ApplicationObject {
public string ApplicationId { get; set; }
public object ObjectInstance { get; set; }
}
}

View File

@@ -18,7 +18,7 @@ namespace Orchard.Host {
} }
public void Stop(bool immediate) { public void Stop(bool immediate) {
//TODO HostingEnvironment.UnregisterObject(this);
} }
public int RunCommand(TextReader input, TextWriter output, Logger logger, OrchardParameters args) { public int RunCommand(TextReader input, TextWriter output, Logger logger, OrchardParameters args) {

View File

@@ -71,6 +71,7 @@
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ApplicationObject.cs" />
<Compile Include="Logger.cs" /> <Compile Include="Logger.cs" />
<Compile Include="OrchardHost.cs" /> <Compile Include="OrchardHost.cs" />
<Compile Include="Parameters\ICommandParametersParser.cs" /> <Compile Include="Parameters\ICommandParametersParser.cs" />
@@ -104,7 +105,9 @@
</BootstrapperPackage> </BootstrapperPackage>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="app.config" /> <None Include="app.config">
<SubType>Designer</SubType>
</None>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@@ -7,6 +7,7 @@ using System.Web;
using System.Web.Hosting; using System.Web.Hosting;
using Orchard.Host; using Orchard.Host;
using Orchard.Parameters; using Orchard.Parameters;
using System.Threading;
namespace Orchard { namespace Orchard {
class OrchardHost { class OrchardHost {
@@ -77,13 +78,23 @@ namespace Orchard {
var orchardDirectory = GetOrchardDirectory(_arguments.WorkingDirectory); var orchardDirectory = GetOrchardDirectory(_arguments.WorkingDirectory);
LogInfo("Orchard root directory: \"{0}\"", orchardDirectory.FullName); LogInfo("Orchard root directory: \"{0}\"", orchardDirectory.FullName);
return CreateHostAndExecute(orchardDirectory);
}
private int CreateHostAndExecute(DirectoryInfo orchardDirectory) {
var appManager = ApplicationManager.GetApplicationManager();
LogInfo("Creating ASP.NET AppDomain for command agent..."); LogInfo("Creating ASP.NET AppDomain for command agent...");
var host = (CommandHost)CreateWorkerAppDomainWithHost(_arguments.VirtualPath, orchardDirectory.FullName, typeof(CommandHost)); var appObject = CreateWorkerAppDomainWithHost(appManager, _arguments.VirtualPath, orchardDirectory.FullName, typeof(CommandHost));
var host = (CommandHost)appObject.ObjectInstance;
LogInfo("Executing command in ASP.NET AppDomain..."); LogInfo("Executing command in ASP.NET AppDomain...");
var result = Execute(host); var result = Execute(host);
LogInfo("Return code for command: {0}", result); LogInfo("Return code for command: {0}", result);
LogInfo("Shutting down ASP.NET AppDomain...");
appManager.ShutdownApplication(appObject.ApplicationId);
return result; return result;
} }
@@ -182,14 +193,13 @@ namespace Orchard {
string.Format("Directory \"{0}\" doesn't seem to contain an Orchard installation", new DirectoryInfo(directory).FullName)); string.Format("Directory \"{0}\" doesn't seem to contain an Orchard installation", new DirectoryInfo(directory).FullName));
} }
private static object CreateWorkerAppDomainWithHost(string virtualPath, string physicalPath, Type hostType) { private static ApplicationObject CreateWorkerAppDomainWithHost(ApplicationManager appManager, string virtualPath, string physicalPath, Type hostType) {
// this creates worker app domain in a way that host doesn't need to be in GAC or bin // this creates worker app domain in a way that host doesn't need to be in GAC or bin
// using BuildManagerHost via private reflection // using BuildManagerHost via private reflection
string uniqueAppString = string.Concat(virtualPath, physicalPath).ToLowerInvariant(); string uniqueAppString = string.Concat(virtualPath, physicalPath).ToLowerInvariant();
string appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture); string appId = (uniqueAppString.GetHashCode()).ToString("x", CultureInfo.InvariantCulture);
// create BuildManagerHost in the worker app domain // create BuildManagerHost in the worker app domain
var appManager = ApplicationManager.GetApplicationManager();
var buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost"); var buildManagerHostType = typeof(HttpRuntime).Assembly.GetType("System.Web.Compilation.BuildManagerHost");
var buildManagerHost = appManager.CreateObject(appId, buildManagerHostType, virtualPath, physicalPath, false); var buildManagerHost = appManager.CreateObject(appId, buildManagerHostType, virtualPath, physicalPath, false);
@@ -202,7 +212,9 @@ namespace Orchard {
new object[] { hostType.Assembly.FullName, hostType.Assembly.Location }); new object[] { hostType.Assembly.FullName, hostType.Assembly.Location });
// create Host in the worker app domain // create Host in the worker app domain
return appManager.CreateObject(appId, hostType, virtualPath, physicalPath, false); return new ApplicationObject {
ApplicationId = appId,
ObjectInstance = appManager.CreateObject(appId, hostType, virtualPath, physicalPath, false) };
} }
} }
} }