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 }