Skip to content

Commit

Permalink
Fixed MassTransit#5015 - States and Events from state machine base cl…
Browse files Browse the repository at this point in the history
…asses are now properly initialized
  • Loading branch information
phatboyg committed Apr 3, 2024
1 parent c5d5b61 commit 596d244
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 2 deletions.
20 changes: 18 additions & 2 deletions src/MassTransit/SagaStateMachine/MassTransitStateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1978,8 +1978,7 @@ IEnumerable<PropertyInfo> GetStateMachineProperties()

bool TryGetBackingField(PropertyInfo property, out FieldInfo backingField)
{
_backingFields ??= GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
_backingFields ??= GetBackingFields(GetType())
.Where(field =>
field.Attributes.HasFlag(FieldAttributes.Private) &&
field.Attributes.HasFlag(FieldAttributes.InitOnly) &&
Expand All @@ -1997,6 +1996,23 @@ bool TryGetBackingField(PropertyInfo property, out FieldInfo backingField)
return backingField != null;
}

static IEnumerable<FieldInfo> GetBackingFields(Type type)
{
while (true)
{
foreach (var fieldInfo in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
yield return fieldInfo;

if (type.BaseType == null)
break;

if (type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(MassTransitStateMachine<>))
break;

type = type.BaseType;
}
}

void InitializeState(MassTransitStateMachine<TInstance> stateMachine, PropertyInfo property, StateMachineState state)
{
if (property.CanWrite)
Expand Down
123 changes: 123 additions & 0 deletions tests/MassTransit.Tests/SagaStateMachineTests/BaseClass_Specs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
namespace MassTransit.Tests.SagaStateMachineTests
{
using System.Threading.Tasks;
using BaseStateMachineTestSubjects;
using MassTransit.Testing;
using Microsoft.Extensions.DependencyInjection;
using NUnit.Framework;


[TestFixture]
public class Using_a_base_state_machine
{
[Test]
public async Task Should_initialize_all_states_and_events()
{
await using var provider = new ServiceCollection()
.AddMassTransitTestHarness(x =>
{
x.AddSagaStateMachine<HappyGoLuckyStateMachine, HappyGoLuckyState>();
})
.BuildServiceProvider(true);

var harness = await provider.StartTestHarness();

var id = NewId.NextGuid();

await harness.Bus.Publish(new HappyEvent(id));

Assert.That(await harness.Consumed.Any<HappyEvent>());

await harness.Bus.Publish(new EndItAllEvent(id));

Assert.That(await harness.Consumed.Any<EndItAllEvent>());
}
}


namespace BaseStateMachineTestSubjects
{
using System;


public class HappyEvent
{
public HappyEvent(Guid correlationId)
{
CorrelationId = correlationId;
}

public Guid CorrelationId { get; set; }
}


public class GoLuckyEvent
{
public GoLuckyEvent(Guid correlationId)
{
CorrelationId = correlationId;
}

public Guid CorrelationId { get; set; }
}


public class EndItAllEvent
{
public EndItAllEvent(Guid correlationId)
{
CorrelationId = correlationId;
}

public Guid CorrelationId { get; set; }
}


public class CommonStateMachine<T> :
MassTransitStateMachine<T>
where T : class, SagaStateMachineInstance
{
//
// ReSharper disable UnassignedGetOnlyAutoProperty
public State Happy { get; }
public State GoLucky { get; }

public Event<HappyEvent> OnHappy { get; }
public Event<GoLuckyEvent> OnGoLucky { get; }
}


public class HappyGoLuckyState :
SagaStateMachineInstance
{
public string CurrentState { get; set; }
public Guid CorrelationId { get; set; }
}


public class HappyGoLuckyStateMachine :
CommonStateMachine<HappyGoLuckyState>
{
public HappyGoLuckyStateMachine()
{
InstanceState(x => x.CurrentState);

Initially(
When(OnHappy)
.TransitionTo(Happy),
When(OnGoLucky)
.TransitionTo(GoLucky));

During(Happy, GoLucky,
When(OnEndItAll)
.TransitionTo(Finished));

SetCompletedWhenFinalized();
}

public State Finished { get; }

public Event<EndItAllEvent> OnEndItAll { get; }
}
}
}

0 comments on commit 596d244

Please sign in to comment.