public async Task ShouldUpdateBlobWhenGeneratingNextIdAfterEndOfBatch() { // Arrange using (var testScope = BuildTestScope()) { var store = await BuildStoreAsync(testScope); var generator = new UniqueIdGenerator(store) { BatchSize = 3 }; // Act await generator.NextIdAsync(testScope.IdScopeName); //1 await generator.NextIdAsync(testScope.IdScopeName); //2 await generator.NextIdAsync(testScope.IdScopeName); //3 await generator.NextIdAsync(testScope.IdScopeName); //4 // Assert Assert.AreEqual("7", await testScope.ReadCurrentPersistedValueAsync()); } }
public async Task ShouldReturnIdsFromThirdBatchIfSecondBatchTakenByAnotherGenerator() { // Arrange using (var testScope = BuildTestScope()) { var store1 = await BuildStoreAsync(testScope); var generator1 = new UniqueIdGenerator(store1) { BatchSize = 3 }; var store2 = await BuildStoreAsync(testScope); var generator2 = new UniqueIdGenerator(store2) { BatchSize = 3 }; // Act await generator1.NextIdAsync(testScope.IdScopeName); //1 await generator1.NextIdAsync(testScope.IdScopeName); //2 await generator1.NextIdAsync(testScope.IdScopeName); //3 await generator2.NextIdAsync(testScope.IdScopeName); //4 var lastId = await generator1.NextIdAsync(testScope.IdScopeName); //7 // Assert Assert.AreEqual(7, lastId); } }
public async Task NextIdShouldReturnNumbersSequentially() { var store = Substitute.For <IOptimisticDataStore>(); store.GetDataAsync("test").Returns(Task.FromResult("0"), Task.FromResult("250")); store.TryOptimisticWriteAsync("test", "3").Returns(Task.FromResult(true)); var subject = new UniqueIdGenerator(store) { BatchSize = 3 }; Assert.AreEqual(0, await subject.NextIdAsync("test")); Assert.AreEqual(1, await subject.NextIdAsync("test")); Assert.AreEqual(2, await subject.NextIdAsync("test")); }
public async Task ShouldSupportUsingMultipleGeneratorsFromMultipleThreads() { // Arrange using (var testScope = BuildTestScope()) { var store = await BuildStoreAsync(testScope); var generator = new UniqueIdGenerator(store) { BatchSize = 1000 }; var store2 = await BuildStoreAsync(testScope); var generator2 = new UniqueIdGenerator(store2) { BatchSize = 1000 }; const int testLength = 10000; // Act var generatedIds = new ConcurrentQueue <long>(); var threadIds = new ConcurrentQueue <int>(); var scopeName = testScope.IdScopeName; var listToExecute = new List <int>(); for (int i = 0; i < testLength; i++) { listToExecute.Add(i); } var tasks = listToExecute.ForEachAsync(10, async item => { var idToAdd = await generator.NextIdAsync(scopeName); generatedIds.Enqueue(idToAdd); threadIds.Enqueue(Thread.CurrentThread.ManagedThreadId); }); var tasks2 = listToExecute.ForEachAsync(10, async item => { var idToAdd = await generator2.NextIdAsync(scopeName); generatedIds.Enqueue(idToAdd); threadIds.Enqueue(Thread.CurrentThread.ManagedThreadId); }); await Task.WhenAll(tasks, tasks2); // Assert we generated the right count of ids Assert.AreEqual(testLength * 2, generatedIds.Count, "wrong number of ids generated"); // Assert there were no duplicates Assert.IsFalse(generatedIds.GroupBy(n => n).Any(g => g.Count() != 1), "duplicated ids were generated"); // Assert we used multiple threads var uniqueThreadsUsed = threadIds.Distinct().Count(); if (uniqueThreadsUsed == 1) { Assert.Inconclusive("The test failed to actually utilize multiple threads. {0} uniqueThreadsUsed", uniqueThreadsUsed); } } }
#pragma warning disable 1998 public async Task NextIdShouldThrowExceptionOnNullData() #pragma warning restore 1998 { var ex = Assert.ThrowsAsync <UniqueIdGenerationException>(async() => { var store = Substitute.For <IOptimisticDataStore>(); store.GetDataAsync("test").Returns(Task.FromResult((string)null)); var generator = new UniqueIdGenerator(store); await generator.NextIdAsync("test"); }); }
public async Task ShouldReturnIdsAcrossMultipleGenerators() { // Arrange using (var testScope = BuildTestScope()) { var store1 = await BuildStoreAsync(testScope); var generator1 = new UniqueIdGenerator(store1) { BatchSize = 3 }; var store2 = await BuildStoreAsync(testScope); var generator2 = new UniqueIdGenerator(store2) { BatchSize = 3 }; // Act var generatedIds = new[] { await generator1.NextIdAsync(testScope.IdScopeName), //1 await generator1.NextIdAsync(testScope.IdScopeName), //2 await generator1.NextIdAsync(testScope.IdScopeName), //3 await generator2.NextIdAsync(testScope.IdScopeName), //4 await generator1.NextIdAsync(testScope.IdScopeName), //7 await generator2.NextIdAsync(testScope.IdScopeName), //5 await generator2.NextIdAsync(testScope.IdScopeName), //6 await generator2.NextIdAsync(testScope.IdScopeName), //10 await generator1.NextIdAsync(testScope.IdScopeName), //8 await generator1.NextIdAsync(testScope.IdScopeName) //9 }; // Assert CollectionAssert.AreEqual( new[] { 1, 2, 3, 4, 7, 5, 6, 10, 8, 9 }, generatedIds); } }
public async Task ShouldInitializeBlobForFirstIdInNewScope() { // Arrange using (var testScope = BuildTestScope()) { var store = await BuildStoreAsync(testScope); var generator = new UniqueIdGenerator(store) { BatchSize = 3 }; // Act await generator.NextIdAsync(testScope.IdScopeName); //1 // Assert Assert.AreEqual("4", await testScope.ReadCurrentPersistedValueAsync()); } }
public async Task ShouldReturnOneForFirstIdInNewScope() { // Arrange using (var testScope = BuildTestScope()) { var store = await BuildStoreAsync(testScope); var generator = new UniqueIdGenerator(store) { BatchSize = 3 }; // Act var generatedId = await generator.NextIdAsync(testScope.IdScopeName); // Assert Assert.AreEqual(1, generatedId); } }
public async Task NextIdShouldThrowExceptionWhenRetriesAreExhausted() { var store = Substitute.For <IOptimisticDataStore>(); store.GetDataAsync("test").Returns(Task.FromResult("0")); store.TryOptimisticWriteAsync("test", "3").Returns(Task.FromResult(false), Task.FromResult(false), Task.FromResult(false), Task.FromResult(true)); var generator = new UniqueIdGenerator(store) { MaxWriteAttempts = 3 }; try { await generator.NextIdAsync("test"); } catch (Exception ex) { StringAssert.StartsWith("Failed to update the data store after 3 attempts.", ex.Message); return; } Assert.Fail("NextId should have thrown and been caught in the try block"); }
public async Task NextIdShouldRollOverToNewBlockWhenCurrentBlockIsExhausted() { var store = Substitute.For <IOptimisticDataStore>(); store.GetDataAsync("test").Returns(Task.FromResult("0"), Task.FromResult("250")); store.TryOptimisticWriteAsync("test", "3").Returns(Task.FromResult(true)); store.TryOptimisticWriteAsync("test", "253").Returns(Task.FromResult(true)); var subject = new UniqueIdGenerator(store) { BatchSize = 3 }; Assert.AreEqual(0, (await subject.NextIdAsync("test"))); Assert.AreEqual(1, (await subject.NextIdAsync("test"))); Assert.AreEqual(2, (await subject.NextIdAsync("test"))); Assert.AreEqual(250, (await subject.NextIdAsync("test"))); Assert.AreEqual(251, (await subject.NextIdAsync("test"))); Assert.AreEqual(252, (await subject.NextIdAsync("test"))); }