github.com/masterhung0112/hk_server/v5@v5.0.0-20220302090640-ec71aef15e1c/store/localcachelayer/user_layer_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package localcachelayer
     5  
     6  import (
     7  	"context"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  
    13  	"github.com/masterhung0112/hk_server/v5/model"
    14  	"github.com/masterhung0112/hk_server/v5/plugin/plugintest/mock"
    15  	"github.com/masterhung0112/hk_server/v5/store"
    16  	"github.com/masterhung0112/hk_server/v5/store/storetest/mocks"
    17  )
    18  
    19  // func TestUserStore(t *testing.T) {
    20  // 	StoreTestWithSqlStore(t, storetest.TestUserStore)
    21  // }
    22  
    23  func TestUserStoreCache(t *testing.T) {
    24  	fakeUserIds := []string{"123"}
    25  	fakeUser := []*model.User{{
    26  		Id:          "123",
    27  		AuthData:    model.NewString("authData"),
    28  		AuthService: "authService",
    29  	}}
    30  
    31  	t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
    32  		mockStore := getMockStore()
    33  		mockCacheProvider := getMockCacheProvider()
    34  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
    35  		require.NoError(t, err)
    36  
    37  		gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    38  		require.NoError(t, err)
    39  		assert.Equal(t, fakeUser, gotUser)
    40  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
    41  
    42  		_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    43  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
    44  	})
    45  
    46  	t.Run("first call not cached, second force not cached", func(t *testing.T) {
    47  		mockStore := getMockStore()
    48  		mockCacheProvider := getMockCacheProvider()
    49  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
    50  		require.NoError(t, err)
    51  
    52  		gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    53  		require.NoError(t, err)
    54  		assert.Equal(t, fakeUser, gotUser)
    55  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
    56  
    57  		_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, false)
    58  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2)
    59  	})
    60  
    61  	t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) {
    62  		mockStore := getMockStore()
    63  		mockCacheProvider := getMockCacheProvider()
    64  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
    65  		require.NoError(t, err)
    66  
    67  		gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    68  		require.NoError(t, err)
    69  		assert.Equal(t, fakeUser, gotUser)
    70  
    71  		cachedStore.User().InvalidateProfileCacheForUser("123")
    72  
    73  		_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    74  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2)
    75  	})
    76  
    77  	t.Run("should always return a copy of the stored data", func(t *testing.T) {
    78  		mockStore := getMockStore()
    79  		mockCacheProvider := getMockCacheProvider()
    80  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
    81  		require.NoError(t, err)
    82  
    83  		storedUsers, err := mockStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, false)
    84  		require.NoError(t, err)
    85  
    86  		originalProps := make([]model.StringMap, len(storedUsers))
    87  
    88  		for i := 0; i < len(storedUsers); i++ {
    89  			originalProps[i] = storedUsers[i].NotifyProps
    90  			storedUsers[i].NotifyProps = map[string]string{}
    91  			storedUsers[i].NotifyProps["key"] = "somevalue"
    92  		}
    93  
    94  		cachedUsers, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
    95  		require.NoError(t, err)
    96  
    97  		for i := 0; i < len(storedUsers); i++ {
    98  			assert.Equal(t, storedUsers[i].Id, cachedUsers[i].Id)
    99  		}
   100  
   101  		cachedUsers, err = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
   102  		require.NoError(t, err)
   103  		for i := 0; i < len(storedUsers); i++ {
   104  			storedUsers[i].Props = model.StringMap{}
   105  			storedUsers[i].Timezone = model.StringMap{}
   106  			assert.Equal(t, storedUsers[i], cachedUsers[i])
   107  			if storedUsers[i] == cachedUsers[i] {
   108  				assert.Fail(t, "should be different pointers")
   109  			}
   110  			cachedUsers[i].NotifyProps["key"] = "othervalue"
   111  			assert.NotEqual(t, storedUsers[i], cachedUsers[i])
   112  		}
   113  
   114  		for i := 0; i < len(storedUsers); i++ {
   115  			storedUsers[i].NotifyProps = originalProps[i]
   116  		}
   117  	})
   118  }
   119  
   120  func TestUserStoreProfilesInChannelCache(t *testing.T) {
   121  	fakeChannelId := "123"
   122  	fakeUserId := "456"
   123  	fakeMap := map[string]*model.User{
   124  		fakeUserId: {Id: "456"},
   125  	}
   126  
   127  	t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
   128  		mockStore := getMockStore()
   129  		mockCacheProvider := getMockCacheProvider()
   130  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   131  		require.NoError(t, err)
   132  
   133  		gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   134  		require.NoError(t, err)
   135  		assert.Equal(t, fakeMap, gotMap)
   136  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
   137  
   138  		_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   139  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
   140  	})
   141  
   142  	t.Run("first call not cached, second force not cached", func(t *testing.T) {
   143  		mockStore := getMockStore()
   144  		mockCacheProvider := getMockCacheProvider()
   145  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   146  		require.NoError(t, err)
   147  
   148  		gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   149  		require.NoError(t, err)
   150  		assert.Equal(t, fakeMap, gotMap)
   151  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
   152  
   153  		_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, false)
   154  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
   155  	})
   156  
   157  	t.Run("first call not cached, invalidate by channel, and then not cached again", func(t *testing.T) {
   158  		mockStore := getMockStore()
   159  		mockCacheProvider := getMockCacheProvider()
   160  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   161  		require.NoError(t, err)
   162  
   163  		gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   164  		require.NoError(t, err)
   165  		assert.Equal(t, fakeMap, gotMap)
   166  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
   167  
   168  		cachedStore.User().InvalidateProfilesInChannelCache("123")
   169  
   170  		_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   171  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
   172  	})
   173  
   174  	t.Run("first call not cached, invalidate by user, and then not cached again", func(t *testing.T) {
   175  		mockStore := getMockStore()
   176  		mockCacheProvider := getMockCacheProvider()
   177  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   178  		require.NoError(t, err)
   179  
   180  		gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   181  		require.NoError(t, err)
   182  		assert.Equal(t, fakeMap, gotMap)
   183  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
   184  
   185  		cachedStore.User().InvalidateProfilesInChannelCacheByUser("456")
   186  
   187  		_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
   188  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
   189  	})
   190  }
   191  
   192  func TestUserStoreGetCache(t *testing.T) {
   193  	fakeUserId := "123"
   194  	fakeUser := &model.User{
   195  		Id:          "123",
   196  		AuthData:    model.NewString("authData"),
   197  		AuthService: "authService",
   198  	}
   199  	t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
   200  		mockStore := getMockStore()
   201  		mockCacheProvider := getMockCacheProvider()
   202  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   203  		require.NoError(t, err)
   204  
   205  		gotUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
   206  		require.NoError(t, err)
   207  		assert.Equal(t, fakeUser, gotUser)
   208  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
   209  
   210  		_, _ = cachedStore.User().Get(context.Background(), fakeUserId)
   211  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
   212  	})
   213  
   214  	t.Run("first call not cached, invalidate, and then not cached again", func(t *testing.T) {
   215  		mockStore := getMockStore()
   216  		mockCacheProvider := getMockCacheProvider()
   217  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   218  		require.NoError(t, err)
   219  
   220  		gotUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
   221  		require.NoError(t, err)
   222  		assert.Equal(t, fakeUser, gotUser)
   223  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
   224  
   225  		cachedStore.User().InvalidateProfileCacheForUser("123")
   226  
   227  		_, _ = cachedStore.User().Get(context.Background(), fakeUserId)
   228  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 2)
   229  	})
   230  
   231  	t.Run("should always return a copy of the stored data", func(t *testing.T) {
   232  		mockStore := getMockStore()
   233  		mockCacheProvider := getMockCacheProvider()
   234  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   235  		require.NoError(t, err)
   236  
   237  		storedUser, err := mockStore.User().Get(context.Background(), fakeUserId)
   238  		require.NoError(t, err)
   239  		originalProps := storedUser.NotifyProps
   240  
   241  		storedUser.NotifyProps = map[string]string{}
   242  		storedUser.NotifyProps["key"] = "somevalue"
   243  
   244  		cachedUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
   245  		require.NoError(t, err)
   246  		assert.Equal(t, storedUser, cachedUser)
   247  
   248  		storedUser.Props = model.StringMap{}
   249  		storedUser.Timezone = model.StringMap{}
   250  		cachedUser, err = cachedStore.User().Get(context.Background(), fakeUserId)
   251  		require.NoError(t, err)
   252  		assert.Equal(t, storedUser, cachedUser)
   253  		if storedUser == cachedUser {
   254  			assert.Fail(t, "should be different pointers")
   255  		}
   256  		cachedUser.NotifyProps["key"] = "othervalue"
   257  		assert.NotEqual(t, storedUser, cachedUser)
   258  
   259  		storedUser.NotifyProps = originalProps
   260  	})
   261  }
   262  
   263  func TestUserStoreGetManyCache(t *testing.T) {
   264  	fakeUser := &model.User{
   265  		Id:          "123",
   266  		AuthData:    model.NewString("authData"),
   267  		AuthService: "authService",
   268  	}
   269  	otherFakeUser := &model.User{
   270  		Id:          "456",
   271  		AuthData:    model.NewString("authData"),
   272  		AuthService: "authService",
   273  	}
   274  	t.Run("first call not cached, second cached and returning same data", func(t *testing.T) {
   275  		mockStore := getMockStore()
   276  		mockCacheProvider := getMockCacheProvider()
   277  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   278  		require.NoError(t, err)
   279  
   280  		gotUsers, err := cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
   281  		require.NoError(t, err)
   282  		assert.Len(t, gotUsers, 2)
   283  		assert.Contains(t, gotUsers, fakeUser)
   284  		assert.Contains(t, gotUsers, otherFakeUser)
   285  
   286  		gotUsers, err = cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
   287  		require.NoError(t, err)
   288  		assert.Len(t, gotUsers, 2)
   289  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetMany", 1)
   290  	})
   291  
   292  	t.Run("first call not cached, invalidate one user, and then check that one is cached and one is fetched from db", func(t *testing.T) {
   293  		mockStore := getMockStore()
   294  		mockCacheProvider := getMockCacheProvider()
   295  		cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
   296  		require.NoError(t, err)
   297  
   298  		gotUsers, err := cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
   299  		require.NoError(t, err)
   300  		assert.Len(t, gotUsers, 2)
   301  		assert.Contains(t, gotUsers, fakeUser)
   302  		assert.Contains(t, gotUsers, otherFakeUser)
   303  
   304  		cachedStore.User().InvalidateProfileCacheForUser("123")
   305  
   306  		gotUsers, err = cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
   307  		require.NoError(t, err)
   308  		assert.Len(t, gotUsers, 2)
   309  		mockStore.User().(*mocks.UserStore).AssertCalled(t, "GetMany", mock.Anything, []string{"123"})
   310  		mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetMany", 2)
   311  	})
   312  }