github.com/teloshs/mattermost-server@v5.11.1+incompatible/store/storetest/channel_member_history_store.go (about)

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