github.com/mad-app/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 }