public void Generates_sequential_values_with_larger_block_size()
        {
            var blockSize           = 10;
            var incrementingValue   = 0L;
            var dbConfigurationMock = new Mock <DbContextConfiguration>();
            var redisDatabaseMock   = new Mock <RedisDatabase>(dbConfigurationMock.Object);

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

            var generator  = new RedisSequenceValueGenerator(redisDatabaseMock.Object, "TestSequenceName", blockSize);
            var stateEntry = TestHelpers.CreateStateEntry <AnEntity>(_model);

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

            for (var l = 0L; l < 100L; l++)
            {
                generator.Next(stateEntry, property);

                Assert.Equal(l, stateEntry[property]);
                Assert.False(stateEntry.HasTemporaryValue(property));
            }
        }
        public void Multiple_threads_can_use_the_same_generator()
        {
            var incrementingValue   = 0L;
            var dbConfigurationMock = new Mock <DbContextConfiguration>();
            var redisDatabaseMock   = new Mock <RedisDatabase>(dbConfigurationMock.Object);

            redisDatabaseMock
            .Setup(db => db.GetNextGeneratedValue(It.IsAny <IProperty>(), It.IsAny <long>(), It.IsAny <string>()))
            .Returns <IProperty, long, string>((p, l, s) =>
            {
                var originalValue  = incrementingValue;
                incrementingValue += l;
                return(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 Action[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]           = () =>
                {
                    var stateEntry = TestHelpers.CreateStateEntry <AnEntity>(_model);

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

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

            Parallel.Invoke(tests);

            // 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 void Throws_when_type_conversion_would_overflow()
        {
            var incrementingValue   = 256L;
            var dbConfigurationMock = new Mock <DbContextConfiguration>();
            var redisDatabaseMock   = new Mock <RedisDatabase>(dbConfigurationMock.Object);

            redisDatabaseMock
            .Setup(db => db.GetNextGeneratedValue(It.IsAny <IProperty>(), It.IsAny <long>(), It.IsAny <string>()))
            .Returns <IProperty, long, string>((p, l, s) => incrementingValue);

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

            var stateEntry   = TestHelpers.CreateStateEntry <AnEntity>(_model);
            var byteProperty = stateEntry.EntityType.GetProperty("Byte");

            Assert.Throws <OverflowException>(() => generator.Next(stateEntry, byteProperty));
        }
        public void Generates_sequential_values()
        {
            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.GetNextGeneratedValue(It.IsAny <IProperty>(), It.IsAny <long>(), It.IsAny <string>()))
            .Returns <IProperty, long, string>((p, l, s) =>
            {
                var originalValue  = incrementingValue;
                incrementingValue += l;
                return(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++)
            {
                generator.Next(stateEntry, intProperty);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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