public async Task Retry_based_on_configured_policy()
        {
            ILockProvider           lockProvider = new LockProvider();
            var                     exponentialRetryControllerObj = new ExponentialRetryController(new ExponentialRetrySettingsProvider());
            var                     globalLockProvider            = new GlobalLock(lockProvider, exponentialRetryControllerObj);//
            Func <Task <DateTime> > writeLockBlockingAction       = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterReadLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                    Thread.Sleep(500);
                }
                return(lockAcquiredTime);
            };

            Func <Task <DateTime> > writeLockAction = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterWriteLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                }
                return(lockAcquiredTime);
            };

            Task <DateTime> dateTimeTask1 = null, dateTimeTask2 = null;

            Parallel.Invoke(
                () => { dateTimeTask1 = writeLockBlockingAction(); },
                () => {
                Thread.Sleep(20);
                dateTimeTask2 = writeLockAction();
            }
                );

            var dateTime1 = dateTimeTask1.Result;
            var dateTime2 = dateTimeTask2.Result;

            var timeDiff = (dateTime2 - dateTime1).TotalMilliseconds;

            Assert.IsTrue(timeDiff >= 1200);
            Assert.IsTrue(timeDiff <= 1400); // (int)Math.Pow(3, _retryCount) * 10;) for ExponentialRetry. 30 + 90 + 270 + 810 = 1200
        }
        public async Task Retry_based_on_configured_linear_policy()
        {
            ILockProvider           lockProvider             = new LockProvider();
            var                     linearRetryControllerObj = new LinearRetryController(new LinearRetrySettingsProvider());
            var                     globalLockProvider       = new GlobalLock(lockProvider, linearRetryControllerObj);//
            Func <Task <DateTime> > writeLockBlockingAction  = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterReadLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                    Thread.Sleep(500);
                }
                return(lockAcquiredTime);
            };

            Func <Task <DateTime> > writeLockAction = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterWriteLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                }
                return(lockAcquiredTime);
            };

            Task <DateTime> dateTimeTask1 = null, dateTimeTask2 = null;

            Parallel.Invoke(
                () => { dateTimeTask1 = writeLockBlockingAction(); },
                () => {
                Thread.Sleep(20);
                dateTimeTask2 = writeLockAction();
            }
                );

            var dateTime1 = dateTimeTask1.Result;
            var dateTime2 = dateTimeTask2.Result;

            var timeDiff = (dateTime2 - dateTime1).TotalMilliseconds;

            Assert.IsTrue(timeDiff >= 600);
            Assert.IsTrue(timeDiff <= 800); // 200 + 200 + 200 = 600
        }
        public async Task Should_be_able_to_acquire_read_and_write_locks_in_async_way()
        {
            ILockProvider lockProvider = new LockProvider();

            var globalLockProvider = new GlobalLock(lockProvider);

            var isReadLockAcquired  = false;
            var isWriteLockAcquired = false;

            using (await globalLockProvider.EnterReadLock("test"))
            {
                isReadLockAcquired = true;
            }
            using (await globalLockProvider.EnterWriteLock("test"))
            {
                isWriteLockAcquired = true;
            }
            Assert.IsTrue(isReadLockAcquired);
            Assert.IsTrue(isWriteLockAcquired);
        }
        public async Task ReadWriteLocks_Should_Wait_For_Completion_Of_WriteLock()
        {
            ILockProvider lockProvider = new LockProvider();

            var globalLockProvider = new GlobalLock(lockProvider);
            Func <Task <DateTime> > writeLockBlockingAction = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterWriteLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                    Thread.Sleep(500);
                }
                return(lockAcquiredTime);
            };

            Func <Task <DateTime> > writeLockAction = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterWriteLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                }
                return(lockAcquiredTime);
            };

            Func <Task <DateTime> > readLockAction = async() =>
            {
                DateTime lockAcquiredTime = new DateTime();
                using (var globalLock = await globalLockProvider.EnterReadLock("test"))
                {
                    lockAcquiredTime = DateTime.Now;
                }
                return(lockAcquiredTime);
            };

            Task <DateTime> dateTimeTask1 = null, dateTimeTask2 = null, dateTimeTask3 = null;

            Parallel.Invoke(
                () => { dateTimeTask1 = writeLockBlockingAction(); },
                () => {
                Thread.Sleep(100);
                dateTimeTask2 = writeLockAction();
            },
                () => {
                Thread.Sleep(100);
                dateTimeTask3 = readLockAction();
            }
                );

            var dateTime1 = dateTimeTask1.Result;
            var dateTime2 = dateTimeTask2.Result;
            var dateTime3 = dateTimeTask3.Result;

            var timeDiff = (dateTime3 - dateTime1).TotalMilliseconds;

            Assert.IsTrue(timeDiff > 500);

            var timeDiff1 = (dateTime2 - dateTime1).TotalMilliseconds;

            Assert.IsTrue(timeDiff1 > 500);
        }