diff --git a/SIL.Core.Tests/Code/RetryUtilityTests.cs b/SIL.Core.Tests/Code/RetryUtilityTests.cs index 5c7c70ba3..32eb6837a 100644 --- a/SIL.Core.Tests/Code/RetryUtilityTests.cs +++ b/SIL.Core.Tests/Code/RetryUtilityTests.cs @@ -1,17 +1,11 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using NUnit.Framework; using SIL.Code; namespace SIL.Tests.Code { - /// - /// This is a work in progress. At this point it only has a test for one recently-added bit of functionality. - /// public class RetryUtilityTests { [Test] @@ -23,5 +17,78 @@ public void TypesIncludes_MainClassAndSubclasses_ButNotSuperclass() Assert.That(RetryUtility.TypesIncludes(types, typeof(FileNotFoundException)), Is.True); Assert.That(RetryUtility.TypesIncludes(types, typeof(SystemException)), Is.False); } + + [Test] + public void Retry_WorksOnFirstAttempt() + { + var n = 0; + RetryUtility.Retry(() => { n++; }, 3, 1); + Assert.That(n, Is.EqualTo(1)); + } + + [Test] + public void Retry_WorksOnSecondAttempt() + { + var n = 0; + RetryUtility.Retry(() => { + n++; + if (n == 1) + throw new ApplicationException(); + }, 3, 1, new HashSet (new[] { typeof(Exception) })); + Assert.That(n, Is.EqualTo(2)); + } + + [Test] + public void Retry_StopsAfter3Attempts() + { + var n = 0; + Assert.That(() => RetryUtility.Retry(() => { + n++; + throw new ApplicationException(); + }, 3, 1, new HashSet (new[] { typeof(Exception) })), Throws.Exception.TypeOf()); + Assert.That(n, Is.EqualTo(3)); + } + + [Test] + public void Retry_NoWorkFor0Attempts() + { + var n = 0; + RetryUtility.Retry(() => { n++; }, 0, 1); + Assert.That(n, Is.EqualTo(0)); + } + + [Test] + public void Retry_NoRetriesWithoutExceptionType() + { + var n = 0; + Assert.That(() => RetryUtility.Retry(() => { + n++; + throw new ApplicationException(); + }, 3, 1, null), Throws.Exception.TypeOf()); + Assert.That(n, Is.EqualTo(1)); + } + + [Test] + public void Retry_DefaultsToIOException() + { + var n = 0; + Assert.That(() => RetryUtility.Retry(() => { + n++; + throw new IOException(); + }, 3, 1, null), Throws.Exception.TypeOf()); + Assert.That(n, Is.EqualTo(3)); + } + + [Test] + public void Retry_CatchesSpecifiedExceptionsOnly() + { + var n = 0; + Assert.That(() => RetryUtility.Retry(() => { + n++; + throw new Exception(); + }, 3, 1, new HashSet (new[] { typeof(ApplicationException) })), + Throws.Exception.TypeOf()); + Assert.That(n, Is.EqualTo(1)); + } } } diff --git a/SIL.Core/Code/RetryUtility.cs b/SIL.Core/Code/RetryUtility.cs index 07523c81f..bdedf4806 100644 --- a/SIL.Core/Code/RetryUtility.cs +++ b/SIL.Core/Code/RetryUtility.cs @@ -31,6 +31,21 @@ public static void Retry(Action action, int maxRetryAttempts = kDefaultMaxRetryA }, maxRetryAttempts, retryDelay, exceptionTypesToRetry, memo); } + /// + /// Retry up to times if it + /// throws one of the exceptions in or a subclassed + /// exception. The default value for is null which + /// will catch IOExceptions. + /// + /// The action to run + /// Number of attempts to run + /// Delay in milliseconds between attempts + /// Exceptions to catch and retry. Not listed exceptions + /// are thrown. + /// Text to append to the debug message in case of + /// throwing an exception. + /// Type that returns + /// Return value of public static T Retry(Func action, int maxRetryAttempts = kDefaultMaxRetryAttempts, int retryDelay = kDefaultRetryDelay, ISet exceptionTypesToRetry = null, string memo = "") { if (exceptionTypesToRetry == null)