Initialize CBDD solution and add a .NET-focused gitignore for generated artifacts.
This commit is contained in:
211
tests/CBDD.Tests/StorageEngineTransactionProtocolTests.cs
Normal file
211
tests/CBDD.Tests/StorageEngineTransactionProtocolTests.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using ZB.MOM.WW.CBDD.Core.Storage;
|
||||
using ZB.MOM.WW.CBDD.Core.Transactions;
|
||||
|
||||
namespace ZB.MOM.WW.CBDD.Tests;
|
||||
|
||||
public class StorageEngineTransactionProtocolTests
|
||||
{
|
||||
[Fact]
|
||||
public void PrepareTransaction_Should_ReturnFalse_For_Unknown_Transaction()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
storage.PrepareTransaction(999_999).ShouldBeFalse();
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CommitTransaction_With_TransactionObject_Should_Throw_When_Not_Active()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
var detached = new Transaction(123, storage);
|
||||
|
||||
Should.Throw<InvalidOperationException>(() => storage.CommitTransaction(detached));
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CommitTransaction_With_TransactionObject_Should_Commit_Writes()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
using var txn = storage.BeginTransaction();
|
||||
|
||||
var pageId = storage.AllocatePage();
|
||||
var data = new byte[storage.PageSize];
|
||||
data[0] = 0xAB;
|
||||
|
||||
storage.WritePage(pageId, txn.TransactionId, data);
|
||||
storage.CommitTransaction(txn);
|
||||
|
||||
storage.ActiveTransactionCount.ShouldBe(0);
|
||||
|
||||
var readBuffer = new byte[storage.PageSize];
|
||||
storage.ReadPage(pageId, 0, readBuffer);
|
||||
readBuffer[0].ShouldBe((byte)0xAB);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CommitTransaction_ById_With_NoWrites_Should_Not_Throw()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
storage.CommitTransaction(424242);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MarkTransactionCommitted_Should_Move_Cache_And_Clear_ActiveCount()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
using var txn = storage.BeginTransaction();
|
||||
|
||||
var pageId = storage.AllocatePage();
|
||||
var data = new byte[storage.PageSize];
|
||||
data[5] = 0x5A;
|
||||
storage.WritePage(pageId, txn.TransactionId, data);
|
||||
|
||||
storage.ActiveTransactionCount.ShouldBe(1);
|
||||
storage.MarkTransactionCommitted(txn.TransactionId);
|
||||
storage.ActiveTransactionCount.ShouldBe(0);
|
||||
|
||||
var readBuffer = new byte[storage.PageSize];
|
||||
storage.ReadPage(pageId, 0, readBuffer);
|
||||
readBuffer[5].ShouldBe((byte)0x5A);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RollbackTransaction_Should_Discard_Uncommitted_Write()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
|
||||
var pageId = storage.AllocatePage();
|
||||
var baseline = new byte[storage.PageSize];
|
||||
baseline[0] = 0x11;
|
||||
storage.WritePageImmediate(pageId, baseline);
|
||||
|
||||
using var txn = storage.BeginTransaction();
|
||||
var changed = new byte[storage.PageSize];
|
||||
changed[0] = 0x99;
|
||||
storage.WritePage(pageId, txn.TransactionId, changed);
|
||||
|
||||
storage.ActiveTransactionCount.ShouldBe(1);
|
||||
storage.RollbackTransaction(txn.TransactionId);
|
||||
storage.ActiveTransactionCount.ShouldBe(0);
|
||||
|
||||
var readBuffer = new byte[storage.PageSize];
|
||||
storage.ReadPage(pageId, 0, readBuffer);
|
||||
readBuffer[0].ShouldBe((byte)0x11);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Transaction_MarkCommitted_Should_Transition_State()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
using var txn = storage.BeginTransaction();
|
||||
|
||||
var pageId = storage.AllocatePage();
|
||||
var data = new byte[storage.PageSize];
|
||||
data[3] = 0x33;
|
||||
storage.WritePage(pageId, txn.TransactionId, data);
|
||||
|
||||
txn.MarkCommitted();
|
||||
|
||||
txn.State.ShouldBe(TransactionState.Committed);
|
||||
storage.ActiveTransactionCount.ShouldBe(0);
|
||||
|
||||
var readBuffer = new byte[storage.PageSize];
|
||||
storage.ReadPage(pageId, 0, readBuffer);
|
||||
readBuffer[3].ShouldBe((byte)0x33);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Transaction_Prepare_Should_Write_Wal_And_Transition_State()
|
||||
{
|
||||
var dbPath = NewDbPath();
|
||||
try
|
||||
{
|
||||
using var storage = new StorageEngine(dbPath, PageFileConfig.Default);
|
||||
using var txn = storage.BeginTransaction();
|
||||
|
||||
var pageId = storage.AllocatePage();
|
||||
var data = new byte[storage.PageSize];
|
||||
data[11] = 0x7B;
|
||||
storage.WritePage(pageId, txn.TransactionId, data);
|
||||
|
||||
txn.Prepare().ShouldBeTrue();
|
||||
txn.State.ShouldBe(TransactionState.Preparing);
|
||||
|
||||
txn.Commit();
|
||||
txn.State.ShouldBe(TransactionState.Committed);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CleanupFiles(dbPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static string NewDbPath()
|
||||
=> Path.Combine(Path.GetTempPath(), $"storage_txn_{Guid.NewGuid():N}.db");
|
||||
|
||||
private static void CleanupFiles(string dbPath)
|
||||
{
|
||||
if (File.Exists(dbPath)) File.Delete(dbPath);
|
||||
|
||||
var walPath = Path.ChangeExtension(dbPath, ".wal");
|
||||
if (File.Exists(walPath)) File.Delete(walPath);
|
||||
|
||||
var altWalPath = dbPath + "-wal";
|
||||
if (File.Exists(altWalPath)) File.Delete(altWalPath);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user