Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Resolution Paths during appdomain creation (Compatibility Isuue) #404

Merged
merged 6 commits into from
May 8, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ private ICollection<UnitTestElement> GetTestsInIsolation(string fullFilePath, IR
typeof(AssemblyEnumerator), new object[] { MSTestSettings.CurrentSettings }) as AssemblyEnumerator;

// After loading adapter reset the child-domain's appbase to point to test source location
isolationHost.UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver();
isolationHost.UpdateAppBaseToTestSourceLocation();

return assemblyEnumerator.EnumerateAssembly(fullFilePath, out warnings);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ private void ExecuteTestsInSource(IEnumerable<TestCase> tests, IRunContext runCo
new object[] { MSTestSettings.CurrentSettings }) as UnitTestRunner;

// After loading adapter reset the chils-domain's appbase to point to test source location
isolationHost.UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver();
isolationHost.UpdateAppBaseToTestSourceLocation();

PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("Created unit-test runner {0}", source);

Expand Down
223 changes: 110 additions & 113 deletions src/Adapter/PlatformServices.Desktop/Services/DesktopTestSourceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,35 +75,123 @@ internal TestSourceHost(string sourceFileName, IRunSettings runSettings, IFramew
/// </summary>
public void SetupHost()
{
if (this.AppDomainCreationDisabledInRunSettings())
List<string> resolutionPaths = this.GetResolutionPaths(this.sourceFileName, VSInstallationUtilities.IsCurrentProcessRunningInPortableMode());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add test for ResolutionPaths being set.


// Check if user specified any runsettings
MSTestAdapterSettings adapterSettings = MSTestSettingsProvider.Settings;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the declaration near to usage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


if (resolutionPaths != null && resolutionPaths.Count > 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be happen. Even if it is empty or null, We should add below two paths.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

{
return;
}
if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("TestSourceHost: Creating assembly resolver with resolution paths {0}.", string.Join(",", resolutionPaths.ToArray()));
}

// Setup app-domain
var appDomainSetup = new AppDomainSetup();
// Adding adapter folder to resolution paths
if (!resolutionPaths.Contains(Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location)))
{
resolutionPaths.Add(Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location));
}

this.targetFrameworkVersion = this.GetTargetFrameworkVersionString(this.sourceFileName);
// Adding extensions folder to resolution paths
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this is runner location(OM assembly location).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (!resolutionPaths.Contains(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location)))
{
resolutionPaths.Add(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location));
}
}

if (EqtTrace.IsInfoEnabled)
// Case when DisableAppDomain setting is present in runsettings and no child-appdomain needs to be created
if (this.AppDomainCreationDisabledInRunSettings())
{
EqtTrace.Info("TestSourceHost: Creating app-domain for source {0} with application base path {1}.", this.sourceFileName, appDomainSetup.ApplicationBase);
if (adapterSettings != null)
{
try
{
this.parentDomainAssemblyResolver = new AssemblyResolver(resolutionPaths);
this.parentDomainAssemblyResolver.AddSearchDirectoriesFromRunSetting(adapterSettings.GetDirectoryListWithRecursiveProperty(null));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GetDirectoryListWithRecursiveProperty should take test source directory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
catch (Exception exception)
{
if (EqtTrace.IsErrorEnabled)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Remove if check for error scenarios.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why so?

{
EqtTrace.Error(exception);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Add more details while logging the exception. At line 190 too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
}
}
}

AppDomainUtilities.SetAppDomainFrameworkVersionBasedOnTestSource(appDomainSetup, this.targetFrameworkVersion);
// Create child-appdomain and set assembly resolver on it
else
{
// Setup app-domain
var appDomainSetup = new AppDomainSetup();

this.targetFrameworkVersion = this.GetTargetFrameworkVersionString(this.sourceFileName);

if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("TestSourceHost: Creating app-domain for source {0} with application base path {1}.", this.sourceFileName, appDomainSetup.ApplicationBase);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: DesktopTestSourceHost.SetupHost: Change all the EqrTrace logs wherever it applies.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

AppDomainUtilities.SetAppDomainFrameworkVersionBasedOnTestSource(appDomainSetup, this.targetFrameworkVersion);

// Temporarily set appbase to the location from where adapter should be picked up from. We will later reset this to test source location
// once adapter gets loaded in the child app domain.
appDomainSetup.ApplicationBase = Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location);

var configFile = this.GetConfigFileForTestSource(this.sourceFileName);
AppDomainUtilities.SetConfigurationFile(appDomainSetup, configFile);

this.domain = this.appDomain.CreateDomain("TestSourceHost: Enumering assembly", null, appDomainSetup);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the name of appdomain to sourcefilename.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// Load objectModel before creating assembly resolver otherwise in 3.5 process, we run into a recurive assembly resolution
// which is trigged by AppContainerUtilities.AttachEventToResolveWinmd method.
EqtTrace.SetupRemoteEqtTraceListeners(this.domain);

// Temporarily set appbase to the location from where adapter should be picked up from. We will later reset this to test source location
// once adapter gets loaded in the child app domain.
appDomainSetup.ApplicationBase = Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location);
// Add an assembly resolver in the child app-domain...
Type assemblyResolverType = typeof(AssemblyResolver);

var configFile = this.GetConfigFileForTestSource(this.sourceFileName);
AppDomainUtilities.SetConfigurationFile(appDomainSetup, configFile);
if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("TestSourceHost: assemblyenumerator location: {0} , fullname: {1} ", assemblyResolverType.Assembly.Location, assemblyResolverType.FullName);
}

var resolver = AppDomainUtilities.CreateInstance(
this.domain,
assemblyResolverType,
new object[] { resolutionPaths });

if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info(
"TestSourceHost: resolver type: {0} , resolve type assembly: {1} ",
resolver.GetType().FullName,
resolver.GetType().Assembly.Location);
}

this.domain = this.appDomain.CreateDomain("TestSourceHost: Enumering assembly", null, appDomainSetup);
this.childDomainAssemblyResolver = (AssemblyResolver)resolver;

// Load objectModel before creating assembly resolver otherwise in 3.5 process, we run into a recurive assembly resolution
// which is trigged by AppContainerUtilities.AttachEventToResolveWinmd method.
EqtTrace.SetupRemoteEqtTraceListeners(this.domain);
if (adapterSettings != null)
{
try
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DRY.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
var additionalSearchDirectories =
adapterSettings.GetDirectoryListWithRecursiveProperty(this.domain.SetupInformation.ApplicationBase);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.domain.SetupInformation.ApplicationBase value should be testsource directory.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reuse additionalSearchDirectories.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if (additionalSearchDirectories?.Count > 0)
{
this.childDomainAssemblyResolver.AddSearchDirectoriesFromRunSetting(
adapterSettings.GetDirectoryListWithRecursiveProperty(this.domain.SetupInformation.ApplicationBase));
}
}
catch (Exception exception)
{
if (EqtTrace.IsErrorEnabled)
{
EqtTrace.Error(exception);
}
}
}
}
}

/// <summary>
Expand Down Expand Up @@ -180,58 +268,11 @@ public void Dispose()
}

/// <summary>
/// Updates child-domain's appbase to point to test source location and sets up
/// Assembly resolver for both parent and child appdomain
/// Updates child-domain's appbase to point to test source location.
/// </summary>
public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver()
public void UpdateAppBaseToTestSourceLocation()
{
List<string> resolutionPaths = this.GetResolutionPaths(this.sourceFileName, VSInstallationUtilities.IsCurrentProcessRunningInPortableMode());

// Check if user specified any runsettings
MSTestAdapterSettings adapterSettings = MSTestSettingsProvider.Settings;

if (resolutionPaths != null && resolutionPaths.Count > 0)
{
if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("TestSourceHost: Creating assembly resolver with resolution paths {0}.", string.Join(",", resolutionPaths.ToArray()));
}

// Adding adapter folder to resolution paths
if (!resolutionPaths.Contains(Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location)))
{
resolutionPaths.Add(Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location));
}

// Adding extensions folder to resolution paths
if (!resolutionPaths.Contains(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location)))
{
resolutionPaths.Add(Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.Location));
}
}

// Case when DisableAppDomain setting is present in runsettings and no child-appdomain is created
if (this.AppDomainCreationDisabledInRunSettings())
{
if (adapterSettings != null)
{
try
{
this.parentDomainAssemblyResolver = new AssemblyResolver(resolutionPaths);
this.parentDomainAssemblyResolver.AddSearchDirectoriesFromRunSetting(adapterSettings.GetDirectoryListWithRecursiveProperty(null));
}
catch (Exception exception)
{
if (EqtTrace.IsErrorEnabled)
{
EqtTrace.Error(exception);
}
}
}
}

// Case when Child-appdomain was created successfully, update appbase and set assembly resolver on it
else if (this.domain != null)
if (this.domain != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to inverted if IsAppDomainCreationDisable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
// After adapter has been loaded, reset appdomains appbase.
// The below logic of preferential setting the appdomains appbase is needed because:
Expand All @@ -249,54 +290,10 @@ public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver()
{
this.domain.SetData("APPBASE", Path.GetDirectoryName(typeof(TestSourceHost).Assembly.Location));
}

// Add an assembly resolver in the child app-domain...
Type assemblyResolverType = typeof(AssemblyResolver);

if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info("TestSourceHost: assemblyenumerator location: {0} , fullname: {1} ", assemblyResolverType.Assembly.Location, assemblyResolverType.FullName);
}

var resolver = AppDomainUtilities.CreateInstance(
this.domain,
assemblyResolverType,
new object[] { resolutionPaths });

if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info(
"TestSourceHost: resolver type: {0} , resolve type assembly: {1} ",
resolver.GetType().FullName,
resolver.GetType().Assembly.Location);
}

this.childDomainAssemblyResolver = (AssemblyResolver)resolver;

if (adapterSettings != null)
{
try
{
var additionalSearchDirectories =
adapterSettings.GetDirectoryListWithRecursiveProperty(this.domain.SetupInformation.ApplicationBase);
if (additionalSearchDirectories?.Count > 0)
{
this.childDomainAssemblyResolver.AddSearchDirectoriesFromRunSetting(
adapterSettings.GetDirectoryListWithRecursiveProperty(this.domain.SetupInformation.ApplicationBase));
}
}
catch (Exception exception)
{
if (EqtTrace.IsErrorEnabled)
{
EqtTrace.Error(exception);
}
}
}
}

// Log error when child-appdomain was expected to be created but wasn't created.
else
else if (!this.AppDomainCreationDisabledInRunSettings())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not required. Are DisableAppDomain settings from runsettings only once.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

{
EqtTrace.ErrorIf(EqtTrace.IsErrorEnabled, "TestSourceHost.AppDomain: Failed to update domain's appbase and setup assembly resolver");
}
Expand Down
5 changes: 2 additions & 3 deletions src/Adapter/PlatformServices.Interface/ITestSourceHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ public interface ITestSourceHost : IDisposable
object CreateInstanceForType(Type type, object[] args);

/// <summary>
/// Updates child-domain's appbase to point to test source location and sets up
/// Assembly resolver for both parent and child appdomain
/// Updates child-domain's appbase to point to test source location
/// </summary>
void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver();
void UpdateAppBaseToTestSourceLocation();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ public void Dispose()
}

/// <summary>
/// Updates child-domain's appbase to point to test source location and sets up
/// Assembly resolver for both parent and child appdomain
/// Updates child-domain's appbase to point to test source location
/// </summary>
public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver()
public void UpdateAppBaseToTestSourceLocation()
{
// Do nothing.
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public void SetupHostShouldSetNewDomainsAppBaseToAdapterLocation()
/// Leaving the test running till then.
/// </summary>
[TestMethod]
public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolverShouldSetDomainsAppBaseToTestSourceLocationForFullCLRTestss()
public void UpdateAppBaseToTestSourceLocationShouldSetDomainsAppBaseToTestSourceLocationForFullCLRTestss()
{
// Arrange
DummyClass dummyclass = new DummyClass();
Expand All @@ -124,7 +124,7 @@ public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolverShouldSetDo
sourceHost.Object.SetupHost();
var expectedObject =
sourceHost.Object.CreateInstanceForType(typeof(DummyClass), null) as DummyClass;
sourceHost.Object.UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver();
sourceHost.Object.UpdateAppBaseToTestSourceLocation();

// Assert
Assert.AreEqual(Path.GetDirectoryName(location), expectedObject.AppDomainAppBase);
Expand All @@ -136,7 +136,7 @@ public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolverShouldSetDo
}

[TestMethod]
public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolverShouldSetDomainsAppBaseToAdaptersLocationForNonFullCLRTests()
public void UpdateAppBaseToTestSourceLocationShouldSetDomainsAppBaseToAdaptersLocationForNonFullCLRTests()
{
// Arrange
DummyClass dummyclass = new DummyClass();
Expand All @@ -151,7 +151,7 @@ public void UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolverShouldSetDo
// Act
sourceHost.Object.SetupHost();
var expectedObject = sourceHost.Object.CreateInstanceForType(typeof(DummyClass), null) as DummyClass;
sourceHost.Object.UpdateAppBaseToTestSourceLocationAndSetupAssemblyResolver();
sourceHost.Object.UpdateAppBaseToTestSourceLocation();

// Assert
Assert.AreEqual(Path.GetDirectoryName(location), expectedObject.AppDomainAppBase);
Expand Down