snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
This commit is contained in:
312
server/pkg/wfexec/session_test.go
Normal file
312
server/pkg/wfexec/session_test.go
Normal file
@@ -0,0 +1,312 @@
|
||||
package wfexec
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cortezaproject/corteza/server/pkg/expr"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/atomic"
|
||||
)
|
||||
|
||||
type (
|
||||
sesTestStep struct {
|
||||
StepIdentifier
|
||||
name string
|
||||
exec func(context.Context, *ExecRequest) (ExecResponse, error)
|
||||
}
|
||||
|
||||
sesTestTemporal struct {
|
||||
StepIdentifier
|
||||
delay time.Duration
|
||||
until time.Time
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
// used for testing to produce lower numbers that are easier to inspect and compare
|
||||
testID = atomic.NewUint64(0)
|
||||
)
|
||||
|
||||
func (s *sesTestStep) Exec(ctx context.Context, r *ExecRequest) (ExecResponse, error) {
|
||||
if s.exec != nil {
|
||||
return s.exec(ctx, r)
|
||||
}
|
||||
|
||||
var (
|
||||
args = &struct {
|
||||
Path string
|
||||
Counter int64
|
||||
}{}
|
||||
)
|
||||
|
||||
if err := r.Scope.Decode(args); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return expr.NewVars(map[string]interface{}{
|
||||
"counter": args.Counter + 1,
|
||||
"path": args.Path + "/" + s.name,
|
||||
s.name: "executed",
|
||||
})
|
||||
}
|
||||
|
||||
func (s *sesTestTemporal) Exec(ctx context.Context, r *ExecRequest) (ExecResponse, error) {
|
||||
if s.until.IsZero() {
|
||||
s.until = now().Add(s.delay)
|
||||
}
|
||||
|
||||
if now().Before(s.until) {
|
||||
return Delay(s.until), nil
|
||||
}
|
||||
|
||||
return expr.NewVars(map[string]interface{}{
|
||||
"waitForMoment": "executed",
|
||||
})
|
||||
}
|
||||
|
||||
func TestSession_TwoStepWorkflow(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
wf = NewGraph()
|
||||
ses = NewSession(ctx, wf)
|
||||
|
||||
s1 = &sesTestStep{name: "s1"}
|
||||
s2 = &sesTestStep{name: "s2"}
|
||||
|
||||
scope = &expr.Vars{}
|
||||
)
|
||||
|
||||
scope.Set("two", 1)
|
||||
scope.Set("three", 1)
|
||||
|
||||
wf.AddStep(s1, s2) // 1st execute s1 then s2
|
||||
req.NoError(ses.Exec(ctx, s1, scope))
|
||||
req.NoError(ses.Wait(ctx))
|
||||
req.NoError(ses.Error())
|
||||
req.NotNil(ses.Result())
|
||||
req.Equal("/s1/s2", expr.Must(expr.Select(ses.Result(), "path")).Get())
|
||||
}
|
||||
|
||||
func TestSession_SplitAndMerge(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
wf = NewGraph()
|
||||
ses = NewSession(ctx, wf, SetDumpStacktraceOnPanic(true))
|
||||
|
||||
start = &sesTestStep{name: "start"}
|
||||
split1 = &sesTestStep{name: "split1"}
|
||||
split2 = &sesTestStep{name: "split2"}
|
||||
split3 = &sesTestStep{name: "split3"}
|
||||
|
||||
end = JoinGateway(split1, split2, split3)
|
||||
)
|
||||
|
||||
wf.AddStep(start, split1, split2, split3)
|
||||
wf.AddStep(split1, end)
|
||||
wf.AddStep(split2, end)
|
||||
wf.AddStep(split3, end)
|
||||
ses.Exec(ctx, start, nil)
|
||||
ses.Wait(ctx)
|
||||
req.True(ses.Idle())
|
||||
req.NoError(ses.Error())
|
||||
req.NotNil(ses.Result())
|
||||
// split3 only!
|
||||
req.Equal("/start/split3", expr.Must(expr.Select(ses.Result(), "path")).Get())
|
||||
req.Contains(ses.Result().Dict(), "split1")
|
||||
req.Contains(ses.Result().Dict(), "split2")
|
||||
req.Contains(ses.Result().Dict(), "split3")
|
||||
}
|
||||
|
||||
func TestSession_Delays(t *testing.T) {
|
||||
t.SkipNow()
|
||||
var (
|
||||
// how fast we want to go (lower = faster)
|
||||
//
|
||||
unit = time.Millisecond
|
||||
delay = unit * 3
|
||||
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
wf = NewGraph()
|
||||
ses = NewSession(ctx, wf,
|
||||
// for testing we need much shorter worker intervals
|
||||
SetWorkerIntervalSuspended(unit),
|
||||
)
|
||||
|
||||
start = &sesTestStep{name: "start"}
|
||||
|
||||
waitForMoment = &sesTestTemporal{delay: delay}
|
||||
|
||||
waitForInputStateId atomic.Uint64
|
||||
waitForInput = &sesTestStep{name: "waitForInput", exec: func(ctx context.Context, r *ExecRequest) (ExecResponse, error) {
|
||||
if !r.Input.Has("input") {
|
||||
waitForInputStateId.Store(r.StateID)
|
||||
return Prompt(0, "", nil), nil
|
||||
}
|
||||
|
||||
out := &expr.Vars{}
|
||||
_ = out.Set("waitForInput", "executed")
|
||||
r.Input.Copy(out, "input")
|
||||
|
||||
return out, nil
|
||||
}}
|
||||
)
|
||||
|
||||
ctx, cancelFn := context.WithTimeout(ctx, time.Second*5)
|
||||
defer cancelFn()
|
||||
|
||||
wf.AddStep(start, waitForMoment)
|
||||
wf.AddStep(waitForMoment, waitForInput)
|
||||
|
||||
req.NoError(ses.Exec(ctx, start, nil))
|
||||
|
||||
// wait-for-moment step needs to be executed before we can resume wait-for-input
|
||||
req.NoError(ses.Wait(ctx))
|
||||
time.Sleep(delay + unit)
|
||||
req.NotZero(waitForInputStateId.Load())
|
||||
|
||||
// should not be completed yet...
|
||||
req.True(ses.Idle())
|
||||
req.True(ses.Delayed())
|
||||
|
||||
// push in the input
|
||||
input := &expr.Vars{}
|
||||
input.Set("inout", "foo")
|
||||
_, err := ses.Resume(ctx, waitForInputStateId.Load(), input)
|
||||
req.NoError(err)
|
||||
|
||||
req.False(ses.Delayed())
|
||||
req.NoError(ses.Wait(ctx))
|
||||
time.Sleep(2 * unit)
|
||||
|
||||
// should not be completed yet...
|
||||
req.True(ses.Idle())
|
||||
req.NoError(ses.Error())
|
||||
req.NotNil(ses.Result())
|
||||
req.Contains(ses.Result().Dict(), "waitForMoment")
|
||||
req.Contains(ses.Result().Dict(), "waitForInput")
|
||||
req.Equal("foo", expr.Must(expr.Select(ses.Result(), "input")).Get())
|
||||
}
|
||||
|
||||
func TestSession_ErrHandler(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
wf = NewGraph()
|
||||
ses = NewSession(
|
||||
ctx,
|
||||
wf,
|
||||
|
||||
// enable if you need to see what is going on
|
||||
// SetLogger(logger.MakeDebugLogger()),
|
||||
|
||||
// enable if you need to see what is going on
|
||||
// SetHandler(func(status SessionStatus, state *State, session *Session) {
|
||||
// if state.step != nil {
|
||||
// println(state.step.(*sesTestStep).name)
|
||||
// }
|
||||
// }),
|
||||
)
|
||||
|
||||
cb_1_1 = &sesTestStep{name: "catch-branch-1-1"}
|
||||
cb_1_2 = &sesTestStep{name: "catch-branch-1-2"}
|
||||
tb_1_1 = &sesTestStep{name: "try-branch-1-1"}
|
||||
|
||||
eh_1 = &sesTestStep{name: "err-handler", exec: func(ctx context.Context, request *ExecRequest) (ExecResponse, error) {
|
||||
return ErrorHandler(cb_1_1, nil), nil
|
||||
}}
|
||||
er_1 = &sesTestStep{name: "err-raiser", exec: func(ctx context.Context, request *ExecRequest) (ExecResponse, error) {
|
||||
return nil, fmt.Errorf("would-be-handled-error")
|
||||
}}
|
||||
|
||||
cb_2_1 = &sesTestStep{name: "catch-branch-2-1"}
|
||||
cb_2_2 = &sesTestStep{name: "catch-branch-2-2"}
|
||||
tb_2_1 = &sesTestStep{name: "try-branch-2-1"}
|
||||
|
||||
eh_2 = &sesTestStep{name: "err-handler", exec: func(ctx context.Context, request *ExecRequest) (ExecResponse, error) {
|
||||
return ErrorHandler(cb_2_1, nil), nil
|
||||
}}
|
||||
er_2 = &sesTestStep{name: "err-raiser", exec: func(ctx context.Context, request *ExecRequest) (ExecResponse, error) {
|
||||
return nil, fmt.Errorf("would-be-handled-error")
|
||||
}}
|
||||
)
|
||||
|
||||
wf.AddStep(eh_1, tb_1_1) // error handling step (entrypoint!)
|
||||
wf.AddStep(tb_1_1) // add try step
|
||||
wf.AddStep(tb_1_1, er_1) // add error raising step right after 1st step in try branch
|
||||
wf.AddStep(cb_1_1, cb_1_2) // catch branch step 1 & 2
|
||||
|
||||
wf.AddStep(cb_1_2, eh_2) // 2nd error handling step right after 1st catch branch
|
||||
wf.AddStep(eh_2, tb_2_1) // step in try branch
|
||||
wf.AddStep(tb_2_1, er_2) // 2nd error raising step on 2nd try branch
|
||||
wf.AddStep(cb_2_1, cb_2_2) // 2nd catch branch step 1 & 2
|
||||
|
||||
req.NoError(ses.Exec(ctx, eh_1, nil))
|
||||
|
||||
req.NoError(ses.Wait(ctx))
|
||||
|
||||
req.Equal(
|
||||
"/try-branch-1-1/catch-branch-1-1/catch-branch-1-2/try-branch-2-1/catch-branch-2-1/catch-branch-2-2",
|
||||
ses.Result().Dict()["path"],
|
||||
)
|
||||
}
|
||||
|
||||
func TestSession_ExecStepWithParents(t *testing.T) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
req = require.New(t)
|
||||
wf = NewGraph()
|
||||
ses = NewSession(ctx, wf)
|
||||
|
||||
p = &sesTestStep{name: "p"}
|
||||
c = &sesTestStep{name: "c"}
|
||||
)
|
||||
|
||||
wf.AddStep(p, c)
|
||||
|
||||
req.Equal(SessionActive, ses.Status())
|
||||
req.Error(ses.Exec(ctx, c, nil))
|
||||
req.Error(ses.Wait(ctx))
|
||||
req.Equal(SessionFailed, ses.Status())
|
||||
}
|
||||
|
||||
func bmSessionSimpleStepSequence(c uint64, b *testing.B) {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
g = NewGraph()
|
||||
err error
|
||||
)
|
||||
|
||||
for i := uint64(1); i <= c; i++ {
|
||||
s := &sesTestStep{name: "start"}
|
||||
s.SetID(i)
|
||||
g.AddStep(s)
|
||||
if i > 1 {
|
||||
g.AddParent(s, g.StepByID(i-1))
|
||||
}
|
||||
}
|
||||
|
||||
b.StartTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
ses := NewSession(ctx, g)
|
||||
if err = ses.Exec(ctx, g.StepByID(1), nil); err != nil {
|
||||
b.Fatal(err.Error())
|
||||
}
|
||||
|
||||
ses.Wait(ctx)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkSessionSimple1StepSequence(b *testing.B) { bmSessionSimpleStepSequence(1, b) }
|
||||
func BenchmarkSessionSimple10StepSequence(b *testing.B) { bmSessionSimpleStepSequence(10, b) }
|
||||
func BenchmarkSessionSimple100StepSequence(b *testing.B) { bmSessionSimpleStepSequence(100, b) }
|
||||
func BenchmarkSessionSimple1000StepSequence(b *testing.B) { bmSessionSimpleStepSequence(1000, b) }
|
||||
func BenchmarkSessionSimple10000StepSequence(b *testing.B) { bmSessionSimpleStepSequence(10000, b) }
|
||||
func BenchmarkSessionSimple100000StepSequence(b *testing.B) { bmSessionSimpleStepSequence(100000, b) }
|
||||
func BenchmarkSessionSimple1000000StepSequence(b *testing.B) { bmSessionSimpleStepSequence(1000000, b) }
|
||||
Reference in New Issue
Block a user