Skip to content

Commit

Permalink
Support exponential backoff
Browse files Browse the repository at this point in the history
  • Loading branch information
Youssef1313 committed Jan 14, 2025
1 parent 275f176 commit aeccb48
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestTools.UnitTesting;

/// <summary>
/// Specifies a backoff type for the delay between retries.
/// </summary>
public enum DelayBackoffType
{
/// <summary>
/// Specifies a constant backoff type. Meaning the delay between retries is constant.
/// </summary>
Constant,

/// <summary>
/// Specifies an exponential backoff type.
/// The delay is calculated as the base delay * 2^(n-1) where n is the retry attempt.
/// For example, if the base delay is 1000ms, the delays will be 1000ms, 2000ms, 4000ms, 8000ms, etc.
/// </summary>
Exponential,
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@

namespace Microsoft.VisualStudio.TestTools.UnitTesting;

public sealed class RetryResult
{
private readonly List<TestResult[]> _testResults = new();

public void AddResult(TestResult[] testResults)
=> _testResults.Add(testResults);

internal TestResult[]? TryGetLast()
=> _testResults.Count > 0 ? _testResults[_testResults.Count - 1] : null;
}

/// <summary>
/// This attribute is used to set a retry count on a test method in case of failure.
/// </summary>
Expand Down Expand Up @@ -47,6 +36,20 @@ public RetryAttribute(int maxRetryAttempts)
/// </summary>
public int MillisecondsDelayBetweenRetries { get; set; }

public DelayBackoffType BackoffType
{
get => field;
set
{
if (value is < DelayBackoffType.Constant or > DelayBackoffType.Exponential)
{
throw new ArgumentOutOfRangeException(nameof(value));
}

field = value;
}
}

/// <summary>
/// Retries the test method <see cref="MaxRetryAttempts"/> times in case of failure.
/// Note that a first run of the method was already executed and failed before this method is called.
Expand All @@ -61,10 +64,15 @@ public RetryAttribute(int maxRetryAttempts)
protected internal virtual async Task<RetryResult> ExecuteAsync(RetryContext retryContext)
{
var result = new RetryResult();
int currentDelay = MillisecondsDelayBetweenRetries;
for (int i = 0; i < MaxRetryAttempts; i++)
{
// The caller already executed the test once. So we need to do the delay here.
await Task.Delay(MillisecondsDelayBetweenRetries);
await Task.Delay(currentDelay);
if (BackoffType == DelayBackoffType.Exponential)
{
currentDelay *= 2;
}

TestResult[] testResults = await retryContext.ExecuteTaskGetter();
result.AddResult(testResults);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.VisualStudio.TestTools.UnitTesting;

public sealed class RetryResult
{
private readonly List<TestResult[]> _testResults = new();

public void AddResult(TestResult[] testResults)
=> _testResults.Add(testResults);

internal TestResult[]? TryGetLast()
=> _testResults.Count > 0 ? _testResults[_testResults.Count - 1] : null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertThrowsExactlyInterpola
Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AssertThrowsExactlyInterpolatedStringHandler<TException>.AssertThrowsExactlyInterpolatedStringHandler(int literalLength, int formattedCount, System.Action! action, out bool shouldAppend) -> void
Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute.IgnoreMessage.get -> string?
Microsoft.VisualStudio.TestTools.UnitTesting.DataRowAttribute.IgnoreMessage.set -> void
Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType
Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType.Constant = 0 -> Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType
Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType.Exponential = 1 -> Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType
Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute.DynamicDataAttribute(string! dynamicDataSourceName) -> void
Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute.DynamicDataAttribute(string! dynamicDataSourceName, Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataSourceType dynamicDataSourceType) -> void
Microsoft.VisualStudio.TestTools.UnitTesting.DynamicDataAttribute.DynamicDataAttribute(string! dynamicDataSourceName, System.Type! dynamicDataDeclaringType) -> void
Expand All @@ -203,6 +206,8 @@ Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSourceIgnoreCapability
Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSourceIgnoreCapability.IgnoreMessage.get -> string?
Microsoft.VisualStudio.TestTools.UnitTesting.ITestDataSourceIgnoreCapability.IgnoreMessage.set -> void
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute.BackoffType.get -> Microsoft.VisualStudio.TestTools.UnitTesting.DelayBackoffType
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute.BackoffType.set -> void
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute.MaxRetryAttempts.get -> int
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute.MillisecondsDelayBetweenRetries.get -> int
Microsoft.VisualStudio.TestTools.UnitTesting.RetryAttribute.MillisecondsDelayBetweenRetries.set -> void
Expand Down

0 comments on commit aeccb48

Please sign in to comment.