2019-10-02 21:07:58 +03:00
|
|
|
using Orleans.Internal;
|
2017-05-10 03:07:39 +03:00
|
|
|
using TestExtensions;
|
|
|
|
using UnitTests.GrainInterfaces;
|
|
|
|
using Xunit;
|
|
|
|
|
|
|
|
namespace DefaultCluster.Tests.General
|
|
|
|
{
|
2017-08-09 18:21:04 +03:00
|
|
|
[TestCategory("BVT"), TestCategory("OneWay")]
|
2017-05-10 03:07:39 +03:00
|
|
|
public class OneWayCallTests : HostedTestClusterEnsureDefaultStarted
|
|
|
|
{
|
|
|
|
public OneWayCallTests(DefaultClusterFixture fixture) : base(fixture) { }
|
|
|
|
|
|
|
|
[Fact]
|
2018-02-09 00:45:13 +03:00
|
|
|
public async Task OneWayMethodsReturnSynchronously_ViaClient()
|
2017-05-10 03:07:39 +03:00
|
|
|
{
|
|
|
|
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
|
|
|
|
|
|
|
|
var observer = new SimpleGrainObserver();
|
2022-02-18 07:19:53 +03:00
|
|
|
var task = grain.Notify(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));
|
2017-05-10 03:07:39 +03:00
|
|
|
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));
|
2017-05-10 03:07:39 +03:00
|
|
|
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.");
|
|
|
|
}
|
|
|
|
|
2018-02-09 00:45:13 +03:00
|
|
|
[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();
|
2022-02-18 07:19:53 +03:00
|
|
|
var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);
|
2018-02-09 00:45:13 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-05-03 22:35:19 +03:00
|
|
|
[Fact]
|
|
|
|
public async Task OneWayMethodsReturnSynchronously_ViaClient_ValueTask()
|
|
|
|
{
|
|
|
|
var grain = this.Client.GetGrain<IOneWayGrain>(Guid.NewGuid());
|
|
|
|
|
|
|
|
var observer = new SimpleGrainObserver();
|
2022-02-18 07:19:53 +03:00
|
|
|
var task = grain.NotifyValueTask(this.Client.CreateObjectReference<ISimpleGrainObserver>(observer));
|
2020-05-03 22:35:19 +03:00
|
|
|
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();
|
2022-02-18 07:19:53 +03:00
|
|
|
var observerReference = this.Client.CreateObjectReference<ISimpleGrainObserver>(observer);
|
2020-05-03 22:35:19 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-05-10 03:07:39 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|