fix: complete retail parity stability pass
This commit is contained in:
parent
d3df4cb20a
commit
f7aa8e0eb7
131 changed files with 7765 additions and 1190 deletions
|
|
@ -142,11 +142,6 @@ public sealed class DatSoundCacheTests
|
|||
[Trait("Status", "KnownFailure")]
|
||||
public void GetWave_ConcurrentSameId_PublishesOneCanonicalWaveAndDecodesOnce()
|
||||
{
|
||||
// #321: a stale caller can pass the resident-cache check, pause, and
|
||||
// reach _inflight after the winning caller has decoded, admitted, and
|
||||
// removed its Lazy. That second Lazy performs a duplicate decode.
|
||||
// R3 preserves this product defect as an explicit known-failure lane;
|
||||
// fixing the cache algorithm is outside the test-only cleanup scope.
|
||||
var dats = new FakeDatObjectSource();
|
||||
dats.AddWave(1, MakePcmWave(1, dataBytes: 1000));
|
||||
var cache = new DatSoundCache(dats, maxWaveBytes: 10_000);
|
||||
|
|
@ -161,6 +156,55 @@ public sealed class DatSoundCacheTests
|
|||
Assert.Equal(1, dats.GetCallCount(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetWave_StaleMissCannotDecodeAgainAfterWinnerPublishes()
|
||||
{
|
||||
using var winnerDecodeEntered = new ManualResetEventSlim();
|
||||
using var releaseWinnerDecode = new ManualResetEventSlim();
|
||||
using var staleMissParked = new ManualResetEventSlim();
|
||||
using var releaseStaleMiss = new ManualResetEventSlim();
|
||||
|
||||
var dats = new FakeDatObjectSource
|
||||
{
|
||||
BeforeWaveGet = _ =>
|
||||
{
|
||||
winnerDecodeEntered.Set();
|
||||
if (!releaseWinnerDecode.Wait(TimeSpan.FromSeconds(5)))
|
||||
throw new TimeoutException("winner decode was never released");
|
||||
},
|
||||
};
|
||||
dats.AddWave(1, MakePcmWave(1, dataBytes: 1000));
|
||||
|
||||
int initialMissOrdinal = 0;
|
||||
var cache = new DatSoundCache(
|
||||
dats,
|
||||
maxWaveBytes: 10_000,
|
||||
afterInitialWaveMiss: _ =>
|
||||
{
|
||||
if (Interlocked.Increment(ref initialMissOrdinal) != 2)
|
||||
return;
|
||||
|
||||
staleMissParked.Set();
|
||||
if (!releaseStaleMiss.Wait(TimeSpan.FromSeconds(5)))
|
||||
throw new TimeoutException("stale miss was never released");
|
||||
});
|
||||
|
||||
Task<WaveData?> winner = Task.Run(() => cache.GetWave(1));
|
||||
Assert.True(winnerDecodeEntered.Wait(TimeSpan.FromSeconds(5)));
|
||||
|
||||
Task<WaveData?> stale = Task.Run(() => cache.GetWave(1));
|
||||
Assert.True(staleMissParked.Wait(TimeSpan.FromSeconds(5)));
|
||||
|
||||
releaseWinnerDecode.Set();
|
||||
WaveData? canonical = await winner;
|
||||
releaseStaleMiss.Set();
|
||||
WaveData? recovered = await stale;
|
||||
|
||||
Assert.NotNull(canonical);
|
||||
Assert.Same(canonical, recovered);
|
||||
Assert.Equal(1, dats.GetCallCount(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetWave_ConcurrentMissingId_NeverThrowsAndAllReturnNull()
|
||||
{
|
||||
|
|
@ -214,6 +258,8 @@ public sealed class DatSoundCacheTests
|
|||
|
||||
public void AddWave(uint id, Wave wave) => _waves[id] = wave;
|
||||
|
||||
public Action<uint>? BeforeWaveGet { get; init; }
|
||||
|
||||
public int GetCallCount(uint id)
|
||||
{
|
||||
lock (_gate)
|
||||
|
|
@ -225,6 +271,7 @@ public sealed class DatSoundCacheTests
|
|||
{
|
||||
if (typeof(T) == typeof(Wave))
|
||||
{
|
||||
BeforeWaveGet?.Invoke(fileId);
|
||||
lock (_gate)
|
||||
{
|
||||
_callCounts.TryGetValue(fileId, out int count);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue