From 6a1b15596723633b77b1bfb156e58880624bf014 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 25 Nov 2019 21:23:57 -0800 Subject: [PATCH] Adding MaximumOSVersionAttribute (dotnet/extensions#2715) \n\nCommit migrated from https://github.com/dotnet/extensions/commit/9f29643656b25b53221de8d11c4b98c7b118f3e1 --- .../ref/Microsoft.AspNetCore.Testing.net46.cs | 7 ++ ...osoft.AspNetCore.Testing.netstandard2.0.cs | 7 ++ .../src/xunit/MaximumOSVersionAttribute.cs | 79 +++++++++++++++++++ .../test/MaximumOSVersionAttributeTest.cs | 77 ++++++++++++++++++ src/Testing/test/MaximumOSVersionTest.cs | 75 ++++++++++++++++++ 5 files changed, 245 insertions(+) create mode 100644 src/Testing/src/xunit/MaximumOSVersionAttribute.cs create mode 100644 src/Testing/test/MaximumOSVersionAttributeTest.cs create mode 100644 src/Testing/test/MaximumOSVersionTest.cs diff --git a/src/Testing/ref/Microsoft.AspNetCore.Testing.net46.cs b/src/Testing/ref/Microsoft.AspNetCore.Testing.net46.cs index 5fa7e9422e..a7191eb156 100644 --- a/src/Testing/ref/Microsoft.AspNetCore.Testing.net46.cs +++ b/src/Testing/ref/Microsoft.AspNetCore.Testing.net46.cs @@ -170,6 +170,13 @@ namespace Microsoft.AspNetCore.Testing System.Threading.Tasks.Task OnTestStartAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Threading.CancellationToken cancellationToken); } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)] + public partial class MaximumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition + { + public MaximumOSVersionAttribute(Microsoft.AspNetCore.Testing.OperatingSystems operatingSystem, string maxVersion) { } + public bool IsMet { get { throw null; } } + public string SkipReason { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + } + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)] public partial class MinimumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition { public MinimumOSVersionAttribute(Microsoft.AspNetCore.Testing.OperatingSystems operatingSystem, string minVersion) { } diff --git a/src/Testing/ref/Microsoft.AspNetCore.Testing.netstandard2.0.cs b/src/Testing/ref/Microsoft.AspNetCore.Testing.netstandard2.0.cs index 5fa7e9422e..a7191eb156 100644 --- a/src/Testing/ref/Microsoft.AspNetCore.Testing.netstandard2.0.cs +++ b/src/Testing/ref/Microsoft.AspNetCore.Testing.netstandard2.0.cs @@ -170,6 +170,13 @@ namespace Microsoft.AspNetCore.Testing System.Threading.Tasks.Task OnTestStartAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Threading.CancellationToken cancellationToken); } [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)] + public partial class MaximumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition + { + public MaximumOSVersionAttribute(Microsoft.AspNetCore.Testing.OperatingSystems operatingSystem, string maxVersion) { } + public bool IsMet { get { throw null; } } + public string SkipReason { [System.Runtime.CompilerServices.CompilerGeneratedAttribute] get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute] set { } } + } + [System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)] public partial class MinimumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition { public MinimumOSVersionAttribute(Microsoft.AspNetCore.Testing.OperatingSystems operatingSystem, string minVersion) { } diff --git a/src/Testing/src/xunit/MaximumOSVersionAttribute.cs b/src/Testing/src/xunit/MaximumOSVersionAttribute.cs new file mode 100644 index 0000000000..82d59910be --- /dev/null +++ b/src/Testing/src/xunit/MaximumOSVersionAttribute.cs @@ -0,0 +1,79 @@ +// 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.Runtime.InteropServices; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Skips a test if the OS is the given type (Windows) and the OS version is greater than specified. + /// E.g. Specifying Window 8 skips on Win 10, but not on Linux. Combine with OSSkipConditionAttribute as needed. + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)] + public class MaximumOSVersionAttribute : Attribute, ITestCondition + { + private readonly OperatingSystems _targetOS; + private readonly Version _maxVersion; + private readonly OperatingSystems _currentOS; + private readonly Version _currentVersion; + private readonly bool _skip; + + public MaximumOSVersionAttribute(OperatingSystems operatingSystem, string maxVersion) : + this(operatingSystem, Version.Parse(maxVersion), GetCurrentOS(), GetCurrentOSVersion()) + { + } + + // to enable unit testing + internal MaximumOSVersionAttribute(OperatingSystems targetOS, Version maxVersion, OperatingSystems currentOS, Version currentVersion) + { + if (targetOS != OperatingSystems.Windows) + { + throw new NotImplementedException("Max version support is only implemented for Windows."); + } + _targetOS = targetOS; + _maxVersion = maxVersion; + _currentOS = currentOS; + _currentVersion = currentVersion; + + // Do not skip other OS's, Use OSSkipConditionAttribute or a separate MaximumOsVersionAttribute for that. + _skip = _targetOS == _currentOS && _maxVersion < _currentVersion; + SkipReason = $"This test requires {_targetOS} {_maxVersion} or earlier."; + } + + // Since a test would be executed only if 'IsMet' is true, return false if we want to skip + public bool IsMet => !_skip; + + public string SkipReason { get; set; } + + private static OperatingSystems GetCurrentOS() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return OperatingSystems.Windows; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return OperatingSystems.Linux; + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return OperatingSystems.MacOSX; + } + throw new PlatformNotSupportedException(); + } + + static private Version GetCurrentOSVersion() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Environment.OSVersion.Version; + } + else + { + // Not implemented, but this will still be called before the OS check happens so don't throw. + return new Version(0, 0); + } + } + } +} diff --git a/src/Testing/test/MaximumOSVersionAttributeTest.cs b/src/Testing/test/MaximumOSVersionAttributeTest.cs new file mode 100644 index 0000000000..ca2faa76e5 --- /dev/null +++ b/src/Testing/test/MaximumOSVersionAttributeTest.cs @@ -0,0 +1,77 @@ +// 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 Xunit; + +namespace Microsoft.AspNetCore.Testing +{ + public class MaximumOSVersionAttributeTest + { + [Fact] + public void Linux_ThrowsNotImplemeneted() + { + Assert.Throws(() => new MaximumOSVersionAttribute(OperatingSystems.Linux, "2.5")); + } + + [Fact] + public void Mac_ThrowsNotImplemeneted() + { + Assert.Throws(() => new MaximumOSVersionAttribute(OperatingSystems.MacOSX, "2.5")); + } + + [Fact] + public void WindowsOrLinux_ThrowsNotImplemeneted() + { + Assert.Throws(() => new MaximumOSVersionAttribute(OperatingSystems.Linux | OperatingSystems.Windows, "2.5")); + } + + [Fact] + public void DoesNotSkip_EarlierVersions() + { + var osSkipAttribute = new MaximumOSVersionAttribute( + OperatingSystems.Windows, + new Version("2.5"), + OperatingSystems.Windows, + new Version("2.0")); + + Assert.True(osSkipAttribute.IsMet); + } + + [Fact] + public void DoesNotSkip_SameVersion() + { + var osSkipAttribute = new MaximumOSVersionAttribute( + OperatingSystems.Windows, + new Version("2.5"), + OperatingSystems.Windows, + new Version("2.5")); + + Assert.True(osSkipAttribute.IsMet); + } + + [Fact] + public void Skip_LaterVersion() + { + var osSkipAttribute = new MaximumOSVersionAttribute( + OperatingSystems.Windows, + new Version("2.5"), + OperatingSystems.Windows, + new Version("3.0")); + + Assert.False(osSkipAttribute.IsMet); + } + + [Fact] + public void DoesNotSkip_WhenOnlyVersionsMatch() + { + var osSkipAttribute = new MaximumOSVersionAttribute( + OperatingSystems.Windows, + new Version("2.5"), + OperatingSystems.Linux, + new Version("2.5")); + + Assert.True(osSkipAttribute.IsMet); + } + } +} diff --git a/src/Testing/test/MaximumOSVersionTest.cs b/src/Testing/test/MaximumOSVersionTest.cs new file mode 100644 index 0000000000..e9a0b08d99 --- /dev/null +++ b/src/Testing/test/MaximumOSVersionTest.cs @@ -0,0 +1,75 @@ +// 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.Runtime.InteropServices; +using Microsoft.Win32; +using Xunit; + +namespace Microsoft.AspNetCore.Testing +{ + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + public class MaximumOSVersionTest + { + [ConditionalFact] + [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win7)] + public void RunTest_Win7DoesRunOnWin7() + { + Assert.True( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + Environment.OSVersion.Version.ToString().StartsWith("6.1"), + "Test should only be running on Win7 or Win2008R2."); + } + + [ConditionalTheory] + [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win7)] + [InlineData(1)] + public void RunTheory_Win7DoesRunOnWin7(int arg) + { + Assert.True( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + Environment.OSVersion.Version.ToString().StartsWith("6.1"), + "Test should only be running on Win7 or Win2008R2."); + } + + [ConditionalFact] + [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_RS4)] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + public void RunTest_Win10_RS4() + { + Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + var versionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + Assert.NotNull(versionKey); + var currentVersion = (string)versionKey.GetValue("CurrentBuildNumber"); + Assert.NotNull(currentVersion); + Assert.True(17134 >= int.Parse(currentVersion)); + } + + [ConditionalFact] + [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_19H2)] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + public void RunTest_Win10_19H2() + { + Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)); + var versionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion"); + Assert.NotNull(versionKey); + var currentVersion = (string)versionKey.GetValue("CurrentBuildNumber"); + Assert.NotNull(currentVersion); + Assert.True(18363 >= int.Parse(currentVersion)); + } + } + + [MaximumOSVersion(OperatingSystems.Windows, WindowsVersions.Win7)] + [OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)] + public class OSMaxVersionClassTest + { + [ConditionalFact] + public void TestSkipClass_Win7DoesRunOnWin7() + { + Assert.True( + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && + Environment.OSVersion.Version.ToString().StartsWith("6.1"), + "Test should only be running on Win7 or Win2008R2."); + } + } +}