zitadel/internal/command/action_v2_execution_test.go
Stefan Benz f37113194d
fix: actions v2 circular check for includes (#7563)
Add a check for circular includes in action v2 executions, so that no
self-includes or infinite loops can happen.

Closes #7445 

### Definition of Ready

- [x] I am happy with the code
- [x] Short description of the feature/issue is added in the pr
description
- [x] PR is linked to the corresponding user story
- [x] Acceptance criteria are met
- [x] All open todos and follow ups are defined in a new ticket and
justified
- [x] Deviations from the acceptance criteria and design are agreed with
the PO and documented.
- [x] No debug or dead code
- [x] My code has no repetitions
- [x] Critical parts are tested automatically
- [x] Where possible E2E tests are implemented
- [x] Documentation/examples are up-to-date
- [x] All non-functional requirements are met
- [x] Functionality of the acceptance criteria is checked manually on
the dev system.

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
2024-05-22 16:05:06 +00:00

2873 lines
61 KiB
Go

package command
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/execution"
"github.com/zitadel/zitadel/internal/repository/target"
"github.com/zitadel/zitadel/internal/zerrors"
)
func existsMock(exists bool) func(method string) bool {
return func(method string) bool {
return exists
}
}
func TestCommands_SetExecutionRequest(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
grpcMethodExists func(method string) bool
grpcServiceExists func(method string) bool
}
type args struct {
ctx context.Context
cond *ExecutionAPICondition
set *SetExecution
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
set: &SetExecution{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no valid cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"notvalid",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty executionType, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty target, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"method not found, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"service not found, error",
fields{
eventstore: expectEventstore(),
grpcServiceExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, method target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
target.NewAddedEvent(context.Background(),
target.NewAggregate("target", "instance"),
"name",
domain.TargetTypeWebhook,
"https://example.com",
time.Second,
true,
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/method", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, service target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
target.NewAddedEvent(context.Background(),
target.NewAggregate("target", "instance"),
"name",
domain.TargetTypeWebhook,
"https://example.com",
time.Second,
true,
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/service", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
grpcServiceExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, all target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
target.NewAddedEvent(context.Background(),
target.NewAggregate("target", "instance"),
"name",
domain.TargetTypeWebhook,
"https://example.com",
time.Second,
true,
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push not found, method include",
fields{
eventstore: expectEventstore(
expectFilter(),
),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, method include",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/method", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
),
),
),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push not found, service include",
fields{
eventstore: expectEventstore(
expectFilter(),
),
grpcServiceExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, service include",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/service", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
),
),
),
grpcServiceExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push not found, all include",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, all include",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "request/include"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
GrpcMethodExisting: tt.fields.grpcMethodExists,
GrpcServiceExisting: tt.fields.grpcServiceExists,
}
details, err := c.SetExecutionRequest(tt.args.ctx, tt.args.cond, tt.args.set, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_SetExecutionResponse(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
grpcMethodExists func(method string) bool
grpcServiceExists func(method string) bool
}
type args struct {
ctx context.Context
cond *ExecutionAPICondition
set *SetExecution
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
set: &SetExecution{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no valid cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"notvalid",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty executionType, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty target, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
target.NewAddedEvent(context.Background(),
target.NewAggregate("target", "instance"),
"name",
domain.TargetTypeWebhook,
"https://example.com",
time.Second,
true,
),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"valid",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"method not found, error",
fields{
eventstore: expectEventstore(),
grpcMethodExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"service not found, error",
fields{
eventstore: expectEventstore(),
grpcServiceExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, method target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
target.NewAddedEvent(context.Background(),
target.NewAggregate("target", "instance"),
"name",
domain.TargetTypeWebhook,
"https://example.com",
time.Second,
true,
),
),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/method", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
grpcMethodExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, service target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/service", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
grpcServiceExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, all target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
GrpcMethodExisting: tt.fields.grpcMethodExists,
GrpcServiceExisting: tt.fields.grpcServiceExists,
}
details, err := c.SetExecutionResponse(tt.args.ctx, tt.args.cond, tt.args.set, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_SetExecutionEvent(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
eventExists func(string) bool
eventGroupExists func(string) bool
}
type args struct {
ctx context.Context
cond *ExecutionEventCondition
set *SetExecution
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{},
set: &SetExecution{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no valid cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"notvalid",
"notvalid",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty executionType, error",
fields{
eventstore: expectEventstore(),
eventExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty target, error",
fields{
eventstore: expectEventstore(),
eventExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"notvalid",
"",
false,
},
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
eventExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"valid",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"event not found, error",
fields{
eventstore: expectEventstore(),
eventExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"event",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"group not found, error",
fields{
eventstore: expectEventstore(),
eventGroupExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"group",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, event target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/event", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
eventExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"event",
"",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, group target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/group.*", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
eventGroupExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"group",
false,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, all target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"",
true,
},
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
EventExisting: tt.fields.eventExists,
EventGroupExisting: tt.fields.eventGroupExists,
}
details, err := c.SetExecutionEvent(tt.args.ctx, tt.args.cond, tt.args.set, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_SetExecutionFunction(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
actionFunctionExists func(string) bool
}
type args struct {
ctx context.Context
cond ExecutionFunctionCondition
set *SetExecution
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "",
set: &SetExecution{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: "",
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty executionType, error",
fields{
eventstore: expectEventstore(),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"empty target, error",
fields{
eventstore: expectEventstore(),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("function/function", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
}, {
"push error, function target",
fields{
eventstore: expectEventstore(
expectFilter(),
),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push error, function not existing",
fields{
eventstore: expectEventstore(),
actionFunctionExists: existsMock(false),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, function target",
fields{
eventstore: expectEventstore(
expectFilter(
targetAddEvent("target", "instance"),
),
expectPush(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("function/function", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
actionFunctionExists: existsMock(true),
},
args{
ctx: context.Background(),
cond: "function",
set: &SetExecution{
Targets: []*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
ActionFunctionExisting: tt.fields.actionFunctionExists,
}
details, err := c.SetExecutionFunction(tt.args.ctx, tt.args.cond, tt.args.set, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_DeleteExecutionRequest(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
cond *ExecutionAPICondition
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no valid cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"notvalid",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("request/valid", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"not found, error",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, method target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/method", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("request/method", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, service target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/service", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("request/service", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, all target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("request", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
details, err := c.DeleteExecutionRequest(tt.args.ctx, tt.args.cond, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_DeleteExecutionResponse(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
cond *ExecutionAPICondition
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no valid cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"notvalid",
"notvalid",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("response/valid", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"not found, error",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, method target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/method", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("response/method", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"method",
"",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, service target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response/service", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("response/service", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"service",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push ok, all target",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("response", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("response", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionAPICondition{
"",
"",
true,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
details, err := c.DeleteExecutionResponse(tt.args.ctx, tt.args.cond, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_DeleteExecutionEvent(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
cond *ExecutionEventCondition
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{},
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{},
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("event/valid", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"push error, not existing",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push error, event",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, event",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/valid", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("event/valid", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"valid",
"",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push error, group",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"valid",
false,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, group",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event/group", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("event/group.*", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"group",
false,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
{
"push error, all",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"",
true,
},
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, all",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("event", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("event", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: &ExecutionEventCondition{
"",
"",
true,
},
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
details, err := c.DeleteExecutionEvent(tt.args.ctx, tt.args.cond, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func TestCommands_DeleteExecutionFunction(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
cond ExecutionFunctionCondition
resourceOwner string
}
type res struct {
details *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"no resourceowner, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: "",
resourceOwner: "",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"no cond, error",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cond: "",
resourceOwner: "instance",
},
res{
err: zerrors.IsErrorInvalidArgument,
},
},
{
"push failed, error",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("function/function", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPushFailed(
zerrors.ThrowPreconditionFailed(nil, "id", "name already exists"),
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("function/function", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: "function",
resourceOwner: "instance",
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"push error, not existing",
fields{
eventstore: expectEventstore(
expectFilter(),
),
},
args{
ctx: context.Background(),
cond: "function",
resourceOwner: "instance",
},
res{
err: zerrors.IsNotFound,
},
},
{
"push ok, function",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("function/function", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
expectPush(
execution.NewRemovedEvent(context.Background(),
execution.NewAggregate("function/function", "instance"),
),
),
),
},
args{
ctx: context.Background(),
cond: "function",
resourceOwner: "instance",
},
res{
details: &domain.ObjectDetails{
ResourceOwner: "instance",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
details, err := c.DeleteExecutionFunction(tt.args.ctx, tt.args.cond, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.details, details)
}
})
}
}
func mockExecutionIncludesCache(cache map[string][]string) includeCacheFunc {
return func(ctx context.Context, id string, resourceOwner string) ([]string, error) {
included, ok := cache[id]
if !ok {
return nil, zerrors.ThrowPreconditionFailed(nil, "", "cache failed")
}
return included, nil
}
}
func TestCommands_checkForIncludeCircular(t *testing.T) {
type args struct {
ctx context.Context
id string
resourceOwner string
includes []string
cache map[string][]string
}
type res struct {
err func(error) bool
}
tests := []struct {
name string
args args
res res
}{
{
"not found, error",
args{
ctx: context.Background(),
id: "id",
resourceOwner: "",
includes: []string{"notexistent"},
cache: map[string][]string{},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"single, ok",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id2"},
cache: map[string][]string{
"id2": {},
},
},
res{},
},
{
"single, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id1"},
cache: map[string][]string{},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 3, ok",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id2"},
cache: map[string][]string{
"id2": {"id3"},
"id3": {},
},
},
res{},
},
{
"multi 3, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id2"},
cache: map[string][]string{
"id2": {"id3"},
"id3": {"id1"},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 5, ok",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id11", "id12"},
cache: map[string][]string{
"id11": {"id21", "id23"},
"id12": {"id22"},
"id21": {},
"id22": {},
"id23": {},
},
},
res{},
},
{
"multi 5, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id11", "id12"},
cache: map[string][]string{
"id11": {"id21", "id23"},
"id12": {"id22"},
"id21": {},
"id22": {},
"id23": {"id1"},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 5, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id11", "id12"},
cache: map[string][]string{
"id11": {"id21", "id23"},
"id12": {"id22"},
"id21": {},
"id22": {},
"id23": {"id11"},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 5, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id11", "id12"},
cache: map[string][]string{
"id11": {"id21", "id23"},
"id12": {"id22"},
"id21": {"id11"},
"id22": {},
"id23": {},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 5, circular",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id11", "id12"},
cache: map[string][]string{
"id11": {"id21", "id23"},
"id12": {"id22"},
"id21": {},
"id22": {"id12"},
"id23": {},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
{
"multi 3, maxlevel",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id2"},
cache: map[string][]string{
"id2": {"id3"},
"id3": {},
},
},
res{},
},
{
"multi 4, over maxlevel",
args{
ctx: context.Background(),
id: "id1",
resourceOwner: "",
includes: []string{"id2"},
cache: map[string][]string{
"id2": {"id3"},
"id3": {"id4"},
"id4": {},
},
},
res{
err: zerrors.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := mockExecutionIncludesCache(tt.args.cache)
err := checkForIncludeCircular(tt.args.ctx, tt.args.id, tt.args.resourceOwner, tt.args.includes, f, 3)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func mockExecutionIncludesCacheFuncs(cache map[string][]string) (func(string) ([]string, bool), func(string, []string)) {
return func(s string) ([]string, bool) {
includes, ok := cache[s]
return includes, ok
}, func(s string, strings []string) {
cache[s] = strings
}
}
func TestCommands_getExecutionIncludes(t *testing.T) {
type fields struct {
eventstore func(t *testing.T) *eventstore.Eventstore
}
type args struct {
ctx context.Context
cache map[string][]string
id string
resourceOwner string
}
type res struct {
includes []string
cache map[string][]string
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
"new empty, ok",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
),
},
args{
ctx: context.Background(),
cache: map[string][]string{},
id: "id",
resourceOwner: "instance",
},
res{
includes: []string{},
cache: map[string][]string{"id": {}},
},
},
{
"new includes, ok",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "include"},
},
),
),
),
),
},
args{
ctx: context.Background(),
cache: map[string][]string{},
id: "id",
resourceOwner: "instance",
},
res{
includes: []string{"include"},
cache: map[string][]string{"id": {"include"}},
},
},
{
"found, ok",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cache: map[string][]string{"id": nil},
id: "id",
resourceOwner: "instance",
},
res{
includes: nil,
cache: map[string][]string{"id": nil},
},
},
{
"found includes, ok",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cache: map[string][]string{"id": {"include1", "include2", "include3"}},
id: "id",
resourceOwner: "instance",
},
res{
includes: []string{"include1", "include2", "include3"},
cache: map[string][]string{"id": {"include1", "include2", "include3"}},
},
},
{
"found multiple, ok",
fields{
eventstore: expectEventstore(),
},
args{
ctx: context.Background(),
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
},
id: "id2",
resourceOwner: "instance",
},
res{
includes: []string{"include1", "include2", "include3"},
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
},
},
},
{
"new multiple, ok",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeTarget, Target: "target"},
},
),
),
),
),
},
args{
ctx: context.Background(),
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
},
id: "id",
resourceOwner: "instance",
},
res{
includes: []string{},
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
"id": {},
},
},
},
{
"new multiple includes, ok",
fields{
eventstore: expectEventstore(
expectFilter(
eventFromEventPusher(
execution.NewSetEventV2(context.Background(),
execution.NewAggregate("request/include", "instance"),
[]*execution.Target{
{Type: domain.ExecutionTargetTypeInclude, Target: "include"},
},
),
),
),
),
},
args{
ctx: context.Background(),
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
},
id: "id",
resourceOwner: "instance",
},
res{
includes: []string{"include"},
cache: map[string][]string{
"id1": {"include1", "include2", "include3"},
"id2": {"include1", "include2", "include3"},
"id3": {"include1", "include2", "include3"},
"id": {"include"},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
c := &Commands{
eventstore: tt.fields.eventstore(t),
}
includes, err := c.getExecutionIncludes(mockExecutionIncludesCacheFuncs(tt.args.cache))(tt.args.ctx, tt.args.id, tt.args.resourceOwner)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.cache, tt.args.cache)
assert.Equal(t, tt.res.includes, includes)
}
})
}
}