Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 8613407

Browse files
committed
Merge pull request #2594 from Sridhar-MS/load-context
Add unit test cases for System.Runtime.Loader.AssemblyLoadContext
2 parents 4b6ce97 + 514f4c7 commit 8613407

13 files changed

+1956
-1
lines changed

run-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ create_test_overlay()
130130
echo "Corefx binaries not found at $CoreFxBins"
131131
exit 1
132132
fi
133-
find $CoreFxBins -name '*.dll' -exec cp '{}' "$OverlayDir" ";"
133+
find $CoreFxBins -name '*.dll' -and -not -name "*Test*" -exec cp '{}' "$OverlayDir" ";"
134134

135135
# Then the native CoreFX binaries
136136
#
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 14
4+
VisualStudioVersion = 14.0.23107.0
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Loader.Tests", "tests\System.Runtime.Loader.Tests.csproj", "{701CB3BC-00DC-435D-BDE4-C5FC29A708A7}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "System.Runtime.Loader.Test.Assembly", "tests\System.Runtime.Loader.Test.Assembly\System.Runtime.Loader.Test.Assembly.csproj", "{396D6EBF-60BD-4DAF-8783-FB403E070A56}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
EndGlobalSection
14+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
15+
{701CB3BC-00DC-435D-BDE4-C5FC29A708A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
16+
{701CB3BC-00DC-435D-BDE4-C5FC29A708A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
17+
{396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18+
{396D6EBF-60BD-4DAF-8783-FB403E070A56}.Debug|Any CPU.Build.0 = Debug|Any CPU
19+
EndGlobalSection
20+
GlobalSection(SolutionProperties) = preSolution
21+
HideSolutionNode = FALSE
22+
EndGlobalSection
23+
EndGlobal
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using Xunit;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Reflection;
10+
using System.Threading.Tasks;
11+
12+
namespace System.Runtime.Loader.Tests
13+
{
14+
public class AssemblyLoadContextTest
15+
{
16+
private const string TestAssembly = "System.Runtime.Loader.Test.Assembly";
17+
18+
[Fact]
19+
public static void GetAssemblyNameTest_ValidAssembly()
20+
{
21+
var expectedName = typeof(ISet<>).GetTypeInfo().Assembly.GetName();
22+
var actualAsmName = AssemblyLoadContext.GetAssemblyName("System.Runtime.dll");
23+
Assert.Equal(expectedName.FullName, actualAsmName.FullName);
24+
}
25+
26+
[Fact]
27+
public static void GetAssemblyNameTest_AssemblyNotFound()
28+
{
29+
Assert.Throws(typeof(FileNotFoundException),
30+
() => AssemblyLoadContext.GetAssemblyName("Non.Existing.Assembly.dll"));
31+
}
32+
33+
[Fact]
34+
public static void GetAssemblyNameTest_NullParameter()
35+
{
36+
Assert.Throws(typeof(ArgumentNullException),
37+
() => AssemblyLoadContext.GetAssemblyName(null));
38+
}
39+
40+
[Fact]
41+
public static void LoadAssemblyByPath_ValidUserAssembly()
42+
{
43+
var asmName = new AssemblyName(TestAssembly);
44+
var loadContext = new ResourceAssemblyLoadContext();
45+
loadContext.LoadBy = LoadBy.Path;
46+
47+
var asm = loadContext.LoadFromAssemblyName(asmName);
48+
49+
Assert.NotNull(asm);
50+
Assert.True(asm.DefinedTypes.Any(t => t.Name == "TestClass"));
51+
}
52+
53+
[Fact]
54+
public static void LoadAssemblyByStream_ValidUserAssembly()
55+
{
56+
var asmName = new AssemblyName(TestAssembly);
57+
var loadContext = new ResourceAssemblyLoadContext();
58+
loadContext.LoadBy = LoadBy.Stream;
59+
60+
var asm = loadContext.LoadFromAssemblyName(asmName);
61+
62+
Assert.NotNull(asm);
63+
Assert.True(asm.DefinedTypes.Any(t => t.Name == "TestClass"));
64+
}
65+
66+
[Fact]
67+
public static void LoadFromAssemblyName_AssemblyNotFound()
68+
{
69+
var asmName = new AssemblyName("Non.Existing.Assembly.dll");
70+
var loadContext = new ResourceAssemblyLoadContext();
71+
loadContext.LoadBy = LoadBy.Path;
72+
73+
Assert.Throws(typeof(FileNotFoundException),
74+
() => loadContext.LoadFromAssemblyName(asmName));
75+
}
76+
77+
[Fact]
78+
public static void LoadFromAssemblyName_ValidTrustedPlatformAssembly()
79+
{
80+
var asmName = AssemblyLoadContext.GetAssemblyName("System.Runtime.dll");
81+
var loadContext = new CustomTPALoadContext();
82+
83+
// Usage of TPA and AssemblyLoadContext is mutually exclusive, you cannot use both.
84+
// Since the premise is that you either want to use the default binding mechanism (via coreclr TPA binder)
85+
// or supply your own (via AssemblyLoadContext) for your own assemblies.
86+
Assert.Throws(typeof(FileLoadException),
87+
() => loadContext.LoadFromAssemblyName(asmName));
88+
}
89+
90+
[Fact]
91+
public static void GetLoadContextTest_ValidUserAssembly()
92+
{
93+
var asmName = new AssemblyName(TestAssembly);
94+
var expectedContext = new ResourceAssemblyLoadContext();
95+
expectedContext.LoadBy = LoadBy.Stream;
96+
97+
var asm = expectedContext.LoadFromAssemblyName(asmName);
98+
var actualContext = AssemblyLoadContext.GetLoadContext(asm);
99+
100+
Assert.Equal(expectedContext, actualContext);
101+
}
102+
103+
[Fact]
104+
public static void GetLoadContextTest_ValidTrustedPlatformAssembly()
105+
{
106+
var asm = typeof(ISet<>).GetTypeInfo().Assembly;
107+
var context = AssemblyLoadContext.GetLoadContext(asm);
108+
109+
Assert.NotNull(context);
110+
}
111+
112+
[Fact]
113+
public static void InitializeDefaultContextTest()
114+
{
115+
var loadContext = new ResourceAssemblyLoadContext();
116+
117+
// because the coreclr binding model is already locked for the appdomain
118+
// and cannot be reset
119+
Assert.Throws(typeof(InvalidOperationException),
120+
() => AssemblyLoadContext.InitializeDefaultContext(loadContext));
121+
}
122+
}
123+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Reflection;
7+
8+
namespace System.Runtime.Loader.Tests
9+
{
10+
public class CustomTPALoadContext : AssemblyLoadContext
11+
{
12+
protected override Assembly Load(AssemblyName assemblyName)
13+
{
14+
string assemblyPath = Path.Combine(Directory.GetCurrentDirectory(), assemblyName.Name + ".dll");
15+
return LoadFromAssemblyPath(assemblyPath);
16+
}
17+
}
18+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.IO;
6+
using System.Reflection;
7+
8+
namespace System.Runtime.Loader.Tests
9+
{
10+
public enum LoadBy
11+
{
12+
Path,
13+
Stream
14+
}
15+
16+
public class ResourceAssemblyLoadContext : AssemblyLoadContext
17+
{
18+
public LoadBy LoadBy { get; set; }
19+
20+
public ResourceAssemblyLoadContext()
21+
{
22+
LoadBy = LoadBy.Path;
23+
}
24+
25+
// A custom load context which only loads a given assembly if it is an embedded resource.
26+
protected override Assembly Load(AssemblyName assemblyName)
27+
{
28+
string assembly = assemblyName.Name + ".dll";
29+
var currentAsm = typeof(ResourceAssemblyLoadContext).GetTypeInfo().Assembly;
30+
var asmStream = currentAsm.GetManifestResourceStream("System.Runtime.Loader.Tests." + assembly);
31+
32+
if (asmStream == null)
33+
{
34+
return null;
35+
}
36+
37+
if (LoadBy == LoadBy.Path)
38+
{
39+
// corerun blindly adds all the assemblies (including test assemblies) in the current directory to the TPA list.
40+
// Custom Load Contexts cannot be used to load an assembly in the TPA list.
41+
// Hence using this hack - where the user test assembly "System.Runtime.Loader.TestAssembly" is added as an embedded resource.
42+
// This custom load context will extract that resource and store it at the %temp% path at runtime.
43+
// This prevents the corerun from adding the the test assembly to the TPA list.
44+
// Once loaded it is not possible to unload the assembly, therefore it cannot be deleted.
45+
string path = Path.Combine(Path.GetTempPath(), assembly);
46+
using (FileStream output = File.OpenWrite(path))
47+
{
48+
asmStream.CopyTo(output);
49+
}
50+
51+
return LoadFromAssemblyPath(path);
52+
}
53+
else if (LoadBy == LoadBy.Stream)
54+
{
55+
return LoadFromStream(asmStream);
56+
}
57+
58+
return null;
59+
}
60+
}
61+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<OutputType>Library</OutputType>
8+
<AppDesignerFolder>Properties</AppDesignerFolder>
9+
<RootNamespace>System.Runtime.Loader.Test.Assembly</RootNamespace>
10+
<AssemblyName>System.Runtime.Loader.Test.Assembly</AssemblyName>
11+
<ProjectGuid>{396D6EBF-60BD-4DAF-8783-FB403E070A56}</ProjectGuid>
12+
</PropertyGroup>
13+
<ItemGroup>
14+
<Compile Include="TestClass.cs" />
15+
</ItemGroup>
16+
<ItemGroup>
17+
<None Include="project.json" />
18+
</ItemGroup>
19+
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
20+
</Project>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+

2+
3+
namespace System.Runtime.Loader.Tests
4+
{
5+
public class TestClass
6+
{
7+
}
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"dependencies": {
3+
"System.Runtime": "4.0.20-beta-*",
4+
"System.Reflection": "4.0.10-beta-*",
5+
"System.Runtime.Extensions": "4.0.10-beta-*"
6+
},
7+
"frameworks": {
8+
"dnxcore50": {}
9+
}
10+
}

0 commit comments

Comments
 (0)