Skip to content

Commit e991c7c

Browse files
committed
bugfix: fix workflow return null handling
- Fix null value handling for execute again - Add unit test and sample for different workflow return
1 parent 9926030 commit e991c7c

File tree

3 files changed

+161
-4
lines changed

3 files changed

+161
-4
lines changed

samples/DtmSample/Controllers/WfTestController.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
using Microsoft.Extensions.Logging;
77
using Microsoft.Extensions.Options;
88
using System;
9+
using System.Diagnostics;
910
using System.Net.Http;
1011
using System.Net.Http.Headers;
1112
using System.Text;
1213
using System.Text.Json;
1314
using System.Threading;
1415
using System.Threading.Tasks;
16+
using Exception = System.Exception;
1517

1618
namespace DtmSample.Controllers
1719
{
@@ -65,6 +67,53 @@ public async Task<IActionResult> Simple(CancellationToken cancellationToken)
6567
}
6668
}
6769

70+
[HttpPost("wf-twice")]
71+
public async Task<IActionResult> SimpleTwice(CancellationToken cancellationToken)
72+
{
73+
try
74+
{
75+
string wfNameReturnNormal = $"wfNameReturnNormal-{Guid.NewGuid().ToString("N")[..8]}";
76+
_globalTransaction.Register(wfNameReturnNormal, async (wf, data) => await Task.FromResult(Encoding.UTF8.GetBytes("my result")));
77+
string wfNameReturnEmpty = $"wfNameReturnEmpty-{Guid.NewGuid().ToString("N")[..8]}";
78+
_globalTransaction.Register(wfNameReturnEmpty, async (wf, data) => await Task.FromResult(Encoding.UTF8.GetBytes("")));
79+
string wfNameReturnNull = $"wfNameReturnNull-{Guid.NewGuid().ToString("N")[..8]}";
80+
_globalTransaction.Register(wfNameReturnNull, (wf, data) => Task.FromResult<byte[]>(null));
81+
82+
string req = JsonSerializer.Serialize(new TransRequest("1", -30));
83+
84+
string gid;
85+
byte[] result1, result2;
86+
string resultStr1, resultStr2;
87+
gid = wfNameReturnNormal + " " + Guid.NewGuid().ToString("N");
88+
result1 = await _globalTransaction.Execute(wfNameReturnNormal, gid, Encoding.UTF8.GetBytes(req), true);
89+
result2 = await _globalTransaction.Execute(wfNameReturnNormal, gid, Encoding.UTF8.GetBytes(req), true);
90+
resultStr1 = Encoding.UTF8.GetString(result1);
91+
resultStr2 = Encoding.UTF8.GetString(result2);
92+
if ("my result" != resultStr1) throw new Exception("\"my result\" != resultStr1");
93+
if (resultStr1 != resultStr2) throw new Exception("resultStr1 != resultStr2");
94+
95+
gid = wfNameReturnEmpty + " " + Guid.NewGuid().ToString("N");
96+
result1 = await _globalTransaction.Execute(wfNameReturnEmpty, gid, Encoding.UTF8.GetBytes(req), true);
97+
result2 = await _globalTransaction.Execute(wfNameReturnEmpty, gid, Encoding.UTF8.GetBytes(req), true);
98+
resultStr1 = Encoding.UTF8.GetString(result1);
99+
if (string.Empty != resultStr1) throw new Exception("\"my result\" != resultStr1");
100+
if (null != result2) throw new Exception("null != result2");
101+
102+
gid = wfNameReturnNull + " " + Guid.NewGuid().ToString("N");
103+
result1 = await _globalTransaction.Execute(wfNameReturnNull, gid, Encoding.UTF8.GetBytes(req), true);
104+
result2 = await _globalTransaction.Execute(wfNameReturnNull, gid, Encoding.UTF8.GetBytes(req), true);
105+
if (null != result1) throw new Exception("String.Empty != resultStr1");
106+
if (result1 != result2) throw new Exception("resultStr1 != resultStr2");
107+
108+
return Ok(TransResponse.BuildSucceedResponse());
109+
}
110+
catch (Exception ex)
111+
{
112+
_logger.LogError(ex, "Workflow Error");
113+
return Ok(TransResponse.BuildFailureResponse());
114+
}
115+
}
116+
68117
[HttpPost("wf-saga")]
69118
public async Task<IActionResult> Saga(CancellationToken cancellationToken)
70119
{

src/Dtmworkflow/Workflow.Imp.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ internal async Task<byte[]> Process(WfFunc2 handler, byte[] data)
3939
var status = reply.Transaction.Status;
4040
if (status == DtmCommon.Constant.StatusSucceed)
4141
{
42-
var sRes = Convert.FromBase64String(reply.Transaction.Result);
42+
var sRes = reply.Transaction.Result != null
43+
? Convert.FromBase64String(reply.Transaction.Result)
44+
: null;
4345
return sRes;
4446
}
4547
else if (status == DtmCommon.Constant.StatusFailed)

tests/Dtmworkflow.Tests/WorkflowHttpTests.cs

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,114 @@ public async void Commit_Should_Be_Executed()
255255
rollBackFunc.Verify(x => x.Invoke(It.IsAny<BranchBarrier>()), Times.Never);
256256
commitFunc.Verify(x => x.Invoke(It.IsAny<BranchBarrier>()), Times.Once);
257257
}
258+
259+
[Fact]
260+
public async Task Execute_Result_Should_Be_WfFunc2()
261+
{
262+
var factory = new Mock<IWorkflowFactory>();
263+
var httpClient = new Mock<IDtmClient>();
264+
var grpcClient = new Mock<IDtmgRPCClient>();
265+
var httpBb = new Mock<Dtmcli.IBranchBarrierFactory>();
266+
267+
SetupPrepareWorkflow(httpClient, DtmCommon.Constant.StatusPrepared, null);
268+
var wf = SetupWorkFlow(httpClient, grpcClient, httpBb);
269+
270+
factory.Setup(x => x.NewWorkflow(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<bool>())).Returns(wf.Object);
271+
272+
var wfgt = new WorlflowGlobalTransaction(factory.Object, NullLoggerFactory.Instance);
273+
274+
var wfName = nameof(Execute_Result_Should_Be_WfFunc2);
275+
var gid = Guid.NewGuid().ToString("N");
276+
277+
wfgt.Register(wfName, (workflow, data) => Task.FromResult(Encoding.UTF8.GetBytes("return value from WfFunc2")));
278+
279+
var req = JsonSerializer.Serialize(new { userId = "1", amount = 30 });
280+
var res = await wfgt.Execute(wfName, gid, Encoding.UTF8.GetBytes(req), true);
281+
282+
Assert.Equal("return value from WfFunc2", Encoding.UTF8.GetString(res));
283+
}
284+
285+
[Fact]
286+
public async Task Execute_Result_Should_Be_Previous()
287+
{
288+
var factory = new Mock<IWorkflowFactory>();
289+
var httpClient = new Mock<IDtmClient>();
290+
var grpcClient = new Mock<IDtmgRPCClient>();
291+
var httpBb = new Mock<Dtmcli.IBranchBarrierFactory>();
292+
293+
SetupPrepareWorkflow(httpClient, DtmCommon.Constant.StatusSucceed, "return value from previous");
294+
var wf = SetupWorkFlow(httpClient, grpcClient, httpBb);
295+
296+
factory.Setup(x => x.NewWorkflow(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<bool>())).Returns(wf.Object);
297+
298+
var wfgt = new WorlflowGlobalTransaction(factory.Object, NullLoggerFactory.Instance);
299+
300+
var wfName = nameof(Execute_Result_Should_Be_Previous);
301+
var gid = Guid.NewGuid().ToString("N");
302+
303+
wfgt.Register(wfName, (workflow, data) => Task.FromResult(Encoding.UTF8.GetBytes("return value from WfFunc2")));
304+
305+
var req = JsonSerializer.Serialize(new { userId = "1", amount = 30 });
306+
var res = await wfgt.Execute(wfName, gid, Encoding.UTF8.GetBytes(req), true);
307+
308+
Assert.Equal("return value from previous", Encoding.UTF8.GetString(res));
309+
}
310+
311+
[Fact]
312+
public async Task Execute_Again_Result_Should_Be_Previous()
313+
{
314+
var factory = new Mock<IWorkflowFactory>();
315+
var httpClient1 = new Mock<IDtmClient>();
316+
var httpClient2 = new Mock<IDtmClient>();
317+
var grpcClient = new Mock<IDtmgRPCClient>();
318+
var httpBb = new Mock<Dtmcli.IBranchBarrierFactory>();
319+
320+
// first
321+
SetupPrepareWorkflow(httpClient1, DtmCommon.Constant.StatusPrepared, null);
322+
var wf = SetupWorkFlow(httpClient1, grpcClient, httpBb);
323+
factory.Setup(x => x.NewWorkflow(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<bool>())).Returns(wf.Object);
324+
var wfgt = new WorlflowGlobalTransaction(factory.Object, NullLoggerFactory.Instance);
325+
var wfName = nameof(Execute_Again_Result_Should_Be_Previous);
326+
var gid = Guid.NewGuid().ToString("N");
327+
wfgt.Register(wfName, (workflow, data) => Task.FromResult(Encoding.UTF8.GetBytes("return value from WfFunc2")));
328+
var req = JsonSerializer.Serialize(new { userId = "1", amount = 30 });
329+
var res = await wfgt.Execute(wfName, gid, Encoding.UTF8.GetBytes(req), true);
330+
Assert.Equal("return value from WfFunc2", Encoding.UTF8.GetString(res));
331+
332+
// again
333+
SetupPrepareWorkflow(httpClient2, DtmCommon.Constant.StatusSucceed, "return value from previous");
334+
wf = SetupWorkFlow(httpClient2, grpcClient, httpBb);
335+
factory.Setup(x => x.NewWorkflow(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<bool>())).Returns(wf.Object);
336+
wfgt = new WorlflowGlobalTransaction(factory.Object, NullLoggerFactory.Instance);
337+
gid = Guid.NewGuid().ToString("N");
338+
wfgt.Register(wfName, (workflow, data) => Task.FromResult(Encoding.UTF8.GetBytes("return value from WfFunc2")));
339+
req = JsonSerializer.Serialize(new { userId = "1", amount = 30 });
340+
res = await wfgt.Execute(wfName, gid, Encoding.UTF8.GetBytes(req), true);
341+
Assert.Equal("return value from previous", Encoding.UTF8.GetString(res));
342+
}
343+
344+
[Fact]
345+
public async Task Execute_Again_Result_StringEmpty()
346+
{
347+
var factory = new Mock<IWorkflowFactory>();
348+
var httpClient = new Mock<IDtmClient>();
349+
var grpcClient = new Mock<IDtmgRPCClient>();
350+
var httpBb = new Mock<Dtmcli.IBranchBarrierFactory>();
351+
352+
// again
353+
SetupPrepareWorkflow(httpClient, DtmCommon.Constant.StatusSucceed, null);
354+
var wf = SetupWorkFlow(httpClient, grpcClient, httpBb);
355+
factory.Setup(x => x.NewWorkflow(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<byte[]>(), It.IsAny<bool>())).Returns(wf.Object);
356+
var wfgt = new WorlflowGlobalTransaction(factory.Object, NullLoggerFactory.Instance);
357+
var wfName = nameof(Execute_Again_Result_StringEmpty);
358+
var gid = Guid.NewGuid().ToString("N");
359+
wfgt.Register(wfName, (workflow, data) => Task.FromResult(Encoding.UTF8.GetBytes("return value from WfFunc2")));
360+
var req = JsonSerializer.Serialize(new { userId = "1", amount = 30 });
361+
var res = await wfgt.Execute(wfName, gid, Encoding.UTF8.GetBytes(req), true);
362+
Assert.Null(res);
363+
}
258364

259-
private void SetupPrepareWorkflow(Mock<IDtmClient> httpClient, string status, string result, List<DtmProgressDto> progressDtos = null)
365+
private void SetupPrepareWorkflow(Mock<IDtmClient> httpClient, string status, string? result, List<DtmProgressDto> progressDtos = null)
260366
{
261367
var httpResp = new HttpResponseMessage(HttpStatusCode.OK);
262368
httpResp.Content = new StringContent(JsonSerializer.Serialize(
@@ -265,9 +371,9 @@ private void SetupPrepareWorkflow(Mock<IDtmClient> httpClient, string status, st
265371
Transaction = new DtmTransactionDto
266372
{
267373
Status = status,
268-
Result = Convert.ToBase64String(Encoding.UTF8.GetBytes(result))
374+
Result = result == null ? null : Convert.ToBase64String(Encoding.UTF8.GetBytes(result))
269375
},
270-
Progresses = progressDtos
376+
Progresses = progressDtos ?? []
271377
}));
272378
httpClient.Setup(x => x.PrepareWorkflow(It.IsAny<DtmCommon.TransBase>(), It.IsAny<CancellationToken>())).Returns(Task.FromResult(httpResp));
273379
}

0 commit comments

Comments
 (0)