Skip to content

Commit 44c9a19

Browse files
authored
Instrument mock operations (Azure#27399)
* Instrument mock operations Resolves Azure#27393 * Resolve PR feedback * Resolve offline feedback
1 parent 5b4d6d0 commit 44c9a19

File tree

7 files changed

+33
-24
lines changed

7 files changed

+33
-24
lines changed

common/ManagementTestShared/Redesign/ManagementRecordedTestBase.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
using System;
99
using System.Collections.Generic;
1010
using System.Linq;
11-
using System.Reflection;
1211
using System.Threading.Tasks;
1312

1413
namespace Azure.ResourceManager.TestFramework
@@ -35,6 +34,8 @@ public abstract class ManagementRecordedTestBase<TEnvironment> : RecordedTestBas
3534

3635
protected ManagementRecordedTestBase(bool isAsync, RecordedTestMode? mode = default) : base(isAsync, mode)
3736
{
37+
AdditionalInterceptors = new[] { new ManagementInterceptor(this) };
38+
3839
SessionEnvironment = new TEnvironment();
3940
SessionEnvironment.Mode = Mode;
4041
Initialize();
@@ -224,8 +225,5 @@ public void OneTimeCleanupResourceGroups()
224225
if (!(GlobalClient is null))
225226
throw new InvalidOperationException("StopSessionRecording was never called please make sure you call that at the end of your OneTimeSetup");
226227
}
227-
228-
protected override object InstrumentOperation(Type operationType, object operation)
229-
=> InstrumentOperationInternal(operationType, operation, new ManagementInterceptor(this));
230228
}
231229
}

sdk/communication/Azure.Communication.NetworkTraversal/tests/CommunicationRelayClient/CommunicationRelayClientLiveTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Azure.Communication.NetworkTraversal.Tests
1818
/// These tests have a dependency on live Azure services and may incur costs for the associated
1919
/// Azure subscription.
2020
/// </remarks>
21+
[Ignore("https://github.com/Azure/azure-sdk-for-net/issues/27522")]
2122
public class CommunicationRelayClientLiveTests : CommunicationRelayClientLiveTestBase
2223
{
2324
/// <summary>

sdk/core/Azure.Core.TestFramework/src/ClientTestBase.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics;
7+
using System.Linq;
78
using System.Reflection;
89
using Castle.DynamicProxy;
910
using NUnit.Framework;
@@ -36,6 +37,8 @@ public ClientTestBase(bool isAsync)
3637
IsAsync = isAsync;
3738
}
3839

40+
protected IReadOnlyCollection<IInterceptor> AdditionalInterceptors { get; set; }
41+
3942
protected virtual DateTime TestStartTime => TestExecutionContext.CurrentContext.StartTime;
4043

4144
[TearDown]
@@ -140,9 +143,20 @@ protected internal virtual object InstrumentClient(Type clientType, object clien
140143

141144
protected internal virtual object InstrumentOperation(Type operationType, object operation)
142145
{
143-
return operation;
146+
var interceptors = AdditionalInterceptors ?? Array.Empty<IInterceptor>();
147+
148+
// The assumption is that any recorded or live tests deriving from RecordedTestBase, and that any unit tests deriving directly from ClientTestBase are equivalent to playback.
149+
var interceptorArray = interceptors.Concat(new IInterceptor[] { new GetOriginalInterceptor(operation), new OperationInterceptor(RecordedTestMode.Playback) }).ToArray();
150+
return ProxyGenerator.CreateClassProxyWithTarget(
151+
operationType,
152+
new[] { typeof(IInstrumented) },
153+
operation,
154+
interceptorArray);
144155
}
145156

157+
protected internal T InstrumentOperation<T>(T operation) where T : Operation =>
158+
(T)InstrumentOperation(typeof(T), operation);
159+
146160
protected T GetOriginal<T>(T instrumented)
147161
{
148162
if (instrumented == null) throw new ArgumentNullException(nameof(instrumented));

sdk/core/Azure.Core.TestFramework/src/Instrumentation/OperationInterceptor.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Linq;
66
using System.Reflection;
7-
using System.Runtime.ExceptionServices;
87
using System.Threading;
98
using Castle.DynamicProxy;
109

@@ -18,16 +17,16 @@ internal class OperationInterceptor : IInterceptor
1817

1918
internal static readonly string PollerWaitForCompletionAsyncName = nameof(OperationPoller.WaitForCompletionAsync);
2019

21-
private readonly bool _noWait;
20+
private readonly RecordedTestMode _mode;
2221

23-
public OperationInterceptor(bool noWait)
22+
public OperationInterceptor(RecordedTestMode mode)
2423
{
25-
_noWait = noWait;
24+
_mode = mode;
2625
}
2726

2827
public void Intercept(IInvocation invocation)
2928
{
30-
if (_noWait)
29+
if (_mode == RecordedTestMode.Playback)
3130
{
3231
if (invocation.Method.Name == WaitForCompletionMethodName)
3332
{

sdk/core/Azure.Core.TestFramework/src/RecordedTestBase.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,17 +344,10 @@ protected internal override object InstrumentClient(Type clientType, object clie
344344
return base.InstrumentClient(clientType, client, preInterceptors);
345345
}
346346

347-
protected internal T InstrumentOperation<T>(T operation) where T: Operation
348-
{
349-
return (T) InstrumentOperation(typeof(T), operation);
350-
}
351-
352347
protected internal override object InstrumentOperation(Type operationType, object operation)
353-
=> InstrumentOperationInternal(operationType, operation);
354-
355-
protected object InstrumentOperationInternal(Type operationType, object operation, params IInterceptor[] interceptors)
356348
{
357-
var interceptorArray = interceptors.Concat(new IInterceptor[] { new GetOriginalInterceptor(operation), new OperationInterceptor(Mode == RecordedTestMode.Playback) }).ToArray();
349+
var interceptors = AdditionalInterceptors ?? Array.Empty<IInterceptor>();
350+
var interceptorArray = interceptors.Concat(new IInterceptor[] { new GetOriginalInterceptor(operation), new OperationInterceptor(Mode) }).ToArray();
358351
return ProxyGenerator.CreateClassProxyWithTarget(
359352
operationType,
360353
new[] { typeof(IInstrumented) },

sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/CertificateClientLiveTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,11 @@ public async Task VerifyGetCertificateCompletedSubsequently()
356356

357357
// Pretend a separate process was started subsequently and we need to get the operation again.
358358
CertificateOperation operation = new CertificateOperation(Client, certName);
359+
operation = InstrumentOperation(operation);
359360

360361
// Need to call the real async wait method or the sync version of this test fails because it's using the instrumented Client directly.
361362
using CancellationTokenSource cts = new CancellationTokenSource(DefaultCertificateOperationTimeout);
362-
await operation.WaitForCompletionAsync(PollingInterval, cts.Token);
363+
await operation.WaitForCompletionAsync(cts.Token);
363364

364365
Assert.IsTrue(operation.HasCompleted);
365366
Assert.IsTrue(operation.HasValue);

sdk/keyvault/Azure.Security.KeyVault.Certificates/tests/CertificateOperationTests.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,11 @@ private CertificateClient CreateClient(HttpPipelineTransport transport)
292292
{
293293
CertificateClientOptions options = new CertificateClientOptions
294294
{
295+
Retry =
296+
{
297+
Delay = TimeSpan.FromMilliseconds(10),
298+
Mode = RetryMode.Fixed,
299+
},
295300
Transport = transport,
296301
};
297302

@@ -303,10 +308,8 @@ private CertificateClient CreateClient(HttpPipelineTransport transport)
303308
));
304309
}
305310

306-
private async ValueTask<KeyVaultCertificateWithPolicy> WaitForOperationAsync(CertificateOperation operation)
307-
{
308-
return await operation.WaitForCompletionAsync(TimeSpan.Zero, default);
309-
}
311+
private async ValueTask<KeyVaultCertificateWithPolicy> WaitForOperationAsync(CertificateOperation operation) =>
312+
await operation.WaitForCompletionAsync();
310313

311314
public class MockCredential : TokenCredential
312315
{

0 commit comments

Comments
 (0)