public Task Write(StoreItems changes) { lock (_syncroot) { foreach (var change in changes) { IStoreItem newValue = change.Value as IStoreItem; IStoreItem oldValue = null; if (_memory.TryGetValue(change.Key, out object x)) { oldValue = x as IStoreItem; } if (oldValue == null || newValue.eTag == "*" || oldValue.eTag == newValue.eTag) { // clone and set etag newValue = FlexObject.Clone <IStoreItem>(newValue); newValue.eTag = (_eTag++).ToString(); _memory[change.Key] = newValue; } else { throw new Exception("etag conflict"); } } } return(Task.CompletedTask); }
public Task <StoreItems> Read(string[] keys) { var storeItems = new StoreItems(); lock (_syncroot) { foreach (var key in keys) { if (_memory.TryGetValue(key, out object value)) { if (value != null) { storeItems[key] = FlexObject.Clone(value); } else { storeItems[key] = null; } } } } return(Task.FromResult(storeItems)); }
protected async Task _updateObjectTest(IStorage storage) { dynamic storeItems = new StoreItems(); storeItems.updatePocoItem = new PocoItem() { Id = "1", Count = 1 }; storeItems.updatePocoStoreItem = new PocoStoreItem() { Id = "1", Count = 1 }; storeItems.updateStoreItem = new StoreItem(); storeItems.updateStoreItem.Id = "3"; storeItems.updateStoreItem.Count = 1; //first write should work await storage.Write(storeItems); dynamic result = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray()); Assert.IsNotNull(result.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be null"); Assert.IsNotNull(result.updateStoreItem.eTag, "updateStoreItem.eTag should not be null"); // 2nd write should work, because we have new etag, or no etag result.updatePocoItem.Count++; result.updatePocoStoreItem.Count++; result.updateStoreItem.Count++; await storage.Write(result); dynamic result2 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray()); Assert.IsNotNull(result2.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be null"); Assert.IsNotNull(result2.updateStoreItem.eTag, "updateStoreItem.eTag should not be null"); Assert.AreNotEqual(result.updatePocoStoreItem.eTag, result2.updatePocoStoreItem.eTag, "updatePocoItem.eTag should not be different"); Assert.AreNotEqual(result.updateStoreItem.eTag, result2.updateStoreItem.eTag, "updateStoreItem.eTag should not be different"); Assert.AreEqual(result2.updatePocoItem.Count, 2, "updatePocoItem.Count should be 2"); Assert.AreEqual(result2.updatePocoStoreItem.Count, 2, "updatePocoStoreItem.Count should be 2"); Assert.AreEqual(result2.updateStoreItem.Count, 2, "updateStoreItem.Count should be 2"); // write with old etag should succeed for updatePocoItem, but fail for the other 2 try { dynamic storeItemsUpdate = new StoreItems(); storeItemsUpdate.updatePocoItem = result.updatePocoItem; storeItemsUpdate.updatePocoItem.Count++; await storage.Write(storeItemsUpdate); } catch { Assert.Fail("Should not throw exception on write with pocoItem"); } try { dynamic storeItemsUpdate = new StoreItems(); storeItemsUpdate.updatePocoStoreItem = result.updatePocoStoreItem; storeItemsUpdate.updatePocoStoreItem.Count++; await storage.Write(storeItemsUpdate); Assert.Fail("Should not throw exception on write with pocoStoreItem because of old etag"); } catch { } try { dynamic storeItemsUpdate = new StoreItems(); storeItemsUpdate.updateStoreItem = result.updateStoreItem; storeItemsUpdate.updateStoreItem.Count++; await storage.Write(storeItemsUpdate); Assert.Fail("Should not throw exception on write with StoreItem because of old etag"); } catch { } dynamic result3 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray()); Assert.AreEqual(result3.updatePocoItem.Count, 3, "updatePocoItem.Count should be 3"); Assert.AreEqual(result3.updatePocoStoreItem.Count, 2, "updatePocoStoreItem.Count should be 2"); Assert.AreEqual(result3.updateStoreItem.Count, 2, "updateStoreItem.Count should be 2"); // write with wildcard etag should work result3.updatePocoItem.Count = 100; result3.updatePocoStoreItem.Count = 100; result3.updatePocoStoreItem.eTag = "*"; result3.updateStoreItem.Count = 100; result3.updateStoreItem.eTag = "*"; await storage.Write(result3); dynamic result4 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray()); Assert.AreEqual(result3.updatePocoItem.Count, 100, "updatePocoItem.Count should be 100"); Assert.AreEqual(result3.updatePocoStoreItem.Count, 100, "updatePocoStoreItem.Count should be 100"); Assert.AreEqual(result3.updateStoreItem.Count, 100, "updateStoreItem.Count should be 100"); // write with empty etag should not work try { dynamic storeItemsUpdate = new StoreItems(); storeItemsUpdate.updatePocoStoreItem = FlexObject.Clone(result4.updatePocoStoreItem); storeItemsUpdate.updatePocoStoreItem.eTag = ""; await storage.Write(result); Assert.Fail("Should not throw exception on write with pocoStoreItem because of empty etag"); } catch { } try { dynamic storeItemsUpdate = new StoreItems(); storeItemsUpdate.updateStoreItem = FlexObject.Clone(result4.updateStoreItem); storeItemsUpdate.updateStoreItem.eTag = ""; await storage.Write(result); Assert.Fail("Should not throw exception on write with storeItem because of empty etag"); } catch { } dynamic result5 = await storage.Read(((StoreItems)storeItems).GetDynamicMemberNames().ToArray()); Assert.AreEqual(result3.updatePocoItem.Count, 100, "updatePocoItem.Count should be 100"); Assert.AreEqual(result3.updatePocoStoreItem.Count, 100, "updatePocoStoreItem.Count should be 100"); Assert.AreEqual(result3.updateStoreItem.Count, 100, "updateStoreItem.Count should be 100"); }