tests/SboxSuperuser.Contracts.Tests/AuditStoreHarness.cs

A test harness implementing IAdminStore, IAuditRetention and IStoreRetentionFiles used by unit tests. It wraps an in-memory file store and a StoreCoordinator to simulate reads, writes and pruning of audit history, and exposes hooks (BeforeWrite, BeforeDelete) and counters for writes and prunes.

File Access
using SboxSuperuser.Core.Storage;
using SboxSuperuser.Engine.Audit;

namespace SboxSuperuser.Contracts.Tests;

internal sealed class AuditStoreHarness : IAdminStore, IAuditRetention, IStoreRetentionFiles
{
	internal MemoryStoreFiles Files { get; } = new();
	internal StoreCoordinator Coordinator { get; }
	internal Func<StoreWriteRequest, Task<StoreWriteStatus?>> BeforeWrite;
	internal Action<string> BeforeDelete;
	internal int Writes;
	internal int Prunes;
	internal AuditStoreHarness() => Coordinator = new( this, () => true );

	public async Task<StoreReadResult> ReadAsync( StoreKey key, int schema, CancellationToken cancellation )
	{
		var result = await Coordinator.ReadAsync( Path( key ), schema, cancellation );
		return new StoreReadResult( Enum.Parse<StoreReadStatus>( result.Status.ToString() ), result.Document is null ? null
			: new VersionedStoreDocument( result.Document.SchemaVersion, result.Document.Revision, result.Document.PayloadJson ) );
	}

	public async Task<StoreWriteResult> WriteAsync( StoreWriteRequest request, CancellationToken cancellation )
	{
		Writes++;
		var injected = BeforeWrite is null ? null : await BeforeWrite( request );
		if ( injected.HasValue )
		{
			return new StoreWriteResult( injected.Value );
		}

		var result = await Coordinator.WriteAsync( Path( request.Key ), 1, request.ExpectedRevision, request.Document.PayloadJson, cancellation );
		return new StoreWriteResult( Enum.Parse<StoreWriteStatus>( result.Status.ToString() ), result.Status == StorageStatus.Committed ? result.Document.Revision : null );
	}

	public Task<StoragePruneResult> PruneAuditAsync( long revision, CancellationToken cancellation )
	{
		Prunes++;
		return Coordinator.PruneAuditHistoryAsync( "audit/journal", revision, cancellation );
	}

	private static string Path( StoreKey key ) => key.ModuleId + "/" + key.DocumentId;
	public bool DirectoryExists( string path ) => Files.DirectoryExists( path );
	public bool FileExists( string path ) => Files.FileExists( path );
	public void CreateDirectory( string path ) => Files.CreateDirectory( path );
	public IReadOnlyList<string> ListFiles( string path ) => Files.ListFiles( path );
	public string Read( string path ) => Files.Read( path );
	public Task WriteNewAsync( string path, string content, CancellationToken cancellation ) => Files.WriteNewAsync( path, content, cancellation );
	public void DeleteFile( string path )
	{
		BeforeDelete?.Invoke( path );
		Files.Files.Remove( path );
	}
}