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 ModifyProcessInstance to client #641

Merged
merged 9 commits into from
Jan 29, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Client.UnitTests/Client.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0;net7.0</TargetFrameworks>
<TargetFrameworks>net6.0;net7.0;net8.0</TargetFrameworks>
<RootNamespace>Zeebe.Client</RootNamespace>
</PropertyGroup>

Expand Down
6 changes: 6 additions & 0 deletions Client.UnitTests/GatewayTestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public GatewayTestService()
typedRequestHandler.Add(typeof(ResolveIncidentRequest), request => new ResolveIncidentResponse());
typedRequestHandler.Add(typeof(CreateProcessInstanceWithResultRequest), request => new CreateProcessInstanceWithResultResponse());
typedRequestHandler.Add(typeof(EvaluateDecisionRequest), request => new EvaluateDecisionResponse());
typedRequestHandler.Add(typeof(ModifyProcessInstanceRequest), request => new ModifyProcessInstanceResponse());

foreach (var pair in typedRequestHandler)
{
Expand Down Expand Up @@ -150,6 +151,11 @@ public override Task<EvaluateDecisionResponse> EvaluateDecision(EvaluateDecision
return Task.FromResult((EvaluateDecisionResponse)HandleRequest(request, context));
}

public override Task<ModifyProcessInstanceResponse> ModifyProcessInstance(ModifyProcessInstanceRequest request, ServerCallContext context)
{
return Task.FromResult((ModifyProcessInstanceResponse)HandleRequest(request, context));
}

public delegate void ConsumeMetadata(Metadata metadata);

public void ConsumeRequestHeaders(ConsumeMetadata consumer)
Expand Down
276 changes: 276 additions & 0 deletions Client.UnitTests/ModifyProcessInstanceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using GatewayProtocol;
using NUnit.Framework;

namespace Zeebe.Client;

[TestFixture]
public class ModifyProcessInstanceTest : BaseZeebeTest
{
private const long TestProcessInstanceKey = 1234567890;
private const long TestAncestorElementInstanceKey = 2345678900;
private const long TestElementInstanceKey = 3456789000;
private const string TestElementId = "element1";
private const string TestVariables = "variable1";
private const string TestScopeId = "scope1";

[Test]
public async Task ShouldSendRequestAsExpectedWithActivateElement()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = 0
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(elementId: TestElementId)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestAsExpectedWithActivateElementWithAncestor()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = TestAncestorElementInstanceKey
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(elementId: TestElementId, ancestorElementInstanceKey: TestAncestorElementInstanceKey)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestAsExpectedWithTerminateElement()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
TerminateInstructions =
{
new ModifyProcessInstanceRequest.Types.TerminateInstruction()
{
ElementInstanceKey = TestElementInstanceKey
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.TerminateElement(TestElementInstanceKey)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestWithActivateAndTerminate()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = TestAncestorElementInstanceKey
}
},
TerminateInstructions =
{
new ModifyProcessInstanceRequest.Types.TerminateInstruction()
{
ElementInstanceKey = TestElementInstanceKey
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(elementId: TestElementId, ancestorElementInstanceKey: TestAncestorElementInstanceKey)
.And()
.TerminateElement(elementInstanceKey: TestElementInstanceKey)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestWithActivateAndTerminateMultiple()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = TestAncestorElementInstanceKey
},
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId + "2",
AncestorElementInstanceKey = TestAncestorElementInstanceKey + 1
}
},
TerminateInstructions =
{
new ModifyProcessInstanceRequest.Types.TerminateInstruction()
{
ElementInstanceKey = TestElementInstanceKey
},
new ModifyProcessInstanceRequest.Types.TerminateInstruction()
{
ElementInstanceKey = TestElementInstanceKey + 1
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(elementId: TestElementId, ancestorElementInstanceKey: TestAncestorElementInstanceKey)
.And()
.TerminateElement(elementInstanceKey: TestElementInstanceKey)
.And()
.ActivateElement(elementId: TestElementId + "2",
ancestorElementInstanceKey: TestAncestorElementInstanceKey + 1)
.And()
.TerminateElement(TestElementInstanceKey + 1)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestWithActivateElementIdAndVariableInstructions()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = 0,
VariableInstructions =
{
new List<ModifyProcessInstanceRequest.Types.VariableInstruction>
{
new () { Variables = TestVariables, ScopeId = TestScopeId }
}
}
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(elementId: TestElementId)
.WithVariables(TestVariables, TestScopeId)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}

[Test]
public async Task ShouldSendRequestWithActivateElementIdVariableAndTerminateInstructions()
{
// given
var expectedRequest = new ModifyProcessInstanceRequest
{
ProcessInstanceKey = TestProcessInstanceKey,
ActivateInstructions =
{
new ModifyProcessInstanceRequest.Types.ActivateInstruction
{
ElementId = TestElementId,
AncestorElementInstanceKey = TestAncestorElementInstanceKey,
VariableInstructions =
{
new List<ModifyProcessInstanceRequest.Types.VariableInstruction>
{
new () { Variables = TestVariables, ScopeId = TestScopeId }
}
}
}
},
TerminateInstructions =
{
new ModifyProcessInstanceRequest.Types.TerminateInstruction()
{
ElementInstanceKey = TestElementInstanceKey
}
}
};

// when
await ZeebeClient.NewModifyProcessInstanceCommand(processInstanceKey: TestProcessInstanceKey)
.ActivateElement(TestElementId, TestAncestorElementInstanceKey)
.WithVariables(TestVariables, TestScopeId)
.And()
.TerminateElement(elementInstanceKey: TestElementInstanceKey)
.Send();

// then
var request = TestService.Requests[typeof(ModifyProcessInstanceRequest)][0];
var typedRequest = request as ModifyProcessInstanceRequest;
Assert.NotNull(typedRequest);
Assert.AreEqual(expectedRequest, typedRequest);
}
}
75 changes: 75 additions & 0 deletions Client/Api/Commands/IModifyProcessInstanceCommandStep1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using Zeebe.Client.Api.Responses;

namespace Zeebe.Client.Api.Commands;

/// <summary>
/// Command to modify a process instance.
/// </summary>
public interface IModifyProcessInstanceCommandStep1
{
/// <summary>
/// Create an activate Instruction
/// for the given element id. The element will be created within an existing element instance of
/// the flow scope. When activating an element inside a multi-instance element the element instance
/// key of the ancestor must be defined. For this use <see cref="ActivateElement(string, long)"/>.
/// </summary>
/// <param name="elementId">The id of the element to activate.</param>
/// <returns>The builder for this command.</returns>
IModifyProcessInstanceCommandStep3 ActivateElement(string elementId);

/// <summary>
/// Create an activate Instruction
/// for the given element id. The element will be created within the scope that is passed. This
/// scope must be an ancestor of the element that's getting activated.
/// </summary>
/// <param name="elementId">The id of the element to activate.</param>
/// <param name="ancestorElementInstanceKey">The element instance key in which the element will be created.</param>
/// <returns>The builder for this command.</returns>
IModifyProcessInstanceCommandStep3 ActivateElement(string elementId, long ancestorElementInstanceKey);


/// <summary>
/// Create a terminate instruction for the given element id.
/// </summary>
/// <param name="elementInstanceKey">The element instance key of the element to terminate.</param>
/// <returns>the builder for this command.</returns>
IModifyProcessInstanceCommandStep2 TerminateElement(long elementInstanceKey);
}

/// <summary>
/// Second command step, to optional add more instructions to activate or terminate.
/// </summary>
public interface IModifyProcessInstanceCommandStep2 :
IFinalCommandWithRetryStep<IModifyProcessInstanceResponse>
{
/// <summary>
/// Acts as a boundary between the different activate and terminate instructions. Use this if you
/// want to activate or terminate another element.
/// Otherwise, use <see cref="IFinalCommandWithRetryStep{T}.SendWithRetry"/> to send the command.
/// </summary>
/// <returns>The builder for this command.</returns>
IModifyProcessInstanceCommandStep1 And();
}

/// <summary>
/// Third command step, to optionally add variables to the element which should be activated.
/// </summary>
public interface IModifyProcessInstanceCommandStep3 : IModifyProcessInstanceCommandStep2
{
/// <summary>
/// Create a variable instruction for the element that's getting activated.
/// These variables will be created in the global scope of the process instance.
/// </summary>
/// <param name="variables">The variables JSON document as String.</param>
/// <returns>The builder for this command.</returns>
IModifyProcessInstanceCommandStep3 WithVariables(string variables);

/// <summary>
/// Create a variable instruction for the element that's getting activated.
/// These variables will be created in the scope of the passed element.
/// </summary>
/// <param name="variables">The variables JSON document as String.</param>
/// <param name="scopeId">The id of the element in which scope the variables should be created.</param>
/// <returns>The builder for this command.</returns>
IModifyProcessInstanceCommandStep3 WithVariables(string variables, string scopeId);
}
8 changes: 8 additions & 0 deletions Client/Api/Responses/IModifyProcessInstanceResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Zeebe.Client.Api.Responses;

/// <summary>
/// Response on a process instance to modification.
/// </summary>
public interface IModifyProcessInstanceResponse
{
}
Loading
Loading