mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-15 01:57:41 +00:00
feat: user commands (#75)
* feat: eventstore repository * fix: remove gorm * version * feat: pkg * feat: add some files for project * feat: eventstore without eventstore-lib * rename files * gnueg * fix: key json * fix: add object * fix: change imports * fix: internal models * fix: some imports * fix: global model * feat: add global view functions * fix: add some functions on repo * feat(eventstore): sdk * fix(eventstore): search query * fix(eventstore): rename app to eventstore * delete empty test * remove unused func * merge master * fix(eventstore): tests * fix(models): delete unused struct * fix: some funcitons * feat(eventstore): implemented push events * fix: move project eventstore to project package * fix: change project eventstore funcs * feat(eventstore): overwrite context data * fix: change project eventstore * fix: add project repo to mgmt server * feat(types): SQL-config * fix: commented code * feat(eventstore): options to overwrite editor * feat: auth interceptor and cockroach migrations * fix: migrations * fix: fix filter * fix: not found on getbyid * fix: use global sql config * fix: add sequence * fix: add some tests * fix(eventstore): nullable sequence * fix: add some tests * merge * fix: add some tests * fix(migrations): correct statements for sequence * fix: add some tests * fix: add some tests * fix: changes from mr * fix: changes from mr * fix: add some tests * Update internal/eventstore/models/field.go Co-Authored-By: livio-a <livio.a@gmail.com> * fix(eventstore): code quality * fix: add types to aggregate/Event-types * fix: try tests * fix(eventstore): rename modifier* to editor* * fix(eventstore): delete editor_org * fix(migrations): remove editor_org field, rename modifier_* to editor_* * fix: query tests * fix: use prepare funcs * fix: go mod * fix: generate files * fix(eventstore): tests * fix(eventstore): rename modifier to editor * fix(migrations): add cluster migration, fix(migrations): fix typo of host in clean clsuter * fix(eventstore): move health * fix(eventstore): AggregateTypeFilter aggregateType as param * code quality * fix: go tests * feat: add member funcs * feat: add member model * feat: add member events * feat: add member repo model * fix: better error func testing * fix: project member funcs * fix: add tests * fix: add tests * feat: implement member requests * fix: merge master * fix: merge master * fix: read existing in project repo * fix: fix tests * feat: add internal cache * feat: add cache mock * fix: return values of cache mock * feat: add project role * fix: add cache config * fix: add role to eventstore * fix: use eventstore sdk * fix: use eventstore sdk * fix: add project role grpc requests * fix: fix getby id * fix: changes for mr * fix: change value to interface * feat: add app event creations * fix: searchmethods * Update internal/project/model/project_member.go Co-Authored-By: Silvan <silvan.reusser@gmail.com> * fix: use get project func * fix: append events * fix: check if value is string on equal ignore case * fix: add changes test * fix: add go mod * fix: add some tests * fix: return err not nil * fix: return err not nil * fix: add aggregate funcs and tests * fix: add oidc aggregate funcs and tests * fix: add oidc * fix: add some tests * fix: tests * fix: oidc validation * fix: generate client secret * fix: generate client id * fix: test change app * fix: deactivate/reactivate application * fix: change oidc config * fix: change oidc config secret * fix: implement grpc app funcs * fix: add application requests * fix: converter * fix: converter * fix: converter and generate clientid * fix: tests * feat: project grant aggregate * feat: project grant * fix: project grant check if role existing * fix: project grant requests * fix: project grant fixes * fix: project grant member model * fix: project grant member aggregate * fix: project grant member eventstore * fix: project grant member requests * feat: user model * feat: user command side * user command side * profile requests * local config with gopass and more * Update internal/user/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/address.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/email.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/mfa.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/password.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/phone.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/model/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/usergrant/repository/eventsourcing/user_grant.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/user_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * Update internal/user/repository/eventsourcing/eventstore_mock_test.go Co-Authored-By: Livio Amstutz <livio.a@gmail.com> * changes from mr review * save files into basedir * changes from mr review * changes from mr review * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/usergrant/repository/eventsourcing/cache.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * changes requested on mr * fix generate codes * fix return if no events * password code * Update internal/user/repository/eventsourcing/model/password.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * Update internal/user/repository/eventsourcing/model/user.go Co-authored-by: Silvan <silvan.reusser@gmail.com> * requests of mr * check email Co-authored-by: adlerhurst <silvan.reusser@gmail.com> Co-authored-by: livio-a <livio.a@gmail.com>
This commit is contained in:
32
internal/usergrant/model/user_grant.go
Normal file
32
internal/usergrant/model/user_grant.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package model
|
||||
|
||||
import es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
type UserGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
State UserGrantState
|
||||
UserID string
|
||||
ProjectID string
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
type UserGrantState int32
|
||||
|
||||
const (
|
||||
USERGRANTSTATE_ACTIVE UserGrantState = iota
|
||||
USERGRANTSTATE_INACTIVE
|
||||
USERGRANTSTATE_REMOVED
|
||||
)
|
||||
|
||||
func (u *UserGrant) IsValid() bool {
|
||||
return u.ProjectID != "" && u.UserID != ""
|
||||
}
|
||||
|
||||
func (u *UserGrant) IsActive() bool {
|
||||
return u.State == USERGRANTSTATE_ACTIVE
|
||||
}
|
||||
|
||||
func (u *UserGrant) IsInactive() bool {
|
||||
return u.State == USERGRANTSTATE_INACTIVE
|
||||
}
|
34
internal/usergrant/repository/eventsourcing/cache.go
Normal file
34
internal/usergrant/repository/eventsourcing/cache.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/cache"
|
||||
"github.com/caos/zitadel/internal/cache/config"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
type UserGrantCache struct {
|
||||
userGrantCache cache.Cache
|
||||
}
|
||||
|
||||
func StartCache(conf *config.CacheConfig) (*UserGrantCache, error) {
|
||||
userGrantCache, err := conf.Config.NewCache()
|
||||
logging.Log("EVENT-vDneN").OnError(err).Panic("unable to create user cache")
|
||||
|
||||
return &UserGrantCache{userGrantCache: userGrantCache}, nil
|
||||
}
|
||||
|
||||
func (c *UserGrantCache) getUserGrant(ID string) *model.UserGrant {
|
||||
user := &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: ID}}
|
||||
err := c.userGrantCache.Get(ID, user)
|
||||
logging.Log("EVENT-4eTZh").OnError(err).Debug("error in getting cache")
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
func (c *UserGrantCache) cacheUserGrant(grant *model.UserGrant) {
|
||||
err := c.userGrantCache.Set(grant.AggregateID, grant)
|
||||
|
||||
logging.Log("EVENT-ThnBb").OnError(err).Debug("error in setting project cache")
|
||||
}
|
159
internal/usergrant/repository/eventsourcing/eventstore.go
Normal file
159
internal/usergrant/repository/eventsourcing/eventstore.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/cache/config"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_int "github.com/caos/zitadel/internal/eventstore"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
"github.com/sony/sonyflake"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type UserGrantEventStore struct {
|
||||
es_int.Eventstore
|
||||
userGrantCache *UserGrantCache
|
||||
idGenerator *sonyflake.Sonyflake
|
||||
}
|
||||
|
||||
type UserGrantConfig struct {
|
||||
es_int.Eventstore
|
||||
Cache *config.CacheConfig
|
||||
}
|
||||
|
||||
func StartUserGrant(conf UserGrantConfig) (*UserGrantEventStore, error) {
|
||||
userGrantCache, err := StartCache(conf.Cache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
idGenerator := sonyflake.NewSonyflake(sonyflake.Settings{})
|
||||
return &UserGrantEventStore{
|
||||
Eventstore: conf.Eventstore,
|
||||
userGrantCache: userGrantCache,
|
||||
idGenerator: idGenerator,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) UserGrantByID(ctx context.Context, id string) (*grant_model.UserGrant, error) {
|
||||
grant := es.userGrantCache.getUserGrant(id)
|
||||
|
||||
query, err := UserGrantByIDQuery(grant.AggregateID, grant.Sequence)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = es_sdk.Filter(ctx, es.FilterEvents, grant.AppendEvents, query)
|
||||
if err != nil && caos_errs.IsNotFound(err) && grant.Sequence == 0 {
|
||||
return nil, err
|
||||
}
|
||||
es.userGrantCache.cacheUserGrant(grant)
|
||||
if grant.State == int32(grant_model.USERGRANTSTATE_REMOVED) {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "EVENT-2ks8d", "UserGrant not found")
|
||||
}
|
||||
return model.UserGrantToModel(grant), nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) AddUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
|
||||
if grant == nil || !grant.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdiw3", "User grant invalid")
|
||||
}
|
||||
//TODO: Check Uniqueness
|
||||
id, err := es.idGenerator.NextID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
grant.AggregateID = strconv.FormatUint(id, 10)
|
||||
|
||||
repoGrant := model.UserGrantFromModel(grant)
|
||||
|
||||
addAggregate := UserGrantAddedAggregate(es.Eventstore.AggregateCreator(), repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoGrant.AppendEvents, addAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return model.UserGrantToModel(repoGrant), nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) ChangeUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
|
||||
if grant == nil {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo0s9", "invalid grant")
|
||||
}
|
||||
existing, err := es.UserGrantByID(ctx, grant.AggregateID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repoExisting := model.UserGrantFromModel(existing)
|
||||
repoGrant := model.UserGrantFromModel(grant)
|
||||
|
||||
projectAggregate := UserGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.userGrantCache.cacheUserGrant(repoExisting)
|
||||
return model.UserGrantToModel(repoExisting), nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) RemoveUserGrant(ctx context.Context, grantID string) error {
|
||||
existing, err := es.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
repoExisting := model.UserGrantFromModel(existing)
|
||||
repoGrant := &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: grantID}}
|
||||
projectAggregate := UserGrantRemovedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
es.userGrantCache.cacheUserGrant(repoExisting)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) DeactivateUserGrant(ctx context.Context, grantID string) (*grant_model.UserGrant, error) {
|
||||
if grantID == "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-8si34", "grantID missing")
|
||||
}
|
||||
existing, err := es.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !existing.IsActive() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo9sw", "deactivate only possible for active grant")
|
||||
}
|
||||
repoExisting := model.UserGrantFromModel(existing)
|
||||
repoGrant := &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: grantID}}
|
||||
|
||||
projectAggregate := UserGrantDeactivatedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.userGrantCache.cacheUserGrant(repoGrant)
|
||||
return model.UserGrantToModel(repoExisting), nil
|
||||
}
|
||||
|
||||
func (es *UserGrantEventStore) ReactivateUserGrant(ctx context.Context, grantID string) (*grant_model.UserGrant, error) {
|
||||
if grantID == "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sksiw", "grantID missing")
|
||||
}
|
||||
existing, err := es.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !existing.IsInactive() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo9sw", "reactivate only possible for inactive grant")
|
||||
}
|
||||
repoExisting := model.UserGrantFromModel(existing)
|
||||
repoGrant := &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: grantID}}
|
||||
|
||||
projectAggregate := UserGrantReactivatedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
|
||||
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
es.userGrantCache.cacheUserGrant(repoExisting)
|
||||
return model.UserGrantToModel(repoExisting), nil
|
||||
}
|
@@ -0,0 +1,112 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
mock_cache "github.com/caos/zitadel/internal/cache/mock"
|
||||
"github.com/caos/zitadel/internal/eventstore/mock"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/sony/sonyflake"
|
||||
)
|
||||
|
||||
func GetMockedEventstore(ctrl *gomock.Controller, mockEs *mock.MockEventstore) *UserGrantEventStore {
|
||||
return &UserGrantEventStore{
|
||||
Eventstore: mockEs,
|
||||
userGrantCache: GetMockCache(ctrl),
|
||||
idGenerator: GetSonyFlacke(),
|
||||
}
|
||||
}
|
||||
|
||||
func GetMockCache(ctrl *gomock.Controller) *UserGrantCache {
|
||||
mockCache := mock_cache.NewMockCache(ctrl)
|
||||
mockCache.EXPECT().Get(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockCache.EXPECT().Set(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
return &UserGrantCache{userGrantCache: mockCache}
|
||||
}
|
||||
|
||||
func GetSonyFlacke() *sonyflake.Sonyflake {
|
||||
return sonyflake.NewSonyflake(sonyflake.Settings{})
|
||||
}
|
||||
|
||||
func GetMockUserGrantByIDOK(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
user := model.UserGrant{
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
||||
|
||||
func GetMockUserGrantByIDRemoved(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
user := model.UserGrant{
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantRemoved},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
||||
|
||||
func GetMockUserGrantByIDNoEvents(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
events := []*es_models.Event{}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
||||
|
||||
func GetMockManipulateUserGrant(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
user := model.UserGrant{
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantAdded, Data: data},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
||||
|
||||
func GetMockManipulateUserGrantInactive(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
user := model.UserGrant{
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"},
|
||||
}
|
||||
data, _ := json.Marshal(user)
|
||||
events := []*es_models.Event{
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantAdded, Data: data},
|
||||
&es_models.Event{AggregateID: "AggregateID", Sequence: 1, Type: model.UserGrantDeactivated},
|
||||
}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
||||
|
||||
func GetMockManipulateUserGrantNoEvents(ctrl *gomock.Controller) *UserGrantEventStore {
|
||||
events := []*es_models.Event{}
|
||||
mockEs := mock.NewMockEventstore(ctrl)
|
||||
mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil)
|
||||
mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST"))
|
||||
mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil)
|
||||
return GetMockedEventstore(ctrl, mockEs)
|
||||
}
|
439
internal/usergrant/repository/eventsourcing/eventstore_test.go
Normal file
439
internal/usergrant/repository/eventsourcing/eventstore_test.go
Normal file
@@ -0,0 +1,439 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/model"
|
||||
"github.com/golang/mock/gomock"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUserByID(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
grant *model.UserGrant
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "user from events, ok",
|
||||
args: args{
|
||||
es: GetMockUserGrantByIDOK(ctrl),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no events found",
|
||||
args: args{
|
||||
es: GetMockUserGrantByIDNoEvents(ctrl),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no id",
|
||||
args: args{
|
||||
es: GetMockUserGrantByIDOK(ctrl),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "removed state",
|
||||
args: args{
|
||||
es: GetMockUserGrantByIDRemoved(ctrl),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.UserGrantByID(nil, tt.args.grant.AggregateID)
|
||||
|
||||
if !tt.res.wantErr && result.AggregateID != tt.res.grant.AggregateID {
|
||||
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.grant.AggregateID, result.AggregateID)
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddUserGrant(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
result *model.UserGrant
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "add grant, ok",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
ProjectID: "ProjectID",
|
||||
UserID: "UserID",
|
||||
RoleKeys: []string{"Key"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
result: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
ProjectID: "ProjectID",
|
||||
UserID: "UserID",
|
||||
RoleKeys: []string{"Key"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid grant",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.AddUserGrant(tt.args.ctx, tt.args.grant)
|
||||
|
||||
if !tt.res.wantErr && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
}
|
||||
if !tt.res.wantErr && result.UserID == "" {
|
||||
t.Errorf("result has no id")
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangeUserGrant(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
result *model.UserGrant
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "change grant, ok",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
RoleKeys: []string{"KeyChanged"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
result: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
RoleKeys: []string{"KeyChanged"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid grant",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: nil,
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing user not found",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrantNoEvents(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
RoleKeys: []string{"KeyChanged"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.ChangeUserGrant(tt.args.ctx, tt.args.grant)
|
||||
|
||||
if !tt.res.wantErr && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
}
|
||||
if !tt.res.wantErr && !reflect.DeepEqual(result.RoleKeys, tt.res.result.RoleKeys) {
|
||||
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.result.RoleKeys, result.RoleKeys)
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveUserGrant(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "remove grant, ok",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no grantID",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing grant not found",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrantNoEvents(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.args.es.RemoveUserGrant(tt.args.ctx, tt.args.grant.AggregateID)
|
||||
|
||||
if !tt.res.wantErr && err != nil {
|
||||
t.Errorf("should not get err")
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeactivateUserGrant(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
result *model.UserGrant
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "deactivate, ok",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
result: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
ProjectID: "ProjectID",
|
||||
State: model.USERGRANTSTATE_INACTIVE,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no grant id",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant not existing",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrantNoEvents(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.DeactivateUserGrant(tt.args.ctx, tt.args.grant.AggregateID)
|
||||
|
||||
if !tt.res.wantErr && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
}
|
||||
if !tt.res.wantErr && result.ProjectID != tt.res.result.ProjectID {
|
||||
t.Errorf("got wrong result AppID: expected: %v, actual: %v ", tt.res.result.ProjectID, result.ProjectID)
|
||||
}
|
||||
if !tt.res.wantErr && result.State != tt.res.result.State {
|
||||
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.res.result.State, result.State)
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReactivateUserGrant(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
type args struct {
|
||||
es *UserGrantEventStore
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
}
|
||||
type res struct {
|
||||
result *model.UserGrant
|
||||
wantErr bool
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "reactivate, ok",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrantInactive(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
result: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1},
|
||||
State: model.USERGRANTSTATE_ACTIVE,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "no grant id",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrant(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant not existing",
|
||||
args: args{
|
||||
es: GetMockManipulateUserGrantNoEvents(ctrl),
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}},
|
||||
},
|
||||
res: res{
|
||||
wantErr: true,
|
||||
errFunc: caos_errs.IsNotFound,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result, err := tt.args.es.ReactivateUserGrant(tt.args.ctx, tt.args.grant.AggregateID)
|
||||
|
||||
if !tt.res.wantErr && result.AggregateID == "" {
|
||||
t.Errorf("result has no id")
|
||||
}
|
||||
if !tt.res.wantErr && result.State != tt.res.result.State {
|
||||
t.Errorf("got wrong result state: expected: %v, actual: %v ", tt.res.result.State, result.State)
|
||||
}
|
||||
if tt.res.wantErr && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
14
internal/usergrant/repository/eventsourcing/model/types.go
Normal file
14
internal/usergrant/repository/eventsourcing/model/types.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package model
|
||||
|
||||
import "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
const (
|
||||
UserGrantAggregate models.AggregateType = "usergrant"
|
||||
UserGrantUniqueAggregate models.AggregateType = "usergrant-unique"
|
||||
|
||||
UserGrantAdded models.EventType = "user.grant.added"
|
||||
UserGrantChanged models.EventType = "user.grant.changed"
|
||||
UserGrantRemoved models.EventType = "user.grant.removed"
|
||||
UserGrantDeactivated models.EventType = "user.grant.deactivated"
|
||||
UserGrantReactivated models.EventType = "user.grant.reactivated"
|
||||
)
|
@@ -0,0 +1,93 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/caos/logging"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/model"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
const (
|
||||
UserGrantVersion = "v1"
|
||||
)
|
||||
|
||||
type UserGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
State int32 `json:"-"`
|
||||
UserID string `json:"userId,omitempty"`
|
||||
ProjectID string `json:"projectId,omitempty"`
|
||||
RoleKeys []string `json:"roleKeys,omitempty"`
|
||||
}
|
||||
|
||||
type UserGrantID struct {
|
||||
es_models.ObjectRoot
|
||||
GrantID string `json:"grantId"`
|
||||
}
|
||||
|
||||
func (g *UserGrant) Changes(changed *UserGrant) map[string]interface{} {
|
||||
changes := make(map[string]interface{}, 1)
|
||||
if !reflect.DeepEqual(g.RoleKeys, changed.RoleKeys) {
|
||||
changes["roleKeys"] = changed.RoleKeys
|
||||
}
|
||||
return changes
|
||||
}
|
||||
|
||||
func UserGrantFromModel(grant *model.UserGrant) *UserGrant {
|
||||
return &UserGrant{
|
||||
ObjectRoot: grant.ObjectRoot,
|
||||
UserID: grant.UserID,
|
||||
ProjectID: grant.ProjectID,
|
||||
State: int32(grant.State),
|
||||
RoleKeys: grant.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantToModel(grant *UserGrant) *model.UserGrant {
|
||||
return &model.UserGrant{
|
||||
ObjectRoot: grant.ObjectRoot,
|
||||
UserID: grant.UserID,
|
||||
ProjectID: grant.ProjectID,
|
||||
State: model.UserGrantState(grant.State),
|
||||
RoleKeys: grant.RoleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *UserGrant) AppendEvents(events ...*es_models.Event) error {
|
||||
for _, event := range events {
|
||||
if err := g.AppendEvent(event); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *UserGrant) AppendEvent(event *es_models.Event) error {
|
||||
g.ObjectRoot.AppendEvent(event)
|
||||
switch event.Type {
|
||||
case UserGrantAdded,
|
||||
UserGrantChanged:
|
||||
return g.setData(event)
|
||||
case UserGrantDeactivated:
|
||||
g.appendGrantStateEvent(model.USERGRANTSTATE_INACTIVE)
|
||||
case UserGrantReactivated:
|
||||
g.appendGrantStateEvent(model.USERGRANTSTATE_ACTIVE)
|
||||
case UserGrantRemoved:
|
||||
g.appendGrantStateEvent(model.USERGRANTSTATE_REMOVED)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *UserGrant) appendGrantStateEvent(state model.UserGrantState) {
|
||||
g.State = int32(state)
|
||||
}
|
||||
|
||||
func (g *UserGrant) setData(event *es_models.Event) error {
|
||||
if err := json.Unmarshal(event.Data, g); err != nil {
|
||||
logging.Log("EVEN-lso9x").WithError(err).Error("could not unmarshal event data")
|
||||
return caos_errs.ThrowInternal(err, "MODEL-o0se3", "could not unmarshal event")
|
||||
}
|
||||
return nil
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAppendGrantStateEvent(t *testing.T) {
|
||||
type args struct {
|
||||
existing *UserGrant
|
||||
grant *UserGrantID
|
||||
event *es_models.Event
|
||||
state model.UserGrantState
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
result *UserGrant
|
||||
}{
|
||||
{
|
||||
name: "append deactivate grant event",
|
||||
args: args{
|
||||
existing: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}},
|
||||
grant: &UserGrantID{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.USERGRANTSTATE_INACTIVE,
|
||||
},
|
||||
result: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}, State: int32(model.USERGRANTSTATE_INACTIVE)},
|
||||
},
|
||||
{
|
||||
name: "append reactivate grant event",
|
||||
args: args{
|
||||
existing: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}},
|
||||
grant: &UserGrantID{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.USERGRANTSTATE_ACTIVE,
|
||||
},
|
||||
result: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}, State: int32(model.USERGRANTSTATE_ACTIVE)},
|
||||
},
|
||||
{
|
||||
name: "append remove grant event",
|
||||
args: args{
|
||||
existing: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}},
|
||||
grant: &UserGrantID{GrantID: "GrantID"},
|
||||
event: &es_models.Event{},
|
||||
state: model.USERGRANTSTATE_REMOVED,
|
||||
},
|
||||
result: &UserGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID", RoleKeys: []string{"Key"}, State: int32(model.USERGRANTSTATE_REMOVED)},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tt.args.existing.appendGrantStateEvent(tt.args.state)
|
||||
if tt.args.existing.State != tt.result.State {
|
||||
t.Errorf("got wrong result: actual: %v, expected: %v ", tt.result.State, tt.args.existing.State)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
92
internal/usergrant/repository/eventsourcing/user_grant.go
Normal file
92
internal/usergrant/repository/eventsourcing/user_grant.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
)
|
||||
|
||||
func UserGrantByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) {
|
||||
if id == "" {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-ols34", "id should be filled")
|
||||
}
|
||||
return UserGrantQuery(latestSequence).
|
||||
AggregateIDFilter(id), nil
|
||||
}
|
||||
|
||||
func UserGrantQuery(latestSequence uint64) *es_models.SearchQuery {
|
||||
return es_models.NewSearchQuery().
|
||||
AggregateTypeFilter(model.UserGrantAggregate).
|
||||
LatestSequenceFilter(latestSequence)
|
||||
}
|
||||
|
||||
func UserGrantAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, grant *model.UserGrant) (*es_models.Aggregate, error) {
|
||||
if grant == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dis83", "existing grant should not be nil")
|
||||
}
|
||||
return aggCreator.NewAggregate(ctx, grant.AggregateID, model.UserGrantAggregate, model.UserGrantVersion, grant.Sequence)
|
||||
}
|
||||
|
||||
func UserGrantAddedAggregate(aggCreator *es_models.AggregateCreator, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
agg, err := UserGrantAggregate(ctx, aggCreator, grant)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserGrantAdded, grant)
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if grant == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-osl8x", "grant should not be nil")
|
||||
}
|
||||
agg, err := UserGrantAggregate(ctx, aggCreator, existing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes := existing.Changes(grant)
|
||||
return agg.AppendEvent(model.UserGrantChanged, changes)
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantDeactivatedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if grant == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-lo21s", "grant should not be nil")
|
||||
}
|
||||
agg, err := UserGrantAggregate(ctx, aggCreator, existing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserGrantDeactivated, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantReactivatedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if grant == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-mks34", "grant should not be nil")
|
||||
}
|
||||
agg, err := UserGrantAggregate(ctx, aggCreator, existing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserGrantReactivated, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func UserGrantRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
return func(ctx context.Context) (*es_models.Aggregate, error) {
|
||||
if grant == nil {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-lo21s", "grant should not be nil")
|
||||
}
|
||||
agg, err := UserGrantAggregate(ctx, aggCreator, existing)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agg.AppendEvent(model.UserGrantRemoved, nil)
|
||||
}
|
||||
}
|
405
internal/usergrant/repository/eventsourcing/user_grant_test.go
Normal file
405
internal/usergrant/repository/eventsourcing/user_grant_test.go
Normal file
@@ -0,0 +1,405 @@
|
||||
package eventsourcing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUserGrantAddedAggregate(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
grant *model.UserGrant
|
||||
aggCreator *models.AggregateCreator
|
||||
}
|
||||
type res struct {
|
||||
eventLen int
|
||||
eventType models.EventType
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "usergrant added ok",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, UserID: "UserID", ProjectID: "ProjectID"},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
eventLen: 1,
|
||||
eventType: model.UserGrantAdded,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
grant: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg, err := UserGrantAddedAggregate(tt.args.aggCreator, tt.args.grant)(tt.args.ctx)
|
||||
|
||||
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||
}
|
||||
if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType {
|
||||
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
|
||||
}
|
||||
if tt.res.errFunc == nil && agg.Events[0].Data == nil {
|
||||
t.Errorf("should have data in event")
|
||||
}
|
||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGrantChangedAggregate(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
existing *model.UserGrant
|
||||
new *model.UserGrant
|
||||
aggCreator *models.AggregateCreator
|
||||
}
|
||||
type res struct {
|
||||
eventLen int
|
||||
eventTypes []models.EventType
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "change project grant",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"}},
|
||||
new: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"KeyChanged"},
|
||||
},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
eventLen: 1,
|
||||
eventTypes: []models.EventType{model.UserGrantChanged},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: nil,
|
||||
new: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"}},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"}},
|
||||
new: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg, err := UserGrantChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
|
||||
|
||||
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||
}
|
||||
for i := 0; i < tt.res.eventLen; i++ {
|
||||
if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] {
|
||||
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
|
||||
}
|
||||
if tt.res.errFunc == nil && agg.Events[i].Data == nil {
|
||||
t.Errorf("should have data in event")
|
||||
}
|
||||
}
|
||||
|
||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGrantRemovedAggregate(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
existing *model.UserGrant
|
||||
new *model.UserGrant
|
||||
aggCreator *models.AggregateCreator
|
||||
}
|
||||
type res struct {
|
||||
eventLen int
|
||||
eventTypes []models.EventType
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "remove app",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"}},
|
||||
new: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
eventLen: 1,
|
||||
eventTypes: []models.EventType{model.UserGrantRemoved},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing project nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
UserID: "UserID",
|
||||
ProjectID: "ProjectID",
|
||||
RoleKeys: []string{"Key"}},
|
||||
new: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg, err := UserGrantRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
|
||||
|
||||
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||
}
|
||||
for i := 0; i < tt.res.eventLen; i++ {
|
||||
if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] {
|
||||
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
|
||||
}
|
||||
}
|
||||
|
||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGrantDeactivatedAggregate(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
existing *model.UserGrant
|
||||
new *model.UserGrant
|
||||
aggCreator *models.AggregateCreator
|
||||
}
|
||||
type res struct {
|
||||
eventLen int
|
||||
eventTypes []models.EventType
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "deactivate project grant",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
},
|
||||
new: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
eventLen: 1,
|
||||
eventTypes: []models.EventType{model.UserGrantDeactivated},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}},
|
||||
new: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg, err := UserGrantDeactivatedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
|
||||
|
||||
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||
}
|
||||
for i := 0; i < tt.res.eventLen; i++ {
|
||||
if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] {
|
||||
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
|
||||
}
|
||||
}
|
||||
|
||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUserGrantReactivatedAggregate(t *testing.T) {
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
existing *model.UserGrant
|
||||
new *model.UserGrant
|
||||
aggCreator *models.AggregateCreator
|
||||
}
|
||||
type res struct {
|
||||
eventLen int
|
||||
eventTypes []models.EventType
|
||||
errFunc func(err error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
res res
|
||||
}{
|
||||
{
|
||||
name: "reactivate project grant",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
},
|
||||
new: &model.UserGrant{
|
||||
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
|
||||
},
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
eventLen: 1,
|
||||
eventTypes: []models.EventType{model.UserGrantReactivated},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "existing grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "grant nil",
|
||||
args: args{
|
||||
ctx: auth.NewMockContext("orgID", "userID"),
|
||||
existing: &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}},
|
||||
new: nil,
|
||||
aggCreator: models.NewAggregateCreator("Test"),
|
||||
},
|
||||
res: res{
|
||||
errFunc: caos_errs.IsPreconditionFailed,
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
agg, err := UserGrantReactivatedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
|
||||
|
||||
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
|
||||
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
|
||||
}
|
||||
for i := 0; i < tt.res.eventLen; i++ {
|
||||
if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] {
|
||||
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
|
||||
}
|
||||
}
|
||||
|
||||
if tt.res.errFunc != nil && !tt.res.errFunc(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user