Files

132 lines
4.0 KiB
C#

using Microsoft.Data.Sqlite;
using ZB.MOM.WW.LocalDb.Internal;
using ZB.MOM.WW.LocalDb.Registration;
namespace ZB.MOM.WW.LocalDb.Tests;
public sealed class RegistrationTests : IDisposable
{
private readonly string _path = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".db");
public void Dispose()
{
SqliteConnection.ClearAllPools();
if (File.Exists(_path))
File.Delete(_path);
}
private SqliteLocalDb Create() => new(new LocalDbOptions { Path = _path });
private static async Task CreateOrders(SqliteLocalDb db) =>
await db.ExecuteAsync("CREATE TABLE orders (id INTEGER PRIMARY KEY, sku TEXT, qty INTEGER)");
private Task<IReadOnlyList<string>> Triggers(SqliteLocalDb db) =>
db.QueryAsync(
"SELECT name FROM sqlite_master WHERE type='trigger' AND tbl_name='orders' ORDER BY name",
r => r.GetString(0));
[Fact]
public async Task Register_TableWithPk_InstallsThreeTriggers()
{
using var db = Create();
await CreateOrders(db);
db.RegisterReplicated("orders");
var triggers = await Triggers(db);
Assert.Equal(
new[] { "__localdb_orders_ad", "__localdb_orders_ai", "__localdb_orders_au" },
triggers);
}
[Fact]
public async Task Register_NoPk_Throws()
{
using var db = Create();
await db.ExecuteAsync("CREATE TABLE nopk (a TEXT, b TEXT)");
var ex = Assert.Throws<LocalDbRegistrationException>(() => db.RegisterReplicated("nopk"));
Assert.Contains("nopk", ex.Message);
}
[Fact]
public void Register_MissingTable_Throws()
{
using var db = Create();
var ex = Assert.Throws<LocalDbRegistrationException>(() => db.RegisterReplicated("ghost"));
Assert.Contains("ghost", ex.Message);
}
[Fact]
public async Task Register_BlobColumn_Throws()
{
using var db = Create();
await db.ExecuteAsync("CREATE TABLE blobby (id INTEGER PRIMARY KEY, data BLOB)");
var ex = Assert.Throws<LocalDbRegistrationException>(() => db.RegisterReplicated("blobby"));
Assert.Contains("blobby", ex.Message);
Assert.Contains("data", ex.Message);
Assert.Contains("BLOB", ex.Message);
}
[Fact]
public async Task Register_IsIdempotent_RegeneratesTriggers()
{
using var db = Create();
await CreateOrders(db);
db.RegisterReplicated("orders");
db.RegisterReplicated("orders");
var triggers = await Triggers(db);
Assert.Equal(3, triggers.Count);
}
[Fact]
public async Task Register_CompositePk_Works()
{
using var db = Create();
await db.ExecuteAsync("CREATE TABLE kv (a INTEGER, b INTEGER, v TEXT, PRIMARY KEY (a, b))");
db.RegisterReplicated("kv");
await db.ExecuteAsync("INSERT INTO kv (a, b, v) VALUES (1, 2, 'x')");
var pk = await db.QueryAsync(
"SELECT pk_json FROM __localdb_oplog WHERE table_name='kv'",
r => r.GetString(0));
Assert.Single(pk);
Assert.Equal("{\"a\":1,\"b\":2}", pk[0]);
}
[Fact]
public async Task Digest_ChangesWhenSchemaChanges()
{
using var db = Create();
await CreateOrders(db);
db.RegisterReplicated("orders");
var before = db.ReplicatedTables["orders"].Digest;
await db.ExecuteAsync("ALTER TABLE orders ADD COLUMN note TEXT");
db.RegisterReplicated("orders");
var after = db.ReplicatedTables["orders"].Digest;
Assert.NotEqual(before, after);
}
[Fact]
public async Task ReplicatedTables_ExposesRegistry()
{
using var db = Create();
await CreateOrders(db);
db.RegisterReplicated("orders");
var table = db.ReplicatedTables["orders"];
Assert.Equal("orders", table.Name);
Assert.Equal(new[] { "id" }, table.PkColumns);
Assert.Equal(new[] { "id", "sku", "qty" }, table.Columns.Select(c => c.Name).ToArray());
}
}