Skip to content

[Tests] LogTailerTests — Hardcoded Task.Delay(300/1000) timing flake risk #749

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Info
File: tests/Servy.Manager.UnitTests/Utils/LogTailerTests.cs lines 76–89

Description:
RunFromPosition_ShouldHandleFileRotation coordinates with the SUT exclusively via fixed Task.Delay:

// Wait for the tailer to actually enter its inner loop
await Task.Delay(300, TestContext.Current.CancellationToken);

// Simulate Rotation: Truncate and write fresh content …
using (var fs = new FileStream(initialPath, FileMode.Truncate,))
using (var sw = new StreamWriter(fs) { AutoFlush = true })
{
    await sw.WriteLineAsync("ROTATED_CONTENT");
}

// Give the polling loop (150ms) and ReadLineAsync enough time to process the truncation
await Task.Delay(1000, TestContext.Current.CancellationToken);

Both delays are tuned to the current polling interval (150ms). The comment acknowledges the timing assumption. On a slow CI agent, a noisy VM, or under parallel-test load, 300ms may not be enough for the tailer to enter its inner loop; 1000ms may not be enough for the poll + ReadLineAsync to catch the truncated file. Failure mode: the test asserts Assert.Contains(capturedLines, …) on an empty list — red CI for reasons unrelated to product behaviour.

Suggested fix:
Replace both delays with deterministic waits:

  • For "enter inner loop": have LogTailer expose a TaskCompletionSource signalling "first poll started" (an internal or testing-only property), and await that from the test.
  • For "poll has observed rotation": wait on capturedLines reaching count >= 1 via a polling helper with a generous timeout (e.g., 10s) that exits as soon as the assertion becomes true, rather than sleeping unconditionally for 1000ms.
static async Task WaitUntilAsync(Func<bool> predicate, TimeSpan timeout) {
    var deadline = DateTime.UtcNow + timeout;
    while (DateTime.UtcNow < deadline) {
        if (predicate()) return;
        await Task.Delay(50);
    }
    throw new TimeoutException();
}

That pattern keeps the test fast on healthy agents and tolerant on slow ones.

Metadata

Metadata

Assignees

Labels

testsChanges to test code and coverage

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions