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