Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Orleans.Transaction.Testkit project structure #5103

Merged
merged 5 commits into from Oct 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 34 additions & 1 deletion Orleans.sln
Expand Up @@ -218,6 +218,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeGenerator.Tests", "test
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.CodeGenerator.MSBuild.Tasks", "src\Orleans.CodeGenerator.MSBuild.Tasks\Orleans.CodeGenerator.MSBuild.Tasks.csproj", "{5EAE884A-52BE-4AA6-9FCB-AD1C45A9BB7C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Transactions", "Transactions", "{3189037B-208D-40A1-A561-169D77D9BB5A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.Transactions.TestKit.Base", "src\Orleans.Transactions.TestkitBase\Orleans.Transactions.TestKit.Base.csproj", "{531A89F5-DD05-4D14-A330-6548359A231A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Orleans.Transactions.TestKit.xUnit", "src\Orleans.Transactions.Testkit.Xunit\Orleans.Transactions.TestKit.xUnit.csproj", "{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1332,6 +1338,30 @@ Global
{5EAE884A-52BE-4AA6-9FCB-AD1C45A9BB7C}.Release|x64.Build.0 = Release|Any CPU
{5EAE884A-52BE-4AA6-9FCB-AD1C45A9BB7C}.Release|x86.ActiveCfg = Release|Any CPU
{5EAE884A-52BE-4AA6-9FCB-AD1C45A9BB7C}.Release|x86.Build.0 = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|x64.ActiveCfg = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|x64.Build.0 = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|x86.ActiveCfg = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Debug|x86.Build.0 = Debug|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|Any CPU.Build.0 = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|x64.ActiveCfg = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|x64.Build.0 = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|x86.ActiveCfg = Release|Any CPU
{531A89F5-DD05-4D14-A330-6548359A231A}.Release|x86.Build.0 = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|x64.ActiveCfg = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|x64.Build.0 = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|x86.ActiveCfg = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Debug|x86.Build.0 = Debug|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|Any CPU.Build.0 = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|x64.ActiveCfg = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|x64.Build.0 = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|x86.ActiveCfg = Release|Any CPU
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1398,7 +1428,7 @@ Global
{0CCA4C5C-1D31-4AA9-A7AF-90DD63C16F5B} = {DA143BBE-5D97-4792-8E36-44A3FA727C74}
{F7D70028-7E3B-48E3-92B9-DB889AE5ABD1} = {DA143BBE-5D97-4792-8E36-44A3FA727C74}
{9B07237D-651C-497D-9E8D-EADC8FAF26FF} = {DA143BBE-5D97-4792-8E36-44A3FA727C74}
{072B1B88-FE98-4354-86FA-AB6EF80EB9C4} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23}
{072B1B88-FE98-4354-86FA-AB6EF80EB9C4} = {3189037B-208D-40A1-A561-169D77D9BB5A}
{CFD22413-CB67-40D6-B389-F038C8C38365} = {E4550469-BCFB-4F3E-B778-3769DE18F45A}
{BE7FB595-FA25-4D88-8504-E9D4F9D8183D} = {4C5D66BF-EE1C-4DD8-8551-D1B7F3768A34}
{651C7B8E-6EEB-4A6B-84A3-B5D7E4554B99} = {E4550469-BCFB-4F3E-B778-3769DE18F45A}
Expand Down Expand Up @@ -1442,6 +1472,9 @@ Global
{D9F12BF9-55AD-4BA3-B850-9A410C287733} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A}
{C831C17D-EB49-4237-B86F-638C9A8E9708} = {D9F12BF9-55AD-4BA3-B850-9A410C287733}
{5EAE884A-52BE-4AA6-9FCB-AD1C45A9BB7C} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23}
{3189037B-208D-40A1-A561-169D77D9BB5A} = {4CD3AA9E-D937-48CA-BB6C-158E12257D23}
{531A89F5-DD05-4D14-A330-6548359A231A} = {3189037B-208D-40A1-A561-169D77D9BB5A}
{B8ABE746-C76F-4E0E-86A5-744E85A55CE8} = {3189037B-208D-40A1-A561-169D77D9BB5A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7BFB3429-B5BB-4DB1-95B4-67D77A864952}
Expand Down
Expand Up @@ -14,18 +14,16 @@ public class AzureTableTransactionalStateStorage<TState> : ITransactionalStateSt
{
private readonly CloudTable table;
private readonly string partition;
private readonly string stateName;
private readonly JsonSerializerSettings jsonSettings;
private readonly ILogger logger;

private KeyEntity key;
private List<KeyValuePair<long, StateEntity>> states;

public AzureTableTransactionalStateStorage(CloudTable table, string partition, string stateName, JsonSerializerSettings JsonSettings, ILogger<AzureTableTransactionalStateStorage<TState>> logger)
public AzureTableTransactionalStateStorage(CloudTable table, string partition, JsonSerializerSettings JsonSettings, ILogger<AzureTableTransactionalStateStorage<TState>> logger)
{
this.table = table;
this.partition = partition;
this.stateName = stateName;
this.jsonSettings = JsonSettings;
this.logger = logger;
}
Expand Down
Expand Up @@ -41,7 +41,7 @@ public AzureTableTransactionalStateStorageFactory(string name, AzureTableTransac
public ITransactionalStateStorage<TState> Create<TState>(string stateName, IGrainActivationContext context) where TState : class, new()
{
string partitionKey = MakePartitionKey(context, stateName);
return ActivatorUtilities.CreateInstance<AzureTableTransactionalStateStorage<TState>>(context.ActivationServices, this.table, partitionKey, stateName, this.jsonSettings);
return ActivatorUtilities.CreateInstance<AzureTableTransactionalStateStorage<TState>>(context.ActivationServices, this.table, partitionKey, this.jsonSettings);
}

public void Participate(ISiloLifecycle lifecycle)
Expand Down
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>Microsoft.Orleans.Transactions.TestKit.xUnit</PackageId>
<Title>Microsoft Orleans Transactions test kit for xUnit</Title>
<Description>xUnit testkit library for transactions</Description>
<PackageTags>$(PackageTags) TransactionTestKit</PackageTags>
</PropertyGroup>

<PropertyGroup>
<AssemblyName>Orleans.Transactions.TestKit.xUnit</AssemblyName>
<RootNamespace>Orleans.Transactions.TestKit.xUnit</RootNamespace>
</PropertyGroup>

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit" Version="$(xUnitVersion)" />
<PackageReference Include="Xunit.SkippableFact" Version="$(XunitSkippableFactVersion)" />
<DotNetCliToolReference Include="dotnet-xunit" Version="$(xUnitVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Orleans.Transactions.TestkitBase\Orleans.Transactions.TestKit.Base.csproj" />
</ItemGroup>

</Project>
@@ -0,0 +1,33 @@
using System;
using System.Threading.Tasks;
using Orleans.Transactions.TestKit.Base;
using Orleans.Transactions.Abstractions;
using Xunit;
using Xunit.Abstractions;

namespace Orleans.Transactions.TestKit.xUnit
{
public abstract class TransactionalStateStorageTestRunnerxUnit<TState> : TransactionalStateStorageTestRunner<TState>
where TState: class, new()
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="stateStorageFactory">factory to create ITransactionalStateStorage, the test runner are assuming the state
/// in storage is empty when ITransactionalStateStorage was created </param>
/// <param name="stateFactory">factory to create TState for test</param>
/// <param name="grainFactory">grain Factory needed for test runner</param>
/// <param name="testOutput">test output to helpful messages</param>
public TransactionalStateStorageTestRunnerxUnit(Func<Task<ITransactionalStateStorage<TState>>> stateStorageFactory,
Func<TState> stateFactory, IGrainFactory grainFactory, ITestOutputHelper testOutput)
: base(stateStorageFactory, stateFactory, grainFactory, testOutput.WriteLine)
{
}

[Fact]
public override Task FirstTime_Load_ShouldReturnEmptyLoadResponse()
{
return base.FirstTime_Load_ShouldReturnEmptyLoadResponse();
}
}
}
@@ -0,0 +1,36 @@
using System.Threading.Tasks;

namespace Orleans.Transactions.TestKit.Base
{
public interface ITransactionTestGrain : IGrainWithGuidKey
{

/// <summary>
/// apply set operation to every transaction state
/// </summary>
/// <param name="newValue"></param>
/// <returns></returns>
[Transaction(TransactionOption.CreateOrJoin)]
Task Set(int newValue);

/// <summary>
/// apply add operation to every transaction state
/// </summary>
/// <param name="numberToAdd"></param>
/// <returns></returns>
[Transaction(TransactionOption.CreateOrJoin)]
Task<int[]> Add(int numberToAdd);

/// <summary>
/// apply get operation to every transaction state
/// </summary>
/// <returns></returns>
[Transaction(TransactionOption.CreateOrJoin)]
Task<int[]> Get();

[Transaction(TransactionOption.CreateOrJoin)]
Task AddAndThrow(int numberToAdd);

Task Deactivate();
}
}
@@ -0,0 +1,151 @@
using Microsoft.Extensions.Logging;
using Orleans.Transactions.Abstractions;
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;

namespace Orleans.Transactions.TestKit.Base
{
[Serializable]
public class GrainData
{
public int Value { get; set; }
}

public class MaxStateTransactionalGrain : MultiStateTransactionalGrainBaseClass
{
public MaxStateTransactionalGrain(ITransactionalStateFactory stateFactory,
ILoggerFactory loggerFactory)
: base(Enumerable.Range(0, TransactionTestConstants.MaxCoordinatedTransactions)
.Select(i => stateFactory.Create<GrainData>(new TransactionalStateAttribute($"data{i}", TransactionTestConstants.TransactionStore)))
.ToArray(),
loggerFactory)
{
}
}

public class DoubleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass
{
public DoubleStateTransactionalGrain(
[TransactionalState("data1", TransactionTestConstants.TransactionStore)]
ITransactionalState<GrainData> data1,
[TransactionalState("data2", TransactionTestConstants.TransactionStore)]
ITransactionalState<GrainData> data2,
ILoggerFactory loggerFactory)
: base(new ITransactionalState<GrainData>[2] { data1, data2 }, loggerFactory)
{
}
}

public class SingleStateTransactionalGrain : MultiStateTransactionalGrainBaseClass
{
public SingleStateTransactionalGrain(
[TransactionalState("data", TransactionTestConstants.TransactionStore)]
ITransactionalState<GrainData> data,
ILoggerFactory loggerFactory)
: base(new ITransactionalState<GrainData>[1] { data }, loggerFactory)
{
}
}

public class NoStateTransactionalGrain : MultiStateTransactionalGrainBaseClass
{
public NoStateTransactionalGrain(
ILoggerFactory loggerFactory)
: base(Array.Empty<ITransactionalState<GrainData>>(), loggerFactory)
{
}
}

public class MultiStateTransactionalGrainBaseClass : Grain, ITransactionTestGrain
{
protected ITransactionalState<GrainData>[] dataArray;
private readonly ILoggerFactory loggerFactory;
protected ILogger logger;

public MultiStateTransactionalGrainBaseClass(
ITransactionalState<GrainData>[] dataArray,
ILoggerFactory loggerFactory)
{
this.dataArray = dataArray;
this.loggerFactory = loggerFactory;
}

public override Task OnActivateAsync()
{
this.logger = this.loggerFactory.CreateLogger(this.GetGrainIdentity().ToString());
return base.OnActivateAsync();
}

public async Task Set(int newValue)
{
foreach(var data in this.dataArray)
{
await data.PerformUpdate(state =>
{
this.logger.LogInformation($"Setting from {state.Value} to {newValue}.");
state.Value = newValue;
this.logger.LogInformation($"Set to {state.Value}.");
});
}
}

public async Task<int[]> Add(int numberToAdd)
{
var result = new int[dataArray.Length];
for(int i = 0; i < dataArray.Length; i++)
{
result[i] = await dataArray[i].PerformUpdate(state =>
{
this.logger.LogInformation($"Adding {numberToAdd} to {state.Value}.");
state.Value += numberToAdd;
this.logger.LogInformation($"Value after Adding {numberToAdd} is {state.Value}.");
return state.Value;
});
}
return result;
}

public async Task<int[]> Get()
{
var result = new int[dataArray.Length];
for (int i = 0; i < dataArray.Length; i++)
{
result[i] = await dataArray[i].PerformRead(state =>
{
this.logger.LogInformation($"Get {state.Value}.");
return state.Value;
});
}
return result;
}

public async Task AddAndThrow(int numberToAdd)
{
await Add(numberToAdd);
throw new AddAndThrowException($"{GetType().Name} test exception");
}

public Task Deactivate()
{
DeactivateOnIdle();
return Task.CompletedTask;
}
}

[Serializable]
public class AddAndThrowException : Exception
{
public AddAndThrowException() : base("Unexpected error.") { }

public AddAndThrowException(string message) : base(message) { }

public AddAndThrowException(string message, Exception innerException) : base(message, innerException) { }

protected AddAndThrowException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}
@@ -0,0 +1,26 @@

using Microsoft.Extensions.Logging;
using Orleans.Hosting;

namespace Orleans.Transactions.TestKit.Base
{
public static class TransactionTestConstants
{
/// <summary>
/// Max number of grains to include in a transaction for test purposes. Not a hard limit of the transaction system.
/// </summary>
public const int MaxCoordinatedTransactions = 8;

// storage providers
public const string TransactionStore = "TransactionStore";

// committer service
public const string RemoteCommitService = "RemoteCommitService";

// grain implementations
public const string NoStateTransactionalGrain = "NoStateTransactionalGrain";
public const string SingleStateTransactionalGrain = "SingleStateTransactionalGrain";
public const string DoubleStateTransactionalGrain = "DoubleStateTransactionalGrain";
public const string MaxStateTransactionalGrain = "MaxStateTransactionalGrain";
}
}
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<PackageId>Microsoft.Orleans.Transactions.TestKit.Base</PackageId>
<Title>Microsoft Orleans Transactions test kit base</Title>
<Description>Testkit base library for transactions</Description>
<PackageTags>$(PackageTags) TransactionTestkKit</PackageTags>
</PropertyGroup>

<PropertyGroup>
<AssemblyName>Orleans.Transactions.TestKit.Base</AssemblyName>
<RootNamespace>Orleans.Transactions.TestKit.Base</RootNamespace>
</PropertyGroup>

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="$(FluentAssertionsVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Orleans.Transactions\Orleans.Transactions.csproj" />
</ItemGroup>

</Project>