Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
<DeterministicSourcePaths Condition="'$(IsSampleProject)' == 'true' OR '$(IsTestAssetProject)' == 'true'">false</DeterministicSourcePaths>
<!-- Projects which reference Microsoft.AspNetCore.Mvc.Testing should import this targets file to ensure dependency .deps.json files are copied into test output. -->
<MvcTestingTargets>$(MSBuildThisFileDirectory)src\Mvc\Mvc.Testing\src\Microsoft.AspNetCore.Mvc.Testing.targets</MvcTestingTargets>
<_MvcTestingTasksAssembly>$(ArtifactsBinDir)\Microsoft.AspNetCore.Mvc.Testing.Tasks\$(Configuration)\netstandard2.0\Microsoft.AspNetCore.Mvc.Testing.Tasks.dll</_MvcTestingTasksAssembly>
<!-- IIS native projects can only be built on Windows for x86 and x64. -->
<BuildIisNativeProjects Condition=" '$(TargetOsName)' == 'win' AND ('$(TargetArchitecture)' == 'x86' OR '$(TargetArchitecture)' == 'x64') ">true</BuildIisNativeProjects>
<!-- This property is shared by several projects to layout the AspNetCore.App targeting pack for installers -->
Expand Down
1 change: 1 addition & 0 deletions eng/ProjectReferences.props
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.RazorPages" ProjectPath="$(RepoRoot)src\Mvc\Mvc.RazorPages\src\Microsoft.AspNetCore.Mvc.RazorPages.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.Razor" ProjectPath="$(RepoRoot)src\Mvc\Mvc.Razor\src\Microsoft.AspNetCore.Mvc.Razor.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.TagHelpers" ProjectPath="$(RepoRoot)src\Mvc\Mvc.TagHelpers\src\Microsoft.AspNetCore.Mvc.TagHelpers.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.Testing.Tasks" ProjectPath="$(RepoRoot)src\Mvc\Mvc.Testing.Tasks\src\Microsoft.AspNetCore.Mvc.Testing.Tasks.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.Testing" ProjectPath="$(RepoRoot)src\Mvc\Mvc.Testing\src\Microsoft.AspNetCore.Mvc.Testing.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc.ViewFeatures" ProjectPath="$(RepoRoot)src\Mvc\Mvc.ViewFeatures\src\Microsoft.AspNetCore.Mvc.ViewFeatures.csproj" />
<ProjectReferenceProvider Include="Microsoft.AspNetCore.Mvc" ProjectPath="$(RepoRoot)src\Mvc\Mvc\src\Microsoft.AspNetCore.Mvc.csproj" />
Expand Down
56 changes: 56 additions & 0 deletions src/Mvc/Mvc.Testing.Tasks/src/GenerateMvcTestManifestTask.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization.Json;
using System.Text;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

namespace Microsoft.AspNetCore.Mvc.Testing.Tasks
{
/// <summary>
/// Generate a JSON file mapping assemblies to content root paths.
/// </summary>
public class GenerateMvcTestManifestTask : Task
{
/// <summary>
/// The path to output the manifest file to.
/// </summary>
[Required]
public string ManifestPath { get; set; }

/// <summary>
/// A list of content root paths and assembly names to generate the
/// manifest from.
/// </summary>
[Required]
public ITaskItem[] Projects { get; set; }

/// <inheritdoc />
public override bool Execute()
{
using var fileStream = File.Create(ManifestPath);
var output = new Dictionary<string, string>();

foreach (var project in Projects)
{
var contentRoot = project.GetMetadata("ContentRoot");
var assemblyName = project.GetMetadata("Identity");
output[assemblyName] = contentRoot;
}

var serializer = new DataContractJsonSerializer(typeof(Dictionary<string, string>), new DataContractJsonSerializerSettings
{
UseSimpleDictionaryFormat = true
});
using var writer = JsonReaderWriterFactory.CreateJsonWriter(fileStream, Encoding.UTF8, ownsStream: false, indent: true);
serializer.WriteObject(writer, output);

return !Log.HasLoggedErrors;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Build tasks for functional tests.</Description>
<TargetFramework>netstandard2.0</TargetFramework>

<GenerateDocumentationFile>false</GenerateDocumentationFile>
<AddPublicApiAnalyzers>false</AddPublicApiAnalyzers>
<IsPackable>false</IsPackable>
<IsShipping>false</IsShipping>
</PropertyGroup>

<ItemGroup>
<Reference Include="Microsoft.Build.Framework" />
<Reference Include="Microsoft.Build.Utilities.Core" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
<Reference Include="Microsoft.Extensions.HostFactoryResolver.Sources" />
</ItemGroup>

<ItemGroup>
<Reference
Include="Microsoft.AspNetCore.Mvc.Testing.Tasks"
Targets="Build"
ReferenceOutputAssembly="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework;TargetFrameworks;RuntimeIdentifier;PublishDir" />
</ItemGroup>

<ItemGroup>
<Content Include="Microsoft.AspNetCore.Mvc.Testing.targets" Pack="true" PackagePath="build/$(TargetFramework)/" />
</ItemGroup>
Expand Down
36 changes: 18 additions & 18 deletions src/Mvc/Mvc.Testing/src/Microsoft.AspNetCore.Mvc.Testing.targets
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

<PropertyGroup>
<_MvcTestingTasksAssembly Condition="$(_MvcTestingTasksAssembly) == ''">$(MSBuildThisFileDirectory)..\tasks\Microsoft.AspNetCore.Mvc.Testing.dll</_MvcTestingTasksAssembly>
</PropertyGroup>
<UsingTask TaskName="GenerateMvcTestManifestTask" AssemblyFile="$(_MvcTestingTasksAssembly)"/>

<!--
Work around https://github.com/NuGet/Home/issues/4412. MVC uses DependencyContext.Load() which looks next to a .dll
for a .deps.json. Information isn't available elsewhere. Need the .deps.json file for all web site applications.
Expand All @@ -23,30 +28,25 @@
</ItemGroup>
</Target>

<Target Name="_AddContentRootForProjectReferences" BeforeTargets="GetAssemblyAttributes" DependsOnTargets="_ResolveMvcTestProjectReferences">
<Target Name="_AddContentRootForProjectReferences" BeforeTargets="PrepareResources" DependsOnTargets="_ResolveMvcTestProjectReferences">
<ItemGroup>
<WebApplicationFactoryContentRootAttribute
Condition="'%(_ContentRootProjectReferences.Identity)' != ''"
Include="%(_ContentRootProjectReferences.Identity)"
AssemblyName="%(_ContentRootProjectReferences.FusionName)"
ContentRootPath="$([System.IO.Path]::GetDirectoryName(%(_ContentRootProjectReferences.MSBuildSourceProjectFile)))"
ContentRootTest="$([System.IO.Path]::GetFileName(%(_ContentRootProjectReferences.MSBuildSourceProjectFile)))"
Priority="0" />
<_ManifestProjects Include="%(_ContentRootProjectReferences.FusionName)">
<ContentRoot>$([System.IO.Path]::GetDirectoryName(%(_ContentRootProjectReferences.MSBuildSourceProjectFile)))</ContentRoot>
</_ManifestProjects>
</ItemGroup>

<GenerateMvcTestManifestTask ManifestPath="$(IntermediateOutputPath)MvcTestingAppManifest.json" Projects="@(_ManifestProjects)"/>

<ItemGroup>
<AssemblyAttribute
Condition=" '%(WebApplicationFactoryContentRootAttribute.Identity)' != '' "
Include="Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactoryContentRootAttribute">
<_Parameter1>%(WebApplicationFactoryContentRootAttribute.AssemblyName)</_Parameter1>
<_Parameter2>%(WebApplicationFactoryContentRootAttribute.ContentRootPath)</_Parameter2>
<_Parameter3>%(WebApplicationFactoryContentRootAttribute.ContentRootTest)</_Parameter3>
<_Parameter4>%(WebApplicationFactoryContentRootAttribute.Priority)</_Parameter4>
</AssemblyAttribute>
<ContentWithTargetPath Include="$(IntermediateOutputPath)MvcTestingAppManifest.json"
TargetPath="MvcTestingAppManifest.json"
CopyToOutputDirectory="PreserveNewest"
CopyToPublishDirectory="Never"/>
<FileWrites Include="$(IntermediateOutputPath)MvcTestingAppManifest.json" />
</ItemGroup>
</Target>

<Target Name="CopyAditionalFiles" AfterTargets="Build;_ResolveMvcTestProjectReferences" Condition="'$(TargetFramework)'!=''">
<Target Name="_MvcCopyDependencyFiles" AfterTargets="Build;_ResolveMvcTestProjectReferences" Condition="'$(TargetFramework)'!=''">
<ItemGroup>
<DepsFilePaths
Condition="'%(_ContentRootProjectReferences.Identity)' != ''"
Expand All @@ -56,4 +56,4 @@
<Copy SourceFiles="%(DepsFilePaths.FullPath)" DestinationFolder="$(OutDir)" Condition="Exists('%(DepsFilePaths.FullPath)')" />
</Target>

</Project>
</Project>
42 changes: 33 additions & 9 deletions src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Text.Json;
using System.Runtime.Serialization.Json;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.TestHost;
Expand Down Expand Up @@ -93,7 +95,7 @@ public virtual IServiceProvider Services

/// <summary>
/// Gets the <see cref="IReadOnlyList{WebApplicationFactory}"/> of factories created from this factory
/// by further customizing the <see cref="IWebHostBuilder"/> when calling
/// by further customizing the <see cref="IWebHostBuilder"/> when calling
/// <see cref="WebApplicationFactory{TEntryPoint}.WithWebHostBuilder(Action{IWebHostBuilder})"/>.
/// </summary>
public IReadOnlyList<WebApplicationFactory<TEntryPoint>> Factories => _derivedFactories.AsReadOnly();
Expand Down Expand Up @@ -171,6 +173,35 @@ private void SetContentRoot(IWebHostBuilder builder)
return;
}

var fromFile = File.Exists("MvcTestingAppManifest.json");
var contentRoot = fromFile ? GetContentRootFromFile("MvcTestingAppManifest.json") : GetContentRootFromAssembly();

if (contentRoot != null)
{
builder.UseContentRoot(contentRoot);
}
else
{
builder.UseSolutionRelativeContentRoot(typeof(TEntryPoint).Assembly.GetName().Name);
}
}

private string GetContentRootFromFile(string file)
{
var data = JsonSerializer.Deserialize<IDictionary<string, string>>(File.ReadAllBytes(file));
var key = typeof(TEntryPoint).Assembly.GetName().FullName;
try
{
return data[key];
} catch
{
throw new KeyNotFoundException($"Could not find content root for project '{key}' in test manifest file '{file}'");
}

}

private string GetContentRootFromAssembly()
{
var metadataAttributes = GetContentRootMetadataAttributes(
typeof(TEntryPoint).Assembly.FullName,
typeof(TEntryPoint).Assembly.GetName().Name);
Expand All @@ -194,14 +225,7 @@ private void SetContentRoot(IWebHostBuilder builder)
}
}

if (contentRoot != null)
{
builder.UseContentRoot(contentRoot);
}
else
{
builder.UseSolutionRelativeContentRoot(typeof(TEntryPoint).Assembly.GetName().Name);
}
return contentRoot;
}

private static bool SetContentRootFromSetting(IWebHostBuilder builder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public void TestingInfrastructure_WebHost_WithWebHostBuilderRespectsCustomizatio
Assert.Equal(new[] { "ConfigureWebHost", "Customization", "FurtherCustomization" }, factory.ConfigureWebHostCalled.ToArray());
Assert.True(factory.CreateServerCalled);
Assert.True(factory.CreateWebHostBuilderCalled);
Assert.True(factory.GetTestAssembliesCalled);
// GetTestAssemblies is not called when reading content roots from MvcAppManifest
Assert.False(factory.GetTestAssembliesCalled);
Assert.True(factory.CreateHostBuilderCalled);
Assert.False(factory.CreateHostCalled);
}
Expand All @@ -46,7 +47,7 @@ public void TestingInfrastructure_GenericHost_WithWithHostBuilderRespectsCustomi

// Assert
Assert.Equal(new[] { "ConfigureWebHost", "Customization", "FurtherCustomization" }, factory.ConfigureWebHostCalled.ToArray());
Assert.True(factory.GetTestAssembliesCalled);
Assert.False(factory.GetTestAssembliesCalled);
Assert.True(factory.CreateHostBuilderCalled);
Assert.True(factory.CreateHostCalled);
Assert.False(factory.CreateServerCalled);
Expand Down