diff --git a/sdk/core/Azure.Core.TestFramework/src/ClientTestFixtureAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/ClientTestFixtureAttribute.cs index e4056dcca563..b834dc6a4f5f 100644 --- a/sdk/core/Azure.Core.TestFramework/src/ClientTestFixtureAttribute.cs +++ b/sdk/core/Azure.Core.TestFramework/src/ClientTestFixtureAttribute.cs @@ -25,7 +25,18 @@ public class ClientTestFixtureAttribute : NUnitAttribute, IFixtureBuilder2, IPre private readonly object[] _additionalParameters; private readonly object[] _serviceVersions; - private readonly int? _maxServiceVersion; + private int? _actualPlaybackServiceVersion; + private int[] _actualLiveServiceVersions; + + /// + /// Specifies which service version is run during recording/playback runs. + /// + public object RecordingServiceVersion { get; set; } + + /// + /// Specifies which service version is run during live runs. + /// + public object[] LiveServiceVersions { get; set; } /// /// Initializes an instance of the accepting additional fixture parameters. @@ -43,8 +54,6 @@ public ClientTestFixtureAttribute(object[] serviceVersions, object[] additionalP { _additionalParameters = additionalParameters ?? new object[] { }; _serviceVersions = serviceVersions ?? new object[] { }; - - _maxServiceVersion = _serviceVersions.Any() ? _serviceVersions.Max(s => Convert.ToInt32(s)) : (int?)null; } public IEnumerable BuildFrom(ITypeInfo typeInfo) @@ -54,6 +63,23 @@ public IEnumerable BuildFrom(ITypeInfo typeInfo) public IEnumerable BuildFrom(ITypeInfo typeInfo, IPreFilter filter) { + var latestVersion = _serviceVersions.Any() ? _serviceVersions.Max(Convert.ToInt32) : (int?)null; + _actualPlaybackServiceVersion = RecordingServiceVersion != null ? Convert.ToInt32(RecordingServiceVersion) : latestVersion; + + var liveVersions = LiveServiceVersions ?? _serviceVersions; + + if (liveVersions.Any()) + { + if (OnlyTestLatestServiceVersionLazy.Value) + { + _actualLiveServiceVersions = new[] { liveVersions.Max(Convert.ToInt32) }; + } + else + { + _actualLiveServiceVersions = liveVersions.Select(Convert.ToInt32).ToArray(); + } + } + var suitePermutations = GeneratePermutations(); foreach (var (fixture, isAsync, serviceVersion, parameter) in suitePermutations) @@ -114,6 +140,8 @@ public IEnumerable BuildFrom(ITypeInfo typeInfo, IPreFilter filter) private void Process(TestSuite testSuite, object serviceVersion, bool isAsync, object parameter) { var serviceVersionNumber = Convert.ToInt32(serviceVersion); + ApplyLimits(serviceVersionNumber, testSuite); + foreach (Test test in testSuite.Tests) { if (test is ParameterizedMethodSuite parameterizedMethodSuite) @@ -157,18 +185,23 @@ private void ProcessTest(object serviceVersion, bool isAsync, int serviceVersion return; } - if (serviceVersionNumber != _maxServiceVersion) + if (serviceVersionNumber != _actualPlaybackServiceVersion) { - test.Properties.Add("SkipRecordings", $"Test is ignored when not running live because the service version {serviceVersion} is not the latest."); + test.Properties.Add("SkipRecordings", $"Test is ignored when not running live because the service version {serviceVersion} is not {_actualPlaybackServiceVersion}."); } - if (OnlyTestLatestServiceVersionLazy.Value && serviceVersionNumber != _maxServiceVersion) + if (_actualLiveServiceVersions != null && + !_actualLiveServiceVersions.Contains(serviceVersionNumber)) { - test.RunState = RunState.Ignored; - test.Properties.Set("_SKIPREASON", - $"Test ignored because {OnlyTestLatestServiceVersionKey} is set in the environment and version {serviceVersion} is not the latest."); + test.Properties.Set("SkipLive", + $"Test ignored when running live service version {serviceVersion} is not one of {string.Join(", " , _actualLiveServiceVersions)}."); } + ApplyLimits(serviceVersionNumber, test); + } + + private static void ApplyLimits(int serviceVersionNumber, Test test) + { var minServiceVersion = test.GetCustomAttributes(true); foreach (ServiceVersionAttribute serviceVersionAttribute in minServiceVersion) { @@ -179,7 +212,7 @@ private void ProcessTest(object serviceVersion, bool isAsync, int serviceVersion test.Properties.Set("_SKIPREASON", $"Test ignored because it's minimum service version is set to {serviceVersionAttribute.Min}"); } - if (serviceVersionAttribute.Max != null && + if (serviceVersionAttribute.Max != null & Convert.ToInt32(serviceVersionAttribute.Max) < serviceVersionNumber) { test.RunState = RunState.Ignored; diff --git a/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs b/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs index f5ca1cc05d8e..94571310f24b 100644 --- a/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs +++ b/sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs @@ -143,6 +143,13 @@ public virtual void StartTestRecording() { throw new IgnoreException((string) test.Properties.Get("SkipRecordings")); } + + if (Mode == RecordedTestMode.Live && + test.Properties.ContainsKey("SkipLive")) + { + throw new IgnoreException((string) test.Properties.Get("SkipLive")); + } + Recording = new TestRecording(Mode, GetSessionFilePath(), Sanitizer, Matcher); ValidateClientInstrumentation = Recording.HasRequests; } diff --git a/sdk/core/Azure.Core.TestFramework/src/ServiceVersionAttribute.cs b/sdk/core/Azure.Core.TestFramework/src/ServiceVersionAttribute.cs index 3b086707d204..23ec2fae2860 100644 --- a/sdk/core/Azure.Core.TestFramework/src/ServiceVersionAttribute.cs +++ b/sdk/core/Azure.Core.TestFramework/src/ServiceVersionAttribute.cs @@ -6,7 +6,7 @@ namespace Azure.Core.TestFramework { - [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = false)] public class ServiceVersionAttribute : NUnitAttribute { public object Min { get; set; } diff --git a/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTests.cs b/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTests.cs index c744d1111757..942d44ed5f4c 100644 --- a/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTests.cs +++ b/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTests.cs @@ -6,7 +6,8 @@ namespace Azure.Core.Tests { - [ClientTestFixture(FakeClientVersion.V1, FakeClientVersion.V2, FakeClientVersion.V3)] + [ClientTestFixture(FakeClientVersion.V0, FakeClientVersion.V1, FakeClientVersion.V2, FakeClientVersion.V3, FakeClientVersion.V4)] + [ServiceVersion(Min = FakeClientVersion.V1, Max = FakeClientVersion.V3)] public class ClientTestBaseMultiVersionTests : ClientTestBase { private readonly FakeClientVersion _version; @@ -59,9 +60,11 @@ public void SyncOnlyWorks() public enum FakeClientVersion { + V0 = 0, V1 = 1, V2 = 2, - V3 = 3 + V3 = 3, + V4 = 4 } } } diff --git a/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTestsWithSpecificVersions.cs b/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTestsWithSpecificVersions.cs new file mode 100644 index 000000000000..4082f0f7cb2a --- /dev/null +++ b/sdk/core/Azure.Core/tests/ClientTestBaseMultiVersionTestsWithSpecificVersions.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core.Pipeline; +using Azure.Core.TestFramework; +using NUnit.Framework; + +namespace Azure.Core.Tests +{ + [ClientTestFixture( + TestClientOptions.ServiceVersion.V0, + TestClientOptions.ServiceVersion.V1, + TestClientOptions.ServiceVersion.V2, + TestClientOptions.ServiceVersion.V3, + RecordingServiceVersion = TestClientOptions.ServiceVersion.V2, + LiveServiceVersions = new object[] { TestClientOptions.ServiceVersion.V1, TestClientOptions.ServiceVersion.V0 })] + public class ClientTestBaseMultiVersionTestsWithSpecificVersions : RecordedTestBase + { + private readonly TestClientOptions.ServiceVersion _version; + + public ClientTestBaseMultiVersionTestsWithSpecificVersions(bool isAsync, TestClientOptions.ServiceVersion version) : base(isAsync) + { + _version = version; + TestDiagnostics = false; + } + + [Test] + public async Task HasValidVersion() + { + var testClientOptions = new TestClientOptions(_version) { Transport = new MockTransport(new MockResponse(200))}; + var client = InstrumentClient(new TestClient(InstrumentClientOptions(testClientOptions))); + await client.GetAsync(default); + if (Mode == RecordedTestMode.Playback || Mode == RecordedTestMode.Record) + { + Assert.IsTrue(_version == TestClientOptions.ServiceVersion.V2); + } + else + { + Assert.IsTrue(_version == TestClientOptions.ServiceVersion.V1 || _version == TestClientOptions.ServiceVersion.V0); + } + } + + public class TestClientOptions: ClientOptions + { + public readonly ServiceVersion Version; + + public enum ServiceVersion + { + V0 = 0, + V1 = 1, + V2 = 2, + V3 = 3 + } + + public TestClientOptions(ServiceVersion serviceVersion) + { + Version = serviceVersion; + } + } + public class TestClient + { + private readonly TestClientOptions _options; + private HttpPipeline _pipeline; + + protected TestClient(){} + public TestClient(TestClientOptions options) + { + _options = options; + _pipeline = HttpPipelineBuilder.Build(options); + } + + public virtual Response Get(CancellationToken cancellationToken) + { + using var request = _pipeline.CreateRequest(); + request.Method = RequestMethod.Get; + request.Uri.Reset(new Uri("http://localhost")); + request.Uri.AppendQuery("api", _options.Version.ToString()); + return _pipeline.SendRequest(request, cancellationToken); + } + + public virtual async Task GetAsync(CancellationToken cancellationToken) + { + using var request = _pipeline.CreateRequest(); + request.Method = RequestMethod.Get; + request.Uri.Reset(new Uri("http://localhost")); + request.Uri.AppendQuery("api", _options.Version.ToString()); + return await _pipeline.SendRequestAsync(request, cancellationToken); + } + } + } +} \ No newline at end of file diff --git a/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersion.json b/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersion.json new file mode 100644 index 000000000000..66cfb8112d74 --- /dev/null +++ b/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersion.json @@ -0,0 +1,20 @@ +{ + "Entries": [ + { + "RequestUri": "http://localhost/?api=V2", + "RequestMethod": "GET", + "RequestHeaders": { + "User-Agent": "azsdk-net-Core.Tests/1.0.0-alpha.20210310.1 (.NET Framework 4.8.4300.0; Microsoft Windows 10.0.19042 )", + "x-ms-client-request-id": "dc85f443de8d5700b37ac3b4cc6f8430", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": {}, + "ResponseBody": null + } + ], + "Variables": { + "RandomSeed": "9840729" + } +} \ No newline at end of file diff --git a/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersionAsync.json b/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersionAsync.json new file mode 100644 index 000000000000..1c0efc9e7b44 --- /dev/null +++ b/sdk/core/Azure.Core/tests/SessionRecords/ClientTestBaseMultiVersionTestsWithSpecificVersions/HasValidVersionAsync.json @@ -0,0 +1,20 @@ +{ + "Entries": [ + { + "RequestUri": "http://localhost/?api=V2", + "RequestMethod": "GET", + "RequestHeaders": { + "User-Agent": "azsdk-net-Core.Tests/1.0.0-alpha.20210310.1 (.NET Framework 4.8.4300.0; Microsoft Windows 10.0.19042 )", + "x-ms-client-request-id": "310df70d817bc1bf9908dbde885585f0", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": {}, + "ResponseBody": null + } + ], + "Variables": { + "RandomSeed": "16931662" + } +} \ No newline at end of file