Search code examples
c#.net-corexunitorleans

How to configure TestClusterBuilder such that the test cluster has access to SMSProvider?


I am trying to follow their tutorial for tests: Link to Orleans test docs

But the configuration shown is pretty simplistic:

var builder = new TestClusterBuilder();
var cluster = builder.Build();
cluster.Deploy();

And does not show how to add SMSProvider.

Let's say that I have the following test:

    [Fact]
    public async Task SaysHelloCorrectly()
    {
        var hello = _cluster.GrainFactory.GetGrain<ISomeGrain>(Guid.NewGuid(), "<Some stream ID>", "Some.Class.Path");
        var guid = Guid.NewGuid();
        var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");
        var photoStream = streamProvider.GetStream<string>(guid, "<Some stream ID>");
        await photoStream.OnNextAsync("Hi");
        Assert.Equal("Hello, World", "Hello, World");
    }

Then I get an error in line:

var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");

Such as:

[xUnit.net 00:00:02.02]     Tests.SaysHelloCorrectly [FAIL]
Failed Tests.FilterTests.SaysHelloCorrectly [8 ms]
Error Message:
  System.Collections.Generic.KeyNotFoundException : SMSProvider

I think that configuring the ClusterFixture correctly would be part of the solution or maybe the way I am getting the StreamProvider in the unit test is not correct.

All of the code looks like the following:

ClusterCollection:

using System;
using Orleans.TestingHost;
using Xunit;

namespace Tests {

    [CollectionDefinition(ClusterCollection.Name)]
    public class ClusterCollection : ICollectionFixture<ClusterFixture>
    {
        public const string Name = "ClusterCollection";
    }
}

ClusterFixture:

public class ClusterFixture : IDisposable
{
    private sealed class Configurator : ISiloBuilderConfigurator
    {
        public void Configure(ISiloHostBuilder siloBuilder)
        {
            siloBuilder.AddSimpleMessageStreamProvider("SMSProvider");
            siloBuilder.AddMemoryGrainStorage("PubSubStore");
        }
    }
    public ClusterFixture()
    {
        var builder = new TestClusterBuilder();
        builder.AddSiloBuilderConfigurator<Configurator>();
        this.Cluster = builder.Build();
        this.Cluster.Deploy();
    }

    public void Dispose()
    {
        this.Cluster.StopAllSilos();
    }

    public TestCluster Cluster { get; private set; }
}

SomeTests:

 [Collection(ClusterCollection.Name)]
    public class SomeTests
    {
        private readonly TestCluster _cluster;

        public SomeTests(ClusterFixture fixture)
        {
            _cluster = fixture.Cluster;
        }

        [Fact]
        public async Task SaysHelloCorrectly()
        {
            var hello = _cluster.GrainFactory.GetGrain<ISomeGrain>(Guid.NewGuid(), "<Some stream ID>", "Some.Class.Path");
            var guid = Guid.NewGuid();
            var streamProvider = _cluster.Client.GetStreamProvider("SMSProvider");
            var photoStream = streamProvider.GetStream<string>(guid, "<Some stream ID>");
            await photoStream.OnNextAsync("Hi");
            Assert.Equal("Hello, World", "Hello, World");
        }
    }

Solution

  • The setup needs to be improved. You can check this sample from the official Orleans GitHub page: https://github.com/dotnet/orleans/blob/main/test/TesterInternal/StreamingTests/SMSStreamingTests.cs

    So, in your ClusterFixture class you should add the SiloConfigurator:

    private class SiloConfigurator : ISiloConfigurator
    {
      public void Configure(ISiloBuilder hostBuilder) =>
         hostBuilder.AddSimpleMessageStreamProvider("SMSProvider")
                    .AddMemoryGrainStorage("PubSubStore");
    }
    

    and the ClientConfiguretor:

    private class ClientConfiguretor : IClientBuilderConfigurator
    {
      public void Configure(IConfiguration configuration, IClientBuilder clientBuilder) => 
        clientBuilder.AddSimpleMessageStreamProvider("SMSProvider");
    }
    

    And then in your ClusterFixture constructor:

    public ClusterFixture()
    {
        var builder = new TestClusterBuilder();
        builder.AddSiloBuilderConfigurator<SiloConfigurator>();
        builder.AddClientBuilderConfigurator<ClientConfiguretor>();
        this.Cluster = builder.Build();
        this.Cluster.Deploy();
    }