167 lines
5.5 KiB
C#
167 lines
5.5 KiB
C#
using System.IO.Compression;
|
|
using ZB.MOM.WW.CBDD.Core.Compression;
|
|
using ZB.MOM.WW.CBDD.Core.Storage;
|
|
using ZB.MOM.WW.CBDD.Shared;
|
|
|
|
namespace ZB.MOM.WW.CBDD.Tests;
|
|
|
|
public class MaintenanceDiagnosticsAndMigrationTests
|
|
{
|
|
/// <summary>
|
|
/// Verifies diagnostics APIs return page usage, compression, and fragmentation data.
|
|
/// </summary>
|
|
[Fact]
|
|
public void DiagnosticsApis_ShouldReturnPageUsageCompressionAndFragmentationData()
|
|
{
|
|
var dbPath = NewDbPath();
|
|
|
|
try
|
|
{
|
|
var options = new CompressionOptions
|
|
{
|
|
EnableCompression = true,
|
|
MinSizeBytes = 0,
|
|
MinSavingsPercent = 0,
|
|
Codec = CompressionCodec.Brotli,
|
|
Level = CompressionLevel.Fastest
|
|
};
|
|
|
|
using var db = new TestDbContext(dbPath, options);
|
|
for (var i = 0; i < 40; i++)
|
|
{
|
|
db.Users.Insert(new User
|
|
{
|
|
Name = BuildPayload(i, 9000),
|
|
Age = i
|
|
});
|
|
}
|
|
|
|
db.SaveChanges();
|
|
db.ForceCheckpoint();
|
|
|
|
var byType = db.GetPageUsageByPageType();
|
|
byType.Count.ShouldBeGreaterThan(0);
|
|
byType.Any(x => x.PageType == PageType.Data && x.PageCount > 0).ShouldBeTrue();
|
|
|
|
var byCollection = db.GetPageUsageByCollection();
|
|
byCollection.Any(x => x.CollectionName.Equals("users", StringComparison.OrdinalIgnoreCase)).ShouldBeTrue();
|
|
|
|
var compressionByCollection = db.GetCompressionRatioByCollection();
|
|
var usersCompression = compressionByCollection.First(x => x.CollectionName.Equals("users", StringComparison.OrdinalIgnoreCase));
|
|
usersCompression.DocumentCount.ShouldBeGreaterThan(0);
|
|
usersCompression.BytesBeforeCompression.ShouldBeGreaterThan(0);
|
|
usersCompression.BytesAfterCompression.ShouldBeGreaterThan(0);
|
|
|
|
var freeList = db.GetFreeListSummary();
|
|
freeList.PageCount.ShouldBeGreaterThan(0u);
|
|
|
|
var fragmentation = db.GetFragmentationMap();
|
|
fragmentation.Pages.Count.ShouldBeGreaterThan(0);
|
|
}
|
|
finally
|
|
{
|
|
CleanupFiles(dbPath);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies compression migration dry-run and apply modes return deterministic stats and preserve data.
|
|
/// </summary>
|
|
[Fact]
|
|
public void MigrateCompression_DryRunAndApply_ShouldReturnDeterministicStatsAndPreserveData()
|
|
{
|
|
var dbPath = NewDbPath();
|
|
|
|
try
|
|
{
|
|
using var db = new TestDbContext(dbPath, CompressionOptions.Default);
|
|
var ids = new List<ZB.MOM.WW.CBDD.Bson.ObjectId>();
|
|
|
|
for (var i = 0; i < 60; i++)
|
|
{
|
|
ids.Add(db.Users.Insert(new User
|
|
{
|
|
Name = BuildPayload(i, 12000),
|
|
Age = i % 17
|
|
}));
|
|
}
|
|
|
|
db.SaveChanges();
|
|
db.ForceCheckpoint();
|
|
|
|
var dryRun = db.MigrateCompression(new CompressionMigrationOptions
|
|
{
|
|
DryRun = true,
|
|
Codec = CompressionCodec.Deflate,
|
|
Level = CompressionLevel.Fastest,
|
|
MinSizeBytes = 0,
|
|
MinSavingsPercent = 0,
|
|
IncludeCollections = ["users"]
|
|
});
|
|
|
|
dryRun.DryRun.ShouldBeTrue();
|
|
dryRun.DocumentsScanned.ShouldBeGreaterThan(0);
|
|
dryRun.BytesBefore.ShouldBeGreaterThan(0);
|
|
dryRun.BytesEstimatedAfter.ShouldBeGreaterThan(0);
|
|
|
|
var apply = db.MigrateCompression(new CompressionMigrationOptions
|
|
{
|
|
DryRun = false,
|
|
Codec = CompressionCodec.Deflate,
|
|
Level = CompressionLevel.Fastest,
|
|
MinSizeBytes = 0,
|
|
MinSavingsPercent = 0,
|
|
IncludeCollections = ["users"]
|
|
});
|
|
|
|
apply.DryRun.ShouldBeFalse();
|
|
apply.DocumentsScanned.ShouldBeGreaterThan(0);
|
|
|
|
foreach (var id in ids)
|
|
{
|
|
var user = db.Users.FindById(id);
|
|
user.ShouldNotBeNull();
|
|
user!.Name.Length.ShouldBeGreaterThan(1000);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
CleanupFiles(dbPath);
|
|
}
|
|
}
|
|
|
|
private static string BuildPayload(int seed, int approxLength)
|
|
{
|
|
var builder = new System.Text.StringBuilder(approxLength + 128);
|
|
var i = 0;
|
|
while (builder.Length < approxLength)
|
|
{
|
|
builder.Append("diag-migrate-");
|
|
builder.Append(seed.ToString("D4"));
|
|
builder.Append('-');
|
|
builder.Append(i.ToString("D6"));
|
|
builder.Append('|');
|
|
i++;
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
private static string NewDbPath()
|
|
=> Path.Combine(Path.GetTempPath(), $"maint_diag_migrate_{Guid.NewGuid():N}.db");
|
|
|
|
private static void CleanupFiles(string dbPath)
|
|
{
|
|
var walPath = Path.ChangeExtension(dbPath, ".wal");
|
|
var markerPath = $"{dbPath}.compact.state";
|
|
var tempPath = $"{dbPath}.compact.tmp";
|
|
var backupPath = $"{dbPath}.compact.bak";
|
|
|
|
if (File.Exists(dbPath)) File.Delete(dbPath);
|
|
if (File.Exists(walPath)) File.Delete(walPath);
|
|
if (File.Exists(markerPath)) File.Delete(markerPath);
|
|
if (File.Exists(tempPath)) File.Delete(tempPath);
|
|
if (File.Exists(backupPath)) File.Delete(backupPath);
|
|
}
|
|
}
|