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 }