-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"There is no active ActorContext" exception in Context.System while running tests #343
Comments
If I put this in the test:
then sometimes the test is green. Making the delay larger doesn't help. |
One thing I am wondering: If I understand the code correctly, the currently executing actor sets the global static Context ( As long as you use Props inside an Actor to create child actors this cannot happen. But in Tests like this the code is normally executed while no Actor is currently executing. This would explain why in my actual code the test is sometimes green when I execute all Tests because some run in parallel and they share the static class I am currently refactoring our code base to use the new Akka.Hosting features. We have lots of tests where we use Props of an Actor to create (non-root) Actors during tests and the Props use the pattern |
I added another test class in the reproduction repo: This code does not use Akka.Hosting and Akka.Hosting.TestKit, it uses the TestKit from the main Akka.Net package. using Akka.Actor;
using Akka.Actor.Setup;
using Akka.DependencyInjection;
using Akka.TestKit.Xunit2;
using Xunit.Abstractions;
namespace DiPropsFail;
public class DiPropsSuccessTest : TestKit, IClassFixture<AkkaDiFixture>
{
public DiPropsSuccessTest(AkkaDiFixture fixture, ITestOutputHelper output) : base(FromActorSystemSetup(
DependencyResolverSetup
.Create(fixture.Provider)
.And(BootstrapSetup.Create().WithConfig(DefaultConfig))), "TestActorSystem", output) { }
private static ActorSystemSetup FromActorSystemSetup(ActorSystemSetup setup)
{
var bootstrapOptions = setup.Get<BootstrapSetup>();
var bootstrap = bootstrapOptions.HasValue ? bootstrapOptions.Value : BootstrapSetup.Create();
return setup.And(bootstrap);
}
[Fact]
public void NonRootActorWithDiTest()
{
Sys.ActorOf(NonRootActorWithDi.Props());
}
// ReSharper disable once ClassNeverInstantiated.Local
private class NonRootActorWithDi : ReceiveActor
{
public static Props Props() =>
DependencyResolver.For(Context.System).Props<NonRootActorWithDi>();
}
} I borrowed some code for this from the main Akka repo (AkkaDiFixture, FromActorSystemSetup). This test is always green. |
I simplified the repro now to this: Working (using Akka.TestKit.XUnit2): using Akka.Actor;
using Akka.TestKit.Xunit2;
using Xunit.Abstractions;
namespace DiPropsFail;
public class DiPropsSuccessTest : TestKit
{
public DiPropsSuccessTest(ITestOutputHelper output) : base(nameof(DiPropsSuccessTest), output)
{
}
[Fact]
public void NonRootActorWithDiTest()
{
Assert.NotNull(MyActor.Context);
}
private class MyActor : ReceiveActor
{
public new static IUntypedActorContext Context => ReceiveActor.Context;
} Failing (using Akka.Hosting.TestKit): using Akka.Actor;
using Akka.Hosting;
using Akka.Hosting.TestKit;
using Xunit.Abstractions;
namespace DiPropsFail;
public class DiPropsFailTest : TestKit
{
public DiPropsFailTest(ITestOutputHelper output) : base(nameof(DiPropsFailTest), output)
{
}
protected override void ConfigureAkka(AkkaConfigurationBuilder builder, IServiceProvider provider)
{
}
[Fact]
public void NonRootActorWithDiTest()
{
Assert.NotNull(MyActor.Context);
}
private class MyActor : ReceiveActor
{
public new static IUntypedActorContext Context => ReceiveActor.Context;
}
} I suspect this problem has the same underlying reason as issue #237, in the Akka.Net TestKit there is an implicit Sender Actor and with that a non-null Context, in Akka.Hosting.TestKit not. |
Thanks for the fix. Now this code:
exists in two places, in the InitializeTest of TestKitBase (Akka itself) and InitializeAsync of TestKit (Akka.Hosting). It looks like the underlying reason is that TestKit (Akka.Hosting) has the interface IAsyncLifetime, so the Testrunner is executing the constructor of TestKitBase and running the Test method (with running InitializeAsync() just before that) on two different threads, hence the problem with the ThreadStaticAttribute. Wouldn't it be better to change TestKitBase itself to use IAsyncLifetime and move the relevant code in InitializeTest to InitializeAsync? TestKit (Akka.Hosting) could override the method and call the base method first. I actually tried this, but had problems with TestProbe, which is derived from TestKitBase. Putting
in the constructor there as a quick hack would at least make everything compile, but about 40 tests were still red. Of course this would also make Akka.Net depending on Xunit. |
Cc @Arkatufus |
That was one of the original problem I encountered when I tried to code
Another approach would be to gut the simple context implementation and make it trully thread safe, but the change would create a systematic drop in performance for Akka.NET due to thread locks etc. |
Maybe its possible to have the cake and eat it? A internal TestKit base implementation with an virtual async initialisation function (not using the IAsyncLifetime interface from XUnit). And two derived classes, one compatible with the current TestKit API (with blocking sync code in the constructor) and another one with the IAsyncLifetime interface which can be used by Akka.Hosting.TestKit. I think even if a Testkit implements IAsyncLifetime, you can still use it with every Test framework. You just have to call the InitializeAsync function yourself because the frameworks doesn't do it for you. Most Test frameworks supports async tests and global hooks (BeforeAsync/AfterAsync). |
That still doesn't address the possibility that the |
Yes, i also don't see how to avoid this. I was just wondering if you could get rid of the same workaround in two places :). But that's probably not worth the effort. |
I still get null reference exceptions sometimes when accessing Context.System inside Tests running under the new Akka.Hosting testkit. It is really hard to reproduce. I have a actor test project here with about 100 tests, and it happens maybe once every 5-10 times when I run all tests. When I run single tests, it doesn't seem to happen. It also happens with different tests (using DependencyResolver.For(Context.System).Props). The test project has a xunit.runner.json file containing parallelizeAssembly and parallelizeTestCollections set to false and I also told Rider to use only a single test runner thread. Maybe it could be reproduced by some kind of stress test but I don't really know whats the best way to do this. |
Version Information
Version of Akka.NET? 1.5.10
Which Akka.NET Modules? Akka.Hosting
Describe the bug
There is no active ActorContext exception in Context.System while running tests
(when trying to create actor props with the DependencyResolver)
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Test is green
Actual behavior
Screenshots
Environment
Rider unter Windows 11
Additional context
The strange things is:
I suspect this is maybe a racing condition.
The text was updated successfully, but these errors were encountered: