strengthen CompositeDiscoveryService tests for deduplication and concurrency
- Replace weak deduplication test with one using distinguishable printers (TM-T30III/ENPC vs POS895/SPRT on same IP) to prove first-wins semantics - Add concurrency test using SlowStubDiscovery to catch sequential regressions (3 * 300ms tasks must complete in < 700ms, not >= 900ms) - Add StubDiscovery constructor accepting List<DiscoveredPrinter> for fully-populated test data Test suite now 13/13 passing with proven concurrent execution. Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
This commit is contained in:
@@ -20,6 +20,11 @@ public class CompositeDiscoveryServiceTests
|
||||
_throws = throws;
|
||||
}
|
||||
|
||||
public StubDiscovery(List<DiscoveredPrinter> printers)
|
||||
{
|
||||
_printers = printers;
|
||||
}
|
||||
|
||||
public Task<List<DiscoveredPrinter>> DiscoverPrintersAsync(
|
||||
TimeSpan? timeout = null,
|
||||
Action<DiscoveredPrinter>? onPrinterDiscovered = null)
|
||||
@@ -38,6 +43,26 @@ public class CompositeDiscoveryServiceTests
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SlowStubDiscovery : IDiscoveryService
|
||||
{
|
||||
private readonly TimeSpan _delay;
|
||||
private readonly string _ip;
|
||||
|
||||
public SlowStubDiscovery(TimeSpan delay, string ip)
|
||||
{
|
||||
_delay = delay;
|
||||
_ip = ip;
|
||||
}
|
||||
|
||||
public async Task<List<DiscoveredPrinter>> DiscoverPrintersAsync(
|
||||
TimeSpan? timeout = null,
|
||||
Action<DiscoveredPrinter>? onPrinterDiscovered = null)
|
||||
{
|
||||
await Task.Delay(_delay);
|
||||
return new List<DiscoveredPrinter> { new DiscoveredPrinter { IPAddress = _ip } };
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Merges_results_from_every_child()
|
||||
{
|
||||
@@ -56,18 +81,51 @@ public class CompositeDiscoveryServiceTests
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Deduplicates_by_ip_first_wins()
|
||||
public async Task Deduplicates_by_ip_keeping_the_first_child_that_reported_it()
|
||||
{
|
||||
// A printer answering both ENPC and SPRT must appear once.
|
||||
var composite = new CompositeDiscoveryService(new IDiscoveryService[]
|
||||
// The two stubs report the same IP but are distinguishable, so this
|
||||
// proves first-wins rather than merely proving that one of them survived.
|
||||
var first = new StubDiscovery(new List<DiscoveredPrinter>
|
||||
{
|
||||
new StubDiscovery("10.0.0.1"),
|
||||
new StubDiscovery("10.0.0.1")
|
||||
new DiscoveredPrinter { IPAddress = "10.0.0.1", ModelName = "TM-T30III", ServiceType = "ENPC" }
|
||||
});
|
||||
var second = new StubDiscovery(new List<DiscoveredPrinter>
|
||||
{
|
||||
new DiscoveredPrinter { IPAddress = "10.0.0.1", ModelName = "POS895", ServiceType = "SPRT" }
|
||||
});
|
||||
|
||||
var composite = new CompositeDiscoveryService(new IDiscoveryService[] { first, second });
|
||||
|
||||
var result = await composite.DiscoverPrintersAsync(TimeSpan.FromMilliseconds(50));
|
||||
|
||||
Assert.Single(result);
|
||||
var only = Assert.Single(result);
|
||||
Assert.Equal("TM-T30III", only.ModelName);
|
||||
Assert.Equal("ENPC", only.ServiceType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Runs_children_concurrently_not_sequentially()
|
||||
{
|
||||
// Three children that each take ~300ms. Sequential execution needs >=900ms;
|
||||
// concurrent should land near 300ms. The 700ms bound leaves generous headroom
|
||||
// for a loaded machine while still failing a sequential regression widely.
|
||||
var children = new IDiscoveryService[]
|
||||
{
|
||||
new SlowStubDiscovery(TimeSpan.FromMilliseconds(300), "10.0.0.1"),
|
||||
new SlowStubDiscovery(TimeSpan.FromMilliseconds(300), "10.0.0.2"),
|
||||
new SlowStubDiscovery(TimeSpan.FromMilliseconds(300), "10.0.0.3")
|
||||
};
|
||||
|
||||
var composite = new CompositeDiscoveryService(children);
|
||||
|
||||
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
|
||||
var result = await composite.DiscoverPrintersAsync(TimeSpan.FromSeconds(5));
|
||||
stopwatch.Stop();
|
||||
|
||||
Assert.Equal(3, result.Count);
|
||||
Assert.True(stopwatch.ElapsedMilliseconds < 700,
|
||||
$"expected concurrent execution near 300ms but took {stopwatch.ElapsedMilliseconds}ms, " +
|
||||
"which indicates the children ran sequentially");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
Reference in New Issue
Block a user