Skip to content
This repository has been archived by the owner on May 22, 2024. It is now read-only.

Concurrency issue when using Amazon.Extensions.Configuration.SystemsManager #104

Closed
JovialJerboa opened this issue Aug 8, 2023 · 5 comments

Comments

@JovialJerboa
Copy link

Getting a concurrency error when trying to use Amazon.Extensions.Configuration.SystemsManager with SpecFlow.DependencyInjection in the [ScenarioDependencies] tagged method

Reproduction

Source

I've created a fork of the project to illustrate the bug here

Specifics

  1. Add the Amazon.Extensions.Configuration.SystemsManager nuget package
  2. Update the [ScenarioDependencies] code to include
[ScenarioDependencies]
public static IServiceCollection CreateServices()
{
    var services = new ServiceCollection();

    // Add test dependencies
    services.AddTransient<ITestService, TestService>();

    // ContextInjectionScope (by using AddScoped instead of AddTransient, the context will be scoped to the Feature across bindings)
    services.AddScoped<TestContext>();

    // Calculator
    services.AddScoped<ICalculator, Calculator>();
    
    // NB: This breaks when parallelizeTestCollections = true (xunit.runner.json)
    //      When debugging, the error does not occur, presumably because the tests are not running in parallel
    var configuration = new ConfigurationBuilder();
    configuration.AddSystemsManager(c =>
    {
        c.Path = "path";
        c.Optional = true;
    });
    configuration.Build();

    return services;
}
  1. Run the tests in parallel (this is the default)
    i. you will receive a Concurrent object resolution timeout (potential circular dependency). error
    ii. if you run any test indivdually, debug all the tests or run with parallelizeTestCollections: false in a xunit.runner.json file the tests will succeed

Full error message

BoDi.ObjectContainerException: Concurrent object resolution timeout (potential circular dependency).

BoDi.ObjectContainerException
Concurrent object resolution timeout (potential circular dependency).
   at BoDi.ObjectContainer.RegistrationWithStrategy.ExecuteWithLock(Object lockObject, Func`1 getter, Func`1 factory, ResolutionList resolutionPath)
   at BoDi.ObjectContainer.FactoryRegistration.ResolvePerContext(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath)
   at BoDi.ObjectContainer.RegistrationWithStrategy.Resolve(ObjectContainer container, RegistrationKey keyToResolve, ResolutionList resolutionPath)
   at BoDi.ObjectContainer.ResolveObject(RegistrationKey keyToResolve, ResolutionList resolutionPath)
   at BoDi.ObjectContainer.Resolve(Type typeToResolve, ResolutionList resolutionPath, String name)
   at BoDi.ObjectContainer.Resolve(Type typeToResolve, String name)
   at BoDi.ObjectContainer.Resolve[T](String name)
   at BoDi.ObjectContainer.Resolve[T]()
   at SolidToken.SpecFlow.DependencyInjection.DependencyInjectionPlugin.CustomizeFeatureDependenciesEventHandler(Object sender, CustomizeFeatureDependenciesEventArgs args) in ..\SpecFlow.DependencyInjection.BugReproduction\SpecFlow.DependencyInjection\DependencyInjectionPlugin.cs:line 77
   at TechTalk.SpecFlow.Plugins.RuntimePluginEvents.RaiseCustomizeFeatureDependencies(ObjectContainer featureContainer)
   at TechTalk.SpecFlow.Infrastructure.ContainerBuilder.CreateFeatureContainer(IObjectContainer testThreadContainer, FeatureInfo featureInfo)
   at TechTalk.SpecFlow.Infrastructure.ContextManager.InitializeFeatureContext(FeatureInfo featureInfo)
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.OnFeatureStartAsync(FeatureInfo featureInfo)
   at TechTalk.SpecFlow.TestRunner.OnFeatureStartAsync(FeatureInfo featureInfo)
   at SolidToken.SpecFlow.DependencyInjection.Tests.Features.CalculatorFeature.FeatureSetupAsync()
   at SolidToken.SpecFlow.DependencyInjection.Tests.Features.CalculatorFeature.FixtureData.Xunit.IAsyncLifetime.InitializeAsync()
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90



-----

System.NullReferenceException
Object reference not set to an instance of an object.
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.GetHookContainer(HookType hookType)
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.FireEventsAsync(HookType hookType)
   at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.OnFeatureEndAsync()
   at TechTalk.SpecFlow.TestRunner.OnFeatureEndAsync()
   at SolidToken.SpecFlow.DependencyInjection.Tests.Features.CalculatorFeature.FeatureTearDownAsync()
   at SolidToken.SpecFlow.DependencyInjection.Tests.Features.CalculatorFeature.FixtureData.Xunit.IAsyncLifetime.DisposeAsync()
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90
@mbhoek
Copy link
Member

mbhoek commented Aug 8, 2023

Hey @JovialJerboa, thanks for raising this issue and providing the test repository.

I am not sure what AddSystemsManager is adding to the services collection that is causing this exception; it does not appear that it interacts with the services at all? Is the same exception raised if you move this code outside of the CreateServices method? Or maybe I'm just missing where you are using the configuration, I could no find it in your commit.

@JovialJerboa
Copy link
Author

JovialJerboa commented Aug 8, 2023

@mbhoek thanks for your response.

You're absolutely correct, in the sample provided the configuration isn't being used, however it doesn't need to be to illustrate the problem. I found that you simply needed to add the Amazon Systems Manager to the configuration builder and run .Build()

I noticed the issue when working on a different project where we're using the Amazon Systems Manager to configure AWS services for use within the SpecFlow tests, for example accessing configuration from Parameter Store / Secrets Manager.

Is the same exception raised if you move this code outside of the CreateServices method?

If the code is decomposed into a separate method that's called from the CreateServices method, as you might expect the error still occurs.

Is there another place I can put that configuration code where it would be available for dependency injection that isn't the CreateServices method?

@JovialJerboa
Copy link
Author

@mbhoek let me know if there is anything else I can do to help with this

@mbhoek
Copy link
Member

mbhoek commented Nov 28, 2023

Thank you for your contribution. Unfortunately I have postponed working on this plugin until I get a better understanding of the future of the SpecFlow project. If they continue, all my focus will be on supporting SpecFlow v4.

@mbhoek
Copy link
Member

mbhoek commented Feb 14, 2024

Closing this issue because the plugin will be donated to Reqnroll.

@mbhoek mbhoek closed this as completed Feb 14, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

2 participants