Make LocalCacheUserStore.Get/GetProfileByIds return a copy of the stored data (#13620)

Этот коммит содержится в:
Claudio Costa
2020-01-15 19:01:04 +01:00
коммит произвёл GitHub
родитель a001ecabe2
Коммит 508fbf2f53
2 изменённых файлов: 83 добавлений и 8 удалений

Просмотреть файл

@@ -105,11 +105,10 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
for _, userId := range userIds { for _, userId := range userIds {
if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId); cacheItem != nil { if cacheItem := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId); cacheItem != nil {
u := &model.User{} u := cacheItem.(*model.User)
*u = *cacheItem.(*model.User)
if options.Since == 0 || u.UpdateAt > options.Since { if options.Since == 0 || u.UpdateAt > options.Since {
users = append(users, u) users = append(users, u.DeepCopy())
} }
} else { } else {
remainingUserIds = append(remainingUserIds, userId) remainingUserIds = append(remainingUserIds, userId)
@@ -127,9 +126,8 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
return nil, model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("SqlUserStore.GetProfileByIds", "store.sql_user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
users = append(users, remainingUsers...)
for _, user := range remainingUsers { for _, user := range remainingUsers {
users = append(users, user.DeepCopy())
s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, user.Id, user) s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, user.Id, user)
} }
} }
@@ -147,8 +145,8 @@ func (s LocalCacheUserStore) Get(id string) (*model.User, *model.AppError) {
if s.rootStore.metrics != nil { if s.rootStore.metrics != nil {
s.rootStore.metrics.AddMemCacheHitCounter("Profile By Id", float64(1)) s.rootStore.metrics.AddMemCacheHitCounter("Profile By Id", float64(1))
} }
u := *cacheItem.(*model.User) u := cacheItem.(*model.User)
return &u, nil return u.DeepCopy(), nil
} }
if s.rootStore.metrics != nil { if s.rootStore.metrics != nil {
s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1)) s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1))
@@ -158,5 +156,5 @@ func (s LocalCacheUserStore) Get(id string) (*model.User, *model.AppError) {
return nil, model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError) return nil, model.NewAppError("SqlUserStore.Get", "store.sql_user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
} }
s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, id, user) s.rootStore.doStandardAddToCache(s.rootStore.userProfileByIdsCache, id, user)
return user, nil return user.DeepCopy(), nil
} }

Просмотреть файл

@@ -66,6 +66,50 @@ func TestUserStoreGetProfileByIdsCache(t *testing.T) {
_, _ = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true) _, _ = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2) mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2)
}) })
t.Run("should always return a copy of the stored data", func(t *testing.T) {
mockStore := getMockStore()
mockCacheProvider := getMockCacheProvider()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
storedUsers, err := mockStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, false)
require.Nil(t, err)
originalProps := make([]model.StringMap, len(storedUsers))
for i := 0; i < len(storedUsers); i++ {
originalProps[i] = storedUsers[i].NotifyProps
storedUsers[i].NotifyProps = map[string]string{}
storedUsers[i].NotifyProps["key"] = "somevalue"
}
cachedUsers, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.Nil(t, err)
for i := 0; i < len(storedUsers); i++ {
assert.Equal(t, storedUsers[i], cachedUsers[i])
if storedUsers[i] == cachedUsers[i] {
assert.Fail(t, "should be different pointers")
}
cachedUsers[i].NotifyProps["key"] = "othervalue"
assert.NotEqual(t, storedUsers[i], cachedUsers[i])
}
cachedUsers, err = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.Nil(t, err)
for i := 0; i < len(storedUsers); i++ {
assert.Equal(t, storedUsers[i], cachedUsers[i])
if storedUsers[i] == cachedUsers[i] {
assert.Fail(t, "should be different pointers")
}
cachedUsers[i].NotifyProps["key"] = "othervalue"
assert.NotEqual(t, storedUsers[i], cachedUsers[i])
}
for i := 0; i < len(storedUsers); i++ {
storedUsers[i].NotifyProps = originalProps[i]
}
})
} }
func TestUserStoreProfilesInChannelCache(t *testing.T) { func TestUserStoreProfilesInChannelCache(t *testing.T) {
@@ -167,4 +211,37 @@ func TestUserStoreGetCache(t *testing.T) {
_, _ = cachedStore.User().Get(fakeUserId) _, _ = cachedStore.User().Get(fakeUserId)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 2) mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 2)
}) })
t.Run("should always return a copy of the stored data", func(t *testing.T) {
mockStore := getMockStore()
mockCacheProvider := getMockCacheProvider()
cachedStore := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
storedUser, err := mockStore.User().Get(fakeUserId)
require.Nil(t, err)
originalProps := storedUser.NotifyProps
storedUser.NotifyProps = map[string]string{}
storedUser.NotifyProps["key"] = "somevalue"
cachedUser, err := cachedStore.User().Get(fakeUserId)
require.Nil(t, err)
assert.Equal(t, storedUser, cachedUser)
if storedUser == cachedUser {
assert.Fail(t, "should be different pointers")
}
cachedUser.NotifyProps["key"] = "othervalue"
assert.NotEqual(t, storedUser, cachedUser)
cachedUser, err = cachedStore.User().Get(fakeUserId)
require.Nil(t, err)
assert.Equal(t, storedUser, cachedUser)
if storedUser == cachedUser {
assert.Fail(t, "should be different pointers")
}
cachedUser.NotifyProps["key"] = "othervalue"
assert.NotEqual(t, storedUser, cachedUser)
storedUser.NotifyProps = originalProps
})
} }