using XFESystem.Kernel;
using Xunit;
namespace XFESystem.Core.Tests;
public sealed class NetworkBootWaitTests
{
[Fact]
public void AlreadyReadyDoesNotWaitForAnyInterrupt()
{
Assert.True(NativeNetworkBootWait.WaitUntilReady(() => true, () => 42, 1_000,
() => throw new InvalidOperationException("No wait expected.")));
}
[Fact]
public void NeverReadyTimesOutAfterFiveSecondsWithoutPitTicks()
{
long now = 0;
int lapicInterrupts = 0, polls = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { polls++; return false; }, () => now, 1_000,
() => { lapicInterrupts++; now += 10; }));
Assert.Equal(5_000, now);
Assert.Equal(500, lapicInterrupts);
Assert.Equal(500, polls);
}
[Theory]
[InlineData(4_990, true)]
[InlineData(5_000, false)]
[InlineData(5_010, false)]
public void ReadinessMustArriveBeforeTheDeadline(int readyAt, bool expected)
{
long now = 0;
Assert.Equal(expected, NativeNetworkBootWait.WaitUntilReady(() => now >= readyAt, () => now, 1_000,
() => now += 10));
Assert.Equal(expected ? readyAt : 5_000, now);
}
[Fact]
public void LongInterruptWaitCountsTowardTheSameBudget()
{
long now = 0;
int polls = 0, waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { polls++; return false; }, () => now, 1_000,
() => { waits++; now += 9_000; }));
Assert.Equal(1, waits);
Assert.Equal(1, polls);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void PollingTimeCannotExtendTheDeadline(bool ready)
{
long now = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { now += 5_000; return ready; }, () => now, 1_000,
() => throw new InvalidOperationException("An expired poll must not wait.")));
}
[Theory]
[InlineData(1)]
[InlineData(1_000)]
[InlineData(1_000_000_001)]
public void UsesTheSuppliedTimestampFrequency(long frequency)
{
long now = 0;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, frequency,
() => { waits++; now += frequency; }));
Assert.Equal(5, waits);
Assert.Equal(frequency * 5, now);
}
[Theory]
[InlineData(long.MaxValue - 2_000)]
[InlineData(-2_000)]
public void TimestampWrapDoesNotOverflowOrSkipTheTimeout(long start)
{
long now = start;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, 1_000,
() => { waits++; now = unchecked(now + 1_000); }));
Assert.Equal(5, waits);
Assert.Equal(unchecked(start + 5_000), now);
}
[Fact]
public void LargestSupportedBudgetDoesNotOverflow()
{
const long frequency = long.MaxValue / 5;
long now = 100;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, frequency,
() => { waits++; now = unchecked(now + frequency * 5); }));
Assert.Equal(1, waits);
}
[Fact]
public void BackwardsClockFailsClosed()
{
long now = 100;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, 1_000,
() => { waits++; now--; }));
Assert.Equal(1, waits);
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
[InlineData(long.MaxValue / 5 + 1)]
[InlineData(long.MaxValue)]
public void InvalidOrUnrepresentableFrequencyIsRejectedBeforeWaiting(long frequency)
{
Assert.Throws<ArgumentOutOfRangeException>(() => NativeNetworkBootWait.WaitUntilReady(
() => throw new InvalidOperationException("No poll expected."),
() => throw new InvalidOperationException("No timestamp expected."), frequency,
() => throw new InvalidOperationException("No wait expected.")));
}
}
using XFESystem.Kernel;
using Xunit;
namespace XFESystem.Core.Tests;
public sealed class NetworkBootWaitTests
{
[Fact]
public void AlreadyReadyDoesNotWaitForAnyInterrupt()
{
Assert.True(NativeNetworkBootWait.WaitUntilReady(() => true, () => 42, 1_000,
() => throw new InvalidOperationException("No wait expected.")));
}
[Fact]
public void NeverReadyTimesOutAfterFiveSecondsWithoutPitTicks()
{
long now = 0;
int lapicInterrupts = 0, polls = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { polls++; return false; }, () => now, 1_000,
() => { lapicInterrupts++; now += 10; }));
Assert.Equal(5_000, now);
Assert.Equal(500, lapicInterrupts);
Assert.Equal(500, polls);
}
[Theory]
[InlineData(4_990, true)]
[InlineData(5_000, false)]
[InlineData(5_010, false)]
public void ReadinessMustArriveBeforeTheDeadline(int readyAt, bool expected)
{
long now = 0;
Assert.Equal(expected, NativeNetworkBootWait.WaitUntilReady(() => now >= readyAt, () => now, 1_000,
() => now += 10));
Assert.Equal(expected ? readyAt : 5_000, now);
}
[Fact]
public void LongInterruptWaitCountsTowardTheSameBudget()
{
long now = 0;
int polls = 0, waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { polls++; return false; }, () => now, 1_000,
() => { waits++; now += 9_000; }));
Assert.Equal(1, waits);
Assert.Equal(1, polls);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void PollingTimeCannotExtendTheDeadline(bool ready)
{
long now = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => { now += 5_000; return ready; }, () => now, 1_000,
() => throw new InvalidOperationException("An expired poll must not wait.")));
}
[Theory]
[InlineData(1)]
[InlineData(1_000)]
[InlineData(1_000_000_001)]
public void UsesTheSuppliedTimestampFrequency(long frequency)
{
long now = 0;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, frequency,
() => { waits++; now += frequency; }));
Assert.Equal(5, waits);
Assert.Equal(frequency * 5, now);
}
[Theory]
[InlineData(long.MaxValue - 2_000)]
[InlineData(-2_000)]
public void TimestampWrapDoesNotOverflowOrSkipTheTimeout(long start)
{
long now = start;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, 1_000,
() => { waits++; now = unchecked(now + 1_000); }));
Assert.Equal(5, waits);
Assert.Equal(unchecked(start + 5_000), now);
}
[Fact]
public void LargestSupportedBudgetDoesNotOverflow()
{
const long frequency = long.MaxValue / 5;
long now = 100;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, frequency,
() => { waits++; now = unchecked(now + frequency * 5); }));
Assert.Equal(1, waits);
}
[Fact]
public void BackwardsClockFailsClosed()
{
long now = 100;
int waits = 0;
Assert.False(NativeNetworkBootWait.WaitUntilReady(() => false, () => now, 1_000,
() => { waits++; now--; }));
Assert.Equal(1, waits);
}
[Theory]
[InlineData(0)]
[InlineData(-1)]
[InlineData(long.MaxValue / 5 + 1)]
[InlineData(long.MaxValue)]
public void InvalidOrUnrepresentableFrequencyIsRejectedBeforeWaiting(long frequency)
{
Assert.Throws<ArgumentOutOfRangeException>(() => NativeNetworkBootWait.WaitUntilReady(
() => throw new InvalidOperationException("No poll expected."),
() => throw new InvalidOperationException("No timestamp expected."), frequency,
() => throw new InvalidOperationException("No wait expected.")));
}
}