public async Task Multiple_threads_can_use_the_same_generator_async()
        {
            var incrementingValue   = 0L;
            var dbConfigurationMock = new Mock <DbContextConfiguration>();
            var redisDatabaseMock   = new Mock <RedisDatabase>(dbConfigurationMock.Object);

            redisDatabaseMock
            .Setup(db => db.GetNextGeneratedValueAsync(
                       It.IsAny <IProperty>(), It.IsAny <long>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns <IProperty, long, string, CancellationToken>((p, l, s, c) =>
            {
                var originalValue  = incrementingValue;
                incrementingValue += l;
                return(Task.FromResult(originalValue));
            });

            var generator = new RedisSequenceValueGenerator(redisDatabaseMock.Object, "TestSequenceName", 1);

            var property = _model.GetEntityType(typeof(AnEntity)).GetProperty("Long");

            const int threadCount = 50;
            const int valueCount  = 35;

            var tests           = new Func <Task> [threadCount];
            var generatedValues = new List <long> [threadCount];

            for (var i = 0; i < tests.Length; i++)
            {
                var testNumber = i;
                generatedValues[testNumber] = new List <long>();
                tests[testNumber]           = async() =>
                {
                    var stateEntry = TestHelpers.CreateStateEntry <AnEntity>(_model);

                    for (var j = 0; j < valueCount; j++)
                    {
                        await generator.NextAsync(stateEntry, property);

                        generatedValues[testNumber].Add((long)stateEntry[property]);
                    }
                };
            }

            var tasks = tests.Select(Task.Run).ToArray();

            foreach (var t in tasks)
            {
                await t;
            }

            // Check that each value was generated once and only once
            var checks = new bool[threadCount * valueCount];

            foreach (var values in generatedValues)
            {
                Assert.Equal(valueCount, values.Count);
                foreach (var value in values)
                {
                    checks[value] = true;
                }
            }

            Assert.True(checks.All(c => c));
        }
        public async Task Generates_sequential_values_async()
        {
            var stateEntry          = TestHelpers.CreateStateEntry <AnEntity>(_model);
            var property            = stateEntry.EntityType.GetProperty("Id");
            var sequenceName        = RedisDatabase.ConstructRedisValueGeneratorKeyName(property);
            var blockSize           = 1;
            var incrementingValue   = 0L;
            var dbConfigurationMock = new Mock <DbContextConfiguration>();
            var redisDatabaseMock   = new Mock <RedisDatabase>(dbConfigurationMock.Object);

            redisDatabaseMock
            .Setup(db => db.GetNextGeneratedValueAsync(
                       It.IsAny <IProperty>(), It.IsAny <long>(), It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns <IProperty, long, string, CancellationToken>((p, l, s, c) =>
            {
                var originalValue  = incrementingValue;
                incrementingValue += l;
                return(Task.FromResult(originalValue));
            });

            var intProperty    = stateEntry.EntityType.GetProperty("Id");
            var longProperty   = stateEntry.EntityType.GetProperty("Long");
            var shortProperty  = stateEntry.EntityType.GetProperty("Short");
            var byteProperty   = stateEntry.EntityType.GetProperty("Byte");
            var uintProperty   = stateEntry.EntityType.GetProperty("UnsignedInt");
            var ulongProperty  = stateEntry.EntityType.GetProperty("UnsignedLong");
            var ushortProperty = stateEntry.EntityType.GetProperty("UnsignedShort");
            var sbyteProperty  = stateEntry.EntityType.GetProperty("SignedByte");

            var generator = new RedisSequenceValueGenerator(redisDatabaseMock.Object, sequenceName, blockSize);

            for (var i = 0; i < 15; i++)
            {
                await generator.NextAsync(stateEntry, intProperty);

                Assert.Equal(i, stateEntry[intProperty]);
                Assert.False(stateEntry.HasTemporaryValue(intProperty));
            }

            for (var i = 15; i < 30; i++)
            {
                await generator.NextAsync(stateEntry, longProperty);

                Assert.Equal((long)i, stateEntry[longProperty]);
                Assert.False(stateEntry.HasTemporaryValue(longProperty));
            }

            for (var i = 30; i < 45; i++)
            {
                await generator.NextAsync(stateEntry, shortProperty);

                Assert.Equal((short)i, stateEntry[shortProperty]);
                Assert.False(stateEntry.HasTemporaryValue(shortProperty));
            }

            for (var i = 45; i < 60; i++)
            {
                await generator.NextAsync(stateEntry, byteProperty);

                Assert.Equal((byte)i, stateEntry[byteProperty]);
                Assert.False(stateEntry.HasTemporaryValue(byteProperty));
            }

            for (var i = 60; i < 75; i++)
            {
                await generator.NextAsync(stateEntry, uintProperty);

                Assert.Equal((uint)i, stateEntry[uintProperty]);
                Assert.False(stateEntry.HasTemporaryValue(uintProperty));
            }

            for (var i = 75; i < 90; i++)
            {
                await generator.NextAsync(stateEntry, ulongProperty);

                Assert.Equal((ulong)i, stateEntry[ulongProperty]);
                Assert.False(stateEntry.HasTemporaryValue(ulongProperty));
            }

            for (var i = 90; i < 105; i++)
            {
                await generator.NextAsync(stateEntry, ushortProperty);

                Assert.Equal((ushort)i, stateEntry[ushortProperty]);
                Assert.False(stateEntry.HasTemporaryValue(ushortProperty));
            }

            for (var i = 105; i < 120; i++)
            {
                await generator.NextAsync(stateEntry, sbyteProperty);

                Assert.Equal((sbyte)i, stateEntry[sbyteProperty]);
                Assert.False(stateEntry.HasTemporaryValue(sbyteProperty));
            }
        }