github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/store/storetest/channel_member_history_store.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package storetest
     5  
     6  import (
     7  	"testing"
     8  
     9  	"math"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  
    14  	"github.com/mattermost/mattermost-server/v5/model"
    15  	"github.com/mattermost/mattermost-server/v5/store"
    16  )
    17  
    18  func TestChannelMemberHistoryStore(t *testing.T, ss store.Store) {
    19  	t.Run("TestLogJoinEvent", func(t *testing.T) { testLogJoinEvent(t, ss) })
    20  	t.Run("TestLogLeaveEvent", func(t *testing.T) { testLogLeaveEvent(t, ss) })
    21  	t.Run("TestGetUsersInChannelAtChannelMemberHistory", func(t *testing.T) { testGetUsersInChannelAtChannelMemberHistory(t, ss) })
    22  	t.Run("TestGetUsersInChannelAtChannelMembers", func(t *testing.T) { testGetUsersInChannelAtChannelMembers(t, ss) })
    23  	t.Run("TestPermanentDeleteBatch", func(t *testing.T) { testPermanentDeleteBatch(t, ss) })
    24  }
    25  
    26  func testLogJoinEvent(t *testing.T, ss store.Store) {
    27  	// create a test channel
    28  	ch := model.Channel{
    29  		TeamId:      model.NewId(),
    30  		DisplayName: "Display " + model.NewId(),
    31  		Name:        "zz" + model.NewId() + "b",
    32  		Type:        model.CHANNEL_OPEN,
    33  	}
    34  	channel, err := ss.Channel().Save(&ch, -1)
    35  	require.NoError(t, err)
    36  
    37  	// and a test user
    38  	user := model.User{
    39  		Email:    MakeEmail(),
    40  		Nickname: model.NewId(),
    41  		Username: model.NewId(),
    42  	}
    43  	userPtr, err := ss.User().Save(&user)
    44  	require.NoError(t, err)
    45  	user = *userPtr
    46  
    47  	// log a join event
    48  	err = ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, model.GetMillis())
    49  	assert.NoError(t, err)
    50  }
    51  
    52  func testLogLeaveEvent(t *testing.T, ss store.Store) {
    53  	// create a test channel
    54  	ch := model.Channel{
    55  		TeamId:      model.NewId(),
    56  		DisplayName: "Display " + model.NewId(),
    57  		Name:        "zz" + model.NewId() + "b",
    58  		Type:        model.CHANNEL_OPEN,
    59  	}
    60  	channel, err := ss.Channel().Save(&ch, -1)
    61  	require.NoError(t, err)
    62  
    63  	// and a test user
    64  	user := model.User{
    65  		Email:    MakeEmail(),
    66  		Nickname: model.NewId(),
    67  		Username: model.NewId(),
    68  	}
    69  	userPtr, err := ss.User().Save(&user)
    70  	require.NoError(t, err)
    71  	user = *userPtr
    72  
    73  	// log a join event, followed by a leave event
    74  	err = ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, model.GetMillis())
    75  	assert.NoError(t, err)
    76  
    77  	err = ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, model.GetMillis())
    78  	assert.NoError(t, err)
    79  }
    80  
    81  func testGetUsersInChannelAtChannelMemberHistory(t *testing.T, ss store.Store) {
    82  	// create a test channel
    83  	ch := &model.Channel{
    84  		TeamId:      model.NewId(),
    85  		DisplayName: "Display " + model.NewId(),
    86  		Name:        "zz" + model.NewId() + "b",
    87  		Type:        model.CHANNEL_OPEN,
    88  	}
    89  	channel, err := ss.Channel().Save(ch, -1)
    90  	require.NoError(t, err)
    91  
    92  	// and a test user
    93  	user := model.User{
    94  		Email:    MakeEmail(),
    95  		Nickname: model.NewId(),
    96  		Username: model.NewId(),
    97  	}
    98  	userPtr, err := ss.User().Save(&user)
    99  	require.NoError(t, err)
   100  	user = *userPtr
   101  
   102  	// the user was previously in the channel a long time ago, before the export period starts
   103  	// the existence of this record makes it look like the MessageExport feature has been active for awhile, and prevents
   104  	// us from looking in the ChannelMembers table for data that isn't found in the ChannelMemberHistory table
   105  	leaveTime := model.GetMillis() - 20000
   106  	joinTime := leaveTime - 10000
   107  	err = ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, joinTime)
   108  	require.NoError(t, err)
   109  	err = ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, leaveTime)
   110  	require.NoError(t, err)
   111  
   112  	// log a join event
   113  	leaveTime = model.GetMillis()
   114  	joinTime = leaveTime - 10000
   115  	err = ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, joinTime)
   116  	require.NoError(t, err)
   117  
   118  	// case 1: user joins and leaves the channel before the export period begins
   119  	channelMembers, err := ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)
   120  	require.NoError(t, err)
   121  	assert.Empty(t, channelMembers)
   122  
   123  	// case 2: user joins the channel after the export period begins, but has not yet left the channel when the export period ends
   124  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)
   125  	require.NoError(t, err)
   126  	assert.Len(t, channelMembers, 1)
   127  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   128  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   129  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   130  	assert.Equal(t, user.Username, channelMembers[0].Username)
   131  	assert.Equal(t, joinTime, channelMembers[0].JoinTime)
   132  	assert.Nil(t, channelMembers[0].LeaveTime)
   133  
   134  	// case 3: user joins the channel before the export period begins, but has not yet left the channel when the export period ends
   135  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)
   136  	require.NoError(t, err)
   137  	assert.Len(t, channelMembers, 1)
   138  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   139  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   140  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   141  	assert.Equal(t, user.Username, channelMembers[0].Username)
   142  	assert.Equal(t, joinTime, channelMembers[0].JoinTime)
   143  	assert.Nil(t, channelMembers[0].LeaveTime)
   144  
   145  	// add a leave time for the user
   146  	err = ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, leaveTime)
   147  	require.NoError(t, err)
   148  
   149  	// case 4: user joins the channel before the export period begins, but has not yet left the channel when the export period ends
   150  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)
   151  	require.NoError(t, err)
   152  	assert.Len(t, channelMembers, 1)
   153  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   154  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   155  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   156  	assert.Equal(t, user.Username, channelMembers[0].Username)
   157  	assert.Equal(t, joinTime, channelMembers[0].JoinTime)
   158  	assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime)
   159  
   160  	// case 5: user joins the channel after the export period begins, and leaves the channel before the export period ends
   161  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)
   162  	require.NoError(t, err)
   163  	assert.Len(t, channelMembers, 1)
   164  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   165  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   166  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   167  	assert.Equal(t, user.Username, channelMembers[0].Username)
   168  	assert.Equal(t, joinTime, channelMembers[0].JoinTime)
   169  	assert.Equal(t, leaveTime, *channelMembers[0].LeaveTime)
   170  
   171  	// case 6: user has joined and left the channel long before the export period begins
   172  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)
   173  	require.NoError(t, err)
   174  	assert.Empty(t, channelMembers)
   175  }
   176  
   177  func testGetUsersInChannelAtChannelMembers(t *testing.T, ss store.Store) {
   178  	// create a test channel
   179  	channel := &model.Channel{
   180  		TeamId:      model.NewId(),
   181  		DisplayName: "Display " + model.NewId(),
   182  		Name:        "zz" + model.NewId() + "b",
   183  		Type:        model.CHANNEL_OPEN,
   184  	}
   185  	channel, err := ss.Channel().Save(channel, -1)
   186  	require.NoError(t, err)
   187  
   188  	// and a test user
   189  	user := model.User{
   190  		Email:    MakeEmail(),
   191  		Nickname: model.NewId(),
   192  		Username: model.NewId(),
   193  	}
   194  	userPtr, err := ss.User().Save(&user)
   195  	require.NoError(t, err)
   196  	user = *userPtr
   197  
   198  	// clear any existing ChannelMemberHistory data that might interfere with our test
   199  	var tableDataTruncated = false
   200  	for !tableDataTruncated {
   201  		var count int64
   202  		count, err = ss.ChannelMemberHistory().PermanentDeleteBatch(model.GetMillis(), 1000)
   203  		require.NoError(t, err, "Failed to truncate ChannelMemberHistory contents")
   204  		tableDataTruncated = count == int64(0)
   205  	}
   206  
   207  	// in this test, we're pretending that Message Export was not activated during the export period, so there's no data
   208  	// available in the ChannelMemberHistory table. Instead, we'll fall back to the ChannelMembers table for a rough approximation
   209  	joinTime := int64(1000)
   210  	leaveTime := joinTime + 5000
   211  	_, err = ss.Channel().SaveMember(&model.ChannelMember{
   212  		ChannelId:   channel.Id,
   213  		UserId:      user.Id,
   214  		NotifyProps: model.GetDefaultChannelNotifyProps(),
   215  	})
   216  	require.NoError(t, err)
   217  
   218  	// in every single case, the user will be included in the export, because ChannelMembers says they were in the channel at some point in
   219  	// the past, even though the time that they were actually in the channel doesn't necessarily overlap with the export period
   220  
   221  	// case 1: user joins and leaves the channel before the export period begins
   222  	channelMembers, err := ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-500, joinTime-100, channel.Id)
   223  	require.NoError(t, err)
   224  	assert.Len(t, channelMembers, 1)
   225  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   226  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   227  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   228  	assert.Equal(t, user.Username, channelMembers[0].Username)
   229  	assert.Equal(t, joinTime-500, channelMembers[0].JoinTime)
   230  	assert.Equal(t, joinTime-100, *channelMembers[0].LeaveTime)
   231  
   232  	// case 2: user joins the channel after the export period begins, but has not yet left the channel when the export period ends
   233  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, joinTime+500, channel.Id)
   234  	require.NoError(t, err)
   235  	assert.Len(t, channelMembers, 1)
   236  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   237  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   238  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   239  	assert.Equal(t, user.Username, channelMembers[0].Username)
   240  	assert.Equal(t, joinTime-100, channelMembers[0].JoinTime)
   241  	assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime)
   242  
   243  	// case 3: user joins the channel before the export period begins, but has not yet left the channel when the export period ends
   244  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, joinTime+500, channel.Id)
   245  	require.NoError(t, err)
   246  	assert.Len(t, channelMembers, 1)
   247  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   248  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   249  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   250  	assert.Equal(t, user.Username, channelMembers[0].Username)
   251  	assert.Equal(t, joinTime+100, channelMembers[0].JoinTime)
   252  	assert.Equal(t, joinTime+500, *channelMembers[0].LeaveTime)
   253  
   254  	// case 4: user joins the channel before the export period begins, but has not yet left the channel when the export period ends
   255  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+100, leaveTime-100, channel.Id)
   256  	require.NoError(t, err)
   257  	assert.Len(t, channelMembers, 1)
   258  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   259  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   260  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   261  	assert.Equal(t, user.Username, channelMembers[0].Username)
   262  	assert.Equal(t, joinTime+100, channelMembers[0].JoinTime)
   263  	assert.Equal(t, leaveTime-100, *channelMembers[0].LeaveTime)
   264  
   265  	// case 5: user joins the channel after the export period begins, and leaves the channel before the export period ends
   266  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime-100, leaveTime+100, channel.Id)
   267  	require.NoError(t, err)
   268  	assert.Len(t, channelMembers, 1)
   269  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   270  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   271  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   272  	assert.Equal(t, user.Username, channelMembers[0].Username)
   273  	assert.Equal(t, joinTime-100, channelMembers[0].JoinTime)
   274  	assert.Equal(t, leaveTime+100, *channelMembers[0].LeaveTime)
   275  
   276  	// case 6: user has joined and left the channel long before the export period begins
   277  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(leaveTime+100, leaveTime+200, channel.Id)
   278  	require.NoError(t, err)
   279  	assert.Len(t, channelMembers, 1)
   280  	assert.Equal(t, channel.Id, channelMembers[0].ChannelId)
   281  	assert.Equal(t, user.Id, channelMembers[0].UserId)
   282  	assert.Equal(t, user.Email, channelMembers[0].UserEmail)
   283  	assert.Equal(t, user.Username, channelMembers[0].Username)
   284  	assert.Equal(t, leaveTime+100, channelMembers[0].JoinTime)
   285  	assert.Equal(t, leaveTime+200, *channelMembers[0].LeaveTime)
   286  }
   287  
   288  func testPermanentDeleteBatch(t *testing.T, ss store.Store) {
   289  	// create a test channel
   290  	channel := &model.Channel{
   291  		TeamId:      model.NewId(),
   292  		DisplayName: "Display " + model.NewId(),
   293  		Name:        "zz" + model.NewId() + "b",
   294  		Type:        model.CHANNEL_OPEN,
   295  	}
   296  	channel, err := ss.Channel().Save(channel, -1)
   297  	require.NoError(t, err)
   298  
   299  	// and two test users
   300  	user := model.User{
   301  		Email:    MakeEmail(),
   302  		Nickname: model.NewId(),
   303  		Username: model.NewId(),
   304  	}
   305  	userPtr, err := ss.User().Save(&user)
   306  	require.NoError(t, err)
   307  	user = *userPtr
   308  
   309  	user2 := model.User{
   310  		Email:    MakeEmail(),
   311  		Nickname: model.NewId(),
   312  		Username: model.NewId(),
   313  	}
   314  	user2Ptr, err := ss.User().Save(&user2)
   315  	require.NoError(t, err)
   316  	user2 = *user2Ptr
   317  
   318  	// user1 joins and leaves the channel
   319  	leaveTime := model.GetMillis()
   320  	joinTime := leaveTime - 10000
   321  	err = ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, joinTime)
   322  	require.NoError(t, err)
   323  	err = ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, leaveTime)
   324  	require.NoError(t, err)
   325  
   326  	// user2 joins the channel but never leaves
   327  	err = ss.ChannelMemberHistory().LogJoinEvent(user2.Id, channel.Id, joinTime)
   328  	require.NoError(t, err)
   329  
   330  	// in between the join time and the leave time, both users were members of the channel
   331  	channelMembers, err := ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)
   332  	require.NoError(t, err)
   333  	assert.Len(t, channelMembers, 2)
   334  
   335  	// the permanent delete should delete at least one record
   336  	rowsDeleted, err := ss.ChannelMemberHistory().PermanentDeleteBatch(leaveTime, math.MaxInt64)
   337  	require.NoError(t, err)
   338  	assert.NotEqual(t, int64(0), rowsDeleted)
   339  
   340  	// after the delete, there should be one less member in the channel
   341  	channelMembers, err = ss.ChannelMemberHistory().GetUsersInChannelDuring(joinTime+10, leaveTime-10, channel.Id)
   342  	require.NoError(t, err)
   343  	assert.Len(t, channelMembers, 1)
   344  	assert.Equal(t, user2.Id, channelMembers[0].UserId)
   345  }