OrleansContrib / OrleansTestKit

Unit Test Toolkit for Microsoft Orleans
http://dotnet.github.io/orleans
MIT License
77 stars 42 forks source link

Add support for transactional state facet #67

Open Johanny opened 5 years ago

Johanny commented 5 years ago

Since the release of Orleans 2.1.0 grains now support transactions.

For a grain to use transactions it should be instanciated with a ITransactionalState<TState> facet:

public AccountGrain(
    [TransactionalState("balance", "TransactionStore")]
    ITransactionalState<Balance> balance)
{
    this.balance = balance ?? throw new ArgumentNullException(nameof(balance));
}

It would be great to be able to unit test grain with a transactionnal state facet with the test kit. Right now trying to get a grain with a ITransactionalState<TState> facet like so:

var grain = await Silo.CreateGrainAsync<AccountGrain>(Guid.NewGuid());

Is throwing this exception:

Orleans.Runtime.OrleansException : Attribute mapper Castle.Proxies.IAttributeToFactoryMapper`1Proxy failed to create a factory for grain type AccountGrain
   at Orleans.Runtime.ConstructorArgumentFactory.ArgumentFactory.GetFactory[TMetadata](IServiceProvider services, ParameterInfo parameter, IFacetMetadata metadata, Type type) in D:\build\agent\_work\23\s\src\Orleans.Runtime\Facet\ConstructorArgumentFactory.cs:line 90

Here is a naive implementation that fulfil the ITransactionalState interface and enable testing such grains:

class TestTransactionalState<TState> : ITransactionalState<TState>
    where TState : class, new()
{
    private readonly TState _state = new TState();

    public Task<TResult> PerformRead<TResult>(Func<TState, TResult> readFunction)
    {
        return Task.FromResult(readFunction(_state));
    }

    public Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateFunction)
    {
        return Task.FromResult(updateFunction(_state));
    }
}

Standalone usage example:

var state = new TestTransactionalState<Balance>();
var grain = new AccountGrain(state);

This implementation works but something integrated to the test kit would be better.

seniorquico commented 5 years ago

This is very similar to #55. We can support constructor injection of ITransactionalState<TState> mock objects by registering our own implementation of IAttributeToFactoryMapper<TransactionalStateAttribute> in the silo's dependency injection container.

erikljung commented 5 years ago

Any progress on this? Would be a great feature!

seniorquico commented 4 years ago

@erikljung Not directly. I have a branch that adds the needed support for constructor injection, but I've only applied it to the state facet interfaces/classes.