diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 15924436e7..8d8fd33ac9 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -10,7 +10,7 @@ - + diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs index 2773f92e80..189e212bc2 100644 --- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -21,9 +21,19 @@ public class StoreTest { private const string path_leveldb = "Data_LevelDB_UT"; private const string path_rocksdb = "Data_RocksDB_UT"; + private static LevelDBStore levelDbStore; + private static RocksDBStore rocksDBStore; [TestInitialize] public void OnStart() + { + levelDbStore ??= new LevelDBStore(); + rocksDBStore ??= new RocksDBStore(); + OnEnd(); + } + + [TestCleanup] + public void OnEnd() { if (Directory.Exists(path_leveldb)) Directory.Delete(path_leveldb, true); if (Directory.Exists(path_rocksdb)) Directory.Delete(path_rocksdb, true); @@ -49,35 +59,138 @@ public void TestMemory() [TestMethod] public void TestLevelDb() { - using var plugin = new LevelDBStore(); - TestPersistenceDelete(plugin.GetStore(path_leveldb)); + TestPersistenceDelete(levelDbStore.GetStore(path_leveldb)); // Test all with the same store - TestStorage(plugin.GetStore(path_leveldb)); + TestStorage(levelDbStore.GetStore(path_leveldb)); // Test with different storages - TestPersistenceWrite(plugin.GetStore(path_leveldb)); - TestPersistenceRead(plugin.GetStore(path_leveldb), true); - TestPersistenceDelete(plugin.GetStore(path_leveldb)); - TestPersistenceRead(plugin.GetStore(path_leveldb), false); + TestPersistenceWrite(levelDbStore.GetStore(path_leveldb)); + TestPersistenceRead(levelDbStore.GetStore(path_leveldb), true); + TestPersistenceDelete(levelDbStore.GetStore(path_leveldb)); + TestPersistenceRead(levelDbStore.GetStore(path_leveldb), false); + } + + [TestMethod] + public void TestLevelDbSnapshot() + { + using var store = levelDbStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + // Data saved to the leveldb snapshot shall not be visible to the store + Assert.IsNull(snapshot.TryGet(testKey)); + + // Value is in the write batch, not visible to the store and snapshot + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(false, store.Contains(testKey)); + + snapshot.Commit(); + + // After commit, the data shall be visible to the store but not to the snapshot + Assert.IsNull(snapshot.TryGet(testKey)); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(true, store.Contains(testKey)); + + snapshot.Dispose(); + } + + [TestMethod] + public void TestLevelDbMultiSnapshot() + { + using var store = levelDbStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + snapshot.Commit(); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + + var snapshot2 = store.GetSnapshot(); + + // Data saved to the leveldb from snapshot1 shall be visible to snapshot2 but not visible to snapshot1 + CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey)); + Assert.IsNull(snapshot.TryGet(testKey)); + + snapshot.Dispose(); + snapshot2.Dispose(); } [TestMethod] public void TestRocksDb() { - using var plugin = new RocksDBStore(); - TestPersistenceDelete(plugin.GetStore(path_rocksdb)); + TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb)); // Test all with the same store - TestStorage(plugin.GetStore(path_rocksdb)); + TestStorage(rocksDBStore.GetStore(path_rocksdb)); // Test with different storages - TestPersistenceWrite(plugin.GetStore(path_rocksdb)); - TestPersistenceRead(plugin.GetStore(path_rocksdb), true); - TestPersistenceDelete(plugin.GetStore(path_rocksdb)); - TestPersistenceRead(plugin.GetStore(path_rocksdb), false); + TestPersistenceWrite(rocksDBStore.GetStore(path_rocksdb)); + TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), true); + TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb)); + TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), false); + } + + [TestMethod] + public void TestRocksDbSnapshot() + { + using var store = rocksDBStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + // Data saved to the leveldb snapshot shall not be visible + Assert.IsNull(snapshot.TryGet(testKey)); + Assert.IsNull(store.TryGet(testKey)); + + // Value is in the write batch, not visible to the store and snapshot + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(false, store.Contains(testKey)); + + snapshot.Commit(); + + // After commit, the data shall be visible to the store but not to the snapshot + Assert.IsNull(snapshot.TryGet(testKey)); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(true, store.Contains(testKey)); + + snapshot.Dispose(); + } + + [TestMethod] + public void TestRocksDbMultiSnapshot() + { + using var store = rocksDBStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + snapshot.Commit(); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + + var snapshot2 = store.GetSnapshot(); + // Data saved to the leveldb from snapshot1 shall only be visible to snapshot2 + CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey)); + + snapshot.Dispose(); + snapshot2.Dispose(); } ///