audit, advisories and doctors/setup work
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
using FluentAssertions;
|
||||
using StellaOps.Provcache;
|
||||
using StellaOps.TestKit;
|
||||
using StellaOps.TestKit.Deterministic;
|
||||
using Xunit;
|
||||
|
||||
|
||||
using StellaOps.TestKit;
|
||||
namespace StellaOps.Provcache.Tests;
|
||||
|
||||
/// <summary>
|
||||
@@ -11,6 +11,7 @@ namespace StellaOps.Provcache.Tests;
|
||||
/// </summary>
|
||||
public sealed class EvidenceChunkerTests
|
||||
{
|
||||
private static readonly DateTimeOffset FixedNow = new(2026, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
private readonly ProvcacheOptions _options;
|
||||
private readonly EvidenceChunker _chunker;
|
||||
|
||||
@@ -21,12 +22,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ChunkAsync_ShouldSplitEvidenceIntoMultipleChunks_WhenLargerThanChunkSize()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = new byte[200];
|
||||
Random.Shared.NextBytes(evidence);
|
||||
var evidence = CreateDeterministicBytes(200, 1);
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
// Act
|
||||
@@ -48,12 +48,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ChunkAsync_ShouldCreateSingleChunk_WhenSmallerThanChunkSize()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = new byte[32];
|
||||
Random.Shared.NextBytes(evidence);
|
||||
var evidence = CreateDeterministicBytes(32, 2);
|
||||
const string contentType = "application/json";
|
||||
|
||||
// Act
|
||||
@@ -67,7 +66,7 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ChunkAsync_ShouldHandleEmptyEvidence()
|
||||
{
|
||||
// Arrange
|
||||
@@ -84,7 +83,7 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ChunkAsync_ShouldProduceUniqueHashForEachChunk()
|
||||
{
|
||||
// Arrange - create evidence with distinct bytes per chunk
|
||||
@@ -102,12 +101,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ReassembleAsync_ShouldRecoverOriginalEvidence()
|
||||
{
|
||||
// Arrange
|
||||
var original = new byte[200];
|
||||
Random.Shared.NextBytes(original);
|
||||
var original = CreateDeterministicBytes(200, 3);
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
var chunked = await _chunker.ChunkAsync(original, contentType);
|
||||
@@ -120,12 +118,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ReassembleAsync_ShouldThrow_WhenMerkleRootMismatch()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = new byte[100];
|
||||
Random.Shared.NextBytes(evidence);
|
||||
var evidence = CreateDeterministicBytes(100, 4);
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
var chunked = await _chunker.ChunkAsync(evidence, contentType);
|
||||
@@ -137,12 +134,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ReassembleAsync_ShouldThrow_WhenChunkCorrupted()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = new byte[100];
|
||||
Random.Shared.NextBytes(evidence);
|
||||
var evidence = CreateDeterministicBytes(100, 5);
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
var chunked = await _chunker.ChunkAsync(evidence, contentType);
|
||||
@@ -161,24 +157,23 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void VerifyChunk_ShouldReturnTrue_WhenChunkValid()
|
||||
{
|
||||
// Arrange
|
||||
var data = new byte[32];
|
||||
Random.Shared.NextBytes(data);
|
||||
var data = CreateDeterministicBytes(32, 6);
|
||||
var hash = ComputeHash(data);
|
||||
|
||||
var chunk = new EvidenceChunk
|
||||
{
|
||||
ChunkId = Guid.NewGuid(),
|
||||
ChunkId = CreateGuid(6),
|
||||
ProofRoot = "sha256:test",
|
||||
ChunkIndex = 0,
|
||||
ChunkHash = hash,
|
||||
Blob = data,
|
||||
BlobSize = data.Length,
|
||||
ContentType = "application/octet-stream",
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
CreatedAt = FixedNow
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
@@ -186,20 +181,20 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void VerifyChunk_ShouldReturnFalse_WhenHashMismatch()
|
||||
{
|
||||
// Arrange
|
||||
var chunk = new EvidenceChunk
|
||||
{
|
||||
ChunkId = Guid.NewGuid(),
|
||||
ChunkId = CreateGuid(7),
|
||||
ProofRoot = "sha256:test",
|
||||
ChunkIndex = 0,
|
||||
ChunkHash = "sha256:wrong_hash",
|
||||
Blob = new byte[32],
|
||||
BlobSize = 32,
|
||||
ContentType = "application/octet-stream",
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
CreatedAt = FixedNow
|
||||
};
|
||||
|
||||
// Act & Assert
|
||||
@@ -207,7 +202,7 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ComputeMerkleRoot_ShouldReturnSameResult_ForSameInput()
|
||||
{
|
||||
// Arrange
|
||||
@@ -223,7 +218,7 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ComputeMerkleRoot_ShouldHandleSingleHash()
|
||||
{
|
||||
// Arrange
|
||||
@@ -237,7 +232,7 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public void ComputeMerkleRoot_ShouldHandleOddNumberOfHashes()
|
||||
{
|
||||
// Arrange
|
||||
@@ -252,12 +247,11 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task ChunkStreamAsync_ShouldYieldChunksInOrder()
|
||||
{
|
||||
// Arrange
|
||||
var evidence = new byte[200];
|
||||
Random.Shared.NextBytes(evidence);
|
||||
var evidence = CreateDeterministicBytes(200, 8);
|
||||
using var stream = new MemoryStream(evidence);
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
@@ -277,15 +271,14 @@ public sealed class EvidenceChunkerTests
|
||||
}
|
||||
|
||||
[Trait("Category", TestCategories.Unit)]
|
||||
[Fact]
|
||||
[Fact]
|
||||
public async Task Roundtrip_ShouldPreserveDataIntegrity()
|
||||
{
|
||||
// Arrange - use realistic chunk size
|
||||
var options = new ProvcacheOptions { ChunkSize = 1024 };
|
||||
var chunker = new EvidenceChunker(options);
|
||||
|
||||
var original = new byte[5000]; // ~5 chunks
|
||||
Random.Shared.NextBytes(original);
|
||||
var original = CreateDeterministicBytes(5000, 9); // ~5 chunks
|
||||
const string contentType = "application/octet-stream";
|
||||
|
||||
// Act
|
||||
@@ -302,4 +295,17 @@ public sealed class EvidenceChunkerTests
|
||||
var hash = System.Security.Cryptography.SHA256.HashData(data);
|
||||
return $"sha256:{Convert.ToHexStringLower(hash)}";
|
||||
}
|
||||
|
||||
private static byte[] CreateDeterministicBytes(int length, int seed)
|
||||
{
|
||||
var random = new DeterministicRandom(seed);
|
||||
var data = new byte[length];
|
||||
random.NextBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static Guid CreateGuid(int seed)
|
||||
{
|
||||
return new DeterministicRandom(seed).NextGuid();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user