Add test to validate binding using Resolving event using static binding
authorGaurav Khanna <gkhanna@microsoft.com>
Fri, 17 Jun 2016 13:30:31 +0000 (06:30 -0700)
committerGaurav Khanna <gkhanna@microsoft.com>
Thu, 23 Jun 2016 17:45:31 +0000 (10:45 -0700)
Commit migrated from https://github.com/dotnet/corefx/commit/04c8661e3e4ec98da8cfcbf467523fba471bfdae

src/libraries/System.Runtime.Loader/tests/DefaultContext/DefaultLoadContextTest.cs

index 6715aa9..642ba0d 100644 (file)
@@ -12,21 +12,48 @@ using System.Threading.Tasks;
 
 namespace System.Runtime.Loader.Tests
 {
+    public class SecondaryLoadContext : AssemblyLoadContext
+    {
+        protected override Assembly Load(AssemblyName assemblyName)
+        {
+            return null;
+        }
+    }
+
     public class DefaultLoadContextTests
     {
         private static string s_loadFromPath = null;
 
+        // Since the first non-Null returning callback should stop Resolving event processing,
+        // this counter is used to assert the same.
+        private static int s_NumNonNullResolutions = 0;
+
         private static Assembly ResolveAssembly(AssemblyLoadContext sender, AssemblyName assembly)
         {
             string assemblyFilename = assembly.Name + ".dll";
-            
+            s_NumNonNullResolutions++;
+
+            return sender.LoadFromAssemblyPath(Path.Combine(s_loadFromPath, assemblyFilename));
+        }
+
+        private static Assembly ResolveAssemblyAgain(AssemblyLoadContext sender, AssemblyName assembly)
+        {
+            string assemblyFilename = assembly.Name + ".dll";
+            s_NumNonNullResolutions++;
+
             return sender.LoadFromAssemblyPath(Path.Combine(s_loadFromPath, assemblyFilename));
         }
 
+        private static Assembly ResolveNullAssembly(AssemblyLoadContext sender, AssemblyName assembly)
+        {
+            return null;
+        }
+
         private static void Init()
         {
             // Delete the assembly from the temp location if it exists.
             var assemblyFilename = "System.Runtime.Loader.Noop.Assembly.dll";
+            s_NumNonNullResolutions = 0;
 
             // Form the dynamic path that would not collide if another instance of this test is running.
             s_loadFromPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
@@ -58,24 +85,74 @@ namespace System.Runtime.Loader.Tests
         {
             Init();
 
-           // This will attempt to load an assembly, by path, in the Default Load context via the Resolving event
-           var assemblyName = "System.Runtime.Loader.Noop.Assembly";
+            // This will attempt to load an assembly, by path, in the Default Load context via the Resolving event
+            var assemblyNameStr = "System.Runtime.Loader.Noop.Assembly";
+            var assemblyName = new AssemblyName(assemblyNameStr);
+
+            // By default, the assembly should not be found in DefaultContext at all
+            Assert.Throws(typeof(FileNotFoundException), () => Assembly.Load(assemblyName));
 
+            // Create a secondary load context and wireup its resolving event
+            SecondaryLoadContext slc = new SecondaryLoadContext();
+            slc.Resolving += ResolveAssembly;
+            
+            // Attempt to load the assembly in secondary load context
+            var slcLoadedAssembly = slc.LoadFromAssemblyName(assemblyName);
+            
+            // We should have successfully loaded the assembly in default context.
+            Assert.NotNull(slcLoadedAssembly);
+
+            // And make sure the simple name matches
+            Assert.Equal(assemblyNameStr, slcLoadedAssembly.GetName().Name);
+
+            // We should have only invoked non-Null returning handler once
+            Assert.Equal(1, s_NumNonNullResolutions);
+
+            slc.Resolving -= ResolveAssembly;
+
+            // Reset the non-Null resolution counter
+            s_NumNonNullResolutions = 0;
+
+            // Now, wireup the Resolving event of default context to locate the assembly via multiple handlers
+            AssemblyLoadContext.Default.Resolving += ResolveNullAssembly;
             AssemblyLoadContext.Default.Resolving += ResolveAssembly;
-            var assemblyExpected = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(assemblyName));
+            AssemblyLoadContext.Default.Resolving += ResolveAssemblyAgain;
+            
+            // This will invoke the resolution via VM requiring to bind using the TPA binder
+            var assemblyExpectedFromLoad = Assembly.Load(assemblyName);
+
+            // We should have successfully loaded the assembly in default context.
+            Assert.NotNull(assemblyExpectedFromLoad);
+
+            // We should have only invoked non-Null returning handler once
+            Assert.Equal(1, s_NumNonNullResolutions);
+
+            // And make sure the simple name matches
+            Assert.Equal(assemblyNameStr, assemblyExpectedFromLoad.GetName().Name);
+
+            // The assembly loaded in DefaultContext should have a different reference from the one in secondary load context
+            Assert.NotEqual(slcLoadedAssembly, assemblyExpectedFromLoad);
+
+            // This will resolve the assembly via event invocation.
+            var assemblyExpected = AssemblyLoadContext.Default.LoadFromAssemblyName(assemblyName);
             
             // We should have successfully loaded the assembly in default context.
             Assert.NotNull(assemblyExpected);
 
+            // What we got via Assembly.Load and LoadFromAssemblyName should be the same
+            Assert.Equal(assemblyExpected, assemblyExpectedFromLoad);
+
             // And make sure the simple name matches
-            Assert.Equal(assemblyExpected.GetName().Name, assemblyName);
+            Assert.Equal(assemblyExpected.GetName().Name, assemblyNameStr);
 
             // Unwire the Resolving event.
+            AssemblyLoadContext.Default.Resolving -= ResolveAssemblyAgain;
             AssemblyLoadContext.Default.Resolving -= ResolveAssembly;
+            AssemblyLoadContext.Default.Resolving -= ResolveNullAssembly;
 
             // Unwire the Resolving event and attempt to load the assembly again. This time
             // it should be found in the Default Load Context.
-            var assemblyLoaded = Assembly.Load(new AssemblyName(assemblyName));
+            var assemblyLoaded = Assembly.Load(new AssemblyName(assemblyNameStr));
 
             // We should have successfully found the assembly in default context.
             Assert.NotNull(assemblyLoaded);