fix(A.5 T10-T12): Start() race + null mesh test + real mesh stub
Code review on T10-T12 bundle (commits 0cf86bb/00bb030/0405947 + audit
fix 76e1a64) found 3 Important issues:
1. LandblockStreamer.Start() had an idempotency race — the XML doc
claimed thread-safety but the implementation checked _worker != null
before assigning, allowing two callers to both pass the check and
spawn duplicate worker threads. Fixed via Interlocked.CompareExchange.
2. No test verified the worker emits Failed when buildMeshOrNull returns
null. Added Load_WhenBuildMeshReturnsNull_ReportsFailed.
3. StreamingControllerTests.cs:81 used MeshData: default! when
constructing a Loaded result. If a future test flows MeshData
through the apply callback, the null reference would NRE rather
than producing a meaningful assertion failure. Replaced with a real
empty LandblockMeshData instance.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
76e1a64d78
commit
774a7070a8
3 changed files with 52 additions and 6 deletions
|
|
@ -66,6 +66,39 @@ public class LandblockStreamerTests
|
|||
Assert.IsType<LandblockStreamResult.Failed>(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Load_WhenBuildMeshReturnsNull_ReportsFailed()
|
||||
{
|
||||
// Phase A.5 T10-T12 follow-up: the mesh-build factory may return
|
||||
// null (e.g., LandBlock dat missing or corrupt). The worker must
|
||||
// emit Failed in that case instead of constructing Loaded with a
|
||||
// null MeshData (which would NRE downstream).
|
||||
var stubLandblock = new LoadedLandblock(
|
||||
0xABCDFFFEu,
|
||||
new LandBlock(),
|
||||
System.Array.Empty<WorldEntity>());
|
||||
|
||||
using var streamer = new LandblockStreamer(
|
||||
loadLandblock: _ => stubLandblock,
|
||||
buildMeshOrNull: (_, _) => null); // mesh-build returns null
|
||||
|
||||
streamer.Start();
|
||||
streamer.EnqueueLoad(0xABCDFFFEu);
|
||||
|
||||
LandblockStreamResult? result = null;
|
||||
for (int i = 0; i < SpinMaxIterations && result is null; i++)
|
||||
{
|
||||
var drained = streamer.DrainCompletions(LandblockStreamer.DefaultDrainBatchSize);
|
||||
if (drained.Count > 0) result = drained[0];
|
||||
else await Task.Delay(SpinStepMs);
|
||||
}
|
||||
|
||||
Assert.NotNull(result);
|
||||
var failed = Assert.IsType<LandblockStreamResult.Failed>(result);
|
||||
Assert.Equal(0xABCDFFFEu, failed.LandblockId);
|
||||
Assert.Contains("mesh", failed.Error, System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Load_WhenLoaderThrows_ReportsFailedWithMessage()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue