Skip to content

Concurrency issue with property initializers #3616

@jorgeparavicini

Description

@jorgeparavicini

We have various applications, each with multiple ClassDataSources. Some also reuse the same data source, which should reuse the same instance. To illustrate, we have this example Application:

public sealed class ApplicationTestHost : ITestHost
{
    [ClassDataSource<MinioContainer>(Shared = SharedType.PerTestSession)]
    public required MinioContainer Minio { get; init; }

    [ClassDataSource<MongoDbContainer>(Shared = SharedType.PerTestSession)]
    public required MongoDbContainer MongoDb { get; init; }

    [ClassDataSource<MailhogContainer>(Shared = SharedType.PerTestSession)]
    public required MailhogContainer Mailhog { get; init; }

    [ClassDataSource<RedisContainer>(Shared = SharedType.PerTestSession)]
    public required RedisContainer Redis { get; init; }

    [ClassDataSource<ClickhouseContainer>(Shared = SharedType.PerTestSession)]
    public required ClickhouseContainer ClickHouse { get; init; }

    [ClassDataSource<PostgresContainer>(Shared = SharedType.PerTestSession)]
    public required PostgresContainer Postgres { get; init; }

    [ClassDataSource<RabbitMqContainer>(Shared = SharedType.PerTestSession)]
    public required RabbitMqContainer RabbitMq { get; init; }

    public async Task InitializeAsync()
    {
        LoadAssemblies();

        _containers = new List<IRapidataContainer>
        {
            Minio,
            MongoDb,
            Mailhog,
            Redis,
            ClickHouse,
            Postgres,
            RabbitMq,
        };
}
public sealed class CampaignApplicationTestHost : ITestHost
{
    [ClassDataSource<MinioContainer>(Shared = SharedType.PerTestSession)]
    public required MinioContainer Minio { get; init; }

    public async Task InitializeAsync()
    {
        LoadAssemblies();

        _containers = new List<IRapidataContainer>
        {
            Minio,
        };
    }
}

This sometimes causes concurrency issues with the following exception:

Failed to inject properties for type 'CreateUnsupportedOrderTests': Failed to initialize data source of type 'ApplicationTestHost': Failed to inject properties for type 'ApplicationTestHost': Failed to initialize data source of type 'MinioContainer': Failed to inject properties for type 'MinioContainer': Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
Stack trace:    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 TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializeSourceGeneratedPropertyAsync(Object instance, PropertyInjectionMetadata metadata, ConcurrentDictionary`2 objectBag, MethodMetadata methodMetadata, TestContextEvents events, ConcurrentDictionary`2 visitedObjects)
   at TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializeSourceGeneratedPropertiesAsync(Object instance, PropertyInjectionMetadata[] properties, ConcurrentDictionary`2 objectBag, MethodMetadata methodMetadata, TestContextEvents events, ConcurrentDictionary`2 visitedObjects)
   at TUnit.Engine.Services.PropertyInitializationOrchestrator.InitializeObjectWithPropertiesAsync(Object instance, PropertyInjectionPlan plan, ConcurrentDictionary`2 objectBag, MethodMetadata methodMetadata, TestContextEvents events, ConcurrentDictionary`2 visitedObjects)
   at TUnit.Engine.Services.PropertyInjectionService.<>c__DisplayClass6_0.<<InjectPropertiesIntoObjectAsyncCore>b__0>d.MoveNext()
--- End of stack trace from previous location ---
   at TUnit.Core.PropertyInjection.PropertyInjectionCache.GetOrAddInjectionTask(Object instance, Func`2 taskFactory)
   at TUnit.Engine.Services.PropertyInjectionService.InjectPropertiesIntoObjectAsyncCore(Object instance, ConcurrentDictionary`2 objectBag, MethodMetadata methodMetadata, TestContextEvents events, ConcurrentDictionary`2 visitedObjects)
Stack trace:    at TUnit.Engine.Services.DataSourceInitializer.InitializeDataSourceAsync(Object dataSource, ConcurrentDictionary`2 objectBag, MethodMetadata methodMetadata, TestContextEvents events)

Im happy to provide additional info if required

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions