mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 19:07:30 +00:00
chore!: Introduce ZITADEL v3 (#9645)
This PR summarizes multiple changes specifically only available with ZITADEL v3: - feat: Web Keys management (https://github.com/zitadel/zitadel/pull/9526) - fix(cmd): ensure proper working of mirror (https://github.com/zitadel/zitadel/pull/9509) - feat(Authz): system user support for permission check v2 (https://github.com/zitadel/zitadel/pull/9640) - chore(license): change from Apache to AGPL (https://github.com/zitadel/zitadel/pull/9597) - feat(console): list v2 sessions (https://github.com/zitadel/zitadel/pull/9539) - fix(console): add loginV2 feature flag (https://github.com/zitadel/zitadel/pull/9682) - fix(feature flags): allow reading "own" flags (https://github.com/zitadel/zitadel/pull/9649) - feat(console): add Actions V2 UI (https://github.com/zitadel/zitadel/pull/9591) BREAKING CHANGE - feat(webkey): migrate to v2beta API (https://github.com/zitadel/zitadel/pull/9445) - chore!: remove CockroachDB Support (https://github.com/zitadel/zitadel/pull/9444) - feat(actions): migrate to v2beta API (https://github.com/zitadel/zitadel/pull/9489) --------- Co-authored-by: Livio Spring <livio.a@gmail.com> Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com> Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com> Co-authored-by: Ramon <mail@conblem.me> Co-authored-by: Elio Bischof <elio@zitadel.com> Co-authored-by: Kenta Yamaguchi <56732734+KEY60228@users.noreply.github.com> Co-authored-by: Harsha Reddy <harsha.reddy@klaviyo.com> Co-authored-by: Livio Spring <livio@zitadel.com> Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Iraq <66622793+kkrime@users.noreply.github.com> Co-authored-by: Florian Forster <florian@zitadel.com> Co-authored-by: Tim Möhlmann <tim+github@zitadel.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Max Peintner <peintnerm@gmail.com>
This commit is contained in:
288
internal/execution/worker_test.go
Normal file
288
internal/execution/worker_test.go
Normal file
@@ -0,0 +1,288 @@
|
||||
package execution
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/riverqueue/river"
|
||||
"github.com/riverqueue/river/rivertype"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/execution/mock"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/action"
|
||||
exec_repo "github.com/zitadel/zitadel/internal/repository/execution"
|
||||
"github.com/zitadel/zitadel/internal/repository/user"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
type fields struct {
|
||||
queries *mock.MockQueries
|
||||
queue *mock.MockQueue
|
||||
}
|
||||
type fieldsWorker struct {
|
||||
now nowFunc
|
||||
}
|
||||
type args struct {
|
||||
event eventstore.Event
|
||||
mapper func(event eventstore.Event) (eventstore.Event, error)
|
||||
}
|
||||
type argsWorker struct {
|
||||
job *river.Job[*exec_repo.Request]
|
||||
}
|
||||
type want struct {
|
||||
noOperation bool
|
||||
err assert.ErrorAssertionFunc
|
||||
stmtErr assert.ErrorAssertionFunc
|
||||
}
|
||||
type wantWorker struct {
|
||||
targets []*query.ExecutionTarget
|
||||
sendStatusCode int
|
||||
err assert.ErrorAssertionFunc
|
||||
}
|
||||
|
||||
func newExecutionWorker(f fieldsWorker) *Worker {
|
||||
return &Worker{
|
||||
config: WorkerConfig{
|
||||
Workers: 1,
|
||||
TransactionDuration: 5 * time.Second,
|
||||
MaxTtl: 5 * time.Minute,
|
||||
},
|
||||
now: f.now,
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
userID = "user1"
|
||||
orgID = "orgID"
|
||||
instanceID = "instanceID"
|
||||
eventID = "eventID"
|
||||
eventData = `{"name":"name","script":"name(){}","timeout":3000000000,"allowedToFail":true}`
|
||||
)
|
||||
|
||||
func Test_handleEventExecution(t *testing.T) {
|
||||
testNow := time.Now
|
||||
tests := []struct {
|
||||
name string
|
||||
test func() (fieldsWorker, argsWorker, wantWorker)
|
||||
}{
|
||||
{
|
||||
"max TTL",
|
||||
func() (fieldsWorker, argsWorker, wantWorker) {
|
||||
return fieldsWorker{
|
||||
now: testNow,
|
||||
},
|
||||
argsWorker{
|
||||
job: &river.Job[*exec_repo.Request]{
|
||||
JobRow: &rivertype.JobRow{
|
||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||
},
|
||||
Args: &exec_repo.Request{
|
||||
Aggregate: &eventstore.Aggregate{
|
||||
InstanceID: instanceID,
|
||||
ID: eventID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
Sequence: 1,
|
||||
CreatedAt: time.Now().Add(-1 * time.Hour),
|
||||
EventType: user.HumanInviteCodeAddedType,
|
||||
UserID: userID,
|
||||
EventData: []byte(eventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantWorker{
|
||||
targets: mockTargets(1),
|
||||
sendStatusCode: http.StatusOK,
|
||||
err: func(tt assert.TestingT, err error, i ...interface{}) bool {
|
||||
return errors.Is(err, new(river.JobCancelError))
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"none",
|
||||
func() (fieldsWorker, argsWorker, wantWorker) {
|
||||
return fieldsWorker{
|
||||
now: testNow,
|
||||
},
|
||||
argsWorker{
|
||||
job: &river.Job[*exec_repo.Request]{
|
||||
JobRow: &rivertype.JobRow{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
Args: &exec_repo.Request{
|
||||
Aggregate: &eventstore.Aggregate{
|
||||
InstanceID: instanceID,
|
||||
ID: eventID,
|
||||
ResourceOwner: instanceID,
|
||||
},
|
||||
Sequence: 1,
|
||||
CreatedAt: time.Now(),
|
||||
EventType: user.HumanInviteCodeAddedType,
|
||||
UserID: userID,
|
||||
EventData: []byte(eventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantWorker{
|
||||
targets: mockTargets(0),
|
||||
sendStatusCode: http.StatusOK,
|
||||
err: nil,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"single",
|
||||
func() (fieldsWorker, argsWorker, wantWorker) {
|
||||
return fieldsWorker{
|
||||
now: testNow,
|
||||
},
|
||||
argsWorker{
|
||||
job: &river.Job[*exec_repo.Request]{
|
||||
JobRow: &rivertype.JobRow{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
Args: &exec_repo.Request{
|
||||
Aggregate: &eventstore.Aggregate{
|
||||
InstanceID: instanceID,
|
||||
Type: action.AggregateType,
|
||||
Version: action.AggregateVersion,
|
||||
ID: eventID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
Sequence: 1,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
EventType: action.AddedEventType,
|
||||
UserID: userID,
|
||||
EventData: []byte(eventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantWorker{
|
||||
targets: mockTargets(1),
|
||||
sendStatusCode: http.StatusOK,
|
||||
err: nil,
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"single, failed 400",
|
||||
func() (fieldsWorker, argsWorker, wantWorker) {
|
||||
return fieldsWorker{
|
||||
now: testNow,
|
||||
},
|
||||
argsWorker{
|
||||
job: &river.Job[*exec_repo.Request]{
|
||||
JobRow: &rivertype.JobRow{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
Args: &exec_repo.Request{
|
||||
Aggregate: &eventstore.Aggregate{
|
||||
InstanceID: instanceID,
|
||||
Type: action.AggregateType,
|
||||
Version: action.AggregateVersion,
|
||||
ID: eventID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
Sequence: 1,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
EventType: action.AddedEventType,
|
||||
UserID: userID,
|
||||
EventData: []byte(eventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantWorker{
|
||||
targets: mockTargets(1),
|
||||
sendStatusCode: http.StatusBadRequest,
|
||||
err: func(tt assert.TestingT, err error, i ...interface{}) bool {
|
||||
return errors.Is(err, zerrors.ThrowPreconditionFailed(nil, "EXEC-dra6yamk98", "Errors.Execution.Failed"))
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
"multiple",
|
||||
func() (fieldsWorker, argsWorker, wantWorker) {
|
||||
return fieldsWorker{
|
||||
now: testNow,
|
||||
},
|
||||
argsWorker{
|
||||
job: &river.Job[*exec_repo.Request]{
|
||||
JobRow: &rivertype.JobRow{
|
||||
CreatedAt: time.Now(),
|
||||
},
|
||||
Args: &exec_repo.Request{
|
||||
Aggregate: &eventstore.Aggregate{
|
||||
InstanceID: instanceID,
|
||||
Type: action.AggregateType,
|
||||
Version: action.AggregateVersion,
|
||||
ID: eventID,
|
||||
ResourceOwner: orgID,
|
||||
},
|
||||
Sequence: 1,
|
||||
CreatedAt: time.Now().UTC(),
|
||||
EventType: action.AddedEventType,
|
||||
UserID: userID,
|
||||
EventData: []byte(eventData),
|
||||
},
|
||||
},
|
||||
},
|
||||
wantWorker{
|
||||
targets: mockTargets(3),
|
||||
sendStatusCode: http.StatusOK,
|
||||
err: nil,
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
f, a, w := tt.test()
|
||||
|
||||
closeFuncs := make([]func(), len(w.targets))
|
||||
calledFuncs := make([]func() bool, len(w.targets))
|
||||
for i := range w.targets {
|
||||
url, closeF, calledF := testServerCall(
|
||||
exec_repo.ContextInfoFromRequest(a.job.Args),
|
||||
time.Second,
|
||||
w.sendStatusCode,
|
||||
nil,
|
||||
)
|
||||
w.targets[i].Endpoint = url
|
||||
closeFuncs[i] = closeF
|
||||
calledFuncs[i] = calledF
|
||||
}
|
||||
|
||||
data, err := json.Marshal(w.targets)
|
||||
require.NoError(t, err)
|
||||
a.job.Args.TargetsData = data
|
||||
|
||||
err = newExecutionWorker(f).Work(
|
||||
authz.WithInstanceID(context.Background(), instanceID),
|
||||
a.job,
|
||||
)
|
||||
|
||||
if w.err != nil {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
for _, closeF := range closeFuncs {
|
||||
closeF()
|
||||
}
|
||||
for _, calledF := range calledFuncs {
|
||||
assert.True(t, calledF())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user