-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update test project to consume framework for recorded tests #19171
Changes from all commits
95a48a2
6cf8c22
f17e9c3
54a864b
8395bcf
5309308
83cc07e
edf8a40
5cc3e44
77c29a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using Azure.Core; | ||
using Azure.Core.TestFramework; | ||
using Azure.ResourceManager.Core; | ||
using NUnit.Framework; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
|
||
namespace Azure.ResourceManager.TestFramework | ||
{ | ||
public abstract class ManagementRecordedTestBase<TEnvironment> : RecordedTestBase<TEnvironment> | ||
where TEnvironment: TestEnvironment, new() | ||
{ | ||
protected ResourceGroupCleanupPolicy CleanupPolicy = new ResourceGroupCleanupPolicy(); | ||
|
||
protected ResourceGroupCleanupPolicy OneTimeCleanupPolicy = new ResourceGroupCleanupPolicy(); | ||
|
||
protected AzureResourceManagerClient GlobalClient { get; private set; } | ||
|
||
public TestEnvironment SessionEnvironment { get; private set; } | ||
|
||
public TestRecording SessionRecording { get; private set; } | ||
|
||
private AzureResourceManagerClient _cleanupClient; | ||
|
||
protected ManagementRecordedTestBase(bool isAsync) : base(isAsync) | ||
{ | ||
SessionEnvironment = new TEnvironment(); | ||
SessionEnvironment.Mode = Mode; | ||
} | ||
|
||
protected ManagementRecordedTestBase(bool isAsync, RecordedTestMode mode) : base(isAsync, mode) | ||
{ | ||
SessionEnvironment = new TEnvironment(); | ||
SessionEnvironment.Mode = Mode; | ||
} | ||
|
||
private AzureResourceManagerClient GetCleanupClient() | ||
{ | ||
if (Mode != RecordedTestMode.Playback) | ||
{ | ||
return new AzureResourceManagerClient( | ||
TestEnvironment.SubscriptionId, | ||
TestEnvironment.Credential, | ||
new AzureResourceManagerClientOptions()); | ||
} | ||
return null; | ||
} | ||
|
||
protected AzureResourceManagerClient GetArmClient() | ||
{ | ||
var options = InstrumentClientOptions(new AzureResourceManagerClientOptions()); | ||
options.AddPolicy(CleanupPolicy, HttpPipelinePosition.PerCall); | ||
|
||
return CreateClient<AzureResourceManagerClient>( | ||
TestEnvironment.SubscriptionId, | ||
TestEnvironment.Credential, | ||
options); | ||
} | ||
|
||
[SetUp] | ||
protected void Setup() | ||
{ | ||
_cleanupClient ??= GetCleanupClient(); | ||
} | ||
|
||
[TearDown] | ||
protected void CleanupResourceGroups() | ||
{ | ||
if (Mode != RecordedTestMode.Playback) | ||
{ | ||
Parallel.ForEach(CleanupPolicy.ResourceGroupsCreated, resourceGroup => | ||
{ | ||
_cleanupClient.GetResourceGroupOperations(TestEnvironment.SubscriptionId, resourceGroup).StartDelete(); | ||
}); | ||
} | ||
} | ||
|
||
private void StartSessionRecording() | ||
{ | ||
// Only create test recordings for the latest version of the service | ||
TestContext.TestAdapter test = TestContext.CurrentContext.Test; | ||
if (Mode != RecordedTestMode.Live && | ||
test.Properties.ContainsKey("SkipRecordings")) | ||
{ | ||
throw new IgnoreException((string)test.Properties.Get("SkipRecordings")); | ||
} | ||
SessionRecording = new TestRecording(Mode, GetSessionFilePath(), Sanitizer, Matcher); | ||
SessionEnvironment.SetRecording(SessionRecording); | ||
ValidateClientInstrumentation = SessionRecording.HasRequests; | ||
} | ||
|
||
protected void StopSessionRecording() | ||
{ | ||
if (ValidateClientInstrumentation) | ||
{ | ||
throw new InvalidOperationException("The test didn't instrument any clients but had recordings. Please call InstrumentClient for the client being recorded."); | ||
} | ||
|
||
SessionRecording?.Dispose(true); | ||
GlobalClient = null; | ||
} | ||
|
||
[OneTimeSetUp] | ||
public void OneTimeSetUp() | ||
{ | ||
if (!HasOneTimeSetup()) | ||
return; | ||
|
||
StartSessionRecording(); | ||
|
||
var options = InstrumentClientOptions(new AzureResourceManagerClientOptions(), SessionRecording); | ||
options.AddPolicy(OneTimeCleanupPolicy, HttpPipelinePosition.PerCall); | ||
|
||
GlobalClient = CreateClient<AzureResourceManagerClient>( | ||
SessionEnvironment.SubscriptionId, | ||
SessionEnvironment.Credential, | ||
options); | ||
} | ||
|
||
private bool HasOneTimeSetup() | ||
{ | ||
HashSet<Type> types = new HashSet<Type>(); | ||
Type type = GetType(); | ||
Type endType = typeof(ManagementRecordedTestBase<TEnvironment>); | ||
while (type != endType) | ||
{ | ||
types.Add(type); | ||
type = type.BaseType; | ||
} | ||
|
||
var methods = GetType().GetMethods().Where(m => types.Contains(m.DeclaringType)); | ||
foreach (var method in methods) | ||
{ | ||
foreach(var attr in method.GetCustomAttributes(false)) | ||
{ | ||
if (attr is OneTimeSetUpAttribute) | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
[OneTimeTearDown] | ||
public void OneTimeCleanupResourceGroups() | ||
{ | ||
if (Mode != RecordedTestMode.Playback) | ||
{ | ||
Parallel.ForEach(OneTimeCleanupPolicy.ResourceGroupsCreated, resourceGroup => | ||
{ | ||
_cleanupClient.GetResourceGroupOperations(SessionEnvironment.SubscriptionId, resourceGroup).StartDelete(); | ||
}); | ||
} | ||
|
||
if (!(GlobalClient is null)) | ||
throw new InvalidOperationException("StopSessionRecording was never called please make sure you call that at the end of your OneTimeSetup"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Generic; | ||
using System.Text.RegularExpressions; | ||
|
||
using Azure.Core; | ||
using Azure.Core.Pipeline; | ||
|
||
namespace Azure.ResourceManager.TestFramework | ||
{ | ||
public class ResourceGroupCleanupPolicy : HttpPipelineSynchronousPolicy | ||
{ | ||
private readonly object _listLock = new object(); | ||
private Regex _resourceGroupPattern = new Regex(@"/subscriptions/[^/]+/resourcegroups/([^?/]+)\?api-version"); | ||
private readonly IList<string> _resourceGroupCreated = new List<string>(); | ||
|
||
public IList<string> ResourceGroupsCreated | ||
{ | ||
get { return _resourceGroupCreated; } | ||
} | ||
|
||
public override void OnSendingRequest(HttpMessage message) | ||
{ | ||
if (message.Request.Method == RequestMethod.Put) | ||
{ | ||
var match = _resourceGroupPattern.Match(message.Request.Uri.ToString()); | ||
if (match.Success) | ||
{ | ||
lock (_listLock) | ||
{ | ||
_resourceGroupCreated.Add(match.Groups[1].Value); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,9 @@ public void Intercept(IInvocation invocation) | |
// We don't want to instrument generated rest clients. | ||
if ((type.Name.EndsWith("Client") && !type.Name.EndsWith("RestClient")) || | ||
// Generated ARM clients will have a property containing the sub-client that ends with Operations. | ||
(invocation.Method.Name.StartsWith("get_") && type.Name.EndsWith("Operations"))) | ||
(invocation.Method.Name.StartsWith("get_") && type.Name.EndsWith("Operations")) || | ||
// Instrument the subscription client that hangs off of the new AzureResouceManagementClient | ||
(type.Name.EndsWith("DefaultSubscription"))) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can, please, add a comment here about why we need this condition |
||
{ | ||
invocation.ReturnValue = _testBase.InstrumentClient(type, result, Array.Empty<IInterceptor>()); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -264,6 +264,11 @@ protected string GetOptionalVariable(string name) | |
value = Environment.GetEnvironmentVariable(name); | ||
} | ||
|
||
if (value == null) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need to support the "AZURE_" prefix? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so that it can read the regular defaultcredential env variables locally. They are the exact same variables just with AZURE_ prepended so I added that to the check list |
||
{ | ||
value = Environment.GetEnvironmentVariable($"AZURE_{name}"); | ||
} | ||
|
||
if (value == null) | ||
{ | ||
_environmentFile.TryGetValue(name, out value); | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might be able to base this check on the session being empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless its the first recording right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the check is here to prevent an empty recording file we can check it before writing the file.