From 351f4e6be2b474d71a82d9d33174503d610289f4 Mon Sep 17 00:00:00 2001 From: Christian Richter Date: Wed, 1 Oct 2025 11:59:06 +0200 Subject: [PATCH] Mock nats & adapt tests Co-authored-by: Florian Schade Signed-off-by: Christian Richter --- .bingo/go-xgettext.mod | 2 - services/graph/.mockery.yaml | 6 ++ services/graph/pkg/service/v0/users.go | 17 ++--- services/graph/pkg/service/v0/users_test.go | 82 ++++++++++++++++++++- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/.bingo/go-xgettext.mod b/.bingo/go-xgettext.mod index b14946a0b8..8e3c6210b5 100644 --- a/.bingo/go-xgettext.mod +++ b/.bingo/go-xgettext.mod @@ -3,5 +3,3 @@ module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT go 1.23.4 require github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a // go-xgettext - -require github.com/jessevdk/go-flags v1.6.1 // indirect diff --git a/services/graph/.mockery.yaml b/services/graph/.mockery.yaml index 3f6957708c..38cf0de422 100644 --- a/services/graph/.mockery.yaml +++ b/services/graph/.mockery.yaml @@ -45,3 +45,9 @@ packages: Client: config: filename: ldapclient.go + github.com/nats-io/nats.go: + config: + dir: mocks + interfaces: + KeyValue: {} + KeyValueEntry: {} diff --git a/services/graph/pkg/service/v0/users.go b/services/graph/pkg/service/v0/users.go index 57c768623c..5cbf4eb34f 100644 --- a/services/graph/pkg/service/v0/users.go +++ b/services/graph/pkg/service/v0/users.go @@ -1154,10 +1154,7 @@ func (g Graph) getUserStateFromNatsKeyValue(ctx context.Context, userID string) logger := g.logger.SubloggerWithRequestID(ctx) if g.natskv == nil { logger.Debug().Msg("nats connection or user state key value store not configured") - return userstate.UserState{ - UserId: userID, - State: userstate.UserStateUnspecified, - }, nil + return userstate.UserState{}, errors.New("nats connection or user state key value store not configured") } entry, err := g.natskv.Get(userID) @@ -1170,18 +1167,14 @@ func (g Graph) getUserStateFromNatsKeyValue(ctx context.Context, userID string) }, nil } logger.Error().Err(err).Str("userid", userID).Msg("error getting user state from nats key value store") - return userstate.UserState{ - State: userstate.UserStateUnspecified, - }, err + return userstate.UserState{}, err } userState := userstate.UserState{} - if err := json.Unmarshal(entry.Value(), &userState); err != nil { + v := entry.Value() + if err := json.Unmarshal(v, &userState); err != nil { logger.Error().Err(err).Str("userid", userID).Msg("error unmarshalling user state from nats key value store") - return userstate.UserState{ - UserId: userID, - State: userstate.UserStateUnspecified, - }, err + return userstate.UserState{}, err } return userState, nil diff --git a/services/graph/pkg/service/v0/users_test.go b/services/graph/pkg/service/v0/users_test.go index ff13e79e8d..152e88121b 100644 --- a/services/graph/pkg/service/v0/users_test.go +++ b/services/graph/pkg/service/v0/users_test.go @@ -16,9 +16,11 @@ import ( provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1" typesv1beta1 "github.com/cs3org/go-cs3apis/cs3/types/v1beta1" "github.com/go-chi/chi/v5" + "github.com/nats-io/nats.go" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" libregraph "github.com/opencloud-eu/libre-graph-api-go" + "github.com/opencloud-eu/opencloud/services/graph/pkg/userstate" revactx "github.com/opencloud-eu/reva/v2/pkg/ctx" "github.com/opencloud-eu/reva/v2/pkg/rgrpc/status" "github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool" @@ -54,6 +56,7 @@ var _ = Describe("Users", func() { valueService *settingsmocks.ValueService permissionService *mocks.Permissions identityBackend *identitymocks.Backend + natsKeyValueMock *mocks.KeyValue rr *httptest.ResponseRecorder @@ -79,6 +82,7 @@ var _ = Describe("Users", func() { identityBackend = &identitymocks.Backend{} roleService = &mocks.RoleService{} + natsKeyValueMock = &mocks.KeyValue{} valueService = &settingsmocks.ValueService{} permissionService = &mocks.Permissions{} @@ -105,6 +109,7 @@ var _ = Describe("Users", func() { service.WithRoleService(roleService), service.WithValueService(valueService), service.PermissionService(permissionService), + service.WithNatsKeyValue(natsKeyValueMock), ) Expect(err).ToNot(HaveOccurred()) }) @@ -968,6 +973,25 @@ var _ = Describe("Users", func() { lu.SetId(currentUser.Id.OpaqueId) identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil) + natsKeyValueMock.EXPECT().Get(mock.Anything).RunAndReturn(func(key string) (nats.KeyValueEntry, error) { + byteRep, _ := json.Marshal(userstate.UserState{ + UserId: lu.GetId(), + State: userstate.UserStateSoftDeleted, + TimeStamp: time.Now().UTC(), + RetentionPeriod: 5 * time.Minute, + Reason: "unit test", + }) + + kve := &mocks.KeyValueEntry{} + kve.On("Value").Return(byteRep) + + return kve, nil + }).Once() + + natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything).RunAndReturn(func(key string, val []byte) (uint64, error) { + return 1, nil + }).Once() + r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil) rctx := chi.NewRouteContext() rctx.URLParams.Add("userID", currentUser.Id.OpaqueId) @@ -1004,6 +1028,25 @@ var _ = Describe("Users", func() { }, }, nil) + natsKeyValueMock.EXPECT().Get(mock.Anything).RunAndReturn(func(key string) (nats.KeyValueEntry, error) { + byteRep, _ := json.Marshal(userstate.UserState{ + UserId: lu.GetId(), + State: userstate.UserStateSoftDeleted, + TimeStamp: time.Now().UTC(), + RetentionPeriod: 5 * time.Minute, + Reason: "unit test", + }) + + kve := &mocks.KeyValueEntry{} + kve.On("Value").Return(byteRep) + + return kve, nil + }).Once() + + natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything).RunAndReturn(func(key string, val []byte) (uint64, error) { + return 1, nil + }).Once() + r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil) rctx := chi.NewRouteContext() rctx.URLParams.Add("userID", lu.GetId()) @@ -1047,7 +1090,7 @@ var _ = Describe("Users", func() { lu := libregraph.User{} lu.SetId(otheruser.Id.OpaqueId) identityBackend.On("GetUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil) - identityBackend.On("DeleteUser", mock.Anything, mock.Anything).Return(nil) + //identityBackend.On("DeleteUser", mock.Anything, mock.Anything).Return(nil) identityBackend.On("UpdateUser", mock.Anything, mock.Anything, mock.Anything).Return(&lu, nil) gatewayClient.On("DeleteStorageSpace", mock.Anything, mock.Anything).Return(&provider.DeleteStorageSpaceResponse{ Status: status.NewOK(ctx), @@ -1065,6 +1108,24 @@ var _ = Describe("Users", func() { }, }, nil) + natsKeyValueMock.EXPECT().Get(mock.Anything).RunAndReturn(func(key string) (nats.KeyValueEntry, error) { + byteRep, _ := json.Marshal(userstate.UserState{ + UserId: lu.GetId(), + State: userstate.UserStateSoftDeleted, + TimeStamp: time.Now().UTC(), + RetentionPeriod: 5 * time.Minute, + Reason: "unit test", + }) + + kve := &mocks.KeyValueEntry{} + kve.On("Value").Return(byteRep) + + return kve, nil + }).Once() + + natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything).RunAndReturn(func(key string, val []byte) (uint64, error) { + return 1, nil + }).Once() r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil) rctx := chi.NewRouteContext() rctx.URLParams.Add("userID", lu.GetId()) @@ -1104,6 +1165,25 @@ var _ = Describe("Users", func() { }, }, nil) + natsKeyValueMock.EXPECT().Get(mock.Anything).RunAndReturn(func(key string) (nats.KeyValueEntry, error) { + byteRep, _ := json.Marshal(userstate.UserState{ + UserId: lu.GetId(), + State: userstate.UserStateSoftDeleted, + TimeStamp: time.Now().UTC(), + RetentionPeriod: 5 * time.Minute, + Reason: "unit test", + }) + + kve := &mocks.KeyValueEntry{} + kve.On("Value").Return(byteRep) + + return kve, nil + }).Once() + + natsKeyValueMock.EXPECT().Put(mock.Anything, mock.Anything).RunAndReturn(func(key string, val []byte) (uint64, error) { + return 1, nil + }).Once() + r := httptest.NewRequest(http.MethodDelete, "/graph/v1.0/users/{userid}", nil) r.Header.Set("Prefer", "purge") // this header is used to indicate a hard delete rctx := chi.NewRouteContext()