| File: TestMatrix.cs | Web Access |
| Project: src\aspnetcore\src\Hosting\Server.IntegrationTesting\src\Microsoft.AspNetCore.Server.IntegrationTesting.csproj (Microsoft.AspNetCore.Server.IntegrationTesting) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Runtime.InteropServices; namespace Microsoft.AspNetCore.Server.IntegrationTesting; public class TestMatrix : IEnumerable<object[]> { public IList<ServerType> Servers { get; set; } = new List<ServerType>(); public IList<string> Tfms { get; set; } = new List<string>(); public IList<ApplicationType> ApplicationTypes { get; set; } = new List<ApplicationType>(); public IList<RuntimeArchitecture> Architectures { get; set; } = new List<RuntimeArchitecture>(); // ANCM specific... public IList<HostingModel> HostingModels { get; set; } = new List<HostingModel>(); private IList<Tuple<Func<TestVariant, bool>, string>> Skips { get; } = new List<Tuple<Func<TestVariant, bool>, string>>(); public static TestMatrix ForServers(params ServerType[] types) { return new TestMatrix() { Servers = types }; } public TestMatrix WithTfms(params string[] tfms) { Tfms = tfms; return this; } public TestMatrix WithApplicationTypes(params ApplicationType[] types) { ApplicationTypes = types; return this; } public TestMatrix WithAllApplicationTypes() { ApplicationTypes.Add(ApplicationType.Portable); ApplicationTypes.Add(ApplicationType.Standalone); return this; } public TestMatrix WithArchitectures(params RuntimeArchitecture[] archs) { Architectures = archs; return this; } /// <summary> /// With all architectures that are compatible with the currently running architecture /// </summary> /// <returns></returns> public TestMatrix WithAllArchitectures() { Architectures.Add(RuntimeArchitectures.Current); if (RuntimeInformation.OSArchitecture == Architecture.X64) { Architectures.Add(RuntimeArchitecture.x86); } return this; } public TestMatrix WithHostingModels(params HostingModel[] models) { HostingModels = models; return this; } public TestMatrix WithAllHostingModels() { HostingModels.Add(HostingModel.OutOfProcess); HostingModels.Add(HostingModel.InProcess); return this; } /// <summary> /// V2 + InProc /// </summary> /// <returns></returns> public TestMatrix WithAncmV2InProcess() => WithHostingModels(HostingModel.InProcess); public TestMatrix Skip(string message, Func<TestVariant, bool> check) { Skips.Add(new Tuple<Func<TestVariant, bool>, string>(check, message)); return this; } private IEnumerable<TestVariant> Build() { if (!Servers.Any()) { throw new ArgumentException("No servers were specified."); } // TFMs. if (!Tfms.Any()) { throw new ArgumentException("No TFMs were specified."); } ResolveDefaultArchitecture(); if (!ApplicationTypes.Any()) { ApplicationTypes.Add(ApplicationType.Portable); } if (!HostingModels.Any()) { HostingModels.Add(HostingModel.OutOfProcess); } var variants = new List<TestVariant>(); VaryByServer(variants); CheckForSkips(variants); return variants; } private void ResolveDefaultArchitecture() { if (!Architectures.Any()) { Architectures.Add(RuntimeArchitectures.Current); } } private void VaryByServer(List<TestVariant> variants) { foreach (var server in Servers) { var skip = SkipIfServerIsNotSupportedOnThisOS(server); VaryByTfm(variants, server, skip); } } private static string SkipIfServerIsNotSupportedOnThisOS(ServerType server) { var skip = false; switch (server) { case ServerType.IIS: case ServerType.IISExpress: case ServerType.HttpSys: skip = !OperatingSystem.IsWindows(); break; case ServerType.Kestrel: break; case ServerType.Nginx: // Technically it's possible but we don't test it. skip = OperatingSystem.IsWindows(); break; default: throw new ArgumentException(server.ToString()); } return skip ? "This server is not supported on this operating system." : null; } private void VaryByTfm(List<TestVariant> variants, ServerType server, string skip) { foreach (var tfm in Tfms) { if (!CheckTfmIsSupportedForServer(tfm, server)) { // Don't generate net462 variations for nginx server. continue; } var skipTfm = skip ?? SkipIfTfmIsNotSupportedOnThisOS(tfm); VaryByApplicationType(variants, server, tfm, skipTfm); } } private static bool CheckTfmIsSupportedForServer(string tfm, ServerType server) { // Not a combination we test return !(Tfm.Matches(Tfm.Net462, tfm) && ServerType.Nginx == server); } private static string SkipIfTfmIsNotSupportedOnThisOS(string tfm) { if (Tfm.Matches(Tfm.Net462, tfm) && !OperatingSystem.IsWindows()) { return "This TFM is not supported on this operating system."; } return null; } private void VaryByApplicationType(List<TestVariant> variants, ServerType server, string tfm, string skip) { foreach (var t in ApplicationTypes) { var type = t; if (Tfm.Matches(Tfm.Net462, tfm) && type == ApplicationType.Portable) { if (ApplicationTypes.Count == 1) { // Override the default type = ApplicationType.Standalone; } else { continue; } } VaryByArchitecture(variants, server, tfm, skip, type); } } private void VaryByArchitecture(List<TestVariant> variants, ServerType server, string tfm, string skip, ApplicationType type) { foreach (var arch in Architectures) { if (!IsArchitectureSupportedOnServer(arch, server)) { continue; } var archSkip = skip ?? SkipIfArchitectureNotSupportedOnCurrentSystem(arch); if (server == ServerType.IISExpress || server == ServerType.IIS) { VaryByAncmHostingModel(variants, server, tfm, type, arch, archSkip); } else { variants.Add(new TestVariant() { Server = server, Tfm = tfm, ApplicationType = type, Architecture = arch, Skip = archSkip, }); } } } private static string SkipIfArchitectureNotSupportedOnCurrentSystem(RuntimeArchitecture arch) { if (arch == RuntimeArchitecture.x64) { // Can't run x64 on a x86 OS. return (RuntimeInformation.OSArchitecture == Architecture.Arm || RuntimeInformation.OSArchitecture == Architecture.X86) ? $"Cannot run {arch} on your current system." : null; } // No x86 runtimes available on MacOS or Linux. return OperatingSystem.IsWindows() ? null : $"No {arch} available for non-Windows systems."; } private static bool IsArchitectureSupportedOnServer(RuntimeArchitecture arch, ServerType server) { // No x86 Mac/Linux runtime, don't generate a test variation that will always be skipped. return !(arch == RuntimeArchitecture.x86 && ServerType.Nginx == server); } private void VaryByAncmHostingModel(IList<TestVariant> variants, ServerType server, string tfm, ApplicationType type, RuntimeArchitecture arch, string skip) { foreach (var hostingModel in HostingModels) { var skipAncm = skip; if (hostingModel == HostingModel.InProcess) { // Not supported if (Tfm.Matches(Tfm.Net462, tfm) || Tfm.Matches(Tfm.NetCoreApp20, tfm)) { continue; } if (!IISExpressAncmSchema.SupportsInProcessHosting) { skipAncm = skipAncm ?? IISExpressAncmSchema.SkipReason; } } variants.Add(new TestVariant() { Server = server, Tfm = tfm, ApplicationType = type, Architecture = arch, HostingModel = hostingModel, Skip = skipAncm, }); } } private void CheckForSkips(List<TestVariant> variants) { foreach (var variant in variants) { foreach (var skipPair in Skips) { if (skipPair.Item1(variant)) { variant.Skip = skipPair.Item2; break; } } } } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<object[]>)this).GetEnumerator(); } // This is what Xunit MemberData expects public IEnumerator<object[]> GetEnumerator() { foreach (var v in Build()) { yield return new[] { v }; } } }