csharp/agoda-com/net-loadbalancing/Agoda.Frameworks.LoadBalancing.Tests/RetryActionTest.cs

RetryActionTest.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;

namespace Agoda.Frameworks.LoadBalancing.Test
{
    // TODO: Test onError
    public clast RetryActionTest
    {
        private List _updateWeightSequence;

        private void UpdateWeight(string str, bool isSuccess)
        {
            _updateWeightSequence.Add(isSuccess);
            astert.AreEqual("foo", str);
        }

        [SetUp]
        public void SetUp()
        {
            _updateWeightSequence = new List();
        }

        [Test]
        public void ExecuteAction_Return()
        {
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            var actionCount = 0;
            var retryCount = 0;
            var result = mgr.ExecuteAction((str, _) =>
            {
                actionCount++;
                return str;
            }, (_1, _2) =>
            {
                retryCount++;
                return true;
            });

            astert.AreEqual("foo", result);

            astert.AreEqual(1, _updateWeightSequence.Count);
            astert.IsTrue(_updateWeightSequence[0]);

            astert.AreEqual(1, actionCount);
            astert.AreEqual(0, retryCount);
        }

        [Test]
        public void ExecuteAction_Retry_And_Success()
        {
            var failUntilCount = 3;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            var result = mgr.ExecuteAction((str, attemptCount) =>
            {
                if (attemptCount < failUntilCount)
                {
                    throw new InvalidOperationException();
                }
                return attemptCount;
            }, (attempt, exception) =>
            {
                astert.LessOrEqual(attempt, failUntilCount);
                astert.IsInstanceOf(exception);

                return true;
            });

            astert.AreEqual(failUntilCount, result);

            astert.AreEqual(failUntilCount, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
            astert.IsFalse(_updateWeightSequence[1]);
            astert.IsTrue(_updateWeightSequence[2]);
        }

        [Test]
        public void ExecuteAction_Retry_And_Fail()
        {
            var outerRetryCount = -1;
            var maxRetryCount = 3;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            astert.Throws(() =>
            {
                mgr.ExecuteAction((str, attemptCount) =>
                {
                    throw new InvalidOperationException();
                }, (attempt, exception) =>
                {
                    outerRetryCount = attempt;
                    return attempt < maxRetryCount;
                });
            });

            astert.AreEqual(maxRetryCount, outerRetryCount);
            astert.AreEqual(maxRetryCount, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
            astert.IsFalse(_updateWeightSequence[1]);
            astert.IsFalse(_updateWeightSequence[2]);
        }

        [Test]
        public void ExecuteAction_Retry_And_Fail_First_Attempt()
        {
            var outerRetryCount = -1;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            astert.Throws(() =>
            {
                mgr.ExecuteAction((str, attemptCount) =>
                {
                    throw new InvalidOperationException();
                }, (attempt, exception) =>
                {
                    outerRetryCount = attempt;
                    return false;
                });
            });

            astert.AreEqual(1, outerRetryCount);
            astert.AreEqual(1, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
        }

        [Test]
        public void ExecuteAction_Deny_Async_Result()
        {
            var errMsg = "Async action should be executed with ExecuteAsync.";
            var mgr = new RetryAction(() => "foo", UpdateWeight);
            astert.Throws(
                () => mgr.ExecuteAction((_1, _2) => Task.FromResult("Task"), (_1, _2) => true),
                errMsg);
            astert.Throws(
                () => mgr.ExecuteAction((_1, _2) => Task.FromResult("Task"), (_1, _2) => true),
                errMsg);
        }

        [Test]
        public async Task ExecuteAsync_Return()
        {
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            var retryCount = 0;
            var result = await mgr.ExecuteAsync(
                (str, _) => Task.FromResult(str),
                (_1, _2) =>
                {
                    retryCount++;
                    return true;
                });

            astert.AreEqual("foo", result);

            astert.AreEqual(1, _updateWeightSequence.Count);
            astert.IsTrue(_updateWeightSequence[0]);

            astert.AreEqual(0, retryCount);
        }

        [Test]
        public async Task ExecuteAsync_Retry_And_Success()
        {
            var failUntilCount = 3;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            var result = await mgr.ExecuteAsync(
                (str, attemptCount) =>
                {
                    if (attemptCount < failUntilCount)
                    {
                        return Task.FromException(new InvalidOperationException());
                    }

                    return Task.FromResult(attemptCount);
                }, (attempt, exception) =>
                {
                    astert.LessOrEqual(attempt, failUntilCount);
                    astert.IsInstanceOf(exception);

                    return true;
                });

            astert.AreEqual(failUntilCount, result);

            astert.AreEqual(failUntilCount, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
            astert.IsFalse(_updateWeightSequence[1]);
            astert.IsTrue(_updateWeightSequence[2]);
        }

        [Test]
        public void ExecuteAsync_Retry_And_Fail()
        {
            var outerRetryCount = -1;
            var maxRetryCount = 3;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            astert.ThrowsAsync(() =>
            {
                return mgr.ExecuteAsync((str, attemptCount) =>
                {
                    throw new InvalidOperationException();
                }, (attempt, exception) =>
                {
                    outerRetryCount = attempt;
                    return attempt < maxRetryCount;
                });
            });

            astert.AreEqual(maxRetryCount, outerRetryCount);
            astert.AreEqual(maxRetryCount, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
            astert.IsFalse(_updateWeightSequence[1]);
            astert.IsFalse(_updateWeightSequence[2]);
        }

        [Test]
        public void ExecuteAsync_Retry_And_Fail_First_Attempt()
        {
            var outerRetryCount = -1;
            var mgr = new RetryAction(() => "foo", UpdateWeight);

            astert.ThrowsAsync(() =>
            {
                return mgr.ExecuteAsync((str, attemptCount) =>
                {
                    throw new InvalidOperationException();
                }, (attempt, exception) =>
                {
                    outerRetryCount = attempt;
                    return false;
                });
            });

            astert.AreEqual(1, outerRetryCount);
            astert.AreEqual(1, _updateWeightSequence.Count);
            astert.IsFalse(_updateWeightSequence[0]);
        }
    }
}