package app import ( "testing" "github.com/mattermost/mattermost-server/model" ) func TestPopulateSyncablesSince(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() singersTeam, err := th.App.CreateTeam(&model.Team{ DisplayName: "Singers", Name: model.NewId(), Email: "singers@test.com", Type: model.TEAM_OPEN, }) if err != nil { t.Errorf("test team not created: %s", err.Error()) } nerdsTeam, err := th.App.CreateTeam(&model.Team{ DisplayName: "Nerds", Name: model.NewId(), Email: "nerds@test.com", Type: model.TEAM_INVITE, }) if err != nil { t.Errorf("test team not created: %s", err.Error()) } practiceChannel, err := th.App.CreateChannel(&model.Channel{ TeamId: singersTeam.Id, DisplayName: "Practices", Name: model.NewId(), Type: model.CHANNEL_OPEN, }, false) if err != nil { t.Errorf("test channel not created: %s", err.Error()) } experimentsChannel, err := th.App.CreateChannel(&model.Channel{ TeamId: singersTeam.Id, DisplayName: "Experiments", Name: model.NewId(), Type: model.CHANNEL_PRIVATE, }, false) if err != nil { t.Errorf("test channel not created: %s", err.Error()) } gleeGroup, err := th.App.CreateGroup(&model.Group{ Name: model.NewId(), DisplayName: "Glee Club", RemoteId: model.NewId(), Source: model.GroupSourceLdap, }) if err != nil { t.Errorf("test group not created: %s", err.Error()) } scienceGroup, err := th.App.CreateGroup(&model.Group{ Name: model.NewId(), DisplayName: "Science Club", RemoteId: model.NewId(), Source: model.GroupSourceLdap, }) if err != nil { t.Errorf("test group not created: %s", err.Error()) } _, err = th.App.CreateGroupSyncable(&model.GroupSyncable{ CanLeave: true, AutoAdd: true, GroupId: gleeGroup.Id, SyncableId: practiceChannel.Id, Type: model.GroupSyncableTypeChannel, }) if err != nil { t.Errorf("test groupchannel not created: %s", err.Error()) } scienceTeamGroupSyncable, err := th.App.CreateGroupSyncable(&model.GroupSyncable{ CanLeave: true, AutoAdd: false, GroupId: scienceGroup.Id, SyncableId: nerdsTeam.Id, Type: model.GroupSyncableTypeTeam, }) if err != nil { t.Errorf("test groupteam not created: %s", err.Error()) } scienceChannelGroupSyncable, err := th.App.CreateGroupSyncable(&model.GroupSyncable{ CanLeave: true, AutoAdd: false, GroupId: scienceGroup.Id, SyncableId: experimentsChannel.Id, Type: model.GroupSyncableTypeChannel, }) if err != nil { t.Errorf("test groupchannel not created: %s", err.Error()) } singer1 := th.BasicUser scientist1 := th.BasicUser2 _, err = th.App.CreateOrRestoreGroupMember(gleeGroup.Id, singer1.Id) if err != nil { t.Errorf("test groupmember not created: %s", err.Error()) } scientistGroupMember, err := th.App.CreateOrRestoreGroupMember(scienceGroup.Id, scientist1.Id) if err != nil { t.Errorf("test groupmember not created: %s", err.Error()) } pErr := th.App.PopulateSyncablesSince(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } // Singer should be in team and channel _, err = th.App.GetTeamMember(singersTeam.Id, singer1.Id) if err != nil { t.Errorf("error retrieving team member: %s", err.Error()) } _, err = th.App.GetChannelMember(practiceChannel.Id, singer1.Id) if err != nil { t.Errorf("error retrieving channel member: %s", err.Error()) } tMembers, err := th.App.GetTeamMembers(singersTeam.Id, 0, 999) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } expected := 1 actual := len(tMembers) if actual != expected { t.Errorf("expected %d team members but got %d", expected, actual) } cMembersCount, err := th.App.GetChannelMemberCount(practiceChannel.Id) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } if cMembersCount != int64(expected) { t.Errorf("expected %d team member but got %d", expected, cMembersCount) } // Scientist should not be in team or channel _, err = th.App.GetTeamMember(nerdsTeam.Id, scientist1.Id) if err.Id != "store.sql_team.get_member.missing.app_error" { t.Errorf("wrong error: %s", err.Id) } _, err = th.App.GetChannelMember(experimentsChannel.Id, scientist1.Id) if err.Id != "store.sql_channel.get_member.missing.app_error" { t.Errorf("wrong error: %s", err.Id) } tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } expected = 0 actual = len(tMembers) if actual != expected { t.Errorf("expected %d team members but got %d", expected, actual) } cMembersCount, err = th.App.GetChannelMemberCount(experimentsChannel.Id) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } if cMembersCount != int64(expected) { t.Errorf("expected %d team members but got %d", expected, cMembersCount) } // update AutoAdd to true scienceTeamGroupSyncable.AutoAdd = true scienceTeamGroupSyncable, err = th.App.UpdateGroupSyncable(scienceTeamGroupSyncable) if err != nil { t.Errorf("error updating group syncable: %s", err.Error()) } // Sync everything after syncable was created (proving that team updates trigger re-sync) pErr = th.App.PopulateSyncablesSince(scientistGroupMember.CreateAt + 1) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } // Scientist should be in team but not the channel _, err = th.App.GetTeamMember(nerdsTeam.Id, scientist1.Id) if err != nil { t.Errorf("error retrieving team member: %s", err.Error()) } _, err = th.App.GetChannelMember(experimentsChannel.Id, scientist1.Id) if err.Id != "store.sql_channel.get_member.missing.app_error" { t.Errorf("wrong error: %s", err.Id) } tMembers, err = th.App.GetTeamMembers(nerdsTeam.Id, 0, 999) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } expected = 1 actual = len(tMembers) if actual != expected { t.Errorf("expected %d team members but got %d", expected, actual) } expected = 0 cMembersCount, err = th.App.GetChannelMemberCount(experimentsChannel.Id) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } if cMembersCount != int64(expected) { t.Errorf("expected %d team members but got %d", expected, cMembersCount) } // Update the channel syncable scienceChannelGroupSyncable.AutoAdd = true scienceChannelGroupSyncable, err = th.App.UpdateGroupSyncable(scienceChannelGroupSyncable) if err != nil { t.Errorf("error updating group syncable: %s", err.Error()) } // Sync everything after syncable was created (proving that channel updates trigger re-sync) pErr = th.App.PopulateSyncablesSince(scientistGroupMember.CreateAt + 1) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } expected = 1 cMembersCount, err = th.App.GetChannelMemberCount(experimentsChannel.Id) if err != nil { t.Errorf("error retrieving team members: %s", err.Error()) } if cMembersCount != int64(expected) { t.Errorf("expected %d team members but got %d", expected, cMembersCount) } // singer leaves team and channel err = th.App.LeaveChannel(practiceChannel.Id, singer1.Id) if err != nil { t.Errorf("error leaving channel: %s", err.Error()) } err = th.App.LeaveTeam(singersTeam, singer1, "") if err != nil { t.Errorf("error leaving team: %s", err.Error()) } // Even re-syncing from the beginning doesn't re-add to channel or team pErr = th.App.PopulateSyncablesSince(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } // Singer should not be in team or channel tMember, err := th.App.GetTeamMember(singersTeam.Id, singer1.Id) if err != nil { t.Errorf("error retrieving team member: %s", err.Error()) } if tMember.DeleteAt == 0 { t.Error("expected team member to remain deleted") } _, err = th.App.GetChannelMember(practiceChannel.Id, singer1.Id) if err == nil { t.Error("Expected channel member to remain deleted") } // Ensure members are in channel _, err = th.App.AddChannelMember(scientist1.Id, experimentsChannel, "", "", false) if err != nil { t.Errorf("unable to add user to channel: %s", err.Error()) } // Add other user so that user can leave channel _, err = th.App.AddTeamMember(singersTeam.Id, singer1.Id) if err != nil { t.Errorf("unable to add user to team: %s", err.Error()) } _, err = th.App.AddChannelMember(singer1.Id, experimentsChannel, "", "", false) if err != nil { t.Errorf("unable to add user to channel: %s", err.Error()) } // the channel syncable is updated scienceChannelGroupSyncable.CanLeave = false scienceChannelGroupSyncable, err = th.App.UpdateGroupSyncable(scienceChannelGroupSyncable) if err != nil { t.Errorf("error updating group syncable: %s", err.Error()) } pErr = th.App.PopulateSyncablesSince(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } timeBeforeLeaving := model.GetMillis() // User leaves channel err = th.App.LeaveChannel(experimentsChannel.Id, scientist1.Id) if err != nil { t.Errorf("unable to add user to channel: %s", err.Error()) } timeAfterLeaving := model.GetMillis() // Purging channelmemberhistory doesn't re-add user to channel result := <-th.App.Srv.Store.ChannelMemberHistory().PermanentDeleteBatch(timeBeforeLeaving, 1000) if result.Err != nil { t.Errorf("error permanently deleting channelmemberhistory: %s", result.Err.Error()) } pErr = th.App.PopulateSyncablesSince(scienceChannelGroupSyncable.UpdateAt) if pErr != nil { t.Errorf("failed to populate syncables: %s", pErr.Error()) } _, err = th.App.GetChannelMember(experimentsChannel.Id, scientist1.Id) if err == nil { t.Error("Expected channel member to remain deleted") } // Purging channelmemberhistory doesn't re-add user to channel result = <-th.App.Srv.Jobs.Store.ChannelMemberHistory().PermanentDeleteBatch(timeAfterLeaving, 1000) if result.Err != nil { t.Errorf("error permanently deleting channelmemberhistory: %s", result.Err.Error()) } pErr = th.App.PopulateSyncablesSince(scienceChannelGroupSyncable.UpdateAt) if pErr != nil { t.Errorf("failed to populate syncables: %s", pErr.Error()) } // Channel member is re-added. _, err = th.App.GetChannelMember(experimentsChannel.Id, scientist1.Id) if err != nil { t.Errorf("expected channel member: %s", err.Error()) } }