Are there any UnitTest samples for Orleans 3.0? Anything like the samples here?https://github.com/dotnet/orleans/tree/master/Samples/2.3/UnitTesting
Right now I am trying to do a reminder test on one of my grains. I am trying to recreate the ClusterFixture from 2.3 so I can capture the reminders and trigger them. However it appears the ability to provide a simple service provider factory has been removed. The ISiloBuilderConfigurator interface has been deprecated, in favor of ISiloConfigurator and IHostConfigurator. IHostConfigurator has a UseServiceProviderFactory method but requires a more complex IServiceProviderFactory<TServiceContainer>.
Basically, how can I accomplish the following in Orleans 3.0?
https://github.com/dotnet/orleans/blob/ae9b5369ae325fdc9f0d10ea146e7242edbede3e/Samples/2.3/UnitTesting/test/Grains.Tests/Hosted/Cluster/ClusterFixture.cs#L126-L140
Or maybe I am missing something obvious to make testing that a reminder was registered when my grain was activated?
Any help is appreciated.
Oh my... that sample is over-complicated. No need for those static dictionaries, or passing a test cluster ID, or anything like that.
You can actually access the IServiceProvider of the test silos directly.
See the below for a 100% untested version that shows this concept, stripped down to just reminders, but it should be obvious how to add back the other services if needed.
```c#
public class ClusterFixture : IDisposable
{
public TestCluster Cluster { get; }
public List<FakeReminderRegistry> ReminderRegistries { get; } = new List<FakeReminderRegistry>();
public FakeReminder GetReminder(IGrain grain, string name)
{
return ReminderRegistries
.Select(_ => _.GetReminder((GrainReference)grain, name).Result)
.Where(_ => _ != null)
.SingleOrDefault();
}
public ClusterFixture()
{
var builder = new TestClusterBuilder();
builder.AddSiloBuilderConfigurator<SiloConfigurator>();
Cluster = builder.Build();
Cluster.Deploy();
var inProcHandles = Cluster.Silos.Cast<InProcessSiloHandle>().ToList();
ReminderRegistries.AddRange(inProcHandles.Select(x => x.SiloHost.Services.GetService<FakeReminderRegistry>()));
}
private class SiloConfigurator : ISiloConfigurator
{
public void Configure(ISiloBuilder siloBuilder)
{
siloBuilder.ConfigureServices(services =>
{
// add the fake reminder registry in a way that lets us extract it afterwards
services.AddSingleton<FakeReminderRegistry>();
services.AddSingleton<IReminderRegistry>(_ => _.GetService<FakeReminderRegistry>());
});
}
}
public void Dispose() => Cluster.StopAllSilos();
}
```
Hope this helps.
The problem I have with that setup is that it is not easy to access the IServiceProvider for the Silo. The Cluster.ServiceProvider is the client provider, not the one we are configuring here. I also didn't see any way to access the Silo service provider on the SiloHandle.
I ended up with a somewhat hacky solution. Mine is a bit different because I am using NUnit instead of XUnit. Since I cannot access the IServiceProvider of the Silo (just haven't figured out how to do that yet) I added logic in the factory method to capture a reference to the FakeReminderRegistry.
```c#
public class OrleansTestBase
{
protected TestCluster Cluster { get; private set; }
protected static List<FakeReminderRegistry> ReminderRegistries { get; } = new List<FakeReminderRegistry>();
public FakeReminder GetReminder(IGrain grain, string name) => ReminderRegistries
.Select(_ => _.GetReminder((GrainReference)grain, name).Result)
.SingleOrDefault(_ => _ != null);
[OneTimeSetUp]
public void OneTimeSetup()
{
var siloAttr =
Attribute.GetCustomAttribute(GetType(), typeof(OrleansTestSiloAttribute)) as OrleansTestSiloAttribute;
var siloCount = siloAttr?.SiloCount ?? (short) 1;
Cluster = new TestClusterBuilder(siloCount)
.AddSiloBuilderConfigurator<SiloConfigurator>()
.Build();
Cluster.Deploy();
}
[OneTimeTearDown]
public void OneTimeTeardown()
{
Cluster.StopAllSilos();
ReminderRegistries.Clear();
}
private class SiloConfigurator : ISiloConfigurator
{
public void Configure(ISiloBuilder siloBuilder) => siloBuilder
.AddMemoryGrainStorage("ClusterStateStorage")
.ConfigureServices(services => services
.AddSingleton<FakeReminderRegistry>()
.AddSingleton<IReminderRegistry>(_ =>
{
var reminderReg = _.GetService<FakeReminderRegistry>();
ReminderRegistries.Add(reminderReg);
return reminderReg;
}));
}
}
```
I'm not sure how it is hard to access the IServiceProvider. The whole point of my reply is that doing so is easy.
The important lines are:
```c#
// Get the handles, while downcasting them to their actual type.
var inProcHandles = Cluster.Silos.Cast
// Use .SiloHost.Services to access the IServiceProvider.
ReminderRegistries.AddRange(inProcHandles.Select(x => x.SiloHost.Services.GetService
```
You need to downcast the SiloHandles to InProcessSiloHandle, because the test host code is designed to work with silos that might be in some other Appdomain, or in a totally separate process. Thus in those cases, it would literally be impossible to get the underlying SiloHost, and access its IServiceProvider.
But you actually need to go well out of your way to even enable those scenarios, and if you don't then the silo handles will be of type InProcessSiloHandle, which lets you retrieve the ISiloHost (since that is possible if the silo is in-process), which in turn lets you get it's IServiceProvider, via the Services property.
I will grant that the need to downcast makes this not discoverable. Personally I would not mind seeing the SiloHost property moved to the SiloHandle base class. It could simply return null in those exotic cases of separate app domain or process. But by being on the base class, it would be far more discoverable.
It's so sad that hasn't a official unittest sample for 3.0.
It's so sad that hasn't a official unittest sample for 3.0.
It depends on what you want to test. For simple performance test you can use OrleansDashboard.
Most helpful comment
Oh my... that sample is over-complicated. No need for those static dictionaries, or passing a test cluster ID, or anything like that.
You can actually access the IServiceProvider of the test silos directly.
See the below for a 100% untested version that shows this concept, stripped down to just reminders, but it should be obvious how to add back the other services if needed.
```c#
public class ClusterFixture : IDisposable
{
public TestCluster Cluster { get; }
```
Hope this helps.