github.com/xzl8028/xenia-server@v0.0.0-20190809101854-18450a97da63/store/storetest/channel_member_history_store.go (about)

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