Skip to content

Flaky Eventuous.Tests: NodaTime.Bogus context cache is not thread-safe under parallel tests #566

Description

@alexeyzimarev

Describe the bug

Eventuous.Tests fails intermittently with a corrupted-collection error from inside Bogus, not from Eventuous code:

InvalidOperationException: Operations that change non-concurrent collections must have exclusive access.
A concurrent update was performed on this collection and corrupted its state.
  at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
  at System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)
  at Bogus.Premium.ContextHelper.GetOrSet[T](String key, Faker f, Func`1 factory)
  at Bogus.Premium.ContextHelper.GetOrSet[T](Faker f, Func`1 factory)
  at Bogus.NodaTimeExtensions.Noda(Faker faker, Func`1 dateTimeZoneBuilder)
  at Bogus.NodaTimeExtensions.Noda(Faker faker)
  at Eventuous.Tests.Fixtures.NaiveFixture..cctor b__6_0(Faker f)
  at Bogus.Faker`1.Generate(String ruleSets)
  at Eventuous.Tests.Fixtures.NaiveFixture.CreateBookRoomCommand()

NodaTimeExtensions.Noda caches its context per Faker through Bogus.Premium.ContextHelper, which uses a plain Dictionary. NaiveFixture holds a single static Faker<BookRoom> (NaiveFixture.cs:11) whose instantiator calls f.Noda() (NaiveFixture.cs:14), and TUnit runs tests in parallel, so several tests can enter that cache at once on first use and corrupt it.

To reproduce

Run dotnet test --project src/Core/test/Eventuous.Tests/Eventuous.Tests.csproj -f net10.0 repeatedly. I saw it once in roughly ten local runs; the failing test was TestOnNew, but the fixture is shared so any test that generates a command can be the victim.

Expected behaviour

The suite passes deterministically.

Notes

Unrelated to any production code — it's purely the test fixture plus a third-party cache. Likely fixes, cheapest first: warm the Noda context once from a static initialiser or a [Before(Assembly)] hook so the cache is populated single-threaded; give each test its own Faker; or drop the Noda() usage in favour of generating the NodaTime values directly.

Worth fixing because a rerun of an otherwise-green suite costs a full CI cycle, and the exception type gives no hint that it's infrastructural rather than a real defect.

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