public void DeleteIfLatestWithoutCurrentData_Deletes_IfOlderConcurrentlyExists() { // Arrange IVersionMetadataMapper versionMapper = CreateMapper(); string id = "Id"; ConcurrentInnerStore innerStore = new ConcurrentInnerStore(id, new ConcurrentMetadataText("1", CreateMetadata(DateTimeOffset.MinValue, versionMapper, "ExistingKey", "ExistingValue"), "ExistingText")); IDictionary<string, string> updatedMetadata = CreateMetadata(DateTimeOffset.Now, versionMapper, "UpdatedKey", "UpdatedValue"); string updatedText = "UpdatedText"; innerStore.OnReadingMetadata += (calls) => { if (calls == 0) { Assert.True(innerStore.TryUpdate(id, "1", updatedMetadata, updatedText)); } }; IVersionedMetadataTextStore product = CreateProductUnderTest(innerStore, versionMapper); // Act bool isLatest = product.DeleteIfLatest(id, DateTimeOffset.MaxValue); // Assert Assert.True(isLatest); ConcurrentMetadataText storedItem = innerStore.Read(id); Assert.Null(storedItem); }
public void DeleteIfLatestWithoutCurrentData_Throws_IfStopsMakingProgress() { // Arrange IVersionMetadataMapper versionMapper = CreateMapper(); string id = "Id"; ConcurrentInnerStore innerStore = new ConcurrentInnerStore(id, new ConcurrentMetadataText("1", CreateMetadata(DateTimeOffset.MinValue, versionMapper, "ExistingKey", "ExistingValue"), "ExistingText")); IDictionary<string, string> updatedMetadata = CreateMetadata(DateTimeOffset.Now, versionMapper, "UpdatedKey", "UpdatedValue"); string updatedText = "UpdatedText"; // Simulate an erroneous inner store that returns false from TryDelete even though the ETag has not changed. // A correct inner store would throw rather that return false if retrying can't help. innerStore.OnReadingMetadata += (calls) => { if (calls == 1) { Assert.True(innerStore.TryDelete(id, "2")); Assert.True(innerStore.TryCreate(id, updatedMetadata, updatedText)); } }; innerStore.OnReadMetadata += (calls) => { if (calls == 0) { Assert.True(innerStore.TryUpdate(id, "1", updatedMetadata, updatedText)); } }; IVersionedMetadataTextStore product = CreateProductUnderTest(innerStore, versionMapper); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => product.DeleteIfLatest(id, DateTimeOffset.MaxValue), "The operation stopped making progress."); }
public void CreateOrUpdateIfLatest_Updates_IfOlderConcurrentlyExists() { // Arrange IVersionMetadataMapper versionMapper = CreateMapper(); string id = "Id"; ConcurrentInnerStore innerStore = new ConcurrentInnerStore(id, new ConcurrentMetadataText("1", CreateMetadata(DateTimeOffset.Now, versionMapper, "ExistingKey", "ExistingValue"), "ExistingText")); IDictionary<string, string> updatedMetadata = CreateMetadata(DateTimeOffset.Now, versionMapper, "UpdatedKey", "UpdatedValue"); string updatedText = "UpdatedText"; innerStore.OnReadMetadata += (calls) => { if (calls == 0) { Assert.True(innerStore.TryUpdate(id, "1", updatedMetadata, updatedText)); } }; IVersionedMetadataTextStore product = CreateProductUnderTest(innerStore, versionMapper); DateTimeOffset newVersion = DateTimeOffset.MaxValue; IDictionary<string, string> newOtherMetadata = CreateMetadata("NewKey", "NewValue"); string newText = "NewText"; // Act bool isLatest = product.CreateOrUpdateIfLatest(id, newVersion, newOtherMetadata, newText); // Assert Assert.True(isLatest); ConcurrentMetadataText storedItem = innerStore.Read(id); IDictionary<string, string> expectedMetadata = CreateMetadata(newVersion, versionMapper, newOtherMetadata); ConcurrentMetadataText expectedItem = new ConcurrentMetadataText("3", expectedMetadata, newText); AssertEqual(expectedItem, storedItem); }