Skip to content

Commit 1a29447

Browse files
committed
wip
1 parent c992a18 commit 1a29447

File tree

5 files changed

+105
-45
lines changed

5 files changed

+105
-45
lines changed

engine/internal/execution.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ func (ec *executionContext) addExecution(execution *ElementInstanceEntity) {
2323

2424
// continueExecutions continues each execution until a wait state is reached or no more outgoing sequence flows exist.
2525
func (ec *executionContext) continueExecutions(ctx Context) error {
26+
now := pgtype.Timestamp{Time: ctx.Time(), Valid: true}
27+
2628
i := 0
2729
for i < len(ec.executions) {
2830
execution := ec.executions[i]
@@ -52,22 +54,21 @@ func (ec *executionContext) continueExecutions(ctx Context) error {
5254

5355
switch execution.State {
5456
case engine.InstanceStarted:
55-
execution.StartedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
57+
execution.StartedAt = now
5658
case engine.InstanceCompleted:
57-
execution.EndedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
58-
5959
if !execution.StartedAt.Valid {
60-
execution.StartedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
60+
execution.StartedAt = now
6161
}
62+
execution.EndedAt = now
6263
case engine.InstanceTerminated:
63-
execution.EndedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
64+
execution.EndedAt = now
6465
}
6566

66-
if scope.State == engine.InstanceCompleted && !scope.ParentId.Valid {
67-
scope.EndedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
67+
if scope.State == engine.InstanceCompleted && scope.BpmnElementType == model.ElementProcess {
68+
scope.EndedAt = now
6869

6970
// complete process instance
70-
ec.processInstance.EndedAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
71+
ec.processInstance.EndedAt = now
7172
ec.processInstance.State = engine.InstanceCompleted
7273
}
7374
}
@@ -312,7 +313,7 @@ func (ec *executionContext) continueExecutions(ctx Context) error {
312313
return err
313314
}
314315

315-
message.ExpiresAt = pgtype.Timestamp{Time: ctx.Time(), Valid: true}
316+
message.ExpiresAt = now
316317
return ctx.Messages().Update(message)
317318
}
318319

engine/internal/graph.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -224,29 +224,26 @@ func (g graph) continueExecution(executions []*ElementInstanceEntity, execution
224224
if execution.ExecutionCount < 0 { // task, sub process or call activity, but not all boundary events defined
225225
execution.State = engine.InstanceCreated
226226
} else if execution.Context.Valid {
227-
switch execution.BpmnElementType {
228-
// defined boundary event
229-
case
230-
model.ElementErrorBoundaryEvent,
231-
model.ElementEscalationBoundaryEvent,
232-
model.ElementMessageBoundaryEvent,
233-
model.ElementSignalBoundaryEvent,
234-
model.ElementTimerBoundaryEvent:
227+
if model.IsBoundaryEvent(execution.BpmnElementType) {
228+
// defined boundary event
235229
execution.State = engine.InstanceCreated
236-
default:
230+
} else {
237231
execution.State = engine.InstanceStarted
238232
}
239233
} else {
240234
execution.State = engine.InstanceStarted
241235
}
236+
} else if model.IsBoundaryEvent(execution.BpmnElementType) {
237+
execution.State = engine.InstanceCreated
242238
} else {
243239
// end branch, if BPMN element requires a job to be completed or a task to be executed
244240
switch execution.BpmnElementType {
245241
case
246242
model.ElementBusinessRuleTask,
247243
model.ElementScriptTask,
248244
model.ElementSendTask,
249-
model.ElementServiceTask:
245+
model.ElementServiceTask,
246+
model.ElementSubProcess:
250247
if execution.State != 0 && execution.ExecutionCount == 0 {
251248
execution.State = engine.InstanceStarted
252249
} else {
@@ -278,13 +275,6 @@ func (g graph) continueExecution(executions []*ElementInstanceEntity, execution
278275
} else {
279276
execution.State = engine.InstanceStarted
280277
}
281-
case
282-
model.ElementErrorBoundaryEvent,
283-
model.ElementEscalationBoundaryEvent,
284-
model.ElementMessageBoundaryEvent,
285-
model.ElementSignalBoundaryEvent,
286-
model.ElementTimerBoundaryEvent:
287-
execution.State = engine.InstanceCreated
288278
default:
289279
// continue branch, if element has no behavior (pass through element)
290280
execution.State = engine.InstanceCompleted
@@ -334,10 +324,10 @@ func (g graph) continueExecution(executions []*ElementInstanceEntity, execution
334324
scope.ExecutionCount--
335325

336326
if scope.ExecutionCount == 0 {
337-
if scope.ParentId.Valid {
338-
executions = append(executions, scope)
339-
} else {
327+
if scope.BpmnElementType == model.ElementProcess {
340328
scope.State = engine.InstanceCompleted
329+
} else {
330+
executions = append(executions, scope)
341331
}
342332
}
343333
case engine.InstanceCreated, engine.InstanceSuspended:
@@ -346,7 +336,8 @@ func (g graph) continueExecution(executions []*ElementInstanceEntity, execution
346336
model.ElementBusinessRuleTask,
347337
model.ElementScriptTask,
348338
model.ElementSendTask,
349-
model.ElementServiceTask:
339+
model.ElementServiceTask,
340+
model.ElementSubProcess:
350341
if execution.ExecutionCount < 0 { // not all boundary events defined
351342
return executions, nil
352343
}
@@ -388,6 +379,18 @@ func (g graph) continueExecution(executions []*ElementInstanceEntity, execution
388379
}
389380
}
390381

382+
if execution.State == engine.InstanceStarted {
383+
if execution.BpmnElementType == model.ElementSubProcess {
384+
// start branch
385+
next, err := g.createExecution(execution)
386+
if err != nil {
387+
return executions, err
388+
}
389+
390+
executions = append(executions, &next)
391+
}
392+
}
393+
391394
return executions, nil
392395
}
393396

@@ -399,7 +402,9 @@ func (g graph) createExecution(scope *ElementInstanceEntity) (ElementInstanceEnt
399402

400403
var noneStartEvents []*model.Element
401404
switch scopeNode.bpmnElement.Type {
402-
case model.ElementProcess:
405+
case
406+
model.ElementProcess,
407+
model.ElementSubProcess:
403408
noneStartEvents = scopeNode.bpmnElement.ChildrenByType(model.ElementNoneStartEvent)
404409
}
405410

engine/internal/graph_test.go

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ func TestValidateProcess(t *testing.T) {
130130
func TestContinueExecution(t *testing.T) {
131131
assert, require := assert.New(t), require.New(t)
132132

133-
scope := &ElementInstanceEntity{}
134-
135133
t.Run("start event", func(t *testing.T) {
136134
// given
137135
graph := mustCreateGraph(t, "start-end.bpmn", "startEndTest")
138136

137+
scope := graph.createProcessScope(&ProcessInstanceEntity{})
138+
139139
t.Run("scope QUEUED", func(t *testing.T) {
140140
// given
141141
scope.State = engine.InstanceQueued
@@ -144,7 +144,7 @@ func TestContinueExecution(t *testing.T) {
144144
BpmnElementId: "startEvent",
145145
BpmnElementType: model.ElementNoneStartEvent,
146146

147-
parent: scope,
147+
parent: &scope,
148148
}
149149

150150
// when
@@ -169,7 +169,7 @@ func TestContinueExecution(t *testing.T) {
169169

170170
assert.Equal("endEvent", executions2[0].BpmnElementId)
171171
assert.Equal(model.ElementNoneEndEvent, executions2[0].BpmnElementType)
172-
assert.Equal(scope, executions2[0].parent)
172+
assert.Equal(&scope, executions2[0].parent)
173173
assert.Nil(executions2[0].prev)
174174
})
175175
})
@@ -178,6 +178,8 @@ func TestContinueExecution(t *testing.T) {
178178
// given
179179
graph := mustCreateGraph(t, "event/error-boundary-event.bpmn", "errorBoundaryEventTest")
180180

181+
scope := graph.createProcessScope(&ProcessInstanceEntity{})
182+
181183
t.Run("scope STARTED", func(t *testing.T) {
182184
// given
183185
scope.State = engine.InstanceStarted
@@ -186,7 +188,7 @@ func TestContinueExecution(t *testing.T) {
186188
BpmnElementId: "serviceTask",
187189
BpmnElementType: model.ElementServiceTask,
188190

189-
parent: scope,
191+
parent: &scope,
190192
}
191193

192194
// when
@@ -201,7 +203,7 @@ func TestContinueExecution(t *testing.T) {
201203

202204
assert.Equal("errorBoundaryEvent", executions1[0].BpmnElementId)
203205
assert.Equal(model.ElementErrorBoundaryEvent, executions1[0].BpmnElementType)
204-
assert.Equal(scope, executions1[0].parent)
206+
assert.Equal(&scope, executions1[0].parent)
205207
assert.Equal(execution, executions1[0].prev)
206208

207209
// when
@@ -222,7 +224,7 @@ func TestContinueExecution(t *testing.T) {
222224
BpmnElementId: "serviceTask",
223225
BpmnElementType: model.ElementServiceTask,
224226

225-
parent: scope,
227+
parent: &scope,
226228
}
227229

228230
// when
@@ -237,7 +239,7 @@ func TestContinueExecution(t *testing.T) {
237239

238240
assert.Equal("errorBoundaryEvent", executions1[0].BpmnElementId)
239241
assert.Equal(model.ElementErrorBoundaryEvent, executions1[0].BpmnElementType)
240-
assert.Equal(scope, executions1[0].parent)
242+
assert.Equal(&scope, executions1[0].parent)
241243
assert.Equal(execution, executions1[0].prev)
242244

243245
// when
@@ -277,13 +279,15 @@ func TestContinueExecution(t *testing.T) {
277279
{BpmnElementId: "errorBoundaryEvent", ErrorCode: pgtype.Text{String: "TEST_CODE"}},
278280
})
279281

282+
scope := graph.createProcessScope(&ProcessInstanceEntity{})
283+
280284
scope.State = engine.InstanceStarted
281285

282286
execution := &ElementInstanceEntity{
283287
BpmnElementId: "serviceTask",
284288
BpmnElementType: model.ElementServiceTask,
285289

286-
parent: scope,
290+
parent: &scope,
287291
}
288292

289293
// when
@@ -305,6 +309,8 @@ func TestContinueExecution(t *testing.T) {
305309
// given
306310
graph := mustCreateGraph(t, "event/error-boundary-event.bpmn", "errorBoundaryEventTest")
307311

312+
scope := graph.createProcessScope(&ProcessInstanceEntity{})
313+
308314
t.Run("scope STARTED", func(t *testing.T) {
309315
// given
310316
scope.State = engine.InstanceStarted
@@ -314,7 +320,7 @@ func TestContinueExecution(t *testing.T) {
314320
BpmnElementType: model.ElementServiceTask,
315321
State: engine.InstanceCreated,
316322

317-
parent: scope,
323+
parent: &scope,
318324
}
319325

320326
// when
@@ -338,7 +344,7 @@ func TestContinueExecution(t *testing.T) {
338344
ExecutionCount: -1,
339345
State: engine.InstanceCreated,
340346

341-
parent: scope,
347+
parent: &scope,
342348
}
343349

344350
// when
@@ -362,7 +368,7 @@ func TestContinueExecution(t *testing.T) {
362368
ExecutionCount: -1,
363369
State: engine.InstanceCreated,
364370

365-
parent: scope,
371+
parent: &scope,
366372
}
367373

368374
// when
@@ -397,7 +403,7 @@ func TestContinueExecution(t *testing.T) {
397403
BpmnElementType: model.ElementServiceTask,
398404
State: engine.InstanceSuspended,
399405

400-
parent: scope,
406+
parent: &scope,
401407
}
402408

403409
// when
@@ -416,6 +422,8 @@ func TestContinueExecution(t *testing.T) {
416422
// given
417423
graph := mustCreateGraph(t, "event/timer-catch.bpmn", "timerCatchTest")
418424

425+
scope := graph.createProcessScope(&ProcessInstanceEntity{})
426+
419427
t.Run("scope STARTED", func(t *testing.T) {
420428
// given
421429
scope.State = engine.InstanceStarted
@@ -424,7 +432,7 @@ func TestContinueExecution(t *testing.T) {
424432
BpmnElementId: "startEvent",
425433
BpmnElementType: model.ElementNoneStartEvent,
426434

427-
parent: scope,
435+
parent: &scope,
428436
}
429437

430438
// when

engine/test/bpmn_all_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,14 @@ func TestBpmn(t *testing.T) {
109109
}
110110
})
111111

112+
t.Run("sub-process", func(t *testing.T) {
113+
for i, e := range engines {
114+
subProcessTest := subProcessTest{e}
115+
116+
t.Run(engineTypes[i]+"start end", subProcessTest.startEnd)
117+
}
118+
})
119+
112120
t.Run("task", func(t *testing.T) {
113121
for i, e := range engines {
114122
taskTest := newTaskTest(t, e)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/gclaussn/go-bpmn/engine"
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
type subProcessTest struct {
12+
e engine.Engine
13+
}
14+
15+
func (x subProcessTest) startEnd(t *testing.T) {
16+
assert, require := assert.New(t), require.New(t)
17+
18+
startEndProcess := mustCreateProcess(t, x.e, "sub-process/start-end.bpmn", "startEndTest")
19+
20+
piAssert := mustCreateProcessInstance(t, x.e, startEndProcess)
21+
piAssert.IsCompleted()
22+
23+
elementInstances := piAssert.ElementInstances()
24+
require.Len(elementInstances, 6)
25+
26+
assert.Equal(engine.InstanceCompleted, elementInstances[0].State)
27+
assert.Equal("startEndTest", elementInstances[0].BpmnElementId)
28+
assert.Equal(engine.InstanceCompleted, elementInstances[1].State)
29+
assert.Equal("startEvent", elementInstances[1].BpmnElementId)
30+
assert.Equal(engine.InstanceCompleted, elementInstances[2].State)
31+
assert.Equal("subProcess", elementInstances[2].BpmnElementId)
32+
assert.Equal(engine.InstanceCompleted, elementInstances[3].State)
33+
assert.Equal("subProcessStartEvent", elementInstances[3].BpmnElementId)
34+
assert.Equal(engine.InstanceCompleted, elementInstances[4].State)
35+
assert.Equal("subProcessEndEvent", elementInstances[4].BpmnElementId)
36+
assert.Equal(engine.InstanceCompleted, elementInstances[5].State)
37+
assert.Equal("endEvent", elementInstances[5].BpmnElementId)
38+
}

0 commit comments

Comments
 (0)