private static void SetupPipelineDomains(string pipelineId, AppDomain host, AppDomain remote) { if (host == null) { throw new ArgumentNullException(nameof(host)); } if (remote == null) { throw new ArgumentNullException(nameof(remote)); } var domainInvokerType = typeof(DomainInvoker); if (domainInvokerType.FullName == null) { throw new InvalidOperationException(); } var setter = new DomainVault.DomainVaultSetter(pipelineId); host.SetRemoteInvoker(pipelineId, remote.CreateObject <DomainInvoker>(pipelineId)); host.DoCallBack(setter.Set); remote.SetRemoteInvoker(pipelineId, host.CreateObject <DomainInvoker>(pipelineId)); remote.DoCallBack(setter.Set); }
List <KeyValuePair <string?, ITestCase?> > BulkDeserialize(List <string> serializations) { Guard.NotNull($"This instance of {typeof(Xunit2).FullName} was created for discovery only; execution-related operations cannot be performed.", remoteExecutor); var callbackContainer = new DeserializeCallback(); Action <List <KeyValuePair <string?, ITestCase?> > > callback = callbackContainer.Callback; if (bulkDeserializer == null) { if (AppDomain.HasAppDomain) { try { AppDomain.CreateObject <object>(TestFrameworkAssemblyName, "Xunit.Sdk.TestCaseBulkDeserializer", remoteDiscoverer, remoteExecutor, serializations, callback); if (callbackContainer.Results != null) { return(callbackContainer.Results); } } catch (TypeLoadException) { } // Only be willing to eat "Xunit.Sdk.TestCaseBulkDeserialize" doesn't exist } bulkDeserializer = new DefaultTestCaseBulkDeserializer(remoteExecutor); } return(bulkDeserializer.BulkDeserialize(serializations)); }
/// <summary> /// Creates a high performance cross-AppDomain message sink that utilizes <see cref="IMessageSinkWithTypes"/> /// which can be passed to <see cref="ITestFrameworkDiscoverer"/> and <see cref="ITestFrameworkExecutor"/>. /// </summary> /// <param name="sink">The local message sink to receive the messages.</param> /// <param name="serializeDiscoveredTestCases">A flag which indicates whether test case serialization is required</param> protected IMessageSink CreateOptimizedRemoteMessageSink( _IMessageSink sink, bool serializeDiscoveredTestCases = true) { Guard.ArgumentNotNull(sink); var v2MessageSink = new Xunit2MessageSink(sink, TestAssemblyUniqueID, serializeDiscoveredTestCases ? remoteDiscoverer : null); try { var asssemblyName = typeof(OptimizedRemoteMessageSink).Assembly.GetName(); var optimizedSink = AppDomain.CreateObject <IMessageSink>(asssemblyName, typeof(OptimizedRemoteMessageSink).FullName !, v2MessageSink); if (optimizedSink != null) { return(optimizedSink); } } catch { } // This really shouldn't happen, but falling back makes sense in catastrophic cases return(v2MessageSink); }
Xunit2( _IMessageSink diagnosticMessageSink, AppDomainSupport appDomainSupport, _ISourceInformationProvider sourceInformationProvider, _IAssemblyInfo?assemblyInfo, string?assemblyFileName, string xunitExecutionAssemblyPath, string?configFileName, bool shadowCopy, string?shadowCopyFolder, bool verifyAssembliesOnDisk) { #if NETFRAMEWORK // Only safe to assume the execution reference is copied in a desktop project if (verifyAssembliesOnDisk) { Guard.FileExists(xunitExecutionAssemblyPath); } CanUseAppDomains = !IsDotNet(xunitExecutionAssemblyPath); #else CanUseAppDomains = false; #endif DiagnosticMessageSink = diagnosticMessageSink; var appDomainAssembly = assemblyFileName ?? xunitExecutionAssemblyPath; AppDomain = AppDomainManagerFactory.Create(appDomainSupport != AppDomainSupport.Denied && CanUseAppDomains, appDomainAssembly, configFileName, shadowCopy, shadowCopyFolder, diagnosticMessageSink); DisposalTracker.Add(AppDomain); #if NETFRAMEWORK var runnerUtilityAssemblyLocation = Path.GetDirectoryName(typeof(AssemblyHelper).Assembly.GetLocalCodeBase()); assemblyHelper = AppDomain.CreateObjectFrom <AssemblyHelper>(typeof(AssemblyHelper).Assembly.Location, typeof(AssemblyHelper).FullName !, runnerUtilityAssemblyLocation); DisposalTracker.Add(assemblyHelper); #endif TestFrameworkAssemblyName = GetTestFrameworkAssemblyName(xunitExecutionAssemblyPath); // We need both a v2 and v3 assembly info, so manufacture the things we're missing IAssemblyInfo remoteAssemblyInfo; if (assemblyInfo != null) { remoteAssemblyInfo = new Xunit2AssemblyInfo(assemblyInfo); } else { remoteAssemblyInfo = Guard.NotNull( "Could not create Xunit.Sdk.TestFrameworkProxy for v2 unit test", AppDomain.CreateObject <IAssemblyInfo>(TestFrameworkAssemblyName, "Xunit.Sdk.ReflectionAssemblyInfo", assemblyFileName) ); assemblyInfo = new Xunit3AssemblyInfo(remoteAssemblyInfo); } this.assemblyInfo = assemblyInfo; this.configFileName = configFileName; TestAssemblyUniqueID = UniqueIDGenerator.ForAssembly(this.assemblyInfo.Name, this.assemblyInfo.AssemblyPath, configFileName); var v2SourceInformationProvider = Xunit2SourceInformationProviderAdapter.Adapt(sourceInformationProvider); var v2DiagnosticMessageSink = new Xunit2MessageSink(DiagnosticMessageSink); remoteFramework = Guard.NotNull( "Could not create Xunit.Sdk.TestFrameworkProxy for v2 unit test", AppDomain.CreateObject <ITestFramework>( TestFrameworkAssemblyName, "Xunit.Sdk.TestFrameworkProxy", remoteAssemblyInfo, v2SourceInformationProvider, v2DiagnosticMessageSink ) ); DisposalTracker.Add(remoteFramework); remoteDiscoverer = Guard.NotNull("Could not get discoverer from test framework for v2 unit test", remoteFramework.GetDiscoverer(remoteAssemblyInfo)); DisposalTracker.Add(remoteDiscoverer); // If we got an assembly file name, that means we can do execution as well as discovery. if (assemblyFileName != null) { #if NETFRAMEWORK var assemblyName = AssemblyName.GetAssemblyName(assemblyFileName); #else var an = Assembly.Load(new AssemblyName { Name = Path.GetFileNameWithoutExtension(assemblyFileName) }).GetName(); var assemblyName = new AssemblyName { Name = an.Name, Version = an.Version }; #endif remoteExecutor = remoteFramework.GetExecutor(assemblyName); DisposalTracker.Add(remoteExecutor); } }