Azure / Azure/azure-functions-core-tools

Flaky test: CompactRendererFunctionBrowserTests alternate-screen test fails ~2 in 5 full-suite runs

Closed
#5,563 0 comments 0 reactions 1 assignee Claimed by @ahmedmuhsin View on GitHub
Needs: Triage (Functions) v5
Dominant language
C#
Stars
1.5k
Forks
498
Avg merge
4d 20h
Merged PRs (30d)
14

Description

## Summary

`CompactRendererFunctionBrowserTests.OnStartAsync_WhenMacOSAndAlternateBufferSupported_UsesAlternateScreen` fails intermittently with:

```
Failed to read input in non-interactive mode
```

It reproduces on a clean `vnext` checkout with no local changes.

## Reproduction

```
dotnet test Azure.Functions.Cli.slnx
```

Roughly 2 in 5 full-suite runs fail. It also fails when the class runs alone, just less often, measured at 1 in 8:

```
dotnet test test/Func.Tests/Func.Tests.csproj --filter "FullyQualifiedName~CompactRendererFunctionBrowserTests"
```

(An earlier revision of this issue said the filtered run always passes. That was too few samples; it fails there too.)

## Cause

The message comes from Spectre.Console, not from our code. `CompactRenderer` starts a background key-reading loop gated on the interaction service:

```csharp
if (_interaction.IsInteractive) // CompactRenderer.cs, OnStartAsync
```

and the loop reads through the injected console:

```csharp
ConsoleKeyInfo? key = await _console.Input.ReadKeyAsync(intercept: true, cancellationToken);
```

The console is properly injected, so this is not an ambient-console leak. The problem is that the *gate* and the console's *input capability* are two independent things. The test builds a Spectre console over a `StringWriter`, whose input profile is non-interactive, so once the gate opens `ReadKeyAsync` throws.

That it fails in both filtered and full-suite runs, at different rates, points at a race rather than a test-ordering dependency: the throw comes off an unobserved background task and only fails the test when it lands before the test finishes. The higher full-suite rate is consistent with more scheduling pressure, not with contamination from another test.

## Suggested fix

Decide the two conditions together instead of separately: don't start the key loop unless the console being rendered to can actually be read from. Whatever the loop does throw should be observed rather than left on a fire-and-forget task, so a real failure surfaces deterministically instead of as a flake in an unrelated test.

## Impact

Every full-suite run is a coin flip, which trains people to re-run on red and makes real regressions easy to wave off. It also costs a CI retry whenever it lands.

## Acceptance criteria

- [ ] The test passes consistently in a full-suite run
- [ ] The key loop's start condition accounts for whether the target console supports input
- [ ] Failures inside the loop are observed rather than swallowed by a detached task
- [ ] No `--filter`-only or serialised-collection workaround; the failure reproduces under `--filter` too, so that wouldn't even hide it

## Context

Hit repeatedly while validating #5543. Unrelated to that PR's changes.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.