Skip to content

Commit

Permalink
Added server testcase for kvstore/plugin_store.go file (#413)
Browse files Browse the repository at this point in the history
* [MM-843]: Added server testcase for kvstore/plugin_store.go file (#18)

* [MM-843]: Added server testcase for kvstore/plugin_store.go file

* [MM-843]: removed ununsed vars

* updated go.mod and go.sum entries

* refactored mock plugin setup

---------

Co-authored-by: Doug Lauder <[email protected]>
Co-authored-by: Raghav Aggarwal <[email protected]>
  • Loading branch information
3 people authored Oct 22, 2024
1 parent ca1d605 commit ef7d055
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 0 deletions.
55 changes: 55 additions & 0 deletions calendar/testutil/mock_setup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package testutil

import (
"github.com/stretchr/testify/mock"

"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/plugin"
)

type MockPluginAPI struct {
plugin.API
mock.Mock
}

func (m *MockPluginAPI) KVGet(key string) ([]byte, *model.AppError) {
args := m.Called(key)
data, _ := args.Get(0).([]byte)
if err := args.Get(1); err != nil {
return nil, err.(*model.AppError)
}
return data, nil
}

func (m *MockPluginAPI) KVSet(key string, data []byte) *model.AppError {
args := m.Called(key, data)
if err := args.Get(0); err != nil {
return err.(*model.AppError)
}
return nil
}

func (m *MockPluginAPI) KVSetWithExpiry(key string, data []byte, ttl int64) *model.AppError {
args := m.Called(key, data, ttl)
if err := args.Get(0); err != nil {
return err.(*model.AppError)
}
return nil
}

func (m *MockPluginAPI) KVSetWithOptions(key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError) {
args := m.Called(key, value, options)
success := args.Bool(0)
if err := args.Get(1); err != nil {
return success, err.(*model.AppError)
}
return success, nil
}

func (m *MockPluginAPI) KVDelete(key string) *model.AppError {
args := m.Called(key)
if err := args.Get(0); err != nil {
return err.(*model.AppError)
}
return nil
}
277 changes: 277 additions & 0 deletions calendar/utils/kvstore/plugin_store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
package kvstore

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/mattermost/mattermost/server/public/model"

"github.com/mattermost/mattermost-plugin-mscalendar/calendar/testutil"
)

func TestLoad(t *testing.T) {
tests := []struct {
name string
key string
setup func(*testutil.MockPluginAPI)
assertions func(*testing.T, []byte, error)
}{
{
name: "Error during KVGet",
key: "error-key",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVGet", "error-key").Return(nil, &model.AppError{Message: "KVGet failed"})
},
assertions: func(t *testing.T, data []byte, err error) {
require.Nil(t, data, "expected nil data")
require.EqualError(t, err, "failed plugin KVGet: KVGet failed", "unexpected error message")
},
},
{
name: "Key not found",
key: "missing-key",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVGet", "missing-key").Return(nil, nil)
},
assertions: func(t *testing.T, data []byte, err error) {
require.Nil(t, data, "expected nil data")
require.EqualError(t, err, ErrNotFound.Error(), "unexpected error message")
},
},
{
name: "Load successfully",
key: "test-key",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVGet", "test-key").Return([]byte("test-value"), nil)
},
assertions: func(t *testing.T, data []byte, err error) {
require.Equal(t, []byte("test-value"), data, "unexpected data returned")
require.NoError(t, err, "unexpected error occurred")
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAPI := &testutil.MockPluginAPI{}
store := NewPluginStore(mockAPI)
tt.setup(mockAPI)

data, err := store.Load(tt.key)

tt.assertions(t, data, err)

mockAPI.AssertExpectations(t)
})
}
}

func TestStore(t *testing.T) {
tests := []struct {
name string
expiryTime int
setup func(*testutil.MockPluginAPI)
assertions func(*testing.T, error)
}{
{
name: "Error during KVSet with TTL",
expiryTime: 60,
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithExpiry", "mockKey", []byte("mockValue"), int64(60)).Return(&model.AppError{Message: "KVSet failed"})
},
assertions: func(t *testing.T, err error) {
require.EqualError(t, err, "failed plugin KVSet (ttl: 60s) \"mockKey\": KVSet failed", "unexpected error message")
},
},
{
name: "Error during KVSet without TTL",
expiryTime: 0,
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSet", "mockKey", []byte("mockValue")).Return(&model.AppError{Message: "KVSet failed"})
},
assertions: func(t *testing.T, err error) {
require.EqualError(t, err, "failed plugin KVSet (ttl: 0s) \"mockKey\": KVSet failed", "unexpected error message")
},
},
{
name: "Store with TTL successfully",
expiryTime: 60,
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithExpiry", "mockKey", []byte("mockValue"), int64(60)).Return(nil)
},
assertions: func(t *testing.T, err error) {
require.NoError(t, err, "unexpected error occurred")
},
},
{
name: "Store without TTL successfully",
expiryTime: 0,
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSet", "mockKey", []byte("mockValue")).Return(nil)
},
assertions: func(t *testing.T, err error) {
require.NoError(t, err, "unexpected error occurred")
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAPI := &testutil.MockPluginAPI{}
store := NewPluginStoreWithExpiry(mockAPI, time.Duration(tt.expiryTime)*time.Second)
tt.setup(mockAPI)

err := store.Store("mockKey", []byte("mockValue"))

tt.assertions(t, err)

mockAPI.AssertExpectations(t)
})
}
}

func TestStoreTTL(t *testing.T) {
tests := []struct {
name string
setup func(*testutil.MockPluginAPI)
assertions func(*testing.T, error)
}{
{
name: "Error during storing with TTL",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithExpiry", "mockKey", []byte("mockValue"), int64(60)).Return(&model.AppError{Message: "KVSet failed"})
},
assertions: func(t *testing.T, err error) {
require.EqualError(t, err, "failed plugin KVSet (ttl: 60s) \"mockKey\": KVSet failed", "unexpected error message")
},
},
{
name: "Store with TTL successfully",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithExpiry", "mockKey", []byte("mockValue"), int64(60)).Return(nil)
},
assertions: func(t *testing.T, err error) {
require.NoError(t, err, "unexpected error occurred")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAPI := &testutil.MockPluginAPI{}
store := NewPluginStoreWithExpiry(mockAPI, 60*time.Second)
tt.setup(mockAPI)

err := store.StoreTTL("mockKey", []byte("mockValue"), 60)

tt.assertions(t, err)

mockAPI.AssertExpectations(t)
})
}
}

func TestStoreWithOptions(t *testing.T) {
tests := []struct {
name string
expiryTime int64
opts model.PluginKVSetOptions
setup func(*testutil.MockPluginAPI)
assertions func(*testing.T, bool, error)
}{
{
name: "Error during KVSetWithOptions",
expiryTime: 60,
opts: model.PluginKVSetOptions{
ExpireInSeconds: 30,
},
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithOptions", "mockKey", []byte("mockValue"), model.PluginKVSetOptions{ExpireInSeconds: 30}).Return(false, &model.AppError{Message: "KVSet failed"})
},
assertions: func(t *testing.T, success bool, err error) {
require.False(t, success, "expected success to be false")
require.EqualError(t, err, "failed plugin KVSet (ttl: 30s) \"mockKey\": KVSet failed", "unexpected error message")
},
},
{
name: "Use default TTL when opts.ExpireInSeconds is 0",
expiryTime: 60,
opts: model.PluginKVSetOptions{},
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithOptions", "mockKey", []byte("mockValue"), model.PluginKVSetOptions{ExpireInSeconds: 60}).Return(true, nil)
},
assertions: func(t *testing.T, success bool, err error) {
require.True(t, success, "expected success to be true")
require.NoError(t, err, "unexpected error occurred")
},
},
{
name: "Store with options successfully",
expiryTime: 60,
opts: model.PluginKVSetOptions{
ExpireInSeconds: 30,
},
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVSetWithOptions", "mockKey", []byte("mockValue"), model.PluginKVSetOptions{ExpireInSeconds: 30}).Return(true, nil)
},
assertions: func(t *testing.T, success bool, err error) {
require.True(t, success, "expected success to be true")
require.NoError(t, err, "unexpected error occurred")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAPI := &testutil.MockPluginAPI{}
store := NewPluginStoreWithExpiry(mockAPI, time.Duration(tt.expiryTime)*time.Second)
tt.setup(mockAPI)

success, err := store.StoreWithOptions("mockKey", []byte("mockValue"), tt.opts)

tt.assertions(t, success, err)

mockAPI.AssertExpectations(t)
})
}
}

func TestDelete(t *testing.T) {
tests := []struct {
name string
setup func(*testutil.MockPluginAPI)
assertions func(*testing.T, error)
}{
{
name: "Error during KVDelete",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVDelete", "mockKey").Return(&model.AppError{Message: "KVDelete failed"})
},
assertions: func(t *testing.T, err error) {
require.EqualError(t, err, "failed plugin KVdelete \"mockKey\": KVDelete failed", "unexpected error message")
},
},
{
name: "Delete successfully",
setup: func(mockAPI *testutil.MockPluginAPI) {
mockAPI.On("KVDelete", "mockKey").Return(nil)
},
assertions: func(t *testing.T, err error) {
require.NoError(t, err, "unexpected error occurred")
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mockAPI := &testutil.MockPluginAPI{}
store := NewPluginStore(mockAPI)
tt.setup(mockAPI)

err := store.Delete("mockKey")

tt.assertions(t, err)

mockAPI.AssertExpectations(t)
})
}
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ require (
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/segmentio/backo-go v1.1.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
Expand Down

0 comments on commit ef7d055

Please sign in to comment.