orleans/test/DefaultCluster.Tests/OneWayCallTests.cs

87 строки
3.8 KiB
C#
Исходник Постоянная ссылка Обычный вид История

using Orleans.Internal;
using TestExtensions;
using UnitTests.GrainInterfaces;
using Xunit;
namespace DefaultCluster.Tests.General
{
[TestCategory("BVT"), TestCategory("OneWay")]
public class OneWayCallTests : HostedTestClusterEnsureDefaultStarted
{
public OneWayCallTests(DefaultClusterFixture fixture) : base(fixture) { }
[Fact]
public async Task OneWayMethodsReturnSynchronously_ViaClient()
{
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var observer = new SimpleGrainObserver();
var task = grain.Notify(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));
Assert.True(task.Status == TaskStatus.RanToCompletion, "Task should be synchronously completed.");
Generate type metadata during codegen (#3518) This commit implements a feature similar to ASP.NET's ApplicationParts. * Users are required to provide a set of assemblies (application parts) when configuring the silo or the client. * Extension methods are provided for adding all assemblies in the current directory or adding all assemblies in the current `AppDomain`. * The process of calling `AssemblyLoader` process has been removed from the startup path. * Instead of scanning every assembly and every type which is loaded for grain interfaces/classes, and serialization information, that occurs at code generation time and the results are loaded on startup. * Runtime Code Generation is removed. It's *possible* that we could enable runtime code generation which runs before the client/silo is created, but that's out of scope. * `CachedTypeResolver` performs a more thorough search when resolving types. * `ITypeResolver` was introduced to allow users to decide how types are resolved and potentially blacklist/whitelist allowed types. `CachedTypeResolver` is the default implementation. The application parts is like so: * An `ApplicationPartManager` holds a collection of *Parts* and *FeatureProviders*. * `ApplicationPartManager` has a method, `void Populate<TFeature>(TFeature feature)`, which can be passed a POCO "feature" class. It gives each FeatureProvider a chance to mutate the feature, given the list of Parts. * The feature is typically an object containing collections of simple metadata about the application (list of grain interfaces, for example). Code generation support is like so: * Code generator defines an assembly level `FeaturePopulatorAttribute` attribute that references generated POCO class which implement an interface `IFeaturePopulator<TFeature>` for each feature (currently: `SerializerFeature`, `GrainInterfaceFeature`, `GrainClassFeature`). * each `IFeaturePopulator<>` implementation has a `Populate(TFeature)` method which contains code to add metadata to the feature. * A FeatureProvider called `AssemblyAttributeFeatureProvider<TFeature>` scans each of the provided parts for assemblies which have the assembly-level attribute `FeaturePopulatorAttribute` and then executes the `Populate(feature)` method of each of the references, augmenting the metadata on the feature. This lays the groundwork for implementing 'type forwarding' where a persisted type is forwarded to a different type with the same layout at runtime (eg different assembly, different namespace, different name). TODO: address `ProviderTypeLoader` which still scans the world
2017-10-14 03:04:34 +03:00
await observer.ReceivedValue.WithTimeout(TimeSpan.FromSeconds(10));
var count = await grain.GetCount();
Assert.Equal(1, count);
// This should not throw.
task = grain.ThrowsOneWay();
Assert.True(task.Status == TaskStatus.RanToCompletion, "Task should be synchronously completed.");
}
[Fact]
public async Task OneWayMethodReturnSynchronously_ViaGrain()
{
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var otherGrain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var observer = new SimpleGrainObserver();
var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);
var completedSynchronously = await grain.NotifyOtherGrain(otherGrain, observerReference);
Assert.True(completedSynchronously, "Task should be synchronously completed.");
await observer.ReceivedValue.WithTimeout(TimeSpan.FromSeconds(10));
var count = await otherGrain.GetCount();
Assert.Equal(1, count);
}
[Fact]
public async Task OneWayMethodsReturnSynchronously_ViaClient_ValueTask()
{
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var observer = new SimpleGrainObserver();
var task = grain.NotifyValueTask(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));
Assert.True(task.IsCompleted, "ValueTask should be synchronously completed.");
await observer.ReceivedValue.WithTimeout(TimeSpan.FromSeconds(10));
var count = await grain.GetCount();
Assert.Equal(1, count);
// This should not throw.
task = grain.ThrowsOneWayValueTask();
Assert.True(task.IsCompleted, "Task should be synchronously completed.");
}
[Fact]
public async Task OneWayMethodReturnSynchronously_ViaGrain_ValueTask()
{
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var otherGrain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
var observer = new SimpleGrainObserver();
var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);
var completedSynchronously = await grain.NotifyOtherGrainValueTask(otherGrain, observerReference);
Assert.True(completedSynchronously, "Task should be synchronously completed.");
await observer.ReceivedValue.WithTimeout(TimeSpan.FromSeconds(10));
var count = await otherGrain.GetCount();
Assert.Equal(1, count);
}
private class SimpleGrainObserver : ISimpleGrainObserver
{
private readonly TaskCompletionSource<int> completion = new TaskCompletionSource<int>();
public Task ReceivedValue => this.completion.Task;
public void StateChanged(int a, int b)
{
this.completion.SetResult(b);
}
}
}
}