From 1a51e64c4b6da0d5218e4616e71ed76a6eac9e66 Mon Sep 17 00:00:00 2001 From: "Curn, Mike" Date: Tue, 27 Nov 2018 19:27:18 -0800 Subject: [PATCH 1/4] Moving IntelliWait into IntelliTect solution --- IntelliTect.IntelliWait.Tests/BaseTest.cs | 75 ++++++ .../ExpectedExceptionsTests.cs | 125 ++++++++++ .../IntelliTect.IntelliWait.Tests.csproj | 20 ++ .../NoExceptionThrownTests.cs | 69 ++++++ .../TypeCheckingTests.cs | 43 ++++ .../UnExpectedExceptionsTests.cs | 105 +++++++++ .../IntelliTect.IntelliWait.csproj | 24 ++ IntelliTect.IntelliWait/Wait.cs | 219 ++++++++++++++++++ IntelliTect.sln | 14 +- 9 files changed, 693 insertions(+), 1 deletion(-) create mode 100644 IntelliTect.IntelliWait.Tests/BaseTest.cs create mode 100644 IntelliTect.IntelliWait.Tests/ExpectedExceptionsTests.cs create mode 100644 IntelliTect.IntelliWait.Tests/IntelliTect.IntelliWait.Tests.csproj create mode 100644 IntelliTect.IntelliWait.Tests/NoExceptionThrownTests.cs create mode 100644 IntelliTect.IntelliWait.Tests/TypeCheckingTests.cs create mode 100644 IntelliTect.IntelliWait.Tests/UnExpectedExceptionsTests.cs create mode 100644 IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj create mode 100644 IntelliTect.IntelliWait/Wait.cs diff --git a/IntelliTect.IntelliWait.Tests/BaseTest.cs b/IntelliTect.IntelliWait.Tests/BaseTest.cs new file mode 100644 index 0000000..6e0713b --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/BaseTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Diagnostics; + +namespace IntelliTect.IntelliWait.Tests +{ + public class BaseTest + { + protected void ThrowExceptionWithNoReturn() + { + throw new Exception(); + } + + protected bool ThrowExceptionWithReturn() + { + throw new Exception(); + } + + protected void ThrowNullRefExceptionWithNoReturn() + { + throw new NullReferenceException(); + } + + protected bool ThrowNullRefExceptionWithReturn() + { + throw new NullReferenceException(); + } + + protected void CheckExceptionsVoidReturn(int secondsToFail = 1, int numberOfDifferentExceptions = 1) + { + ThrowExceptions(secondsToFail, numberOfDifferentExceptions); + } + + protected bool CheckExceptionsBoolReturn(int secondsToFail = 1, int numberOfDifferentExceptions = 1) + { + ThrowExceptions(secondsToFail, numberOfDifferentExceptions); + return true; + } + + // Find a better way to do this to better facilitate test parallelization + private void ThrowExceptions(int secondsToFail, int numberOfExceptions) + { + if (_Timeout == TimeSpan.MinValue) + { + _Timeout = TimeSpan.FromSeconds(secondsToFail); + _Sw.Start(); + } + + while (_Sw.Elapsed <= _Timeout) + { + _Attempts++; + if (_Attempts > numberOfExceptions) + { + _Attempts = 1; + } + switch (_Attempts) + { + case 1: + throw new InvalidOperationException(); + case 2: + throw new InvalidProgramException(); + case 3: + throw new IndexOutOfRangeException(); + case 4: + throw new ArgumentNullException(); + default: + throw new ArgumentException(); + } + } + } + + private int _Attempts = 0; + private TimeSpan _Timeout = TimeSpan.MinValue; + private Stopwatch _Sw = new Stopwatch(); + } +} diff --git a/IntelliTect.IntelliWait.Tests/ExpectedExceptionsTests.cs b/IntelliTect.IntelliWait.Tests/ExpectedExceptionsTests.cs new file mode 100644 index 0000000..356ef66 --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/ExpectedExceptionsTests.cs @@ -0,0 +1,125 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace IntelliTect.IntelliWait.Tests +{ + public class ExpectedExceptionsTests : BaseTest + { + [Fact] + public async Task CheckActionsParamsForBaseTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(ThrowExceptionWithNoReturn, TimeSpan.FromSeconds(1), typeof(Exception))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(Exception)); + } + + [Fact] + public async Task CheckFuncParamsForBaseTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(ThrowExceptionWithReturn, TimeSpan.FromSeconds(1), typeof(Exception))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(Exception)); + } + + [Fact] + public async Task CheckActionParamsForMixedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync( + () => Wait.Until(ThrowExceptionWithNoReturn, TimeSpan.FromSeconds(1), typeof(Exception), typeof(NullReferenceException))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(Exception)); + // Verify that we only catch the actual exceptions thrown + Assert.DoesNotContain(ae.InnerExceptions, e => e.GetType() == typeof(NullReferenceException)); + } + + [Fact] + public async Task CheckFuncParamsForMixedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync( + () => Wait.Until(ThrowExceptionWithReturn, TimeSpan.FromSeconds(1), typeof(Exception), typeof(NullReferenceException))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(Exception)); + // Verify that we only catch the actual exceptions thrown + Assert.DoesNotContain(ae.InnerExceptions, e => e.GetType() == typeof(NullReferenceException)); + } + + [Fact] + public async Task CheckActionsParamsForOneDerivedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(1), typeof(InvalidOperationException))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckFuncParamsForOneDerivedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(1), typeof(InvalidOperationException))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckActionsGenericForOneDerivedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckFuncGenericForOneDerivedTypeChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckActionsGenericForTwoDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsVoidReturn(1, 2), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + } + + [Fact] + public async Task CheckFuncGenericForTwoDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsBoolReturn(1, 2), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + } + + [Fact] + public async Task CheckActionsGenericForThreeDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsVoidReturn(1, 3), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(IndexOutOfRangeException)); + } + + [Fact] + public async Task CheckFuncGenericForThreeDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsBoolReturn(1, 3), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(IndexOutOfRangeException)); + } + + [Fact] + public async Task CheckActionsGenericForFourDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsVoidReturn(1, 4), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(IndexOutOfRangeException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(ArgumentNullException)); + } + + [Fact] + public async Task CheckFuncGenericForFourDerivedTypesChecking() + { + AggregateException ae = await Assert.ThrowsAsync(() => Wait.Until(() => CheckExceptionsBoolReturn(1, 4), TimeSpan.FromSeconds(1))); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidOperationException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(InvalidProgramException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(IndexOutOfRangeException)); + Assert.Contains(ae.InnerExceptions, e => e.GetType() == typeof(ArgumentNullException)); + } + } +} diff --git a/IntelliTect.IntelliWait.Tests/IntelliTect.IntelliWait.Tests.csproj b/IntelliTect.IntelliWait.Tests/IntelliTect.IntelliWait.Tests.csproj new file mode 100644 index 0000000..5393533 --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/IntelliTect.IntelliWait.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.0 + + false + + + + + + + + + + + + + + diff --git a/IntelliTect.IntelliWait.Tests/NoExceptionThrownTests.cs b/IntelliTect.IntelliWait.Tests/NoExceptionThrownTests.cs new file mode 100644 index 0000000..b15b0cc --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/NoExceptionThrownTests.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace IntelliTect.IntelliWait.Tests +{ + public class NoExceptionThrownTests : BaseTest + { + [Fact] + public async Task CheckActionParamsForExpectedExpectionDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(2), typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckFuncParamsForExpectedExpectionDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(2), typeof(InvalidOperationException)); + } + + [Fact] + public async Task CheckActionsGenericForOneExpectedExceptionDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckFuncGenericForOneExpectedExceptionDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckActionsGenericForTwoExpectedExceptiosnDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsVoidReturn(1, 2), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckFuncGenericForTwoExpectedExceptionsDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsBoolReturn(1, 2), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckActionsGenericForThreeExpectedExceptiosnDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsVoidReturn(1, 3), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckFuncGenericForThreeExpectedExceptionsDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsBoolReturn(1, 3), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckActionsGenericForFourExpectedExceptiosnDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsVoidReturn(1, 4), TimeSpan.FromSeconds(2)); + } + + [Fact] + public async Task CheckFuncGenericForFourExpectedExceptionsDoesNotThrow() + { + await Wait.Until(() => CheckExceptionsBoolReturn(1, 4), TimeSpan.FromSeconds(2)); + } + } +} diff --git a/IntelliTect.IntelliWait.Tests/TypeCheckingTests.cs b/IntelliTect.IntelliWait.Tests/TypeCheckingTests.cs new file mode 100644 index 0000000..a456fbd --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/TypeCheckingTests.cs @@ -0,0 +1,43 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace IntelliTect.IntelliWait.Tests +{ + public class TypeCheckingTests : BaseTest + { + [Fact] + public async Task CheckActionParamsForInvalidTypeChecking() + { + Exception ex = await Assert.ThrowsAsync( + () => Wait.Until(ThrowExceptionWithNoReturn, TimeSpan.FromSeconds(1), typeof(string))); + Assert.Equal(ExceptionMessage, ex.Message); + } + + [Fact] + public async Task CheckFuncParamsForInvalidTypeChecking() + { + Exception ex = await Assert.ThrowsAsync( + () => Wait.Until(ThrowExceptionWithReturn, TimeSpan.FromSeconds(1), typeof(string))); + Assert.Equal(ExceptionMessage, ex.Message); + } + + [Fact] + public async Task CheckActionParamsForMixedInvalidTypeChecking() + { + Exception ex = await Assert.ThrowsAsync( + () => Wait.Until(ThrowNullRefExceptionWithNoReturn, TimeSpan.FromSeconds(1), typeof(Exception), typeof(string))); + Assert.Equal(ExceptionMessage, ex.Message); + } + + [Fact] + public async Task CheckFuncParamsForMixedInvalidTypeChecking() + { + Exception ex = await Assert.ThrowsAsync( + () => Wait.Until(ThrowNullRefExceptionWithReturn, TimeSpan.FromSeconds(1), typeof(string), typeof(NullReferenceException))); + Assert.Equal(ExceptionMessage, ex.Message); + } + + private const string ExceptionMessage = "Invalid type passed into exceptionsToIgnore parameter. Must be of type Exception."; + } +} diff --git a/IntelliTect.IntelliWait.Tests/UnExpectedExceptionsTests.cs b/IntelliTect.IntelliWait.Tests/UnExpectedExceptionsTests.cs new file mode 100644 index 0000000..9a60a88 --- /dev/null +++ b/IntelliTect.IntelliWait.Tests/UnExpectedExceptionsTests.cs @@ -0,0 +1,105 @@ +using System; +using System.Threading.Tasks; +using Xunit; + +namespace IntelliTect.IntelliWait.Tests +{ + public class UnExpectedExceptionsTests : BaseTest + { + [Fact] + public async Task CheckActionParamsWithNoExceptionArgumentThrowsException() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckFuncParamsForNoExceptionArgumentThrowsException() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckActionParamsForUnExpectedExpectionThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(2), typeof(NullReferenceException))); + } + + [Fact] + public async Task CheckFuncParamsForUnExpectedExpectionThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(2), typeof(NullReferenceException))); + } + + [Fact] + public async Task CheckActionGenericForOneUnExpectedExpectionThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 1), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckFuncGenericForOneUnExpectedExpectionThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 1), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckActionGenericForTwoUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 2), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckFuncGenericForTwoUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 2), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckActionGenericForThreeUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 3), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckFuncGenericForThreeUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 3), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckActionGenericForFourUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsVoidReturn(1, 4), TimeSpan.FromSeconds(2))); + } + + [Fact] + public async Task CheckFuncGenericForFourUnExpectedExpectionsThrows() + { + await Assert.ThrowsAsync( + () => Wait.Until( + () => CheckExceptionsBoolReturn(1, 4), TimeSpan.FromSeconds(2))); + } + } +} diff --git a/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj new file mode 100644 index 0000000..5fae34a --- /dev/null +++ b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj @@ -0,0 +1,24 @@ + + + + netstandard2.0 + true + + true + 0.9.0 + Mike Curn + IntelliTect + Set of methods to facilitate waiting a certain amount of time for a delegate to evaluate, while ignoring certain exceptions while attempting to evaluate, and throwing after a specified time limit (or throwing immediately if an unexpected exception is encountered) + https://github.com/IntelliTect/TestTools/blob/master/LICENSE + 2018 + https://github.com/IntelliTect/TestTools + https://github.com/IntelliTect/TestTools/tree/master/IntelliTect.TestTools.Selenate + Git + ui test, automated test, testing, api test, web test, integration test, await, async + Initial release independant from Selenium dependency + 0.9.0.0 + 0.9.0.0 + IntelliTect.IntelliWait + + + diff --git a/IntelliTect.IntelliWait/Wait.cs b/IntelliTect.IntelliWait/Wait.cs new file mode 100644 index 0000000..6f9d549 --- /dev/null +++ b/IntelliTect.IntelliWait/Wait.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; + +namespace IntelliTect.IntelliWait +{ + public static class Wait + { + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// Return type of the function to evaluate + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// A list of exceptions to ignore when attempting to evaluate the function + /// An async task that can return a value of type TResult + public static Task Until(Func func, TimeSpan timeToWait, params Type[] exceptionsToIgnore) + { + VerifyAllExceptionTypes(exceptionsToIgnore); + return ExecuteWait(func, timeToWait, exceptionsToIgnore); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// A list of exceptions to ignore when attempting to evaluate the function + /// An async task for the operation + public static Task Until(Action action, TimeSpan timeToWait, params Type[] exceptionsToIgnore) + { + VerifyAllExceptionTypes(exceptionsToIgnore); + return ExecuteWait(action, timeToWait, exceptionsToIgnore); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// Return type of the function to evaluate + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task that can return a value of type TResult + public static Task Until(Func func, TimeSpan timeToWait) + where TException : Exception + { + return ExecuteWait(func, timeToWait, typeof(TException)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task for the operation + public static Task Until(Action action, TimeSpan timeToWait) + where TException : Exception + { + return ExecuteWait(action, timeToWait, typeof(TException)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Return type of the function to evaluate + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task that can return a value of type TResult + public static Task Until(Func func, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + { + return ExecuteWait(func, timeToWait, typeof(TException1), typeof(TException2)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task for the operation + public static Task Until(Action action, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + { + return ExecuteWait(action, timeToWait, typeof(TException1), typeof(TException2)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Return type of the function to evaluate + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task that can return a value of type TResult + public static Task Until(Func func, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + where TException3 : Exception + { + return ExecuteWait(func, timeToWait, typeof(TException1), typeof(TException2), typeof(TException3)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task for the operation + public static Task Until(Action action, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + where TException3 : Exception + { + return ExecuteWait(action, timeToWait, typeof(TException1), typeof(TException2), typeof(TException3)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Return type of the function to evaluate + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task that can return a value of type TResult + public static Task Until(Func func, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + where TException3 : Exception + where TException4 : Exception + { + return ExecuteWait(func, timeToWait, typeof(TException1), typeof(TException2), typeof(TException3), typeof(TException4)); + } + + /// + /// Repeatedly checks for a condition with void return type until it is satisifed or a timeout is reached + /// + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// An exception type to ignore when attempting to evaluate the function + /// Function to check for valid evaluation + /// Time to try evaluating the given function until an exception is thrown + /// An async task for the operation + public static Task Until(Action action, TimeSpan timeToWait) + where TException1 : Exception + where TException2 : Exception + where TException3 : Exception + where TException4 : Exception + { + return ExecuteWait(action, timeToWait, typeof(TException1), typeof(TException2), typeof(TException3), typeof(TException4)); + } + + private static async Task ExecuteWait(Func actionToWaitForComplete, TimeSpan timeToWait, params Type[] types) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + List exceptions = new List(); + do + { + try + { + return actionToWaitForComplete(); + } + catch (Exception ex) when (types.Contains(ex.GetType())) + { + exceptions.Add(ex); + } + await Task.Delay(250); + } while (sw.Elapsed < timeToWait); + throw new AggregateException(exceptions); + } + + private static async Task ExecuteWait(Action actionToWaitForComplete, TimeSpan timeToWait, params Type[] types) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + List exceptions = new List(); + do + { + try + { + actionToWaitForComplete(); + return; + } + catch (Exception ex) when (types.Contains(ex.GetType())) + { + exceptions.Add(ex); + } + await Task.Delay(250); + } while (sw.Elapsed < timeToWait); + throw new AggregateException(exceptions); + } + + private static void VerifyAllExceptionTypes(params Type[] exes) + { + if (!exes.All(e => e.IsSubclassOf(typeof(Exception)) || e == typeof(Exception))) + { + throw new ArgumentException("Invalid type passed into exceptionsToIgnore parameter. Must be of type Exception."); + } + } + } +} diff --git a/IntelliTect.sln b/IntelliTect.sln index 1b6ee60..006ce3f 100644 --- a/IntelliTect.sln +++ b/IntelliTect.sln @@ -5,7 +5,11 @@ VisualStudioVersion = 15.0.26730.15 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntelliTect.Utilities", "IntelliTect.Utilities\IntelliTect.Utilities.csproj", "{4AEDF7B5-8FD1-4361-B230-173646A0D20C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IntelliTect.Utilities.Tests", "IntelliTect.Utilities.Tests\IntelliTect.Utilities.Tests.csproj", "{B0281AA3-FAED-4A2C-8C5A-C2F3DC39511A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntelliTect.Utilities.Tests", "IntelliTect.Utilities.Tests\IntelliTect.Utilities.Tests.csproj", "{B0281AA3-FAED-4A2C-8C5A-C2F3DC39511A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntelliTect.IntelliWait", "IntelliTect.IntelliWait\IntelliTect.IntelliWait.csproj", "{C38B5217-6221-4D72-B264-CD7FF3D201BC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntelliTect.IntelliWait.Tests", "IntelliTect.IntelliWait.Tests\IntelliTect.IntelliWait.Tests.csproj", "{174B4C67-DEFA-4387-A947-52395E4C79A5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +25,14 @@ Global {B0281AA3-FAED-4A2C-8C5A-C2F3DC39511A}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0281AA3-FAED-4A2C-8C5A-C2F3DC39511A}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0281AA3-FAED-4A2C-8C5A-C2F3DC39511A}.Release|Any CPU.Build.0 = Release|Any CPU + {C38B5217-6221-4D72-B264-CD7FF3D201BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C38B5217-6221-4D72-B264-CD7FF3D201BC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C38B5217-6221-4D72-B264-CD7FF3D201BC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C38B5217-6221-4D72-B264-CD7FF3D201BC}.Release|Any CPU.Build.0 = Release|Any CPU + {174B4C67-DEFA-4387-A947-52395E4C79A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {174B4C67-DEFA-4387-A947-52395E4C79A5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {174B4C67-DEFA-4387-A947-52395E4C79A5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {174B4C67-DEFA-4387-A947-52395E4C79A5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 488a3dc87d3afd95795c7d98b10b8263d01ea7f2 Mon Sep 17 00:00:00 2001 From: "Curn, Mike" Date: Wed, 28 Nov 2018 08:48:13 -0800 Subject: [PATCH 2/4] Updates to package --- .../IntelliTect.IntelliWait.csproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj index 5fae34a..b82b8b8 100644 --- a/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj +++ b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj @@ -5,19 +5,19 @@ true true - 0.9.0 + 1.0.0 Mike Curn IntelliTect Set of methods to facilitate waiting a certain amount of time for a delegate to evaluate, while ignoring certain exceptions while attempting to evaluate, and throwing after a specified time limit (or throwing immediately if an unexpected exception is encountered) - https://github.com/IntelliTect/TestTools/blob/master/LICENSE + https://github.com/IntelliTect/IntelliTect/blob/master/LICENSE 2018 - https://github.com/IntelliTect/TestTools - https://github.com/IntelliTect/TestTools/tree/master/IntelliTect.TestTools.Selenate + https://github.com/IntelliTect/IntelliTect + https://github.com/IntelliTect/IntelliTect Git ui test, automated test, testing, api test, web test, integration test, await, async - Initial release independant from Selenium dependency - 0.9.0.0 - 0.9.0.0 + Initial release for long-term home, independant from Selenium dependency + 1.0.0.0 + 1.0.0.0 IntelliTect.IntelliWait From 51fa8c1fd1254c091299706cf74dfd292eb23489 Mon Sep 17 00:00:00 2001 From: Kelly Adams Date: Wed, 28 Nov 2018 10:42:52 -0800 Subject: [PATCH 3/4] Removed version hardcoding in proj file --- IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj index b82b8b8..5558d58 100644 --- a/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj +++ b/IntelliTect.IntelliWait/IntelliTect.IntelliWait.csproj @@ -5,7 +5,6 @@ true true - 1.0.0 Mike Curn IntelliTect Set of methods to facilitate waiting a certain amount of time for a delegate to evaluate, while ignoring certain exceptions while attempting to evaluate, and throwing after a specified time limit (or throwing immediately if an unexpected exception is encountered) @@ -16,8 +15,6 @@ Git ui test, automated test, testing, api test, web test, integration test, await, async Initial release for long-term home, independant from Selenium dependency - 1.0.0.0 - 1.0.0.0 IntelliTect.IntelliWait From 5294119956d8b187ddfde27646ac38060229b5dd Mon Sep 17 00:00:00 2001 From: Kelly Adams Date: Wed, 28 Nov 2018 10:52:30 -0800 Subject: [PATCH 4/4] Update readme --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 9c6917a..09ea8ab 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,15 @@ Libraries * IntelliTect.Utilities.Security - ClaimsPrincipalExtensions: Extention methods to get a user ID and roles. +### IntelliTect.IntelliWait: [![NuGet](https://img.shields.io/nuget/v/IntelliTect.IntelliWait.svg)](https://www.nuget.org/packages/IntelliTect.IntelliWait/) + +### Namespaces within this library: + +* IntelliTect.IntelliWait + - Wait: Set of methods to facilitate waiting a certain amount of time for a delegate to evaluate, while + ignoring certain exceptions while attempting to evaluate, and throwing after a specified time limit + (or throwing immediately if an unexpected exception is encountered). + Contributing ============