Skip to content

[Bug]: ILogger test-double ownership exclusion (ADR-0055) not applied under default parallel MSBuild build #132

Description

@ncipollina

What happened?

TransitiveClosureWalker.IsLoggingOwned (ADR-0055 Amendment 4) is supposed to make Compono.Logging the sole owner of ILogger/ILogger<T> when ComponoGeneratedLogging is enabled - excluding it from Compono.TestDoubles generation so there's exactly one Verify() extension. In practice this exclusion silently fails to apply when the consumer solution is built with MSBuild's default parallelism.

Reproduced in alexa-vox-craft (a real dogfood consumer) after bumping all Compono packages to the real, lockstep 1.0.0 NuGet.org release (Compono, Compono.XunitV3, Compono.Http, Compono.TestDoubles, Compono.Bogus, Compono.Logging all at 1.0.0) with a clean obj/bin and a clean NuGet restore - so this isn't a stale-cache or version-skew artifact.

With the default parallel build, AlexaVoxCraft.MediatR.Tests/Pipeline/PerformanceLoggingBehaviorTests.cs fails with 14 errors like:

error CS1061: 'Microsoft_Extensions_Logging_ILogger_global__AlexaVoxCraft_MediatR_Pipeline_PerformanceLoggingBehavior__bb9c11a6_DoubleVerifier' does not contain a definition for 'AtLevel' and no accessible extension method 'AtLevel' accepting a first argument of type '...DoubleVerifier' could be found

This is exactly the ownership collision ADR-0055 Amendment 4 exists to prevent: Compono.TestDoubles generated its own double + Verify()/...DoubleVerifier for ILogger<PerformanceLoggingBehavior> instead of yielding to Compono.Logging's Verify() (which returns LogVerificationBuilder with AtLevel).

Both ComponoGeneratedLogging and ComponoGeneratedTestDoubles resolve to true via -getProperty in this project, and the consumer's composition profile already registers UseLogging() before UseGeneratedTestDoubles() per the documented ordering guidance - so this isn't a consumer-side ordering mistake.

Consistently reproducible, not a flake: ran the default parallel dotnet build 3x from a clean obj/bin - failed all 3 times with the identical 14 errors. Ran dotnet build -m:1 (single MSBuild node) 2x from a clean obj/bin - succeeded both times, 0 errors.

Suspect area: LoggingWellKnownTypes.TryCreate's per-process BoundedCacheWithFactory<Compilation, LoggingWellKnownTypes?> (src/Compono.Generators/WellKnownTypes/BoundedCacheWithFactory.cs) - it's a size-5 bounded cache shared across the whole VBCSCompiler build-server process. Under the default parallel build, many projects/TFMs compile concurrently against that one shared generator instance; haven't nailed the exact mechanism, but that's the most likely place a Compilation-keyed lookup could go wrong/stale/get evicted in a way that causes IsLoggingOwned (src/Compono.Generators/Discovery/TransitiveClosureWalker.cs:190-218) to see a null/incorrect LoggingWellKnownTypes for a compilation that should have it.

Steps to reproduce

  1. In a consumer repo referencing Compono, Compono.XunitV3, Compono.TestDoubles, Compono.Logging all pinned to 1.0.0 (lockstep) via Central Package Management, with a project that composes an ILogger<T> used both via UseLogging() (Compono.Logging capturing logger) and via generated test doubles elsewhere in the same project.
  2. rm -rf every obj/bin in the solution, then dotnet restore.
  3. dotnet build (default parallelism).
  4. Observe CS1061 ... does not contain a definition for 'AtLevel' on the ILogger<T>.Verify() call sites.
  5. rm -rf obj/bin again, then dotnet build -m:1.
  6. Build succeeds with 0 errors.

Environment

  • .NET SDK targeting net8.0/net9.0/net10.0/net11.0 (multi-targeted test project)
  • macOS (Darwin 25.6.0)
  • Compono 1.0.0, Compono.XunitV3 1.0.0, Compono.TestDoubles 1.0.0, Compono.Logging 1.0.0 (all from nuget.org, Central Package Management)
  • Consumer repo: LayeredCraft/alexa-vox-craft, AlexaVoxCraft.MediatR.Tests project

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    🐛 bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions