Add module load location check (#94)
This commit is contained in:
parent
c9c21d2ce9
commit
5e3a7922fe
|
|
@ -9,12 +9,12 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Templates\*.*" CopyToOutputDirectory="PreserveNewest" />
|
<None Include="Templates\*.*" CopyToOutputDirectory="PreserveNewest" />
|
||||||
<ContentWithTargetPath Include="NuGet.config.template" CopyToOutputDirectory="PreserveNewest" TargetPath="NuGet.config"/>
|
<ContentWithTargetPath Include="NuGet.config.template" CopyToOutputDirectory="PreserveNewest" TargetPath="NuGet.config" />
|
||||||
<ContentWithTargetPath Include="global.json.template" CopyToOutputDirectory="PreserveNewest" TargetPath="global.json"/>
|
<ContentWithTargetPath Include="global.json.template" CopyToOutputDirectory="PreserveNewest" TargetPath="global.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(AspNetIntegrationTestingVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(AspNetCoreVersion)" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Process.Sources" Version="$(AspNetCoreVersion)" />
|
<PackageReference Include="Microsoft.Extensions.Process.Sources" Version="$(AspNetCoreVersion)" />
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
|
{
|
||||||
|
public class PathUtilities
|
||||||
|
{
|
||||||
|
public static string[] GetStoreModules(string dotnetPath)
|
||||||
|
{
|
||||||
|
var dotnetHome = Path.GetDirectoryName(dotnetPath);
|
||||||
|
return new DirectoryInfo(Path.Combine(dotnetHome, "store", "x64", "netcoreapp2.0"))
|
||||||
|
.GetDirectories()
|
||||||
|
.Select(d => d.Name)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string[] GetSharedRuntimeAssemblies(string dotnetPath)
|
||||||
|
{
|
||||||
|
var dotnetHome = Path.GetDirectoryName(dotnetPath);
|
||||||
|
return new DirectoryInfo(Path.Combine(dotnetHome, "shared", "Microsoft.NETCore.App"))
|
||||||
|
.GetDirectories()
|
||||||
|
.Single()
|
||||||
|
.GetFiles("*.dll")
|
||||||
|
.Select(f => f.Name)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetBundledAspNetCoreVersion(string dotnetPath)
|
||||||
|
{
|
||||||
|
var dotnetHome = Path.GetDirectoryName(dotnetPath);
|
||||||
|
return new DirectoryInfo(Path.Combine(dotnetHome, "store", "x64", "netcoreapp2.0", "microsoft.aspnetcore"))
|
||||||
|
.GetDirectories()
|
||||||
|
.Single()
|
||||||
|
.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,8 +7,10 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Xunit.Abstractions;
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
|
@ -17,6 +19,10 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
[Collection("Azure")]
|
[Collection("Azure")]
|
||||||
public class TemplateFunctionalTests
|
public class TemplateFunctionalTests
|
||||||
{
|
{
|
||||||
|
private const string RuntimeInformationMiddlewareType = "Microsoft.AspNetCore.AzureAppServices.FunctionalTests.RuntimeInformationMiddleware";
|
||||||
|
|
||||||
|
private const string RuntimeInformationMiddlewareFile = "Templates\\RuntimeInformationMiddleware.cs";
|
||||||
|
|
||||||
readonly AzureFixture _fixture;
|
readonly AzureFixture _fixture;
|
||||||
|
|
||||||
private readonly ITestOutputHelper _outputHelper;
|
private readonly ITestOutputHelper _outputHelper;
|
||||||
|
|
@ -43,6 +49,8 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
|
|
||||||
await dotnet.ExecuteAndAssertAsync("new " + template);
|
await dotnet.ExecuteAndAssertAsync("new " + template);
|
||||||
|
|
||||||
|
InjectMiddlware(testDirectory, RuntimeInformationMiddlewareType, RuntimeInformationMiddlewareFile);
|
||||||
|
|
||||||
await site.BuildPublishProfileAsync(testDirectory.FullName);
|
await site.BuildPublishProfileAsync(testDirectory.FullName);
|
||||||
|
|
||||||
await dotnet.ExecuteAndAssertAsync("publish /p:PublishProfile=Profile");
|
await dotnet.ExecuteAndAssertAsync("publish /p:PublishProfile=Profile");
|
||||||
|
|
@ -52,6 +60,12 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
var getResult = await httpClient.GetAsync("/");
|
var getResult = await httpClient.GetAsync("/");
|
||||||
getResult.EnsureSuccessStatusCode();
|
getResult.EnsureSuccessStatusCode();
|
||||||
Assert.Contains(expected, await getResult.Content.ReadAsStringAsync());
|
Assert.Contains(expected, await getResult.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
|
getResult = await httpClient.GetAsync("/runtimeInfo");
|
||||||
|
getResult.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var runtimeInfo = JsonConvert.DeserializeObject<RuntimeInfo>(await getResult.Content.ReadAsStringAsync());
|
||||||
|
ValidateRuntimeInfo(runtimeInfo, dotnet.Command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -80,6 +94,8 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
|
|
||||||
await dotnet.ExecuteAndAssertAsync("new " + template);
|
await dotnet.ExecuteAndAssertAsync("new " + template);
|
||||||
|
|
||||||
|
InjectMiddlware(testDirectory, RuntimeInformationMiddlewareType, RuntimeInformationMiddlewareFile);
|
||||||
|
|
||||||
FixAspNetCoreVersion(testDirectory, dotnet.Command);
|
FixAspNetCoreVersion(testDirectory, dotnet.Command);
|
||||||
|
|
||||||
await dotnet.ExecuteAndAssertAsync("restore");
|
await dotnet.ExecuteAndAssertAsync("restore");
|
||||||
|
|
@ -93,23 +109,58 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
var getResult = await httpClient.GetAsync("/");
|
var getResult = await httpClient.GetAsync("/");
|
||||||
getResult.EnsureSuccessStatusCode();
|
getResult.EnsureSuccessStatusCode();
|
||||||
Assert.Contains(expected, await getResult.Content.ReadAsStringAsync());
|
Assert.Contains(expected, await getResult.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
|
getResult = await httpClient.GetAsync("/runtimeInfo");
|
||||||
|
getResult.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var runtimeInfo = JsonConvert.DeserializeObject<RuntimeInfo>(await getResult.Content.ReadAsStringAsync());
|
||||||
|
ValidateRuntimeInfo(runtimeInfo, dotnet.Command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ValidateRuntimeInfo(RuntimeInfo runtimeInfo, string dotnetPath)
|
||||||
|
{
|
||||||
|
var storeModules = PathUtilities.GetStoreModules(dotnetPath);
|
||||||
|
|
||||||
|
var runtimeModules = PathUtilities.GetSharedRuntimeAssemblies(dotnetPath);
|
||||||
|
|
||||||
|
foreach (var runtimeInfoModule in runtimeInfo.Modules)
|
||||||
|
{
|
||||||
|
if (storeModules.Any(f => runtimeInfoModule.ModuleName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
{
|
||||||
|
Assert.Contains("store\\x86\\netcoreapp2.0\\", runtimeInfoModule.FileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Native modules would prefer to be loaded from windows folder, skip them
|
||||||
|
if (runtimeModules.Any(f => runtimeInfoModule.ModuleName.StartsWith(f, StringComparison.InvariantCultureIgnoreCase)) &&
|
||||||
|
runtimeInfoModule.FileName.IndexOf("windows\\system32", StringComparison.InvariantCultureIgnoreCase) == -1)
|
||||||
|
{
|
||||||
|
Assert.Contains("shared\\Microsoft.NETCore.App\\", runtimeInfoModule.FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InjectMiddlware(DirectoryInfo projectRoot, string typeName, string fileName)
|
||||||
|
{
|
||||||
|
// Copy implementation file to project directory
|
||||||
|
var implementationFile = Path.Combine(Directory.GetCurrentDirectory(), fileName);
|
||||||
|
var destinationImplementationFile = Path.Combine(projectRoot.FullName, Path.GetFileName(fileName));
|
||||||
|
File.Copy(implementationFile, destinationImplementationFile, true);
|
||||||
|
|
||||||
|
// Register middleware in Startup.cs/Configure
|
||||||
|
var startupFile = Path.Combine(projectRoot.FullName, "Startup.cs");
|
||||||
|
var startupText = File.ReadAllText(startupFile);
|
||||||
|
startupText = Regex.Replace(startupText, "public void Configure\\([^{]+{", match => match.Value + $" app.UseMiddleware<{typeName}>();");
|
||||||
|
File.WriteAllText(startupFile, startupText);
|
||||||
|
}
|
||||||
|
|
||||||
private static void FixAspNetCoreVersion(DirectoryInfo testDirectory, string dotnetPath)
|
private static void FixAspNetCoreVersion(DirectoryInfo testDirectory, string dotnetPath)
|
||||||
{
|
{
|
||||||
// TODO: Temporary workaround for broken templates in latest CLI
|
// TODO: Temporary workaround for broken templates in latest CLI
|
||||||
|
|
||||||
// Detect what version of aspnet core was shipped with this CLI installation
|
// Detect what version of aspnet core was shipped with this CLI installation
|
||||||
var aspnetCoreVersion =
|
var aspnetCoreVersion = PathUtilities.GetBundledAspNetCoreVersion(dotnetPath);
|
||||||
new DirectoryInfo(
|
|
||||||
Path.Combine(
|
|
||||||
Path.GetDirectoryName(dotnetPath),
|
|
||||||
"store", "x64", "netcoreapp2.0", "microsoft.aspnetcore"))
|
|
||||||
.GetDirectories()
|
|
||||||
.Single()
|
|
||||||
.Name;
|
|
||||||
|
|
||||||
var csproj = testDirectory.GetFiles("*.csproj").Single().FullName;
|
var csproj = testDirectory.GetFiles("*.csproj").Single().FullName;
|
||||||
var projectContents = XDocument.Load(csproj);
|
var projectContents = XDocument.Load(csproj);
|
||||||
|
|
@ -149,14 +200,14 @@ namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
|
|
||||||
private TestCommand DotNet(TestLogger logger, DirectoryInfo workingDirectory, string sufix)
|
private TestCommand DotNet(TestLogger logger, DirectoryInfo workingDirectory, string sufix)
|
||||||
{
|
{
|
||||||
return new TestCommand(GetDotnetPath(sufix))
|
return new TestCommand(GetDotNetPath(sufix))
|
||||||
{
|
{
|
||||||
Logger = logger,
|
Logger = logger,
|
||||||
WorkingDirectory = workingDirectory.FullName
|
WorkingDirectory = workingDirectory.FullName
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string GetDotnetPath(string sufix)
|
private static string GetDotNetPath(string sufix)
|
||||||
{
|
{
|
||||||
var current = new DirectoryInfo(Directory.GetCurrentDirectory());
|
var current = new DirectoryInfo(Directory.GetCurrentDirectory());
|
||||||
while (current != null)
|
while (current != null)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.AzureAppServices.FunctionalTests
|
||||||
|
{
|
||||||
|
public class ModuleInfo
|
||||||
|
{
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string ModuleName { get; set; }
|
||||||
|
public string Version { get; set; }
|
||||||
|
public string InformationalVersion { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RuntimeInfo
|
||||||
|
{
|
||||||
|
public IDictionary Environment { get; set; }
|
||||||
|
public IList<ModuleInfo> Modules { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
class RuntimeInformationMiddleware
|
||||||
|
{
|
||||||
|
private readonly RequestDelegate _next;
|
||||||
|
|
||||||
|
public RuntimeInformationMiddleware(RequestDelegate next)
|
||||||
|
{
|
||||||
|
_next = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Invoke(HttpContext context)
|
||||||
|
{
|
||||||
|
if (context.Request.Path == "/runtimeInfo")
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync(
|
||||||
|
JsonConvert.SerializeObject(
|
||||||
|
new RuntimeInfo
|
||||||
|
{
|
||||||
|
Environment = Environment.GetEnvironmentVariables(),
|
||||||
|
Modules = Process.GetCurrentProcess().Modules.OfType<ProcessModule>().Select(m =>
|
||||||
|
{
|
||||||
|
Assembly assembly = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
assembly = Assembly.Load(Path.GetFileNameWithoutExtension(m.ModuleName));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
return new ModuleInfo
|
||||||
|
{
|
||||||
|
FileName = m.FileName,
|
||||||
|
ModuleName = m.ModuleName,
|
||||||
|
Version = assembly?.GetName().Version.ToString(),
|
||||||
|
InformationalVersion = assembly?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion
|
||||||
|
};
|
||||||
|
}).ToList()
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Call the next delegate/middleware in the pipeline
|
||||||
|
await _next(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue