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

This commit is contained in:
upstream-mirror
2026-09-18 01:22:23 +05:00
commit 7e385fc126
8391 changed files with 1766236 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
package workflows
import (
"context"
"fmt"
"sync"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/stretchr/testify/require"
)
func Test0001_basics(t *testing.T) {
ctx := bypassRBAC(context.Background())
loadScenario(ctx, t)
var (
req = require.New(t)
aux = struct{ Foo int64 }{}
vars, _ = mustExecWorkflow(ctx, t, "basic", types.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
req.Equal(int64(42), aux.Foo)
}
func Test0001_basics_detect_datarace_issues(t *testing.T) {
ctx := bypassRBAC(context.Background())
loadScenarioWithName(ctx, t, "S0001_basics")
var (
wg = &sync.WaitGroup{}
)
for i := 0; i < 10; i++ {
wg.Add(1)
go t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
defer wg.Done()
var (
aux = struct{ Foo int64 }{}
req = require.New(t)
vars, _ = mustExecWorkflow(ctx, t, "basic", types.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
req.Equal(int64(42), aux.Foo)
})
}
wg.Wait()
}

View File

@@ -0,0 +1,34 @@
package workflows
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/rbac"
"github.com/stretchr/testify/require"
)
func Test0002_rbac_fn(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
req.Len(rbac.Global().Rules(), 0)
var (
aux = struct {
CanCurrentRead string
CanOtherRead string
}{}
vars, _ = mustExecWorkflow(ctx, t, "check-and-grant", types.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
req.Equal("y", aux.CanCurrentRead)
req.Equal("n", aux.CanOtherRead)
req.Len(rbac.Global().Rules(), 1)
}

View File

@@ -0,0 +1,28 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func Test0003_create_user(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
var (
aux = struct {
User *sysTypes.User
}{}
vars, _ = mustExecWorkflow(ctx, t, "create-user", autTypes.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
}

View File

@@ -0,0 +1,50 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func Test0003_role_members(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoleMembers(ctx))
req.NoError(defStore.TruncateUsers(ctx))
req.NoError(defStore.TruncateRoles(ctx))
loadScenario(ctx, t)
var (
aux = struct {
UsersPre_r1 sysTypes.UserSet
TotalPre_r1 uint64
UsersPre_r2 sysTypes.UserSet
TotalPre_r2 uint64
UsersPost_r1 sysTypes.UserSet
TotalPost_r1 uint64
UsersPost_r2 sysTypes.UserSet
TotalPost_r2 uint64
}{}
vars, _ = mustExecWorkflow(ctx, t, "role-members", autTypes.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
req.Len(aux.UsersPre_r1, 1)
req.Equal(uint64(1), aux.TotalPre_r1)
req.Len(aux.UsersPre_r2, 1)
req.Equal(uint64(1), aux.TotalPre_r2)
req.Len(aux.UsersPost_r1, 0)
req.Equal(uint64(0), aux.TotalPost_r1)
req.Len(aux.UsersPost_r2, 1)
req.Equal(uint64(1), aux.TotalPost_r2)
}

View File

@@ -0,0 +1,58 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
func Test0004_user_membership(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoleMembers(ctx))
req.NoError(defStore.TruncateUsers(ctx))
req.NoError(defStore.TruncateRoles(ctx))
loadScenario(ctx, t)
var (
aux = struct {
RolesPre_u1 sysTypes.RoleSet
TotalPre_u1 uint64
RolesPre_u2 sysTypes.RoleSet
TotalPre_u2 uint64
MemberPre_u1 bool
MemberPre_u2 bool
RolesPost_u1 sysTypes.RoleSet
TotalPost_u1 uint64
RolesPost_u2 sysTypes.RoleSet
TotalPost_u2 uint64
MemberPost_u1 bool
MemberPost_u2 bool
}{}
vars, _ = mustExecWorkflow(ctx, t, "user-membership", autTypes.WorkflowExecParams{})
)
req.NoError(vars.Decode(&aux))
req.Len(aux.RolesPre_u1, 2)
req.Equal(uint64(2), aux.TotalPre_u1)
req.True(aux.MemberPre_u1)
req.Len(aux.RolesPre_u2, 0)
req.Equal(uint64(0), aux.TotalPre_u2)
req.False(aux.MemberPre_u2)
req.Len(aux.RolesPost_u1, 1)
req.Equal(uint64(1), aux.TotalPost_u1)
req.False(aux.MemberPost_u1)
req.Len(aux.RolesPost_u2, 0)
req.Equal(uint64(0), aux.TotalPost_u2)
req.False(aux.MemberPost_u2)
}

View File

@@ -0,0 +1,138 @@
package workflows
import (
"testing"
)
func Test0005_iterator_records(t *testing.T) {
t.Skip("@todo envoy not yet refactored")
// wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
// defer func() {
// wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
// }()
// var (
// ctx = bypassRBAC(context.Background())
// req = require.New(t)
// )
// req.NoError(truncateRecords(ctx))
// req.NoError(defStore.TruncateComposeModules(ctx))
// req.NoError(defStore.TruncateComposeNamespaces(ctx))
// loadScenario(ctx, t)
// var (
// _, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
// )
// // 6x iterator, 5x continue, 1x terminator, 1x completed
// req.Len(trace, 13)
// // there are 4 iterator calls; each on the *2 index
// ctr := int64(-1)
// for j := 0; j <= 4; j++ {
// ix := j * 2
// ctr++
// frame := trace[ix]
// req.Equal(uint64(10), frame.StepID)
// i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
// req.NoError(err)
// req.Equal(ctr, i.Get().(int64))
// rec, err := automation.NewComposeRecord(frame.Results.GetValue()["r"])
// req.NoError(err)
// rv := rec.GetValue().Values[0]
// req.Equal(fmt.Sprintf("%d", ctr+1), rv.Value)
// }
}
func Test0005_iterator_records_chunked(t *testing.T) {
t.Skip("@todo envoy not yet refactored")
// wfexec.MaxIteratorBufferSize = 2
// defer func() {
// wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
// }()
// var (
// ctx = bypassRBAC(context.Background())
// req = require.New(t)
// )
// req.NoError(truncateRecords(ctx))
// req.NoError(defStore.TruncateComposeModules(ctx))
// req.NoError(defStore.TruncateComposeNamespaces(ctx))
// loadScenarioWithName(ctx, t, "S0005_iterator_records")
// var (
// _, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
// )
// // 6x iterator, 5x continue, 1x terminator, 1x completed
// req.Len(trace, 13)
// // there are 4 iterator calls; each on the *2 index
// ctr := int64(-1)
// for j := 0; j <= 4; j++ {
// ix := j * 2
// ctr++
// frame := trace[ix]
// req.Equal(uint64(10), frame.StepID)
// i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
// req.NoError(err)
// req.Equal(ctr, i.Get().(int64))
// rec, err := automation.NewComposeRecord(frame.Results.GetValue()["r"])
// req.NoError(err)
// rv := rec.GetValue().Values[0]
// req.Equal(fmt.Sprintf("%d", ctr+1), rv.Value)
// }
}
func Test0005_iterator_records_limited(t *testing.T) {
t.Skip("@todo envoy not yet refactored")
// var (
// ctx = bypassRBAC(context.Background())
// req = require.New(t)
// )
// req.NoError(truncateRecords(ctx))
// req.NoError(defStore.TruncateComposeModules(ctx))
// req.NoError(defStore.TruncateComposeNamespaces(ctx))
// loadScenarioWithName(ctx, t, "iterator_records_limit")
// var (
// _, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
// )
// // 3x iterator, 2x continue, 1x terminator, 1x completed
// req.Len(trace, 7)
// // there are 4 iterator calls; each on the *2 index
// ctr := int64(-1)
// for j := 0; j <= 1; j++ {
// ix := j * 2
// ctr++
// frame := trace[ix]
// req.Equal(uint64(10), frame.StepID)
// i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
// req.NoError(err)
// req.Equal(ctr, i.Get().(int64))
// rec, err := automation.NewComposeRecord(frame.Results.GetValue()["r"])
// req.NoError(err)
// rv := rec.GetValue().Values[0]
// req.Equal(fmt.Sprintf("%d", ctr+1), rv.Value)
// }
}

View File

@@ -0,0 +1,131 @@
package workflows
import (
"context"
"fmt"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/cortezaproject/corteza/server/system/automation"
"github.com/stretchr/testify/require"
)
func Test0006_iterator_users(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
loadScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewUser(frame.Results.GetValue()["u"])
req.NoError(err)
req.Equal(fmt.Sprintf("u%d", ctr+1), usr.GetValue().Handle)
}
}
func Test0006_iterator_users_chunked(t *testing.T) {
wfexec.MaxIteratorBufferSize = 2
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
loadScenarioWithName(ctx, t, "S0006_iterator_users")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewUser(frame.Results.GetValue()["u"])
req.NoError(err)
req.Equal(fmt.Sprintf("u%d", ctr+1), usr.GetValue().Handle)
}
}
func Test0006_iterator_users_limited(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
loadScenarioWithName(ctx, t, "iterator_users_limit")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 3x iterator, 2x continue, 1x terminator, 1x completed
req.Len(trace, 7)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 1; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewUser(frame.Results.GetValue()["u"])
req.NoError(err)
req.Equal(fmt.Sprintf("u%d", ctr+1), usr.GetValue().Handle)
}
}

View File

@@ -0,0 +1,131 @@
package workflows
import (
"context"
"fmt"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/cortezaproject/corteza/server/system/automation"
"github.com/stretchr/testify/require"
)
func Test0007_iterator_roles(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoles(ctx))
loadScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewRole(frame.Results.GetValue()["r"])
req.NoError(err)
req.Equal(fmt.Sprintf("r%d", ctr+1), usr.GetValue().Handle)
}
}
func Test0008_iterator_roles_chunked(t *testing.T) {
wfexec.MaxIteratorBufferSize = 2
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoles(ctx))
loadScenarioWithName(ctx, t, "S0007_iterator_roles")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewRole(frame.Results.GetValue()["r"])
req.NoError(err)
req.Equal(fmt.Sprintf("r%d", ctr+1), usr.GetValue().Handle)
}
}
func Test0008_iterator_roles_limited(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoles(ctx))
loadScenarioWithName(ctx, t, "iterator_roles_limit")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 3x iterator, 2x continue, 1x terminator, 1x completed
req.Len(trace, 7)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 1; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewRole(frame.Results.GetValue()["r"])
req.NoError(err)
req.Equal(fmt.Sprintf("r%d", ctr+1), usr.GetValue().Handle)
}
}

View File

@@ -0,0 +1,57 @@
package workflows
import (
"context"
"fmt"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/cortezaproject/corteza/server/system/automation"
"github.com/stretchr/testify/require"
)
func Test0008_iterator_role_members(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateRoleMembers(ctx))
req.NoError(defStore.TruncateRoles(ctx))
req.NoError(defStore.TruncateUsers(ctx))
loadScenario(ctx, t)
addRoleMember(ctx, req, "r1", "u1", "u2", "u3", "u4", "u5")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewUser(frame.Results.GetValue()["u"])
req.NoError(err)
req.Equal(fmt.Sprintf("u%d", ctr+1), usr.GetValue().Handle)
}
}

View File

@@ -0,0 +1,131 @@
package workflows
import (
"context"
"fmt"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/cortezaproject/corteza/server/system/automation"
"github.com/stretchr/testify/require"
)
func Test0009_iterator_templates(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateTemplates(ctx))
loadScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
usr, err := automation.NewTemplate(frame.Results.GetValue()["tpl"])
req.NoError(err)
req.Equal(fmt.Sprintf("t%d", ctr+1), usr.GetValue().Handle)
}
}
func Test0009_iterator_templates_chunked(t *testing.T) {
wfexec.MaxIteratorBufferSize = 2
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateTemplates(ctx))
loadScenarioWithName(ctx, t, "S0009_iterator_templates")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 4; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
tpl, err := automation.NewTemplate(frame.Results.GetValue()["tpl"])
req.NoError(err)
req.Equal(fmt.Sprintf("t%d", ctr+1), tpl.GetValue().Handle)
}
}
func Test0009_iterator_templates_limited(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateTemplates(ctx))
loadScenarioWithName(ctx, t, "iterator_templates_limit")
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 3x iterator, 2x continue, 1x terminator, 1x completed
req.Len(trace, 7)
// there are 4 iterator calls; each on the *2 index
ctr := int64(-1)
for j := 0; j <= 1; j++ {
ix := j * 2
ctr++
frame := trace[ix]
req.Equal(uint64(10), frame.StepID)
i, err := expr.Integer{}.Cast(frame.Results.GetValue()["i"])
req.NoError(err)
req.Equal(ctr, i.Get().(int64))
tpl, err := automation.NewTemplate(frame.Results.GetValue()["tpl"])
req.NoError(err)
req.Equal(fmt.Sprintf("t%d", ctr+1), tpl.GetValue().Handle)
}
}

View File

@@ -0,0 +1,52 @@
package workflows
import (
"testing"
)
func Test0010_stacktrace(t *testing.T) {
t.Skip("@todo envoy not yet refactored")
// var (
// ctx = bypassRBAC(context.Background())
// req = require.New(t)
// )
// req.NoError(truncateRecords(ctx))
// req.NoError(defStore.TruncateComposeModules(ctx))
// req.NoError(defStore.TruncateComposeNamespaces(ctx))
// loadScenario(ctx, t)
// for rep := 0; rep < 11; rep++ {
// t.Run(fmt.Sprintf("iteration %d", rep), func(t *testing.T) {
// var (
// _, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
// )
// // 6x iterator, 5x continue, 1x terminator, 1x completed
// req.Len(trace, 13)
// steps := []uint64{
// 10,
// 11,
// 10,
// 11,
// 10,
// 11,
// 10,
// 11,
// 10,
// 11,
// 10,
// 12,
// 0,
// }
// for i := 0; i < 13; i++ {
// req.Equal(steps[i], trace[i].StepID)
// }
// })
// }
}

View File

@@ -0,0 +1,27 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/stretchr/testify/require"
)
func Test0011_termination_explicit(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
req.Len(trace, 3)
req.Equal(uint64(10), trace[0].StepID)
req.Equal(uint64(11), trace[1].StepID)
req.Equal(uint64(0), trace[2].StepID)
}

View File

@@ -0,0 +1,26 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/stretchr/testify/require"
)
func Test0012_termination_implicit(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
req.Len(trace, 2)
req.Equal(uint64(10), trace[0].StepID)
req.Equal(uint64(0), trace[1].StepID)
}

View File

@@ -0,0 +1,48 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/stretchr/testify/require"
)
func Test0013_gateway_exclusive(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
t.Run("first path match", func(t *testing.T) {
_, trace := mustExecWorkflow(ctx, t, "case1", autTypes.WorkflowExecParams{})
req.Len(trace, 4)
req.Equal(uint64(10), trace[0].StepID)
req.Equal(uint64(11), trace[1].StepID)
req.Equal(uint64(14), trace[2].StepID)
req.Equal(uint64(0), trace[3].StepID)
})
t.Run("second path match", func(t *testing.T) {
_, trace := mustExecWorkflow(ctx, t, "case2", autTypes.WorkflowExecParams{})
req.Len(trace, 4)
req.Equal(uint64(10), trace[0].StepID)
req.Equal(uint64(12), trace[1].StepID)
req.Equal(uint64(14), trace[2].StepID)
req.Equal(uint64(0), trace[3].StepID)
})
t.Run("default path match", func(t *testing.T) {
_, trace := mustExecWorkflow(ctx, t, "case3", autTypes.WorkflowExecParams{})
req.Len(trace, 4)
req.Equal(uint64(10), trace[0].StepID)
req.Equal(uint64(13), trace[1].StepID)
req.Equal(uint64(14), trace[2].StepID)
req.Equal(uint64(0), trace[3].StepID)
})
}

View File

@@ -0,0 +1,64 @@
package workflows
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/cortezaproject/corteza/server/automation/types"
)
func Test0015_step_issue(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
t.Run("exclusive gateway step issue", func(t *testing.T) {
_, _, _, err := execWorkflow(ctx, "case1", types.WorkflowExecParams{})
issues, is := err.(types.WorkflowIssueSet)
req.True(is)
// It should return only 2 issues
// 1. gateway step expects at least 1 outbound path(s)
// 2. expecting at least two paths for exclusive gateway
req.Len(issues, 2)
})
t.Run("inclusive gateway step issue", func(t *testing.T) {
_, _, _, err := execWorkflow(ctx, "case2", types.WorkflowExecParams{})
issues, is := err.(types.WorkflowIssueSet)
req.True(is)
// It should return only 2 issues
// 1. gateway step expects at least 1 outbound path(s)
// 2. expecting at least two paths for inclusive gateway
req.Len(issues, 2)
})
t.Run("function step issue", func(t *testing.T) {
_, _, _, err := execWorkflow(ctx, "case3", types.WorkflowExecParams{})
issues, is := err.(types.WorkflowIssueSet)
req.True(is)
// It should return only 1 issue
// 1. failed to verify argument expressions for function logInfo: parameter message is required
req.Len(issues, 1)
})
t.Run("iterator step issue", func(t *testing.T) {
_, _, _, err := execWorkflow(ctx, "case4", types.WorkflowExecParams{})
issues, is := err.(types.WorkflowIssueSet)
req.True(is)
// It should return only 3 issues
// 1. iterator step expects reference
// 2. iterator step expects exactly 2 outbound path(s)
// 3. unknown function ""
req.Len(issues, 3)
})
}

View File

@@ -0,0 +1,116 @@
package workflows
import (
"context"
cmpTypes "github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/stretchr/testify/require"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
)
func Test0016_kv_expressions_step(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
t.Run("KV related expressions", func(t *testing.T) {
type (
testInput struct {
Out map[string]string
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "kv_expressions", types.WorkflowExecParams{})
expected = testInput{
Out: map[string]string{
"testString": "testing string",
},
}
)
req.NoError(vars.Decode(&aux))
req.Equal(expected, aux)
})
t.Run("KVV related expressions", func(t *testing.T) {
type (
testInput struct {
Out map[string][]string
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "kvv_expressions", types.WorkflowExecParams{})
expected = testInput{
Out: map[string][]string{
"testString": {"foo", "bar"},
},
}
)
req.NoError(vars.Decode(&aux))
req.Equal(expected, aux)
})
t.Run("Vars related expressions", func(t *testing.T) {
type (
testInput struct {
Out map[string]expr.TypedValue
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "vars_expressions", types.WorkflowExecParams{})
testString = expr.Must(expr.NewString("testing string"))
testInt = expr.Must(expr.NewInteger(40))
testVar = expr.Must(expr.NewVars(map[string]interface{}{
"testString": testString,
"testFloat": expr.Must(expr.NewFloat(50)),
}))
expectedVars = map[string]expr.TypedValue{
"testString": testString,
"testInt": testInt,
"testVar": testVar,
}
expected = testInput{
Out: expectedVars,
}
)
req.NoError(vars.Decode(&aux))
req.Equal(expected, aux)
})
t.Run("ComposeRecordValues related expressions", func(t *testing.T) {
type (
testInput struct {
Out *cmpTypes.Record
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "compose_record_values_expressions", types.WorkflowExecParams{})
expected = testInput{
Out: &cmpTypes.Record{
Values: []*cmpTypes.RecordValue{
{
Name: "testFloat",
Value: "50",
},
},
},
}
)
req.NoError(vars.Decode(&aux))
req.Equal(expected, aux)
})
}

View File

@@ -0,0 +1,33 @@
package workflows
import (
"context"
"github.com/stretchr/testify/require"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
)
func Test0017_subworkflows(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
type (
testInput struct {
Out string
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "main", types.WorkflowExecParams{})
expected = testInput{Out: "main + sub"}
)
req.NoError(vars.Decode(&aux))
req.Equal(expected, aux)
}

View File

@@ -0,0 +1,50 @@
package workflows
import (
"context"
"github.com/cortezaproject/corteza/server/pkg/errors"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/stretchr/testify/require"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
)
func Test0018_error_handler_step(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
loadScenario(ctx, t)
t.Run("error handler with result", func(t *testing.T) {
type (
testInput struct {
E expr.TypedValue
EM expr.TypedValue
EsID expr.TypedValue
}
)
var (
aux = testInput{}
vars, _ = mustExecWorkflow(ctx, t, "error_handler_results", types.WorkflowExecParams{})
expected = testInput{
E: expr.Must(expr.NewAny(errors.New(errors.KindAutomation, "TestingError"))),
EM: expr.Must(expr.NewString("TestingError")),
EsID: expr.Must(expr.NewInteger(2)),
}
)
req.NoError(vars.Decode(&aux))
errA := expr.Must(expr.NewAny(aux.E.Get()))
req.Error(errors.Unwrap(errA.Get().(*errors.Error)))
req.Equal(errors.Unwrap(errA.Get().(*errors.Error)).Error(), "TestingError")
req.True(errors.IsKind(errA.Get().(*errors.Error), errors.KindAutomation))
req.Equal(expected.EM, aux.EM)
req.Equal(expected.EsID, aux.EsID)
})
}

View File

@@ -0,0 +1,56 @@
package workflows
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
)
func Test0019_workflow_graph_and_scope(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
)
loadScenario(ctx, t)
t.Run("iterator inside fork/join resolves", func(t *testing.T) {
req := require.New(t)
_, _, _, err := execWorkflow(ctx, "iterator_in_fork", types.WorkflowExecParams{})
if issues, is := err.(types.WorkflowIssueSet); is {
for _, i := range issues {
t.Logf("issue: %s", i.Description)
}
}
req.NoError(err)
})
t.Run("mid-branch variable survives join", func(t *testing.T) {
req := require.New(t)
vars, _ := mustExecWorkflow(ctx, t, "join_new_var", types.WorkflowExecParams{})
req.Equal(expr.Must(expr.NewString("fromB")), vars.GetValue()["foo"])
})
t.Run("mid-branch change to pre-existing variable survives join", func(t *testing.T) {
req := require.New(t)
vars, _ := mustExecWorkflow(ctx, t, "join_existing_var", types.WorkflowExecParams{})
req.Equal(expr.Must(expr.NewString("fromB")), vars.GetValue()["foo"])
})
t.Run("nested parallel section keeps its own changes", func(t *testing.T) {
req := require.New(t)
vars, _ := mustExecWorkflow(ctx, t, "join_nested", types.WorkflowExecParams{})
req.Equal(expr.Must(expr.NewString("fromA")), vars.GetValue()["foo"])
req.Equal(expr.Must(expr.NewString("b1")), vars.GetValue()["b1"])
req.Equal(expr.Must(expr.NewString("b2")), vars.GetValue()["b2"])
})
t.Run("error handler vars survive a normal step", func(t *testing.T) {
req := require.New(t)
vars, _ := mustExecWorkflow(ctx, t, "errhandler_after_step", types.WorkflowExecParams{})
req.Equal(expr.Must(expr.NewString("Boom")), vars.GetValue()["caught"])
})
}

View File

@@ -0,0 +1,49 @@
package workflows
import (
"context"
"testing"
automationService "github.com/cortezaproject/corteza/server/automation/service"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/actionlog"
"github.com/cortezaproject/corteza/server/pkg/logger"
"github.com/cortezaproject/corteza/server/system/automation"
"github.com/stretchr/testify/require"
)
func Test_actionlog_functions(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateActionlogs(ctx))
//// register action log with storage backend
automation.ActionlogHandler(
automationService.Registry(),
actionlog.NewService(defStore, logger.Default(), logger.Default(), actionlog.NewPolicyAll()),
)
loadNewScenario(ctx, t)
var (
aux = struct {
Actions actionlog.ActionSet
}{}
)
vars, _ := mustExecWorkflow(ctx, t, "logger", types.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
// Expecting both, invoker & runner to be same as invoker
req.Len(aux.Actions, 2)
//undo action log registration
automation.ActionlogHandler(
automationService.Registry(),
automationService.DefaultActionlog,
)
}

View File

@@ -0,0 +1,43 @@
package workflows
import (
"context"
"io"
"io/ioutil"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
cmpTypes "github.com/cortezaproject/corteza/server/compose/types"
"github.com/stretchr/testify/require"
)
func Test_attachment_management(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateAttachments(ctx))
loadNewScenario(ctx, t)
var (
aux = struct {
Base64blackGif string
LoadedAttBlackGif *cmpTypes.Attachment
StoredAttBlackGif *cmpTypes.Attachment
LoadedContent io.ReadSeeker
}{}
)
vars, _ := mustExecWorkflow(ctx, t, "attachments", types.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
req.Equal(int(aux.LoadedAttBlackGif.Meta.Original.Size), len(aux.Base64blackGif))
req.Equal(int(aux.StoredAttBlackGif.Meta.Original.Size), len(aux.Base64blackGif))
b, err := ioutil.ReadAll(aux.LoadedContent)
req.NoError(err)
req.Equal(aux.Base64blackGif, string(b))
}

View File

@@ -0,0 +1,68 @@
package workflows
import (
"context"
"io"
"strings"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
cmpTypes "github.com/cortezaproject/corteza/server/compose/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/stretchr/testify/require"
)
type (
auxReader struct {
read bool
}
)
func Test_attachment_management_types(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateAttachments(ctx))
loadNewScenario(ctx, t)
var (
aux = struct {
AttachedString *cmpTypes.Attachment
AttachedReader *cmpTypes.Attachment
AttachedReadSeeker *cmpTypes.Attachment
AttachedBytes *cmpTypes.Attachment
}{}
)
v := &expr.Vars{}
v.AssignFieldValue("sourceString", expr.Must(expr.NewString("hello")))
v.AssignFieldValue("sourceReader", expr.Must(expr.NewReader(&auxReader{})))
v.AssignFieldValue("sourceReadSeeker", expr.Must(expr.NewReader(strings.NewReader("hello"))))
v.AssignFieldValue("sourceBytes", expr.Must(expr.NewBytes([]byte{'h', 'e', 'l', 'l', 'o'})))
vars, _ := mustExecWorkflow(ctx, t, "attachments", types.WorkflowExecParams{
Input: v,
})
req.NoError(vars.Decode(&aux))
req.NotNil(aux.AttachedString)
req.NotNil(aux.AttachedReader)
req.NotNil(aux.AttachedReadSeeker)
req.NotNil(aux.AttachedBytes)
}
func (ar *auxReader) Read(dst []byte) (int, error) {
if ar.read {
return 0, io.EOF
}
for i := range dst {
dst[i] = byte('a')
}
ar.read = true
return len(dst), nil
}

View File

@@ -0,0 +1,62 @@
package workflows
import (
"context"
"testing"
"github.com/cortezaproject/corteza/server/automation/service"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/rbac"
"github.com/cortezaproject/corteza/server/tests/helpers"
"github.com/stretchr/testify/require"
)
func Test_exec_permissions(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
req.NoError(defStore.TruncateRoles(ctx))
req.NoError(defStore.TruncateRoleMembers(ctx))
req.NoError(defStore.TruncateRbacRules(ctx))
loadNewScenario(ctx, t)
// user that the workflow is configured to use for run-as
execAllowed, err := defStore.LookupUserByHandle(ctx, "exec-allowed")
req.NoError(err)
// user that the workflow is configured to use for run-as
execDenied, err := defStore.LookupUserByHandle(ctx, "exec-denied")
req.NoError(err)
// invokers group with permissions to execute workflow
executors, err := defStore.LookupRoleByHandle(ctx, "executors")
req.NoError(err)
//err = defStore.CreateRoleMember(ctx, &sysTypes.RoleMember{UserID: wfInvoker.ID, RoleID: wfInvokers.ID})
//req.NoError(err)
execAllowed.SetRoles(executors.ID)
helpers.UpdateRBAC(
executors.ID,
)
rbac.Global().Reload(ctx)
t.Run("exec allowed", func(t *testing.T) {
ctx = auth.SetIdentityToContext(ctx, execAllowed)
_, _ = mustExecWorkflow(ctx, t, "wf", types.WorkflowExecParams{})
})
t.Run("exec denied", func(t *testing.T) {
req = require.New(t)
ctx = auth.SetIdentityToContext(ctx, execDenied)
_, _, _, err = execWorkflow(ctx, "wf", types.WorkflowExecParams{})
req.ErrorIs(err, service.WorkflowErrNotAllowedToExecute())
})
}

View File

@@ -0,0 +1,89 @@
package workflows
import (
"context"
"fmt"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/rbac"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/cortezaproject/corteza/server/tests/helpers"
"github.com/stretchr/testify/require"
)
func Test_invoker_and_runner_in_scope(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
req.NoError(defStore.TruncateRoles(ctx))
req.NoError(defStore.TruncateRoleMembers(ctx))
req.NoError(defStore.TruncateRbacRules(ctx))
loadNewScenario(ctx, t)
// user that the workflow is configured to use for run-as
wfRunner, err := defStore.LookupUserByHandle(ctx, "wf-runner")
req.NoError(err)
// user invoking the workflow
wfInvoker, err := defStore.LookupUserByHandle(ctx, "wf-invoker")
req.NoError(err)
// invokers group with permissions to execute workflow
wfInvokers, err := defStore.LookupRoleByHandle(ctx, "wf-invokers")
req.NoError(err)
err = defStore.CreateRoleMember(ctx, &sysTypes.RoleMember{Resource: fmt.Sprintf("corteza::system:user/%d", wfInvoker.ID), RoleID: wfInvokers.ID})
req.NoError(err)
wfInvoker.SetRoles(wfInvokers.ID)
ctx = auth.SetIdentityToContext(ctx, wfInvoker)
helpers.UpdateRBAC(
wfInvokers.ID,
)
rbac.Global().Reload(ctx)
t.Run("invoker set in scope", func(t *testing.T) {
var (
req = require.New(t)
aux = struct {
Invoker *sysTypes.User
Runner *sysTypes.User
}{}
)
vars, _ := mustExecWorkflow(ctx, t, "invoker", types.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
// Expecting both, invoker & runner to be same as invoker
req.NotNil(aux.Runner)
req.NotNil(aux.Invoker)
req.Equal(aux.Runner.Handle, wfInvoker.Handle)
req.Equal(aux.Invoker.Handle, wfInvoker.Handle)
})
t.Run("runner set in scope", func(t *testing.T) {
var (
req = require.New(t)
aux = struct {
Invoker *sysTypes.User
Runner *sysTypes.User
}{}
)
vars, _ := mustExecWorkflow(ctx, t, "runner", types.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
// Expecting runner and invoker to be different.
req.NotNil(aux.Runner)
req.NotNil(aux.Invoker)
req.Equal(aux.Runner.Handle, wfRunner.Handle)
req.Equal(aux.Invoker.Handle, wfInvoker.Handle)
})
}

View File

@@ -0,0 +1,56 @@
package workflows
import (
"context"
"testing"
"time"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
// Test_iterator_reminders_total iterates with incTotal over more reminders than
// the buffer holds; total is fetched with the first page and reported on every
// iteration
func Test_iterator_reminders_total(t *testing.T) {
wfexec.MaxIteratorBufferSize = 2
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateReminders(ctx))
loadNewScenario(ctx, t)
for j := 0; j < 5; j++ {
req.NoError(defStore.CreateReminder(ctx, &sysTypes.Reminder{
ID: id.Next(),
Resource: "test:resource",
AssignedTo: auth.GetIdentityFromContext(ctx).Identity(),
CreatedAt: time.Now(),
}))
}
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
for j := 0; j <= 4; j++ {
total, err := expr.Integer{}.Cast(trace[j*2].Results.GetValue()["t"])
req.NoError(err)
req.Equal(int64(5), total.Get().(int64))
}
}

View File

@@ -0,0 +1,51 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/spf13/cast"
"github.com/stretchr/testify/require"
)
func Test_iterator_sequence_complex(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(truncateRecords(ctx))
req.NoError(defStore.TruncateComposeModules(ctx))
req.NoError(defStore.TruncateComposeNamespaces(ctx))
loadNewScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
req.Len(trace, 7)
frame := trace[1]
req.True(frame.Scope.GetValue()["first"].Get().(bool))
req.False(frame.Scope.GetValue()["last"].Get().(bool))
aux := frame.Scope.GetValue()["i"].Get()
i, err := cast.ToIntE(aux)
req.NoError(err)
req.Equal(2, i)
frame = trace[len(trace)-1]
req.False(frame.Scope.GetValue()["first"].Get().(bool))
req.True(frame.Scope.GetValue()["last"].Get().(bool))
aux = frame.Scope.GetValue()["i"].Get()
i, err = cast.ToIntE(aux)
req.NoError(err)
req.Equal(4, i)
}

View File

@@ -0,0 +1,51 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/spf13/cast"
"github.com/stretchr/testify/require"
)
func Test_iterator_sequence(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(truncateRecords(ctx))
req.NoError(defStore.TruncateComposeModules(ctx))
req.NoError(defStore.TruncateComposeNamespaces(ctx))
loadNewScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
req.Len(trace, 9)
frame := trace[1]
req.True(frame.Scope.GetValue()["first"].Get().(bool))
req.False(frame.Scope.GetValue()["last"].Get().(bool))
aux := frame.Scope.GetValue()["i"].Get()
i, err := cast.ToIntE(aux)
req.NoError(err)
req.Equal(0, i)
frame = trace[len(trace)-1]
req.False(frame.Scope.GetValue()["first"].Get().(bool))
req.True(frame.Scope.GetValue()["last"].Get().(bool))
aux = frame.Scope.GetValue()["i"].Get()
i, err = cast.ToIntE(aux)
req.NoError(err)
req.Equal(2, i)
}

View File

@@ -0,0 +1,54 @@
package workflows
import (
"context"
"fmt"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/filter"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/cortezaproject/corteza/server/system/automation"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
// Test_iterator_users_cursor starts iteration from a page cursor and yields
// only the items that follow it
func Test_iterator_users_cursor(t *testing.T) {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
loadNewScenario(ctx, t)
// Take the cursor that points past the first two users
_, uf, err := defStore.SearchUsers(ctx, sysTypes.UserFilter{Paging: filter.Paging{Limit: 2}})
req.NoError(err)
req.NotNil(uf.NextPage)
input := &expr.Vars{}
req.NoError(input.Set("cursor", expr.Must(expr.NewString(uf.NextPage.Encode()))))
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{Input: input})
)
// 3 of the 5 users remain: 4x iterator, 3x continue, 1x terminator, 1x completed
req.Len(trace, 9)
for j := 0; j <= 2; j++ {
usr, err := automation.NewUser(trace[j*2].Results.GetValue()["u"])
req.NoError(err)
req.Equal(fmt.Sprintf("u%d", j+3), usr.GetValue().Handle)
}
}

View File

@@ -0,0 +1,43 @@
package workflows
import (
"context"
"testing"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/wfexec"
"github.com/stretchr/testify/require"
)
// Test_iterator_users_total iterates with incTotal and incPageNavigation over
// more items than the buffer holds; total is fetched with the first page and
// reported on every iteration
func Test_iterator_users_total(t *testing.T) {
wfexec.MaxIteratorBufferSize = 2
defer func() {
wfexec.MaxIteratorBufferSize = wfexec.DefaultMaxIteratorBufferSize
}()
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
)
req.NoError(defStore.TruncateUsers(ctx))
loadNewScenario(ctx, t)
var (
_, trace = mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
)
// 6x iterator, 5x continue, 1x terminator, 1x completed
req.Len(trace, 13)
for j := 0; j <= 4; j++ {
total, err := expr.Integer{}.Cast(trace[j*2].Results.GetValue()["t"])
req.NoError(err)
req.Equal(int64(5), total.Get().(int64))
}
}

View File

@@ -0,0 +1,34 @@
package workflows
import (
"context"
_ "embed"
"strings"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/stretchr/testify/require"
)
//go:embed testdata/jwt_generate/match_token
var tkn string
func Test_jwt_generate(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
aux = struct {
Token string
}{}
)
req.NoError(defStore.TruncateAttachments(ctx))
loadNewScenario(ctx, t)
vars, _ := mustExecWorkflow(ctx, t, "jwt_generate", types.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
req.Equal(strings.TrimSuffix(tkn, "\n"), aux.Token)
}

View File

@@ -0,0 +1,200 @@
package workflows
import (
"context"
"fmt"
// "fmt"
"path"
"testing"
"github.com/cortezaproject/corteza/server/app"
"github.com/cortezaproject/corteza/server/automation/service"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/dal"
"github.com/cortezaproject/corteza/server/pkg/envoy"
"github.com/cortezaproject/corteza/server/pkg/envoy/csv"
"github.com/cortezaproject/corteza/server/pkg/envoy/directory"
"github.com/cortezaproject/corteza/server/pkg/envoy/json"
envoyStore "github.com/cortezaproject/corteza/server/pkg/envoy/store"
"github.com/cortezaproject/corteza/server/pkg/envoy/yaml"
"github.com/cortezaproject/corteza/server/pkg/eventbus"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/cortezaproject/corteza/server/pkg/id"
"github.com/cortezaproject/corteza/server/pkg/logger"
"github.com/cortezaproject/corteza/server/store"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/cortezaproject/corteza/server/tests/helpers"
"github.com/stretchr/testify/require"
)
var (
defApp *app.CortezaApp
defStore store.Storer
defDal dal.FullService
eventBus = eventbus.New()
)
func init() {
helpers.RecursiveDotEnvLoad()
}
func TestMain(m *testing.M) {
logger.SetDefault(logger.MakeDebugLogger())
ctx := context.Background()
defApp = helpers.NewIntegrationTestApp(ctx, func(app *app.CortezaApp) (err error) {
// some test suites require action-log enabled
app.Opt.ActionLog.WorkflowFunctionsEnabled = true
// trace assertions in this suite expect every executed step to be
// recorded; the default only keeps the last iteration of each loop
app.Opt.Workflow.StackTraceFull = true
defStore = app.Store
eventbus.Set(eventBus)
return nil
})
defDal = dal.Service()
if err := defApp.Activate(ctx); err != nil {
panic(fmt.Errorf("could not activate corteza: %v", err))
}
if err := defApp.InitExpr(ctx); err != nil {
panic(fmt.Errorf("could not init expressions: %v", err))
}
m.Run()
}
func cleanup(t *testing.T) {
var (
ctx = context.Background()
)
if err := defStore.TruncateAutomationWorkflows(ctx); err != nil {
t.Fatalf("failed to decode scenario data: %v", err)
}
}
func truncateRecords(ctx context.Context) error {
models, err := defDal.SearchModels(ctx)
if err != nil {
return err
}
for _, model := range models {
err = defDal.Truncate(ctx, model.ToFilter(), nil)
if err != nil {
return err
}
}
return nil
}
func loadScenario(ctx context.Context, t *testing.T) {
loadScenarioWithName(ctx, t, "S"+t.Name()[4:])
}
// 1st step in migration to workflow testdata w/o number prefix
//
// When all old scenarios are renamed, replace it with loadScenario.
func loadNewScenario(ctx context.Context, t *testing.T) {
loadScenarioWithName(ctx, t, t.Name()[5:])
}
func loadScenarioWithName(ctx context.Context, t *testing.T, scenario string) {
var (
err error
)
cleanup(t)
decoded, err := directory.Decode(
ctx,
path.Join("testdata", scenario),
yaml.Decoder(),
csv.Decoder(),
json.Decoder(),
)
if err != nil {
t.Fatalf("failed to decode scenario data: %v", err)
}
storeEnc := envoyStore.NewStoreEncoder(defStore, dal.Service(), &envoyStore.EncoderConfig{})
b := envoy.NewBuilder(storeEnc)
g, err := b.Build(ctx, decoded...)
if err != nil {
t.Fatalf("failed to build structure graph: %v", err)
}
if err = envoy.Encode(ctx, g, storeEnc); err != nil {
t.Fatalf("failed to build structure graph: %v", err)
}
// Reload and register workflows
if err = service.DefaultWorkflow.Load(ctx); err != nil {
t.Fatalf("failed to reload workflows: %v", err)
}
}
func bypassRBAC(ctx context.Context) context.Context {
u := &sysTypes.User{
ID: id.Next(),
}
if err := defStore.CreateUser(ctx, u); err != nil {
panic(err)
}
u.SetRoles(auth.BypassRoles().IDs()...)
return auth.SetIdentityToContext(ctx, u)
}
func execWorkflow(ctx context.Context, name string, p autTypes.WorkflowExecParams) (*expr.Vars, uint64, autTypes.Stacktrace, error) {
wf, err := defStore.LookupAutomationWorkflowByHandle(ctx, name)
if err != nil {
return nil, 0, nil, err
}
return service.DefaultWorkflow.Exec(ctx, wf.ID, p)
}
func mustExecWorkflow(ctx context.Context, t *testing.T, name string, p autTypes.WorkflowExecParams) (vars *expr.Vars, strace autTypes.Stacktrace) {
var err error
vars, _, strace, err = execWorkflow(ctx, name, p)
if err != nil {
if issues, is := err.(autTypes.WorkflowIssueSet); is {
for _, i := range issues {
t.Logf("issue: %s", i.Description)
t.Logf(" %v", i.Culprit)
}
}
t.Fatalf("could not exec %q: %v", name, err)
}
return
}
func addRoleMember(ctx context.Context, req *require.Assertions, r string, uu ...string) {
role, err := store.LookupRoleByHandle(ctx, defStore, r)
req.NoError(err)
rr := make([]*sysTypes.RoleMember, len(uu))
for i, u := range uu {
usr, err := store.LookupUserByHandle(ctx, defStore, u)
req.NoError(err)
rr[i] = &sysTypes.RoleMember{
RoleID: role.ID,
Resource: fmt.Sprintf("corteza::system:user/%d", usr.ID),
}
}
req.NoError(store.CreateRoleMember(ctx, defStore, rr...))
}

View File

@@ -0,0 +1,39 @@
package workflows
import (
"context"
_ "embed"
"testing"
"github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/expr"
"github.com/stretchr/testify/require"
)
// make test.integration.workflows TEST_FLAGS="-run Test_nested_iterators -v"
func Test_nested_iterators(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
aux = struct {
Token string
}{}
input, err = expr.NewVars(map[string]interface{}{
"L1": 3,
"L2": 3,
"L3": 3,
})
)
req.NoError(err)
req.NoError(defStore.TruncateAttachments(ctx))
loadNewScenario(ctx, t)
vars, _ := mustExecWorkflow(ctx, t, "nested_iterators", types.WorkflowExecParams{Input: input})
req.NoError(vars.Decode(&aux))
}

View File

@@ -0,0 +1,48 @@
package workflows
import (
"context"
"testing"
"time"
autTypes "github.com/cortezaproject/corteza/server/automation/types"
"github.com/cortezaproject/corteza/server/pkg/auth"
"github.com/cortezaproject/corteza/server/pkg/id"
sysTypes "github.com/cortezaproject/corteza/server/system/types"
"github.com/stretchr/testify/require"
)
// Test_results_without_trace asserts on what a workflow returns rather than on
// its stacktrace, so it holds whether or not frame collection is turned on
// (WORKFLOW_STACK_TRACE_ENABLED)
func Test_results_without_trace(t *testing.T) {
var (
ctx = bypassRBAC(context.Background())
req = require.New(t)
aux = struct {
Total uint64
Found int
}{}
)
req.NoError(defStore.TruncateReminders(ctx))
rr := make([]*sysTypes.Reminder, 5)
for i := range rr {
rr[i] = &sysTypes.Reminder{
ID: id.Next(),
Resource: "test:resource",
AssignedTo: auth.GetIdentityFromContext(ctx).Identity(),
CreatedAt: time.Now(),
}
}
req.NoError(defStore.CreateReminder(ctx, rr...))
loadNewScenario(ctx, t)
vars, _ := mustExecWorkflow(ctx, t, "testing", autTypes.WorkflowExecParams{})
req.NoError(vars.Decode(&aux))
req.Equal(uint64(5), aux.Total)
req.Equal(5, aux.Found)
}

View File

@@ -0,0 +1,18 @@
workflows:
basic:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "40" } ]
- stepID: 2
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "foo + 2" } ]
paths:
- { parentID: 1, childID: 2 }

View File

@@ -0,0 +1,66 @@
roles:
testers:
users:
tester:
email: tester@testing-samples.tld
workflows:
check-and-grant:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: function
ref: rolesLookup
arguments:
- { target: lookup, type: Handle, value: "testers" }
results:
- { target: res, expr: role }
- stepID: 2
kind: function
ref: rbacCheck
arguments:
- { target: resource, type: RbacResource, expr: "res" }
- { target: operation, type: String, value: "read" }
results:
- { target: canCurrentRead, type: String, expr: 'can ? "y":"n"' }
- stepID: 3
kind: function
ref: usersLookup
arguments:
- { target: lookup, type: Handle, value: "tester" }
results:
- { target: usr, expr: user }
- stepID: 4
kind: function
ref: rbacCheck
arguments:
- { target: resource, type: RbacResource, expr: "res" }
- { target: operation, type: String, value: "read" }
- { target: user, type: User, expr: "usr" }
results:
- { target: canOtherRead, type: String, expr: 'can ? "y":"n"' }
- stepID: 5
kind: function
ref: rbacAllow
arguments:
- { target: resource, type: RbacResource, expr: "res" }
- { target: operation, type: String, value: "read" }
- { target: role, type: Role, expr: "res" }
paths:
- { parentID: 1, childID: 2 }
- { parentID: 2, childID: 3 }
- { parentID: 3, childID: 4 }
- { parentID: 4, childID: 5 }

View File

@@ -0,0 +1,24 @@
workflows:
create-user:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments:
- { target: dummy, type: User }
- { target: dummy.email, type: String, value: "some.email@domain.tld" }
- { target: dummy.name, type: String, value: "Not Sure" }
- stepID: 2
kind: function
ref: usersCreate
arguments:
- { target: user, type: User, expr: "dummy" }
paths:
- { parentID: 1, childID: 2 }

View File

@@ -0,0 +1,7 @@
users:
u1: u1@example.tld
u2: u2@example.tld
roles:
r1: Role1
r2: Role2

View File

@@ -0,0 +1,74 @@
workflows:
role-members:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
# Adding membership
- stepID: 10
kind: function
ref: rolesAddMember
arguments:
- { target: role, type: Handle, value: r1 }
- { target: user, type: Handle, value: u1 }
- stepID: 11
kind: function
ref: rolesAddMember
arguments:
- { target: role, type: Handle, value: r2 }
- { target: user, type: Handle, value: u1 }
# Get current state
- stepID: 20
kind: function
ref: rolesSearchMembers
arguments:
- { target: lookup, type: Handle, value: r1 }
results:
- { target: usersPre_r1, expr: "users" }
- { target: totalPre_r1, expr: "total" }
- stepID: 21
kind: function
ref: rolesSearchMembers
arguments:
- { target: lookup, type: Handle, value: r2 }
results:
- { target: usersPre_r2, expr: "users" }
- { target: totalPre_r2, expr: "total" }
# Removing membership
- stepID: 30
kind: function
ref: rolesRemoveMember
arguments:
- { target: role, type: Handle, value: r1 }
- { target: user, type: Handle, value: u1 }
# Get final state
- stepID: 40
kind: function
ref: rolesSearchMembers
arguments:
- { target: lookup, type: Handle, value: r1 }
results:
- { target: usersPost_r1, expr: "users" }
- { target: totalPost_r1, expr: "total" }
- stepID: 41
kind: function
ref: rolesSearchMembers
arguments:
- { target: lookup, type: Handle, value: r2 }
results:
- { target: usersPost_r2, expr: "users" }
- { target: totalPost_r2, expr: "total" }
paths:
- { parentID: 10, childID: 11 }
- { parentID: 11, childID: 20 }
- { parentID: 20, childID: 21 }
- { parentID: 21, childID: 30 }
- { parentID: 30, childID: 40 }
- { parentID: 40, childID: 41 }

View File

@@ -0,0 +1,7 @@
users:
u1: u1@example.tld
u2: u2@example.tld
roles:
r1: Role1
r2: Role2

View File

@@ -0,0 +1,115 @@
workflows:
user-membership:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
# Adding membership
- stepID: 10
kind: function
ref: rolesAddMember
arguments:
- { target: role, type: Handle, value: r1 }
- { target: user, type: Handle, value: u1 }
- stepID: 11
kind: function
ref: rolesAddMember
arguments:
- { target: role, type: Handle, value: r2 }
- { target: user, type: Handle, value: u1 }
# Get current state
- stepID: 20
kind: function
ref: usersSearchMembership
arguments:
- { target: lookup, type: Handle, value: u1 }
results:
- { target: rolesPre_u1, expr: "roles" }
- { target: totalPre_u1, expr: "total" }
- stepID: 21
kind: function
ref: usersSearchMembership
arguments:
- { target: lookup, type: Handle, value: u2 }
results:
- { target: rolesPre_u2, expr: "roles" }
- { target: totalPre_u2, expr: "total" }
- stepID: 22
kind: function
ref: usersCheckMembership
arguments:
- { target: user, type: Handle, value: u1 }
- { target: role, type: Handle, value: r1 }
results:
- { target: memberPre_u1, expr: "member" }
- stepID: 23
kind: function
ref: usersCheckMembership
arguments:
- { target: user, type: Handle, value: u2 }
- { target: role, type: Handle, value: r1 }
results:
- { target: memberPre_u2, expr: "member" }
# Removing membership
- stepID: 30
kind: function
ref: rolesRemoveMember
arguments:
- { target: role, type: Handle, value: r1 }
- { target: user, type: Handle, value: u1 }
# Get final state
- stepID: 40
kind: function
ref: usersSearchMembership
arguments:
- { target: lookup, type: Handle, value: u1 }
results:
- { target: rolesPost_u1, expr: "roles" }
- { target: totalPost_u1, expr: "total" }
- stepID: 41
kind: function
ref: usersSearchMembership
arguments:
- { target: lookup, type: Handle, value: u2 }
results:
- { target: rolesPost_u2, expr: "roles" }
- { target: totalPost_u2, expr: "total" }
- stepID: 42
kind: function
ref: usersCheckMembership
arguments:
- { target: user, type: Handle, value: u1 }
- { target: role, type: Handle, value: r1 }
results:
- { target: memberPost_u1, expr: "member" }
- stepID: 43
kind: function
ref: usersCheckMembership
arguments:
- { target: user, type: Handle, value: u2 }
- { target: role, type: Handle, value: r1 }
results:
- { target: memberPost_u2, expr: "member" }
paths:
- { parentID: 10, childID: 11 }
- { parentID: 11, childID: 20 }
- { parentID: 20, childID: 21 }
- { parentID: 21, childID: 22 }
- { parentID: 22, childID: 23 }
- { parentID: 23, childID: 30 }
- { parentID: 30, childID: 40 }
- { parentID: 40, childID: 41 }
- { parentID: 41, childID: 42 }
- { parentID: 42, childID: 43 }

View File

@@ -0,0 +1,25 @@
namespaces:
ns1:
name: ns1 name
modules:
mod1:
name: mod1 name
fields:
f1:
label: f1 label
kind: String
required: false
records:
mod1:
- values:
f1: 1
- values:
f1: 2
- values:
f1: 3
- values:
f1: 4
- values:
f1: 5

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: composeRecordsEach
arguments:
- { "target": "module", "value": "mod1", "type": "Handle" }
- { "target": "namespace", "value": "ns1", "type": "Handle" }
results:
- { "target": "r", "expr": "record" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
users:
u1: u1@example.tld
u2: u2@example.tld
u3: u3@example.tld
u4: u4@example.tld
u5: u5@example.tld

View File

@@ -0,0 +1,28 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: usersEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
results:
- { "target": "u", "expr": "user" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
roles:
r1: r1 name
r2: r2 name
r3: r3 name
r4: r4 name
r5: r5 name

View File

@@ -0,0 +1,28 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: rolesEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
results:
- { "target": "r", "expr": "role" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,9 @@
roles:
r1: r1 name
users:
u1: u1@mail.tld
u2: u2@mail.tld
u3: u3@mail.tld
u4: u4@mail.tld
u5: u5@mail.tld

View File

@@ -0,0 +1,28 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: rolesEachMember
arguments:
- { "target": "lookup", "value": "r1", "type": "Handle" }
results:
- { "target": "u", "expr": "user" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,11 @@
templates:
t1:
type: text/html
t2:
type: text/html
t3:
type: text/html
t4:
type: text/html
t5:
type: text/html

View File

@@ -0,0 +1,28 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: templatesEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
results:
- { "target": "tpl", "expr": "template" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,25 @@
namespaces:
ns1:
name: ns1 name
modules:
mod1:
name: mod1 name
fields:
f1:
label: f1 label
kind: String
required: false
records:
mod1:
- values:
f1: 1
- values:
f1: 2
- values:
f1: 3
- values:
f1: 4
- values:
f1: 5

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: composeRecordsEach
arguments:
- { "target": "module", "value": "mod1", "type": "Handle" }
- { "target": "namespace", "value": "ns1", "type": "Handle" }
results:
- { "target": "r", "expr": "record" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,19 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: expressions
arguments:
- { "target": "test", "value": "42", "type": "Any" }
- stepID: 11
kind: termination
paths:
- { parentID: 10, childID: 11 }

View File

@@ -0,0 +1,13 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: expressions
arguments:
- { "target": "test", "value": "42", "type": "Any" }

View File

@@ -0,0 +1,120 @@
workflows:
case1:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: excl
- stepID: 11
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 1", type: "String"}
- stepID: 12
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 2", type: "String"}
- stepID: 13
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 3", type: "String"}
- stepID: 14
kind: termination
paths:
- { parentID: 10, childID: 11, expr: "true == true" }
- { parentID: 10, childID: 12, expr: "true == true" }
- { parentID: 10, childID: 13, expr: "" }
- { parentID: 11, childID: 14 }
- { parentID: 12, childID: 14 }
- { parentID: 13, childID: 14 }
case2:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: excl
- stepID: 11
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 1", type: "String"}
- stepID: 12
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 2", type: "String"}
- stepID: 13
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 3", type: "String"}
- stepID: 14
kind: termination
paths:
- { parentID: 10, childID: 11, expr: "true == false" }
- { parentID: 10, childID: 12, expr: "true == true" }
- { parentID: 10, childID: 13, expr: "" }
- { parentID: 11, childID: 14 }
- { parentID: 12, childID: 14 }
- { parentID: 13, childID: 14 }
case3:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: excl
- stepID: 11
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 1", type: "String"}
- stepID: 12
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 2", type: "String"}
- stepID: 13
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 3", type: "String"}
- stepID: 14
kind: termination
paths:
- { parentID: 10, childID: 11, expr: "true == false" }
- { parentID: 10, childID: 12, expr: "true == false" }
- { parentID: 10, childID: 13, expr: "" }
- { parentID: 11, childID: 14 }
- { parentID: 12, childID: 14 }
- { parentID: 13, childID: 14 }

View File

@@ -0,0 +1,46 @@
workflows:
case1:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: fork
- stepID: 11
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 1", type: "String"}
- stepID: 12
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 2", type: "String"}
- stepID: 13
kind: function
ref: logInfo
arguments:
- {target: "message", value: "log 3", type: "String"}
- stepID: 14
kind: gateway
ref: join
- stepID: 15
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }
- { parentID: 10, childID: 13 }
- { parentID: 11, childID: 14 }
- { parentID: 12, childID: 14 }
- { parentID: 13, childID: 14 }
- { parentID: 14, childID: 15 }

View File

@@ -0,0 +1,83 @@
workflows:
case1:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "40" } ]
- stepID: 2
kind: expressions
arguments: [ { target: bar, type: Integer, expr: "50" } ]
- stepID: 3
kind: gateway
ref: excl
paths:
- { parentID: 1, childID: 2 }
case2:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "40" } ]
- stepID: 2
kind: expressions
arguments: [ { target: bar, type: Integer, expr: "50" } ]
- stepID: 3
kind: gateway
ref: incl
paths:
- { parentID: 1, childID: 2 }
case3:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "40" } ]
- stepID: 2
kind: expressions
arguments: [ { target: bar, type: Integer, expr: "50" } ]
- stepID: 3
kind: function
ref: logInfo
paths:
- { parentID: 1, childID: 2 }
case4:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [ { target: foo, type: Integer, expr: "40" } ]
- stepID: 2
kind: expressions
arguments: [ { target: bar, type: Integer, expr: "50" } ]
- stepID: 3
kind: iterator
paths:
- { parentID: 1, childID: 2 }

View File

@@ -0,0 +1,156 @@
workflows:
kv_expressions:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [
## Initialize empty kv
{ target: aux, type: KV, value: null },
## Initialize key and value(string) for set expression
{ target: testString, type: String, value: "testString" },
{ target: foo, type: String, value: "testing string" },
# Evaluate set for KV(1st argument) with string value(3rd argument);
# it will set string value type for given key to KV(out)
{ target: out, type: KV, expr: "set(aux, testString, foo)" },
{ target: out, type: KV, expr: "set(out, \"deleteMe\", \"foobar\")" },
# Evaluate omit for KV(1st argument) for key(Name);
# it will omit values with matching keys from KV(out)
{ target: out, type: KV, expr: "omit(out, \"deleteMe\")" },
]
- stepID: 2
kind: termination
paths:
- { parentID: 1, childID: 2 }
kvv_expressions:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [
## Initialize empty kvv
{ target: aux, type: KVV, expr: "{\"test\": [\"z\", \"y\", \"x\"], \"deleteMe\": [\"foo\", \"bar\"], }" },
## Initialize key and value(Array) for set expression
{ target: testString, type: String, value: "testString" },
{ target: testArray, type: Any, expr: "[\"foo\", \"bar\"]" },
# Evaluate set for KVV(1st argument) with []string value(3rd argument);
# it will set []string value for given key to KVV(out)
{ target: out, type: KVV, expr: "set(aux, testString, testArray)" },
# Evaluate omit for KVV(1st argument) for key(Name);
# it will omit values with matching keys from KVV(out)
{ target: out, type: KVV, expr: "omit(out, \"test\", \"deleteMe\")" },
]
- stepID: 2
kind: termination
paths:
- { parentID: 1, childID: 2 }
vars_expressions:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [
## Initialize empty vars
{ target: aux, type: Vars, value: null },
## Initialize key and value(string) for set expression
{ target: testString, type: String, value: "testString" },
{ target: foo, type: String, value: "testing string" },
# Evaluate set for Vars(1st argument) with string value(3rd argument);
# it will set string value type for given key to Vars(out)
{ target: out, type: Vars, expr: "set(aux, testString, foo)" },
## Initialize key and value(int) for set expression
{ target: testInt, type: String, value: "testInt" },
{ target: bar, type: Integer, expr: "40" },
# Evaluate set for Vars(1st argument) with int value(3rd argument);
# it will set int value type for given key to Vars(out)
{ target: out, type: Vars, expr: "set(out, testInt, bar)" },
## Initialize key and value(Vars) for set expression
{ target: testVar, type: String, value: "testVar" },
{ target: foobar, type: Vars, expr: "{\"testString\": \"testing string\", \"testFloat\": 50}" },
# Evaluate set for Vars(1st argument) with Vars value(3rd argument);
# it will set Vars value type for given key to Vars(out)
{ target: out, type: Vars, expr: "set(out, testVar, foobar)" },
## Evaluate set for constant: `{}`(1st argument) with string value(3rd argument);
# it will set string value type for given key to Vars(outConstStr)
{ target: outConstStr, type: Vars, expr: "set({}, \"testConstKey\", \"testConstValue\")" },
## Evaluate set for constant value(1st argument) with int value(3rd argument);
# it will set int value type for given key to Vars(outConstInt)
{ target: outConstInt, type: Vars, expr: "set({}, testInt, bar)" },
# Evaluate omit for Vars(1st argument) for keys;
# it will omit values matching keys from Vars(outConstInt)
{ target: outConstInt, type: Vars, expr: "omit(outConstInt, testInt)" },
]
- stepID: 2
kind: termination
paths:
- { parentID: 1, childID: 2 }
compose_record_values_expressions:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments: [
## Initialize rv(ComposeRecordValues) and key for set expression
{ target: rv, type: ComposeRecordValues, expr: "{}" },
{ target: testRv, type: String, value: "testRv" },
{ target: foo, type: String, value: "testing string" },
# Evaluate set for ComposeRecordValues(1st argument) with string value(3rd argument);
# it will set string value for given key(Name) to ComposeRecordValues(outRv)
{ target: out, type: ComposeRecordValues, expr: "set(rv, testRv, foo)" },
# Evaluate set for ComposeRecordValues(1st argument) with float value(3rd argument);
# it will set float value for given key(Name) to ComposeRecordValues(outRv)
{ target: out, type: ComposeRecordValues, expr: "set(out, \"testFloat\", 50)" },
{ target: out, type: ComposeRecordValues, expr: "set(out, \"removeMe\", \"I will be removed\")" },
# Evaluate omit for ComposeRecordValues(1st argument) for key(Name);
# it will omit values matching Name from ComposeRecordValues(outRv)
{ target: out, type: ComposeRecordValues, expr: "omit(out, \"testRv\", \"removeMe\")" },
]
- stepID: 2
kind: termination
paths:
- { parentID: 1, childID: 2 }

View File

@@ -0,0 +1,44 @@
workflows:
sub:
enabled: true
trace: true
steps:
- stepID: 1
kind: expressions
arguments:
- { target: breadcrumbs, expr: 'breadcrumbs + " + sub"' }
- stepID: 2
kind: termination
paths:
- { parentID: 1, childID: 2 }
main:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: expressions
arguments:
- { target: scope4sub, type: Vars }
- { target: scope4sub.breadcrumbs, value: 'main' }
- stepID: 2
kind: exec-workflow
arguments:
- { target: workflow, type: Handle, value: "sub" }
- { target: scope, type: Vars, source: scope4sub }
results:
- { target: out, source: breadcrumbs }
- stepID: 3
kind: termination
paths:
- { parentID: 1, childID: 2 }
- { parentID: 2, childID: 3 }

View File

@@ -0,0 +1,31 @@
workflows:
error_handler_results:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: error-handler
results:
- { target: e, type: Any, expr: "error" }
- { target: eM, type: String, expr: "errorMessage" }
- { target: esID, type: Integer, expr: "errorStepID" }
- stepID: 2
kind: error
arguments:
- { target: message, type: String, value: "TestingError" }
- stepID: 3
kind: function
ref: logInfo
arguments:
- { target: message, type: String, expr: "format(\"%s, %s, %d\", e, eM, esID)" }
paths:
- { parentID: 1, childID: 2 }
- { parentID: 1, childID: 3 }

View File

@@ -0,0 +1,221 @@
workflows:
# 1. iterator placed inside a parallel fork/join
iterator_in_fork:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: fork
# branch A: iterator; its exit path leads to the join
- stepID: 11
kind: iterator
ref: templatesEach
arguments:
- { target: incTotal, value: "false", type: Boolean }
results:
- { target: tpl, expr: template }
- stepID: 12
kind: continue
# branch B: plain step
- stepID: 13
kind: expressions
arguments: [ { target: b, type: String, value: "B" } ]
- stepID: 14
kind: gateway
ref: join
- stepID: 15
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 13 }
- { parentID: 11, childID: 12 }
- { parentID: 11, childID: 14 }
- { parentID: 13, childID: 14 }
- { parentID: 14, childID: 15 }
# 3a. variable created mid-branch in a non-first branch
join_new_var:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: gateway
ref: fork
# branch A -> paths[0]
- stepID: 11
kind: expressions
arguments: [ { target: a, type: String, value: "A" } ]
# branch B: sets foo mid-branch, then does something else
- stepID: 12
kind: expressions
arguments: [ { target: foo, type: String, value: "fromB" } ]
- stepID: 13
kind: expressions
arguments: [ { target: bLast, type: String, value: "last" } ]
- stepID: 14
kind: gateway
ref: join
- stepID: 15
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }
- { parentID: 12, childID: 13 }
- { parentID: 11, childID: 14 }
- { parentID: 13, childID: 14 }
- { parentID: 14, childID: 15 }
# 3b. variable that already existed before the fork, changed mid-branch
join_existing_var:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 9
steps:
- stepID: 9
kind: expressions
arguments: [ { target: foo, type: String, value: "base" } ]
- stepID: 10
kind: gateway
ref: fork
# branch A -> paths[0], never touches foo
- stepID: 11
kind: expressions
arguments: [ { target: a, type: String, value: "A" } ]
# branch B changes foo mid-branch
- stepID: 12
kind: expressions
arguments: [ { target: foo, type: String, value: "fromB" } ]
- stepID: 13
kind: expressions
arguments: [ { target: bLast, type: String, value: "last" } ]
- stepID: 14
kind: gateway
ref: join
- stepID: 15
kind: termination
paths:
- { parentID: 9, childID: 10 }
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }
- { parentID: 12, childID: 13 }
- { parentID: 11, childID: 14 }
- { parentID: 13, childID: 14 }
- { parentID: 14, childID: 15 }
# 2. error handler registered, then a normal step runs before the error
errhandler_after_step:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: error-handler
results:
- { target: eM, type: String, expr: errorMessage }
# normal continuation (out[0])
- stepID: 2
kind: expressions
arguments: [ { target: noise, type: String, value: "noise" } ]
- stepID: 3
kind: error
arguments: [ { target: message, type: String, value: "Boom" } ]
# error handler (out[1])
- stepID: 4
kind: expressions
arguments: [ { target: caught, type: String, expr: eM } ]
paths:
- { parentID: 1, childID: 2 }
- { parentID: 1, childID: 4 }
- { parentID: 2, childID: 3 }
# 3c. a nested parallel section must not claim variables it never changed
join_nested:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 9
steps:
- stepID: 9
kind: expressions
arguments: [ { target: foo, type: String, value: "base" } ]
- stepID: 10
kind: gateway
ref: fork
# branch A -> paths[0], changes foo mid-branch
- stepID: 11
kind: expressions
arguments: [ { target: foo, type: String, value: "fromA" } ]
- stepID: 12
kind: expressions
arguments: [ { target: aLast, type: String, value: "last" } ]
# branch B holds a parallel section of its own and never touches foo
- stepID: 13
kind: gateway
ref: fork
- stepID: 14
kind: expressions
arguments: [ { target: b1, type: String, value: "b1" } ]
- stepID: 15
kind: expressions
arguments: [ { target: b2, type: String, value: "b2" } ]
- stepID: 16
kind: gateway
ref: join
- stepID: 20
kind: gateway
ref: join
- stepID: 21
kind: termination
paths:
- { parentID: 9, childID: 10 }
- { parentID: 10, childID: 11 }
- { parentID: 11, childID: 12 }
- { parentID: 10, childID: 13 }
- { parentID: 13, childID: 14 }
- { parentID: 13, childID: 15 }
- { parentID: 14, childID: 16 }
- { parentID: 15, childID: 16 }
- { parentID: 12, childID: 20 }
- { parentID: 16, childID: 20 }
- { parentID: 20, childID: 21 }

View File

@@ -0,0 +1,59 @@
workflows:
logger:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: function
ref: actionlogRecord
arguments:
- { target: action, type: String, value: "action" }
- { target: resource, type: String, value: "resource" }
- { target: error, type: String, value: "error" }
- { target: severity, type: String, value: "severity" }
- { target: description, type: String, value: "description" }
- stepID: 11
kind: function
ref: actionlogRecord
arguments:
- { target: action, type: String, value: "action" }
- { target: resource, type: String, value: "resource" }
- { target: error, type: String, value: "error" }
- { target: severity, type: String, value: "severity" }
- { target: description, type: String, value: "description" }
- stepID: 12
kind: function
ref: actionlogRecord
arguments:
- { target: action, type: String, value: "action" }
- { target: resource, type: String, value: "find-me" }
- { target: error, type: String, value: "error" }
- { target: severity, type: String, value: "severity" }
- { target: description, type: String, value: "description" }
- stepID: 13
kind: function
ref: actionlogRecord
arguments:
- { target: action, type: String, value: "action" }
- { target: resource, type: String, value: "find-me" }
- { target: error, type: String, value: "error" }
- { target: severity, type: String, value: "severity" }
- { target: description, type: String, value: "description" }
- stepID: 20
kind: function
ref: actionlogSearch
arguments:
- { target: resource, type: String, value: "find-me" }
results:
- { target: actions, expr: "actions" }
paths:
- { parentID: 10, childID: 11 }
- { parentID: 11, childID: 12 }
- { parentID: 12, childID: 13 }
- { parentID: 13, childID: 20 }

View File

@@ -0,0 +1,9 @@
namespaces:
ns1:
name: Namespace#1
modules:
mod1:
name: Module#1
fields:
f1: { label: 'Field1', kind: 'File' }

View File

@@ -0,0 +1,59 @@
workflows:
attachments:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: expressions
arguments:
- { target: base64blackGif, value: "R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=" }
- stepID: 11
kind: function
ref: composeRecordsNew
arguments:
- { target: module, type: Handle, value: "mod1" }
- { target: namespace, type: Handle, value: "ns1" }
results:
- { target: attachable, expr: "record" }
# Store attachment from given string
- stepID: 20
kind: function
ref: attachmentCreate
arguments:
- { target: content, type: String, expr: "base64blackGif" }
- { target: name, type: String, value: "black-from-base64-string.gif" }
- { target: resource, type: ComposeRecord, expr: "attachable" }
- { target: fieldName, type: String, value: "f1" }
results:
- { target: storedAttBlackGif, expr: "attachment" }
# Load attachment
- stepID: 30
kind: function
ref: attachmentLookup
arguments:
- { target: attachment, type: ID, expr: "storedAttBlackGif.ID" }
results:
- { target: loadedAttBlackGif, expr: "attachment" }
# Open attachment
- stepID: 31
kind: function
ref: attachmentOpenOriginal
arguments:
- { target: attachment, type: "Attachment", expr: "storedAttBlackGif" }
results:
- { target: loadedContent, expr: "content" }
paths:
- { parentID: 10, childID: 11 }
- { parentID: 11, childID: 20 }
- { parentID: 20, childID: 30 }
- { parentID: 30, childID: 31 }

View File

@@ -0,0 +1,9 @@
namespaces:
ns1:
name: Namespace#1
modules:
mod1:
name: Module#1
fields:
f1: { label: 'Field1', kind: 'File' }

View File

@@ -0,0 +1,96 @@
workflows:
attachments:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 11
steps:
- stepID: 11
kind: function
ref: composeRecordsNew
arguments:
- { target: module, type: Handle, value: "mod1" }
- { target: namespace, type: Handle, value: "ns1" }
results:
- { target: attachableString, expr: "record" }
- stepID: 12
kind: function
ref: composeRecordsNew
arguments:
- { target: module, type: Handle, value: "mod1" }
- { target: namespace, type: Handle, value: "ns1" }
results:
- { target: attachableReader, expr: "record" }
- stepID: 13
kind: function
ref: composeRecordsNew
arguments:
- { target: module, type: Handle, value: "mod1" }
- { target: namespace, type: Handle, value: "ns1" }
results:
- { target: attachableReadSeeker, expr: "record" }
- stepID: 14
kind: function
ref: composeRecordsNew
arguments:
- { target: module, type: Handle, value: "mod1" }
- { target: namespace, type: Handle, value: "ns1" }
results:
- { target: attachableBytes, expr: "record" }
# Store attachment from given string
- stepID: 20
kind: function
ref: attachmentCreate
arguments:
- { target: content, type: String, expr: "sourceString" }
- { target: name, type: String, value: "att.txt" }
- { target: resource, type: ComposeRecord, expr: "attachableString" }
- { target: fieldName, type: String, value: "f1" }
results:
- { target: attachedString, expr: "attachment" }
- stepID: 21
kind: function
ref: attachmentCreate
arguments:
- { target: content, type: Reader, expr: "sourceReader" }
- { target: name, type: String, value: "att.txt" }
- { target: resource, type: ComposeRecord, expr: "attachableReader" }
- { target: fieldName, type: String, value: "f1" }
results:
- { target: attachedReader, expr: "attachment" }
- stepID: 22
kind: function
ref: attachmentCreate
arguments:
- { target: content, type: Reader, expr: "sourceReadSeeker" }
- { target: name, type: String, value: "att.txt" }
- { target: resource, type: ComposeRecord, expr: "attachableReadSeeker" }
- { target: fieldName, type: String, value: "f1" }
results:
- { target: attachedReadSeeker, expr: "attachment" }
- stepID: 23
kind: function
ref: attachmentCreate
arguments:
- { target: content, type: Bytes, expr: "sourceBytes" }
- { target: name, type: String, value: "att.txt" }
- { target: resource, type: ComposeRecord, expr: "attachableBytes" }
- { target: fieldName, type: String, value: "f1" }
results:
- { target: attachedBytes, expr: "attachment" }
paths:
- { parentID: 11, childID: 12 }
- { parentID: 12, childID: 13 }
- { parentID: 13, childID: 14 }
- { parentID: 14, childID: 20 }
- { parentID: 20, childID: 21 }
- { parentID: 21, childID: 22 }
- { parentID: 22, childID: 23 }

View File

@@ -0,0 +1,8 @@
users:
exec-allowed: exec-allowed@cortezaproject.org
exec-denied: exec-denied@cortezaproject.org
roles:
executors:
members:
- exec-allowed

View File

@@ -0,0 +1,16 @@
workflows:
wf:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: termination
paths: []
allow:
executors:
- execute

View File

@@ -0,0 +1,8 @@
users:
wf-runner: workflow-runner@cortezaproject.org
wf-invoker: workflow-invoker@cortezaproject.org
roles:
wf-invokers:
members:
- wf-invoker

View File

@@ -0,0 +1,33 @@
workflows:
invoker:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: termination
paths: []
allow:
wf-invokers:
- execute
runner:
enabled: true
trace: true
runAs: wf-runner
triggers:
- enabled: true
stepID: 1
steps:
- stepID: 1
kind: termination
paths: []
allow:
wf-invokers:
- execute

View File

@@ -0,0 +1,25 @@
namespaces:
ns1:
name: ns1 name
modules:
mod1:
name: mod1 name
fields:
f1:
label: f1 label
kind: String
required: false
records:
mod1:
- values:
f1: 1
- values:
f1: 2
- values:
f1: 3
- values:
f1: 4
- values:
f1: 5

View File

@@ -0,0 +1,30 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: composeRecordsEach
arguments:
- { "target": "module", "value": "mod1", "type": "Handle" }
- { "target": "namespace", "value": "ns1", "type": "Handle" }
- { "target": "limit", "value": "2", "type": "UnsignedInteger" }
results:
- { "target": "r", "expr": "record" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,27 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: remindersEach
arguments:
- { "target": "incTotal", "value": "true", "type": "Boolean" }
results:
- { "target": "r", "expr": "reminder" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
roles:
r1: r1 name
r2: r2 name
r3: r3 name
r4: r4 name
r5: r5 name

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: rolesEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
- { "target": "limit", "value": "2", "type": "UnsignedInteger" }
results:
- { "target": "r", "expr": "role" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: loopSequence
arguments:
- { target: "last", expr: "3", type: "Integer"}
- { target: "step", expr: "1", type: "Integer"}
results:
- { target: "i", expr: "counter" }
- { target: "first", expr: "isFirst" }
- { target: "last", expr: "isLast" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,30 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: loopSequence
arguments:
- { target: "first", expr: "2", type: "Integer"}
- { target: "last", expr: "5", type: "Integer"}
- { target: "step", expr: "2", type: "Integer"}
results:
- { target: "i", expr: "counter" }
- { target: "first", expr: "isFirst" }
- { target: "last", expr: "isLast" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,11 @@
templates:
t1:
type: text/html
t2:
type: text/html
t3:
type: text/html
t4:
type: text/html
t5:
type: text/html

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: templatesEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
- { "target": "limit", "value": "2", "type": "UnsignedInteger" }
results:
- { "target": "tpl", "expr": "template" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
users:
u1: u1@example.tld
u2: u2@example.tld
u3: u3@example.tld
u4: u4@example.tld
u5: u5@example.tld

View File

@@ -0,0 +1,26 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: usersEach
arguments:
- { "target": "pageCursor", "expr": "cursor", "type": "String" }
results:
- { "target": "u", "expr": "user" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
users:
u1: u1@example.tld
u2: u2@example.tld
u3: u3@example.tld
u4: u4@example.tld
u5: u5@example.tld

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: usersEach
arguments:
- { "target": "incTotal", "value": "false", "type": "Boolean" }
- { "target": "limit", "value": "2", "type": "UnsignedInteger" }
results:
- { "target": "u", "expr": "user" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1,6 @@
users:
u1: u1@example.tld
u2: u2@example.tld
u3: u3@example.tld
u4: u4@example.tld
u5: u5@example.tld

View File

@@ -0,0 +1,29 @@
workflows:
testing:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: iterator
ref: usersEach
arguments:
- { "target": "incTotal", "value": "true", "type": "Boolean" }
- { "target": "incPageNavigation", "value": "true", "type": "Boolean" }
results:
- { "target": "u", "expr": "user" }
- { "target": "i", "expr": "index" }
- { "target": "t", "expr": "total" }
- stepID: 11
kind: continue
- stepID: 12
kind: termination
paths:
- { parentID: 10, childID: 11 }
- { parentID: 10, childID: 12 }

View File

@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsImZvbyI6ImJhciIsInR5cCI6IkpXVCJ9.eyJleHAiOjcyODY1NDQwMCwiaWF0Ijo3Mjg2NTA4MDAsInNjb3BlIjpbXSwic3ViIjoiMTIzNDU2Nzg5MCJ9.Tk19aAqkcSuVd54OHSSX6VOjLk4MFhxoeufiEDGo8U7wtsW6EL3YGFCiWtcMpjrK03aNVUqQwue2BjB8ysqq3NsNvFVWiJFDUZR-4jaRHrz4FALZpb43do95YQFhJHliAnzmAEgbFQY704FTd9PYP9IGuw0EUwq_WOAtIiaKNHG20rPIRvltr_p1t54rDG0Xx_9iGCU-J-GJSWuYV7-XNHsdz0xJqxRAUeaH4Ly5BzjHBX8HSB0VezopZly2sJDlqfZCUBkL80eMvECJWc7g4znN9dPHKDcKclqvFI5sPSdQIQ7zZVeSbTizqXe-KXz9TykVTDOudnY4iRXzNerZ0_rzq7qT253qGoypkM0_N3oidFU0UkSnLgWIyeuw09bFraDyWuYEhYbsDif7qT8tP-w6YaKv0mFZ8BwRKl6yZafR8Ji7UNWhVQ3Qz8rJjAclX4elEFGq0deK7B2Kiwo6U33tNyx2Xi56QRMs6r26S9QoA3fNbA7C2HrFwy3coZxyJAKVCAHcfYOue-u1oersq0vAk_HGXytBrdiz6xL6wbRjNqfrT--I-uq2MfUEsZSh2Xy0SCEUt8IJeX6vt7nGeKqu6AUuKbCpA6CrXRI7K9jShuAsFeyTdKKjJsKCXwZRQp9ZyTmWYXcyXlDHf63I8JXNP2wzPM_3p0CCQ313S_Q

View File

@@ -0,0 +1,93 @@
workflows:
jwt_generate:
enabled: true
trace: true
triggers:
- enabled: true
stepID: 5
steps:
- stepID: 5
kind: function
ref: jwtGenerate
arguments:
- target: scope
type: String
- target: header
value: |-
{
"foo": "bar"
}
type: String
- target: payload
expr: |-
{
"sub": "1234567890",
"iat": int(strftime(date("1993-02-02T06:00:00-05:00"), "%L")),
"exp": int(strftime(modTime(date("1993-02-02T06:00:00-05:00"), "+1h"), "%L"))
}
type: Vars
- target: secret
value: |-
-----BEGIN PRIVATE KEY-----
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDSVsDogkXN3C+a
Ic+iiOQ6f00qj2DSm6AZGHfDMdFiZ7oZn8bV83uA9QcLjXoSVRyCijvyY5V+YSfM
GYXiHCiXwOt5riMKVv+Wx5Ov8IDetYqVL+NNmeslDKuuGwHpCvm10O6VVRgDMq6y
j+N+CSjBROnSjNtN9QdzD4rguB80SRDcwudTaaiw8T4yWaDONySDhTBG58DcIW/4
hhZl3C2sWlIgqSAjccfiHKopgrU2FPl3WCv44sEa1IzogerUFSdnxbepJpV3mQBa
3avuzxlIYVA+pIJMmnGmr7caiTN+dS8q8GBVYu69uppD7GtQPmU8AQ25PUtRH4KS
M0wv2ET473xUzzKBDaHV7RsmOd0S9lhLlKjpB3GhgbQhA3FRtBCwRTacXKIf9KxR
AF668TxpSynomXIAid9kXnuKXW0r2F+dmOWCUb8nFkSTXpJTKk+71IeoE1FsPkCQ
WCI+aUtnrZ+LZvfc6IE9GoLfYzjrt8kAedJAatXjCVBiHvIixIN90vSmPS0nC3Lg
3F8PrzgGk26hMynIKnILrMaR1e4wDf7xiOqrBXEklrNCWbTD9b0BjNhhvMtJp7+W
OyuN7FlORVy9axUMpFXSFfJaA9Vdr9eBRyI7HIZ1Q827rDHusG/XVNk7V0M4yNDa
I77aBn0Vyvqfn+NawmcDMIsBfbgx7QIDAQABAoICAHRBrQgWEPzyaYEYlQnx/atz
dzRB4TMm/zs/sdo6a8+nI05MaHsSw72IMOeqv8DoOATS4MVdU2Bx1KxToxNRmwId
iElN/WIWqdgt4SxKkwAFeV5yBIF8xGJK+Y0WslybS1+55lS1nrsNxU8+hm/AIj2I
mHBemEwjVYW8HneMbPraM67BL1iEOs/p1wW/UkkIY28qK3/VUlyZQqkre6+7Had4
mJIiyHeuyNrqGwcsjnog562WF1/N/QuWVXehbyjftFMADj447D4ZW//dK82nvAKs
fszQ4o/ygUSvNFY/ZS3NGU/zYltvfiNxwxgt0Tad9hhPQMWU4k8pSmMCZWbAc4Xe
REXzkNrYhx2wwR6sKKrH+xA8JGne0W4r0jETFCKU5YUWipItVaFICmkFGKDll5P0
MDF2rmltDpv1Sdy3/zAt8goFtSY9bON4UzTllU1Hv5QLJdUPj9+h0a+Fy+fIuV/g
9pcWeqsz3rzoNaiwH/rtk11zrOvSlWvH7F0XV41WJ/d4qHRt081YjjXeAUyYyDBF
gIhOpPYtOtchTSUV7yEiEet0/nREVIGhIFXbgb2fD1tqvjjHE24X/5BC1hYbZt4A
3ehgz9XWr37U92Pk9mr1W88KjI8M2vJRTOthDRkyYkvjJOHlAec7Bc2Obp85Q2YT
6inuQ3uolN3re90ymWvBAoIBAQD+flOOGFPot6CpPT6x0LCx1jIQQYB2n2S1qKAU
ijpQIX8wowv0qi3q3kcDy9Ibhaor9cpyQgG7En4hV4gn4zAbddcvg+AU8m/YlrWi
BOvajykvbkuGwfWMNIPTa59Gw846T64hx5K3pBzw+98FwTuQiwUtvY8BHIfsbR1g
y+QV6JhsucQ1fX/R+U7TAEF3/5Pg2KiIqHPCTRp6bsqrSKDfM5sS1XDwr74d5JBN
F+AGciqKzWiVo1dYCBCe4wjorHyxHdBKTb8jbBpM98pjDLjY3uLC4Hn9gsZ2M0Nh
oD8HsAd42ZH80Dkks7h8hHMEI6zDHHJFre45dtyJDLYd48G9AoIBAQDTlYNJjJC2
kNjf8XFM0I1fruXhvqP1O1X7tib20t330xszETr2diKp8+mUTg9CIzR/cDwnoGS4
9krp6PJmh8i/BldoJoQQIEt4O/tJWnox8XdTFWNhYSSagOejPcCCawsKkh7G4grk
XD2Bk0OTtF/6P9ji1Nt7MyioHsoczDH2gYbpaETLRBDkivXN+3vqgZD4G8rq/iIM
+492JRo8RzeNs30kMcF/8LPFGXmeI58AWmCoYAZhgnFJgdKOiOyyHHVdzLk4cD4k
f4cPQwX9QCOQzu7pff35m2VizNkdLBds6Bujpwejrq44BpjB4LaaL7710PK9bl2z
O3w3Szw2LXvxAoIBAQDb8dHEvMHIHut7WLMWeoY7LCOYaQPdgWRIm7O+DLjZCBok
rsVmbq3AjtpRLZYosxyfYY3VsbZNN25K4puJ3Y92LCINrqu7bsu7JIVVwWsVOSUf
GPOtQ3Qz+C72Sc0eG5vgSXz1NMZYcD2TCBt3nckc4wlWvr0Y+M+ARc1eGtjFFoCl
dudcU1pk3lKBiXcLfpcPfDAr62ogQwLfTWFbJynhvXgIju9NFJX6v8720euLpp+d
1mjM6p5SNqYmq5DHhks9x8Z8cTUAKC2S15TShew7gmX4hojn0F41SZiyhwvyWPAc
Qe0p0cuRLMIE23OL4EkvVyZrkiaRA2kWCSZcLrsBAoIBAAOUkx0qgMRmHRVlC4rG
OK420nMIe9PJhkH1KiGhHdp0uxAZKYtEIoAHvZsh2wY+fEPvzUTKZQnwOQJOS9PK
Vm5NGCuOA0wWj9BgC3eJTWoM8Pz57q2WLD1lEwZjJB/Q2eX65QRujMqiePP5Xvpf
4gPlErF78p7aFcUKiFcGaY4HURYgCpH5++MyKsiqicVFHgPkzIE/faoEk7/nDtOY
TOtb7zEumlyk4RXjwXgYmDc0UFBpF5KM14fr53k7/e1hp+bHcRbwZ0zMz6dFdhN8
A14O8mIHHMYdiBCs8LuapGbWYqlZSTrO2OnfyrP1LoHbbvrP51unQ3Sl/AsffcxY
5rECggEBAJmKbtMjOAIM4CpH7cOtID7pY0j1AujGesbUvqv2pQ+i/DTil0xVIBu7
wlXfx6QJLpeGCxz0nunJhvwaIveiDURxZBqm3oBniKIG/6qFM3WK41V3z8riV5Br
yuWP09xSaDc5SPWnHwmwLVjRQMGr7yWRjtxNx2CKqPG7SNb2LPrBOp+eDmAJUuQJ
lWmTHhmdsQRb/70O6WxGxPCLwvhi4FtT0nnL03qJkIZIBdEYgF4q9XFBybllu+Th
mY1n/s77ALXBJh1VcL1ayrMe2oQlpWwbJdpQsmRk+9kS+qeXmrE41JzzOAZV0tqc
C/p2c759krBsxv/zOxJJsWDEF1AolQI=
-----END PRIVATE KEY-----
type: String
results:
- target: token
expr: token

View File

@@ -0,0 +1,57 @@
workflows:
nested_iterators:
enabled: true
trace: true
triggers: [ { enabled: true, stepID: 10001 } ]
steps:
## LEVEL 1
- stepID: 10001
kind: iterator
ref: loopDo
arguments: [ { target: "while", type: "String", value: "L1 > 0" }]
- stepID: 10002
kind: expressions
arguments: [ { target: "L1", expr: "L1 - 1" } ]
## LEVEL 2
- stepID: 20001
kind: iterator
ref: loopDo
arguments: [ { target: "while", type: "String", value: "L2 > 0" }]
- stepID: 20002
kind: expressions
arguments: [ { target: "L2", expr: "L2 - 1" } ]
- stepID: 20003
kind: break
- stepID: 20009
kind: function
ref: logInfo
arguments: [{ target: "message", expr: '"loop level #2 break; L1:" + L1 + ", L2:" + L2', type: "String" }]
## /LEVEL 2
- stepID: 10009
kind: function
ref: logInfo
arguments: [{ target: "message", expr: '"L1:" + L1 + ", L2:" + L2', type: "String" }]
## /LEVEL 1
paths:
- { parentID: 10001, childID: 10002 }
- { parentID: 10001, childID: 10009 }
- { parentID: 10002, childID: 20001 }
- { parentID: 20001, childID: 20002 }
- { parentID: 20002, childID: 20003 }
- { parentID: 20001, childID: 20009 }

View File

@@ -0,0 +1,23 @@
workflows:
testing:
enabled: true
trace: false
triggers:
- enabled: true
stepID: 10
steps:
- stepID: 10
kind: function
ref: remindersSearch
arguments:
- { target: incTotal, type: Boolean, value: "true" }
results:
- { target: total, expr: total }
- { target: found, expr: "length(reminders)" }
- stepID: 11
kind: termination
paths:
- { parentID: 10, childID: 11 }