From 25fd96201638488f4c2a802181a4a70238287186 Mon Sep 17 00:00:00 2001 From: Martin Kraft Date: Tue, 2 Apr 2019 09:22:50 -0400 Subject: [PATCH] MM-14412: Enables force removals of team/channel members base on group constraints. (#10490) * MM-14412: Enables force removals of team/channel members base on group constraints. * Renames some existing methods and variables. * Change return types to ChannelMembers and TeamMembers for some existing methods. * Adds option to change LDAP_DATA to either 'qa' or 'test' with env variable. * Adds methods to retrieve ChannelMembers and TeamMembers that, based on group constraints, should be deleted. * Adds helper functions to create GroupTeams and GroupChannels. * MM-14412: Switches to helper methods for GroupSyncable creation in test files. * MM-14412: Style fix. * MM-14412: Switches remaining GroupSyncable instances to be created with helper functions. * MM-14412: Typo fix. * MM-11412: Build fixes. * MM-14412: Checks if user is team member before re-adding. * MM-14412: Update for change of GroupConstrained fields type. --- Makefile | 7 +- app/group.go | 24 +- app/group_test.go | 28 +- app/syncables.go | 78 +- app/syncables_test.go | 105 +- app/team.go | 1 + build/Jenkinsfile.pr | 4 +- build/docker-compose.yml | 4 +- i18n/en.json | 4 + model/group_syncable.go | 18 + store/layered_store.go | 20 +- store/layered_store_supplier.go | 7 +- store/local_cache_supplier_groups.go | 16 +- store/redis_supplier_groups.go | 18 +- store/sqlstore/group_supplier.go | 113 +- store/sqlstore/upgrade.go | 3 + store/store.go | 7 +- store/storetest/group_supplier.go | 1025 ++++++++++------- store/storetest/mocks/GroupStore.go | 48 +- .../mocks/LayeredStoreDatabaseLayer.go | 62 +- store/storetest/mocks/LayeredStoreSupplier.go | 62 +- tests/add-groups.ldif | 81 -- tests/{add-users.ldif => test-data.ldif} | 84 +- 23 files changed, 1212 insertions(+), 607 deletions(-) delete mode 100644 tests/add-groups.ldif rename tests/{add-users.ldif => test-data.ldif} (50%) diff --git a/Makefile b/Makefile index 53e2c119b2..a33e963912 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ BUILD_ENTERPRISE ?= true BUILD_ENTERPRISE_READY = false BUILD_TYPE_NAME = team BUILD_HASH_ENTERPRISE = none +LDAP_DATA ?= test ifneq ($(wildcard $(BUILD_ENTERPRISE_DIR)/.),) ifeq ($(BUILD_ENTERPRISE),true) BUILD_ENTERPRISE_READY = true @@ -157,11 +158,9 @@ ifeq ($(BUILD_ENTERPRISE_READY),true) -e LDAP_ADMIN_PASSWORD="mostest" \ -d osixia/openldap:1.2.2 > /dev/null;\ sleep 10; \ - docker cp tests/add-users.ldif mattermost-openldap:/add-users.ldif;\ - docker cp tests/add-groups.ldif mattermost-openldap:/add-groups.ldif;\ + docker cp tests/test-data.ldif mattermost-openldap:/test-data.ldif;\ docker cp tests/qa-data.ldif mattermost-openldap:/qa-data.ldif;\ - docker exec -ti mattermost-openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /add-users.ldif';\ - docker exec -ti mattermost-openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /add-groups.ldif';\ + docker exec -ti mattermost-openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /$(LDAP_DATA)-data.ldif';\ elif [ $(shell docker ps | grep -ci mattermost-openldap) -eq 0 ]; then \ echo restarting mattermost-openldap; \ docker start mattermost-openldap > /dev/null; \ diff --git a/app/group.go b/app/group.go index 102e5d2a0f..a8b14f6fa6 100644 --- a/app/group.go +++ b/app/group.go @@ -133,18 +133,34 @@ func (a *App) DeleteGroupSyncable(groupID string, syncableID string, syncableTyp return result.Data.(*model.GroupSyncable), nil } -func (a *App) PendingAutoAddTeamMembers(minGroupMembersCreateAt int64) ([]*model.UserTeamIDPair, *model.AppError) { - result := <-a.Srv.Store.Group().PendingAutoAddTeamMembers(minGroupMembersCreateAt) +func (a *App) TeamMembersToAdd(since int64) ([]*model.UserTeamIDPair, *model.AppError) { + result := <-a.Srv.Store.Group().TeamMembersToAdd(since) if result.Err != nil { return nil, result.Err } return result.Data.([]*model.UserTeamIDPair), nil } -func (a *App) PendingAutoAddChannelMembers(minGroupMembersCreateAt int64) ([]*model.UserChannelIDPair, *model.AppError) { - result := <-a.Srv.Store.Group().PendingAutoAddChannelMembers(minGroupMembersCreateAt) +func (a *App) ChannelMembersToAdd(since int64) ([]*model.UserChannelIDPair, *model.AppError) { + result := <-a.Srv.Store.Group().ChannelMembersToAdd(since) if result.Err != nil { return nil, result.Err } return result.Data.([]*model.UserChannelIDPair), nil } + +func (a *App) TeamMembersToRemove() ([]*model.TeamMember, *model.AppError) { + result := <-a.Srv.Store.Group().TeamMembersToRemove() + if result.Err != nil { + return nil, result.Err + } + return result.Data.([]*model.TeamMember), nil +} + +func (a *App) ChannelMembersToRemove() ([]*model.ChannelMember, *model.AppError) { + result := <-a.Srv.Store.Group().ChannelMembersToRemove() + if result.Err != nil { + return nil, result.Err + } + return result.Data.([]*model.ChannelMember), nil +} diff --git a/app/group_test.go b/app/group_test.go index 50c28d39af..60afa3f008 100644 --- a/app/group_test.go +++ b/app/group_test.go @@ -135,12 +135,7 @@ func TestCreateGroupSyncable(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() group := th.CreateGroup() - groupSyncable := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: th.BasicTeam.Id, - Type: model.GroupSyncableTypeTeam, - } + groupSyncable := model.NewGroupTeam(group.Id, th.BasicTeam.Id, false) gs, err := th.App.CreateGroupSyncable(groupSyncable) require.Nil(t, err) @@ -155,12 +150,7 @@ func TestGetGroupSyncable(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() group := th.CreateGroup() - groupSyncable := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: th.BasicTeam.Id, - Type: model.GroupSyncableTypeTeam, - } + groupSyncable := model.NewGroupTeam(group.Id, th.BasicTeam.Id, false) gs, err := th.App.CreateGroupSyncable(groupSyncable) require.Nil(t, err) @@ -177,12 +167,7 @@ func TestGetGroupSyncables(t *testing.T) { group := th.CreateGroup() // Create a group team - groupSyncable := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: th.BasicTeam.Id, - Type: model.GroupSyncableTypeTeam, - } + groupSyncable := model.NewGroupTeam(group.Id, th.BasicTeam.Id, false) gs, err := th.App.CreateGroupSyncable(groupSyncable) require.Nil(t, err) @@ -198,12 +183,7 @@ func TestDeleteGroupSyncable(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() group := th.CreateGroup() - groupChannel := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: th.BasicChannel.Id, - Type: model.GroupSyncableTypeChannel, - } + groupChannel := model.NewGroupChannel(group.Id, th.BasicChannel.Id, false) gs, err := th.App.CreateGroupSyncable(groupChannel) require.Nil(t, err) diff --git a/app/syncables.go b/app/syncables.go index 0d04ff6441..50d7a4f977 100644 --- a/app/syncables.go +++ b/app/syncables.go @@ -7,15 +7,15 @@ import ( "github.com/mattermost/mattermost-server/mlog" ) -// PopulateSyncablesSince adds users to teams and channels based on their group memberships and how those groups are +// CreateDefaultMemberships adds users to teams and channels based on their group memberships and how those groups are // configured to sync with teams and channels for group members on or after the given timestamp. -func (a *App) PopulateSyncablesSince(groupMembersCreatedAfter int64) error { - userTeamIDs, appErr := a.PendingAutoAddTeamMembers(groupMembersCreatedAfter) +func (a *App) CreateDefaultMemberships(since int64) error { + teamMembers, appErr := a.TeamMembersToAdd(since) if appErr != nil { return appErr } - for _, userTeam := range userTeamIDs { + for _, userTeam := range teamMembers { _, err := a.AddTeamMember(userTeam.TeamID, userTeam.UserID) if err != nil { return err @@ -27,26 +27,33 @@ func (a *App) PopulateSyncablesSince(groupMembersCreatedAfter int64) error { ) } - userChannelIDs, appErr := a.PendingAutoAddChannelMembers(groupMembersCreatedAfter) + channelMembers, appErr := a.ChannelMembersToAdd(since) if appErr != nil { return appErr } - for _, userChannel := range userChannelIDs { + for _, userChannel := range channelMembers { channel, err := a.GetChannel(userChannel.ChannelID) if err != nil { return err } - // First add user to team - _, err = a.AddTeamMember(channel.TeamId, userChannel.UserID) - if err != nil { + tmem, err := a.GetTeamMember(channel.TeamId, userChannel.UserID) + if err != nil && err.Id != "store.sql_team.get_member.missing.app_error" { return err } - a.Log.Info("added teammember", - mlog.String("user_id", userChannel.UserID), - mlog.String("team_id", channel.TeamId), - ) + + // First add user to team + if tmem == nil { + _, err = a.AddTeamMember(channel.TeamId, userChannel.UserID) + if err != nil { + return err + } + a.Log.Info("added teammember", + mlog.String("user_id", userChannel.UserID), + mlog.String("team_id", channel.TeamId), + ) + } _, err = a.AddChannelMember(userChannel.UserID, channel, "", "", "") if err != nil { @@ -61,3 +68,48 @@ func (a *App) PopulateSyncablesSince(groupMembersCreatedAfter int64) error { return nil } + +// DeleteGroupConstrainedMemberships deletes team and channel memberships of users who aren't members of the allowed +// groups of all group-constrained teams and channels. +func (a *App) DeleteGroupConstrainedMemberships() error { + channelMembers, appErr := a.ChannelMembersToRemove() + if appErr != nil { + return appErr + } + + for _, userChannel := range channelMembers { + channel, err := a.GetChannel(userChannel.ChannelId) + if err != nil { + return err + } + + err = a.RemoveUserFromChannel(userChannel.UserId, "", channel) + if err != nil { + return err + } + + a.Log.Info("removed channelmember", + mlog.String("user_id", userChannel.UserId), + mlog.String("channel_id", channel.Id), + ) + } + + teamMembers, appErr := a.TeamMembersToRemove() + if appErr != nil { + return appErr + } + + for _, userTeam := range teamMembers { + err := a.RemoveUserFromTeam(userTeam.TeamId, userTeam.UserId, "") + if err != nil { + return err + } + + a.Log.Info("removed teammember", + mlog.String("user_id", userTeam.UserId), + mlog.String("team_id", userTeam.TeamId), + ) + } + + return nil +} diff --git a/app/syncables_test.go b/app/syncables_test.go index bf2a676d2e..cca329d4e1 100644 --- a/app/syncables_test.go +++ b/app/syncables_test.go @@ -4,9 +4,10 @@ import ( "testing" "github.com/mattermost/mattermost-server/model" + "github.com/stretchr/testify/require" ) -func TestPopulateSyncablesSince(t *testing.T) { +func TestCreateDefaultMemberships(t *testing.T) { th := Setup(t).InitBasic() defer th.TearDown() @@ -70,32 +71,17 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("test group not created: %s", err.Error()) } - _, err = th.App.CreateGroupSyncable(&model.GroupSyncable{ - AutoAdd: true, - GroupId: gleeGroup.Id, - SyncableId: practiceChannel.Id, - Type: model.GroupSyncableTypeChannel, - }) + _, err = th.App.CreateGroupSyncable(model.NewGroupChannel(gleeGroup.Id, practiceChannel.Id, true)) if err != nil { t.Errorf("test groupchannel not created: %s", err.Error()) } - scienceTeamGroupSyncable, err := th.App.CreateGroupSyncable(&model.GroupSyncable{ - AutoAdd: false, - GroupId: scienceGroup.Id, - SyncableId: nerdsTeam.Id, - Type: model.GroupSyncableTypeTeam, - }) + scienceTeamGroupSyncable, err := th.App.CreateGroupSyncable(model.NewGroupTeam(scienceGroup.Id, nerdsTeam.Id, false)) if err != nil { t.Errorf("test groupteam not created: %s", err.Error()) } - scienceChannelGroupSyncable, err := th.App.CreateGroupSyncable(&model.GroupSyncable{ - AutoAdd: false, - GroupId: scienceGroup.Id, - SyncableId: experimentsChannel.Id, - Type: model.GroupSyncableTypeChannel, - }) + scienceChannelGroupSyncable, err := th.App.CreateGroupSyncable(model.NewGroupChannel(scienceGroup.Id, experimentsChannel.Id, false)) if err != nil { t.Errorf("test groupchannel not created: %s", err.Error()) } @@ -113,7 +99,7 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("test groupmember not created: %s", err.Error()) } - pErr := th.App.PopulateSyncablesSince(0) + pErr := th.App.CreateDefaultMemberships(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } @@ -183,7 +169,7 @@ func TestPopulateSyncablesSince(t *testing.T) { } // Sync everything after syncable was created (proving that team updates trigger re-sync) - pErr = th.App.PopulateSyncablesSince(scientistGroupMember.CreateAt + 1) + pErr = th.App.CreateDefaultMemberships(scientistGroupMember.CreateAt + 1) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } @@ -226,7 +212,7 @@ func TestPopulateSyncablesSince(t *testing.T) { } // Sync everything after syncable was created (proving that channel updates trigger re-sync) - pErr = th.App.PopulateSyncablesSince(scientistGroupMember.CreateAt + 1) + pErr = th.App.CreateDefaultMemberships(scientistGroupMember.CreateAt + 1) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } @@ -251,7 +237,7 @@ func TestPopulateSyncablesSince(t *testing.T) { } // Even re-syncing from the beginning doesn't re-add to channel or team - pErr = th.App.PopulateSyncablesSince(0) + pErr = th.App.CreateDefaultMemberships(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } @@ -292,7 +278,7 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("error updating group syncable: %s", err.Error()) } - pErr = th.App.PopulateSyncablesSince(0) + pErr = th.App.CreateDefaultMemberships(0) if pErr != nil { t.Errorf("faild to populate syncables: %s", pErr.Error()) } @@ -313,7 +299,7 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("error permanently deleting channelmemberhistory: %s", result.Err.Error()) } - pErr = th.App.PopulateSyncablesSince(scienceChannelGroupSyncable.UpdateAt) + pErr = th.App.CreateDefaultMemberships(scienceChannelGroupSyncable.UpdateAt) if pErr != nil { t.Errorf("failed to populate syncables: %s", pErr.Error()) } @@ -329,7 +315,7 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("error permanently deleting channelmemberhistory: %s", result.Err.Error()) } - pErr = th.App.PopulateSyncablesSince(scienceChannelGroupSyncable.UpdateAt) + pErr = th.App.CreateDefaultMemberships(scienceChannelGroupSyncable.UpdateAt) if pErr != nil { t.Errorf("failed to populate syncables: %s", pErr.Error()) } @@ -340,3 +326,70 @@ func TestPopulateSyncablesSince(t *testing.T) { t.Errorf("expected channel member: %s", err.Error()) } } + +func TestDeleteGroupMemberships(t *testing.T) { + th := Setup(t).InitBasic() + defer th.TearDown() + + group := th.CreateGroup() + + userIDs := []string{th.BasicUser.Id, th.BasicUser2.Id, th.SystemAdminUser.Id} + + var err *model.AppError + // add users to teams and channels + for _, userID := range userIDs { + _, err = th.App.AddTeamMember(th.BasicTeam.Id, userID) + require.Nil(t, err) + + _, err = th.App.AddChannelMember(userID, th.BasicChannel, "", "", "") + require.Nil(t, err) + } + + // make team group-constrained + team := th.BasicTeam + team.GroupConstrained = model.NewBool(true) + team, err = th.App.UpdateTeam(team) + require.Nil(t, err) + require.True(t, *team.GroupConstrained) + + // make channel group-constrained + channel := th.BasicChannel + channel.GroupConstrained = model.NewBool(true) + channel, err = th.App.UpdateChannel(channel) + require.Nil(t, err) + require.True(t, *channel.GroupConstrained) + + // create groupteam and groupchannel + _, err = th.App.CreateGroupSyncable(model.NewGroupTeam(group.Id, team.Id, true)) + require.Nil(t, err) + _, err = th.App.CreateGroupSyncable(model.NewGroupChannel(group.Id, channel.Id, true)) + require.Nil(t, err) + + // verify the member count + tmembers, err := th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100) + require.Nil(t, err) + require.Len(t, tmembers, 3) + + cmemberCount, err := th.App.GetChannelMemberCount(th.BasicChannel.Id) + require.Nil(t, err) + require.Equal(t, 3, int(cmemberCount)) + + // add a user to the group + _, err = th.App.CreateOrRestoreGroupMember(group.Id, th.SystemAdminUser.Id) + require.Nil(t, err) + + // run the delete + appErr := th.App.DeleteGroupConstrainedMemberships() + require.Nil(t, appErr) + + // verify the new member counts + tmembers, err = th.App.GetTeamMembers(th.BasicTeam.Id, 0, 100) + require.Nil(t, err) + require.Len(t, tmembers, 1) + require.Equal(t, th.SystemAdminUser.Id, tmembers[0].UserId) + + cmembers, err := th.App.GetChannelMembersPage(channel.Id, 0, 99) + require.Nil(t, err) + require.Len(t, (*cmembers), 1) + require.Equal(t, th.SystemAdminUser.Id, (*cmembers)[0].UserId) +} diff --git a/app/team.go b/app/team.go index 67293dd0fe..cf81cb877f 100644 --- a/app/team.go +++ b/app/team.go @@ -122,6 +122,7 @@ func (a *App) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) { oldTeam.CompanyName = team.CompanyName oldTeam.AllowedDomains = team.AllowedDomains oldTeam.LastTeamIconUpdate = team.LastTeamIconUpdate + oldTeam.GroupConstrained = team.GroupConstrained oldTeam, err = a.updateTeamUnsanitized(oldTeam) if err != nil { diff --git a/build/Jenkinsfile.pr b/build/Jenkinsfile.pr index a119ddecb2..2b84380769 100644 --- a/build/Jenkinsfile.pr +++ b/build/Jenkinsfile.pr @@ -108,6 +108,7 @@ pipeline { MM_EMAILSETTINGS_SMTPSERVER = "inbucket" MM_EMAILSETTINGS_SMTPPORT = "10025" MM_ELASTICSEARCHSETTINGS_CONNECTIONURL = "http://elasticsearch:9200" + LDAP_DATA = "test" } steps { @@ -116,8 +117,7 @@ pipeline { sh """ docker-compose --no-ansi run --rm start_dependencies docker-compose --no-ansi ps - docker-compose --no-ansi exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /add-users.ldif'; - docker-compose --no-ansi exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /add-groups.ldif'; + docker-compose --no-ansi exec -T openldap bash -c 'ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest -f /${LDAP_DATA}-data.ldif'; """ } } diff --git a/build/docker-compose.yml b/build/docker-compose.yml index bac8ff7179..2a0900f947 100644 --- a/build/docker-compose.yml +++ b/build/docker-compose.yml @@ -48,8 +48,8 @@ services: LDAP_DOMAIN: "mm.test.com" LDAP_ADMIN_PASSWORD: "mostest" volumes: - - "../tests/add-users.ldif:/add-users.ldif" - - "../tests/add-groups.ldif:/add-groups.ldif" + - "../tests/test-data.ldif:/test-data.ldif" + - "../tests/qa-data.ldif:/qa-data.ldif" elasticsearch: image: "mattermost/mattermost-elasticsearch-docker:6.5.1" networks: diff --git a/i18n/en.json b/i18n/en.json index 8b4046c0f5..6678fbc8dc 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -6982,6 +6982,10 @@ "id": "ent.ldap.syncronize.populate_syncables", "translation": "error populating syncables" }, + { + "id": "ent.ldap.syncronize.delete_group_constained_memberships", + "translation": "error deleting team or channel memberships" + }, { "id": "model.group.create_at.app_error", "translation": "invalid create at property for group" diff --git a/model/group_syncable.go b/model/group_syncable.go index 8466084893..038164f217 100644 --- a/model/group_syncable.go +++ b/model/group_syncable.go @@ -155,3 +155,21 @@ func GroupSyncablesFromJson(data io.Reader) []*GroupSyncable { json.Unmarshal(bodyBytes, &groupSyncables) return groupSyncables } + +func NewGroupTeam(groupID, teamID string, autoAdd bool) *GroupSyncable { + return &GroupSyncable{ + GroupId: groupID, + SyncableId: teamID, + Type: GroupSyncableTypeTeam, + AutoAdd: autoAdd, + } +} + +func NewGroupChannel(groupID, channelID string, autoAdd bool) *GroupSyncable { + return &GroupSyncable{ + GroupId: groupID, + SyncableId: channelID, + Type: GroupSyncableTypeChannel, + AutoAdd: autoAdd, + } +} diff --git a/store/layered_store.go b/store/layered_store.go index d8d2753c1f..70d72be571 100644 --- a/store/layered_store.go +++ b/store/layered_store.go @@ -454,14 +454,26 @@ func (s *LayeredGroupStore) DeleteGroupSyncable(groupID string, syncableID strin }) } -func (s *LayeredGroupStore) PendingAutoAddTeamMembers(minGroupMembersCreateAt int64) StoreChannel { +func (s *LayeredGroupStore) TeamMembersToAdd(since int64) StoreChannel { return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { - return supplier.PendingAutoAddTeamMembers(s.TmpContext, minGroupMembersCreateAt) + return supplier.TeamMembersToAdd(s.TmpContext, since) }) } -func (s *LayeredGroupStore) PendingAutoAddChannelMembers(minGroupMembersCreateAt int64) StoreChannel { +func (s *LayeredGroupStore) ChannelMembersToAdd(since int64) StoreChannel { return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { - return supplier.PendingAutoAddChannelMembers(s.TmpContext, minGroupMembersCreateAt) + return supplier.ChannelMembersToAdd(s.TmpContext, since) + }) +} + +func (s *LayeredGroupStore) TeamMembersToRemove() StoreChannel { + return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { + return supplier.TeamMembersToRemove(s.TmpContext) + }) +} + +func (s *LayeredGroupStore) ChannelMembersToRemove() StoreChannel { + return s.RunQuery(func(supplier LayeredStoreSupplier) *LayeredStoreSupplierResult { + return supplier.ChannelMembersToRemove(s.TmpContext) }) } diff --git a/store/layered_store_supplier.go b/store/layered_store_supplier.go index b1b075b5b9..3487806a63 100644 --- a/store/layered_store_supplier.go +++ b/store/layered_store_supplier.go @@ -68,6 +68,9 @@ type LayeredStoreSupplier interface { GroupUpdateGroupSyncable(ctx context.Context, groupSyncable *model.GroupSyncable, hints ...LayeredStoreHint) *LayeredStoreSupplierResult GroupDeleteGroupSyncable(ctx context.Context, groupID string, syncableID string, syncableType model.GroupSyncableType, hints ...LayeredStoreHint) *LayeredStoreSupplierResult - PendingAutoAddTeamMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult - PendingAutoAddChannelMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + TeamMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + ChannelMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + + TeamMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult + ChannelMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult } diff --git a/store/local_cache_supplier_groups.go b/store/local_cache_supplier_groups.go index 4bedbb7cca..2d62193bed 100644 --- a/store/local_cache_supplier_groups.go +++ b/store/local_cache_supplier_groups.go @@ -93,10 +93,18 @@ func (s *LocalCacheSupplier) GroupDeleteGroupSyncable(ctx context.Context, group return s.Next().GroupDeleteGroupSyncable(ctx, groupID, syncableID, syncableType, hints...) } -func (s *LocalCacheSupplier) PendingAutoAddTeamMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { - return s.Next().PendingAutoAddTeamMembers(ctx, minGroupMembersCreateAt, hints...) +func (s *LocalCacheSupplier) TeamMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().TeamMembersToAdd(ctx, since, hints...) } -func (s *LocalCacheSupplier) PendingAutoAddChannelMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { - return s.Next().PendingAutoAddChannelMembers(ctx, minGroupMembersCreateAt, hints...) +func (s *LocalCacheSupplier) ChannelMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().ChannelMembersToAdd(ctx, since, hints...) +} + +func (s *LocalCacheSupplier) TeamMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().TeamMembersToRemove(ctx, hints...) +} + +func (s *LocalCacheSupplier) ChannelMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + return s.Next().ChannelMembersToRemove(ctx, hints...) } diff --git a/store/redis_supplier_groups.go b/store/redis_supplier_groups.go index ee8bcb04ae..e057a20c75 100644 --- a/store/redis_supplier_groups.go +++ b/store/redis_supplier_groups.go @@ -89,12 +89,22 @@ func (s *RedisSupplier) GroupDeleteGroupSyncable(ctx context.Context, groupID st return s.Next().GroupDeleteGroupSyncable(ctx, groupID, syncableID, syncableType, hints...) } -func (s *RedisSupplier) PendingAutoAddTeamMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { +func (s *RedisSupplier) TeamMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { // TODO: Redis caching. - return s.Next().PendingAutoAddTeamMembers(ctx, minGroupMembersCreateAt, hints...) + return s.Next().TeamMembersToAdd(ctx, since, hints...) } -func (s *RedisSupplier) PendingAutoAddChannelMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { +func (s *RedisSupplier) ChannelMembersToAdd(ctx context.Context, since int64, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { // TODO: Redis caching. - return s.Next().PendingAutoAddChannelMembers(ctx, minGroupMembersCreateAt, hints...) + return s.Next().ChannelMembersToAdd(ctx, since, hints...) +} + +func (s *RedisSupplier) TeamMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // TODO: Redis caching. + return s.Next().TeamMembersToRemove(ctx, hints...) +} + +func (s *RedisSupplier) ChannelMembersToRemove(ctx context.Context, hints ...LayeredStoreHint) *LayeredStoreSupplierResult { + // TODO: Redis caching. + return s.Next().ChannelMembersToRemove(ctx, hints...) } diff --git a/store/sqlstore/group_supplier.go b/store/sqlstore/group_supplier.go index b8b17f7e76..11b05fa2d0 100644 --- a/store/sqlstore/group_supplier.go +++ b/store/sqlstore/group_supplier.go @@ -668,11 +668,11 @@ func (s *SqlSupplier) GroupDeleteGroupSyncable(ctx context.Context, groupID stri return result } -// PendingAutoAddTeamMembers returns a slice of UserTeamIDPair that need newly created memberships +// TeamMembersToAdd returns a slice of UserTeamIDPair that need newly created memberships // based on the groups configurations. // // Typically since will be the last successful group sync time. -func (s *SqlSupplier) PendingAutoAddTeamMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +func (s *SqlSupplier) TeamMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { result := store.NewSupplierResult() sql := ` @@ -698,23 +698,23 @@ func (s *SqlSupplier) PendingAutoAddTeamMembers(ctx context.Context, since int64 AND (GroupMembers.CreateAt >= :Since OR GroupTeams.UpdateAt >= :Since)` - var userTeamIDs []*model.UserTeamIDPair + var teamMembers []*model.UserTeamIDPair - _, err := s.GetMaster().Select(&userTeamIDs, sql, map[string]interface{}{"Since": since}) + _, err := s.GetReplica().Select(&teamMembers, sql, map[string]interface{}{"Since": since}) if err != nil { - result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddTeamMembers", "store.select_error", nil, err.Error(), http.StatusInternalServerError) + result.Err = model.NewAppError("SqlGroupStore.TeamMembersToAdd", "store.select_error", nil, err.Error(), http.StatusInternalServerError) } - result.Data = userTeamIDs + result.Data = teamMembers return result } -// PendingAutoAddChannelMembers returns a slice of UserChannelIDPair that need newly created memberships +// ChannelMembersToAdd returns a slice of UserChannelIDPair that need newly created memberships // based on the groups configurations. // // Typically since will be the last successful group sync time. -func (s *SqlSupplier) PendingAutoAddChannelMembers(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +func (s *SqlSupplier) ChannelMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { result := store.NewSupplierResult() sql := ` @@ -740,14 +740,14 @@ func (s *SqlSupplier) PendingAutoAddChannelMembers(ctx context.Context, since in AND (GroupMembers.CreateAt >= :Since OR GroupChannels.UpdateAt >= :Since)` - var userChannelIDs []*model.UserChannelIDPair + var channelMembers []*model.UserChannelIDPair - _, err := s.GetMaster().Select(&userChannelIDs, sql, map[string]interface{}{"Since": since}) + _, err := s.GetReplica().Select(&channelMembers, sql, map[string]interface{}{"Since": since}) if err != nil { - result.Err = model.NewAppError("SqlGroupStore.PendingAutoAddChannelMembers", "store.select_error", nil, "", http.StatusInternalServerError) + result.Err = model.NewAppError("SqlGroupStore.ChannelMembersToAdd", "store.select_error", nil, "", http.StatusInternalServerError) } - result.Data = userChannelIDs + result.Data = channelMembers return result } @@ -765,3 +765,92 @@ func groupSyncableToGroupChannel(groupSyncable *model.GroupSyncable) *groupChann ChannelId: groupSyncable.SyncableId, } } + +// TeamMembersToRemove returns all team members that should be removed based on group constraints. +func (s *SqlSupplier) TeamMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + result := store.NewSupplierResult() + + sql := ` + SELECT + TeamMembers.* + FROM + TeamMembers + JOIN Teams ON Teams.Id = TeamMembers.TeamId + WHERE + TeamMembers.DeleteAt = 0 + AND Teams.DeleteAt = 0 + AND Teams.GroupConstrained = TRUE + AND (TeamMembers.TeamId, TeamMembers.UserId) + NOT IN ( + SELECT + Teams.Id AS TeamId, GroupMembers.UserId + FROM + Teams + JOIN GroupTeams ON GroupTeams.TeamId = Teams.Id + JOIN UserGroups ON UserGroups.Id = GroupTeams.GroupId + JOIN GroupMembers ON GroupMembers.GroupId = UserGroups.Id + WHERE + Teams.GroupConstrained = TRUE + AND GroupTeams.DeleteAt = 0 + AND UserGroups.DeleteAt = 0 + AND Teams.DeleteAt = 0 + AND GroupMembers.DeleteAt = 0 + GROUP BY + Teams.Id, + GroupMembers.UserId)` + + var teamMembers []*model.TeamMember + + _, err := s.GetReplica().Select(&teamMembers, sql) + if err != nil { + result.Err = model.NewAppError("SqlGroupStore.TeamMembersToRemove", "store.select_error", nil, "", http.StatusInternalServerError) + } + + result.Data = teamMembers + + return result +} + +// ChannelMembersToRemove returns all channel members that should be removed based on group constraints. +func (s *SqlSupplier) ChannelMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + result := store.NewSupplierResult() + + sql := ` + SELECT + ChannelMembers.* + FROM + ChannelMembers + JOIN Channels ON Channels.Id = ChannelMembers.ChannelId + WHERE + Channels.DeleteAt = 0 + AND Channels.GroupConstrained = TRUE + AND (ChannelMembers.ChannelId, ChannelMembers.UserId) + NOT IN ( + SELECT + Channels.Id AS ChannelId, GroupMembers.UserId + FROM + Channels + JOIN GroupChannels ON GroupChannels.ChannelId = Channels.Id + JOIN UserGroups ON UserGroups.Id = GroupChannels.GroupId + JOIN GroupMembers ON GroupMembers.GroupId = UserGroups.Id + WHERE + Channels.GroupConstrained = TRUE + AND GroupChannels.DeleteAt = 0 + AND UserGroups.DeleteAt = 0 + AND Channels.DeleteAt = 0 + AND GroupMembers.DeleteAt = 0 + GROUP BY + Channels.Id, + GroupMembers.UserId)` + + var channelMembers []*model.ChannelMember + + _, err := s.GetReplica().Select(&channelMembers, sql) + if err != nil { + result.Err = model.NewAppError("SqlGroupStore.ChannelMembersToRemove", "store.select_error", nil, err.Error(), http.StatusInternalServerError) + } + + result.Data = channelMembers + + return result +} diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index 9ffa45cfa9..2c71a6c4d8 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -640,6 +640,9 @@ func UpgradeDatabaseToVersion510(sqlStore SqlStore) { sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "GroupConstrained", "tinyint(4)", "boolean") sqlStore.CreateColumnIfNotExistsNoDefault("Teams", "GroupConstrained", "tinyint(4)", "boolean") + sqlStore.CreateIndexIfNotExists("idx_groupteams_teamid", "GroupTeams", "TeamId") + sqlStore.CreateIndexIfNotExists("idx_groupchannels_channelid", "GroupChannels", "ChannelId") + saveSchemaVersion(sqlStore, VERSION_5_10_0) } } diff --git a/store/store.go b/store/store.go index baa0338348..af2255e21e 100644 --- a/store/store.go +++ b/store/store.go @@ -580,8 +580,11 @@ type GroupStore interface { UpdateGroupSyncable(groupSyncable *model.GroupSyncable) StoreChannel DeleteGroupSyncable(groupID string, syncableID string, syncableType model.GroupSyncableType) StoreChannel - PendingAutoAddTeamMembers(minGroupMembersCreateAt int64) StoreChannel - PendingAutoAddChannelMembers(minGroupMembersCreateAt int64) StoreChannel + TeamMembersToAdd(since int64) StoreChannel + ChannelMembersToAdd(since int64) StoreChannel + + TeamMembersToRemove() StoreChannel + ChannelMembersToRemove() StoreChannel } type LinkMetadataStore interface { diff --git a/store/storetest/group_supplier.go b/store/storetest/group_supplier.go index ae2592cdbd..1f5ed7e5ff 100644 --- a/store/storetest/group_supplier.go +++ b/store/storetest/group_supplier.go @@ -9,7 +9,7 @@ import ( "github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/store" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestGroupStore(t *testing.T, ss store.Store) { @@ -31,8 +31,11 @@ func TestGroupStore(t *testing.T, ss store.Store) { t.Run("UpdateGroupSyncable", func(t *testing.T) { testUpdateGroupSyncable(t, ss) }) t.Run("DeleteGroupSyncable", func(t *testing.T) { testDeleteGroupSyncable(t, ss) }) - t.Run("PendingAutoAddTeamMembers", func(t *testing.T) { testPendingAutoAddTeamMembers(t, ss) }) - t.Run("PendingAutoAddChannelMembers", func(t *testing.T) { testPendingAutoAddChannelMembers(t, ss) }) + t.Run("TeamMembersToAdd", func(t *testing.T) { testPendingAutoAddTeamMembers(t, ss) }) + t.Run("ChannelMembersToAdd", func(t *testing.T) { testPendingAutoAddChannelMembers(t, ss) }) + + t.Run("TeamMembersToRemove", func(t *testing.T) { testPendingTeamMemberRemovals(t, ss) }) + t.Run("ChannelMembersToRemove", func(t *testing.T) { testPendingChannelMemberRemovals(t, ss) }) } func testGroupStoreCreate(t *testing.T, ss store.Store) { @@ -47,16 +50,16 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { // Happy path res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) d1 := res1.Data.(*model.Group) - assert.Len(t, d1.Id, 26) - assert.Equal(t, g1.Name, d1.Name) - assert.Equal(t, g1.DisplayName, d1.DisplayName) - assert.Equal(t, g1.Description, d1.Description) - assert.Equal(t, g1.RemoteId, d1.RemoteId) - assert.NotZero(t, d1.CreateAt) - assert.NotZero(t, d1.UpdateAt) - assert.Zero(t, d1.DeleteAt) + require.Len(t, d1.Id, 26) + require.Equal(t, g1.Name, d1.Name) + require.Equal(t, g1.DisplayName, d1.DisplayName) + require.Equal(t, g1.Description, d1.Description) + require.Equal(t, g1.RemoteId, d1.RemoteId) + require.NotZero(t, d1.CreateAt) + require.NotZero(t, d1.UpdateAt) + require.Zero(t, d1.DeleteAt) // Requires name and display name g2 := &model.Group{ @@ -66,16 +69,16 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res2 := <-ss.Group().Create(g2) - assert.Nil(t, res2.Data) - assert.NotNil(t, res2.Err) - assert.Equal(t, res2.Err.Id, "model.group.name.app_error") + require.Nil(t, res2.Data) + require.NotNil(t, res2.Err) + require.Equal(t, res2.Err.Id, "model.group.name.app_error") g2.Name = model.NewId() g2.DisplayName = "" res3 := <-ss.Group().Create(g2) - assert.Nil(t, res3.Data) - assert.NotNil(t, res3.Err) - assert.Equal(t, res3.Err.Id, "model.group.display_name.app_error") + require.Nil(t, res3.Data) + require.NotNil(t, res3.Err) + require.Equal(t, res3.Err.Id, "model.group.display_name.app_error") // Won't accept a duplicate name g4 := &model.Group{ @@ -85,7 +88,7 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res5 := <-ss.Group().Create(g4) - assert.Nil(t, res5.Err) + require.Nil(t, res5.Err) g4b := &model.Group{ Name: g4.Name, DisplayName: model.NewId(), @@ -93,8 +96,8 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res5b := <-ss.Group().Create(g4b) - assert.Nil(t, res5b.Data) - assert.Equal(t, res5b.Err.Id, "store.sql_group.unique_constraint") + require.Nil(t, res5b.Data) + require.Equal(t, res5b.Err.Id, "store.sql_group.unique_constraint") // Fields cannot be greater than max values g5 := &model.Group{ @@ -104,22 +107,22 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { Source: model.GroupSourceLdap, RemoteId: model.NewId(), } - assert.Nil(t, g5.IsValidForCreate()) + require.Nil(t, g5.IsValidForCreate()) g5.Name = g5.Name + "x" - assert.Equal(t, g5.IsValidForCreate().Id, "model.group.name.app_error") + require.Equal(t, g5.IsValidForCreate().Id, "model.group.name.app_error") g5.Name = model.NewId() - assert.Nil(t, g5.IsValidForCreate()) + require.Nil(t, g5.IsValidForCreate()) g5.DisplayName = g5.DisplayName + "x" - assert.Equal(t, g5.IsValidForCreate().Id, "model.group.display_name.app_error") + require.Equal(t, g5.IsValidForCreate().Id, "model.group.display_name.app_error") g5.DisplayName = model.NewId() - assert.Nil(t, g5.IsValidForCreate()) + require.Nil(t, g5.IsValidForCreate()) g5.Description = g5.Description + "x" - assert.Equal(t, g5.IsValidForCreate().Id, "model.group.description.app_error") + require.Equal(t, g5.IsValidForCreate().Id, "model.group.description.app_error") g5.Description = model.NewId() - assert.Nil(t, g5.IsValidForCreate()) + require.Nil(t, g5.IsValidForCreate()) // Must use a valid type g6 := &model.Group{ @@ -129,7 +132,7 @@ func testGroupStoreCreate(t *testing.T, ss store.Store) { Source: model.GroupSource("fake"), RemoteId: model.NewId(), } - assert.Equal(t, g6.IsValidForCreate().Id, "model.group.source.app_error") + require.Equal(t, g6.IsValidForCreate().Id, "model.group.source.app_error") } func testGroupStoreGet(t *testing.T, ss store.Store) { @@ -142,27 +145,27 @@ func testGroupStoreGet(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) d1 := res1.Data.(*model.Group) - assert.Len(t, d1.Id, 26) + require.Len(t, d1.Id, 26) // Get the group res2 := <-ss.Group().Get(d1.Id) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) d2 := res2.Data.(*model.Group) - assert.Equal(t, d1.Id, d2.Id) - assert.Equal(t, d1.Name, d2.Name) - assert.Equal(t, d1.DisplayName, d2.DisplayName) - assert.Equal(t, d1.Description, d2.Description) - assert.Equal(t, d1.RemoteId, d2.RemoteId) - assert.Equal(t, d1.CreateAt, d2.CreateAt) - assert.Equal(t, d1.UpdateAt, d2.UpdateAt) - assert.Equal(t, d1.DeleteAt, d2.DeleteAt) + require.Equal(t, d1.Id, d2.Id) + require.Equal(t, d1.Name, d2.Name) + require.Equal(t, d1.DisplayName, d2.DisplayName) + require.Equal(t, d1.Description, d2.Description) + require.Equal(t, d1.RemoteId, d2.RemoteId) + require.Equal(t, d1.CreateAt, d2.CreateAt) + require.Equal(t, d1.UpdateAt, d2.UpdateAt) + require.Equal(t, d1.DeleteAt, d2.DeleteAt) // Get an invalid group res3 := <-ss.Group().Get(model.NewId()) - assert.NotNil(t, res3.Err) - assert.Equal(t, res3.Err.Id, "store.sql_group.no_rows") + require.NotNil(t, res3.Err) + require.Equal(t, res3.Err.Id, "store.sql_group.no_rows") } func testGroupStoreGetByRemoteID(t *testing.T, ss store.Store) { @@ -175,27 +178,27 @@ func testGroupStoreGetByRemoteID(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) d1 := res1.Data.(*model.Group) - assert.Len(t, d1.Id, 26) + require.Len(t, d1.Id, 26) // Get the group res2 := <-ss.Group().GetByRemoteID(d1.RemoteId, model.GroupSourceLdap) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) d2 := res2.Data.(*model.Group) - assert.Equal(t, d1.Id, d2.Id) - assert.Equal(t, d1.Name, d2.Name) - assert.Equal(t, d1.DisplayName, d2.DisplayName) - assert.Equal(t, d1.Description, d2.Description) - assert.Equal(t, d1.RemoteId, d2.RemoteId) - assert.Equal(t, d1.CreateAt, d2.CreateAt) - assert.Equal(t, d1.UpdateAt, d2.UpdateAt) - assert.Equal(t, d1.DeleteAt, d2.DeleteAt) + require.Equal(t, d1.Id, d2.Id) + require.Equal(t, d1.Name, d2.Name) + require.Equal(t, d1.DisplayName, d2.DisplayName) + require.Equal(t, d1.Description, d2.Description) + require.Equal(t, d1.RemoteId, d2.RemoteId) + require.Equal(t, d1.CreateAt, d2.CreateAt) + require.Equal(t, d1.UpdateAt, d2.UpdateAt) + require.Equal(t, d1.DeleteAt, d2.DeleteAt) // Get an invalid group res3 := <-ss.Group().GetByRemoteID(model.NewId(), model.GroupSource("fake")) - assert.NotNil(t, res3.Err) - assert.Equal(t, res3.Err.Id, "store.sql_group.no_rows") + require.NotNil(t, res3.Err) + require.Equal(t, res3.Err.Id, "store.sql_group.no_rows") } func testGroupStoreGetAllByType(t *testing.T, ss store.Store) { @@ -214,13 +217,13 @@ func testGroupStoreGetAllByType(t *testing.T, ss store.Store) { } groups = append(groups, g) res := <-ss.Group().Create(g) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) } // Returns all the groups res1 := <-ss.Group().GetAllBySource(model.GroupSourceLdap) d1 := res1.Data.([]*model.Group) - assert.Condition(t, func() bool { return len(d1) >= numGroups }) + require.Condition(t, func() bool { return len(d1) >= numGroups }) for _, expectedGroup := range groups { present := false for _, dbGroup := range d1 { @@ -229,7 +232,7 @@ func testGroupStoreGetAllByType(t *testing.T, ss store.Store) { break } } - assert.True(t, present) + require.True(t, present) } } @@ -245,7 +248,7 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { // Create a group res := <-ss.Group().Create(g1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) d1 := res.Data.(*model.Group) // Update happy path @@ -257,19 +260,19 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { g1Update.RemoteId = model.NewId() res2 := <-ss.Group().Update(g1Update) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) ud1 := res2.Data.(*model.Group) // Not changed... - assert.Equal(t, d1.Id, ud1.Id) - assert.Equal(t, d1.CreateAt, ud1.CreateAt) - assert.Equal(t, d1.Source, ud1.Source) + require.Equal(t, d1.Id, ud1.Id) + require.Equal(t, d1.CreateAt, ud1.CreateAt) + require.Equal(t, d1.Source, ud1.Source) // Still zero... - assert.Zero(t, ud1.DeleteAt) + require.Zero(t, ud1.DeleteAt) // Updated... - assert.Equal(t, g1Update.Name, ud1.Name) - assert.Equal(t, g1Update.DisplayName, ud1.DisplayName) - assert.Equal(t, g1Update.Description, ud1.Description) - assert.Equal(t, g1Update.RemoteId, ud1.RemoteId) + require.Equal(t, g1Update.Name, ud1.Name) + require.Equal(t, g1Update.DisplayName, ud1.DisplayName) + require.Equal(t, g1Update.Description, ud1.Description) + require.Equal(t, g1Update.RemoteId, ud1.RemoteId) // Requires name and display name res3 := <-ss.Group().Update(&model.Group{ @@ -280,9 +283,9 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { RemoteId: model.NewId(), Description: model.NewId(), }) - assert.Nil(t, res3.Data) - assert.NotNil(t, res3.Err) - assert.Equal(t, res3.Err.Id, "model.group.name.app_error") + require.Nil(t, res3.Data) + require.NotNil(t, res3.Err) + require.Equal(t, res3.Err.Id, "model.group.name.app_error") res4 := <-ss.Group().Update(&model.Group{ Id: d1.Id, @@ -291,9 +294,9 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { Source: model.GroupSourceLdap, RemoteId: model.NewId(), }) - assert.Nil(t, res4.Data) - assert.NotNil(t, res4.Err) - assert.Equal(t, res4.Err.Id, "model.group.display_name.app_error") + require.Nil(t, res4.Data) + require.NotNil(t, res4.Err) + require.Equal(t, res4.Err.Id, "model.group.display_name.app_error") // Create another Group g2 := &model.Group{ @@ -304,7 +307,7 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res5 := <-ss.Group().Create(g2) - assert.Nil(t, res5.Err) + require.Nil(t, res5.Err) d2 := res5.Data.(*model.Group) // Can't update the name to be a duplicate of an existing group's name @@ -316,26 +319,26 @@ func testGroupStoreUpdate(t *testing.T, ss store.Store) { Description: model.NewId(), RemoteId: model.NewId(), }) - assert.Equal(t, res6.Err.Id, "store.update_error") + require.Equal(t, res6.Err.Id, "store.update_error") // Cannot update CreateAt someVal := model.GetMillis() d1.CreateAt = someVal res7 := <-ss.Group().Update(d1) d3 := res7.Data.(*model.Group) - assert.NotEqual(t, someVal, d3.CreateAt) + require.NotEqual(t, someVal, d3.CreateAt) // Cannot update DeleteAt to non-zero d1.DeleteAt = 1 res9 := <-ss.Group().Update(d1) - assert.Equal(t, "model.group.delete_at.app_error", res9.Err.Id) + require.Equal(t, "model.group.delete_at.app_error", res9.Err.Id) //...except for 0 for DeleteAt d1.DeleteAt = 0 res8 := <-ss.Group().Update(d1) - assert.Nil(t, res8.Err) + require.Nil(t, res8.Err) d4 := res8.Data.(*model.Group) - assert.Zero(t, d4.DeleteAt) + require.Zero(t, d4.DeleteAt) } func testGroupStoreDelete(t *testing.T, ss store.Store) { @@ -349,13 +352,13 @@ func testGroupStoreDelete(t *testing.T, ss store.Store) { } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) d1 := res1.Data.(*model.Group) - assert.Len(t, d1.Id, 26) + require.Len(t, d1.Id, 26) // Check the group is retrievable res2 := <-ss.Group().Get(d1.Id) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) // Get the before count res7 := <-ss.Group().GetAllBySource(model.GroupSourceLdap) @@ -364,27 +367,27 @@ func testGroupStoreDelete(t *testing.T, ss store.Store) { // Delete the group res3 := <-ss.Group().Delete(d1.Id) - assert.Nil(t, res3.Err) + require.Nil(t, res3.Err) // Check the group is deleted res4 := <-ss.Group().Get(d1.Id) d4 := res4.Data.(*model.Group) - assert.NotZero(t, d4.DeleteAt) + require.NotZero(t, d4.DeleteAt) // Check the after count res5 := <-ss.Group().GetAllBySource(model.GroupSourceLdap) d5 := res5.Data.([]*model.Group) afterCount := len(d5) - assert.Condition(t, func() bool { return beforeCount == afterCount+1 }) + require.Condition(t, func() bool { return beforeCount == afterCount+1 }) // Try and delete a nonexistent group res6 := <-ss.Group().Delete(model.NewId()) - assert.NotNil(t, res6.Err) - assert.Equal(t, res6.Err.Id, "store.sql_group.no_rows") + require.NotNil(t, res6.Err) + require.Equal(t, res6.Err.Id, "store.sql_group.no_rows") // Cannot delete again res8 := <-ss.Group().Delete(d1.Id) - assert.Equal(t, res8.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res8.Err.Id, "store.sql_group.no_rows") } func testGroupGetMemberUsers(t *testing.T, ss store.Store) { @@ -397,7 +400,7 @@ func testGroupGetMemberUsers(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res := <-ss.Group().Create(g1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) group := res.Data.(*model.Group) u1 := &model.User{ @@ -405,32 +408,32 @@ func testGroupGetMemberUsers(t *testing.T, ss store.Store) { Username: model.NewId(), } res = <-ss.User().Save(u1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user1 := res.Data.(*model.User) res = <-ss.Group().CreateOrRestoreMember(group.Id, user1.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) u2 := &model.User{ Email: MakeEmail(), Username: model.NewId(), } res = <-ss.User().Save(u2) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user2 := res.Data.(*model.User) res = <-ss.Group().CreateOrRestoreMember(group.Id, user2.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Check returns members res = <-ss.Group().GetMemberUsers(group.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) groupMembers := res.Data.([]*model.User) - assert.Equal(t, 2, len(groupMembers)) + require.Equal(t, 2, len(groupMembers)) // Check madeup id res = <-ss.Group().GetMemberUsers(model.NewId()) - assert.Equal(t, 0, len(res.Data.([]*model.User))) + require.Equal(t, 0, len(res.Data.([]*model.User))) // Delete a member <-ss.Group().DeleteMember(group.Id, user1.Id) @@ -438,7 +441,7 @@ func testGroupGetMemberUsers(t *testing.T, ss store.Store) { // Should not return deleted members res = <-ss.Group().GetMemberUsers(group.Id) groupMembers = res.Data.([]*model.User) - assert.Equal(t, 1, len(groupMembers)) + require.Equal(t, 1, len(groupMembers)) } func testGroupGetMemberUsersPage(t *testing.T, ss store.Store) { @@ -451,7 +454,7 @@ func testGroupGetMemberUsersPage(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res := <-ss.Group().Create(g1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) group := res.Data.(*model.Group) u1 := &model.User{ @@ -459,46 +462,46 @@ func testGroupGetMemberUsersPage(t *testing.T, ss store.Store) { Username: model.NewId(), } res = <-ss.User().Save(u1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user1 := res.Data.(*model.User) res = <-ss.Group().CreateOrRestoreMember(group.Id, user1.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) u2 := &model.User{ Email: MakeEmail(), Username: model.NewId(), } res = <-ss.User().Save(u2) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user2 := res.Data.(*model.User) res = <-ss.Group().CreateOrRestoreMember(group.Id, user2.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Check returns members res = <-ss.Group().GetMemberUsersPage(group.Id, 0, 100) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) groupMembers := res.Data.([]*model.User) - assert.Equal(t, 2, len(groupMembers)) + require.Equal(t, 2, len(groupMembers)) // Check page 1 res = <-ss.Group().GetMemberUsersPage(group.Id, 0, 1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) groupMembers = res.Data.([]*model.User) - assert.Equal(t, 1, len(groupMembers)) - assert.Equal(t, user2.Id, groupMembers[0].Id) + require.Equal(t, 1, len(groupMembers)) + require.Equal(t, user2.Id, groupMembers[0].Id) // Check page 2 res = <-ss.Group().GetMemberUsersPage(group.Id, 1, 1) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) groupMembers = res.Data.([]*model.User) - assert.Equal(t, 1, len(groupMembers)) - assert.Equal(t, user1.Id, groupMembers[0].Id) + require.Equal(t, 1, len(groupMembers)) + require.Equal(t, user1.Id, groupMembers[0].Id) // Check madeup id res = <-ss.Group().GetMemberUsersPage(model.NewId(), 0, 100) - assert.Equal(t, 0, len(res.Data.([]*model.User))) + require.Equal(t, 0, len(res.Data.([]*model.User))) // Delete a member <-ss.Group().DeleteMember(group.Id, user1.Id) @@ -506,7 +509,7 @@ func testGroupGetMemberUsersPage(t *testing.T, ss store.Store) { // Should not return deleted members res = <-ss.Group().GetMemberUsersPage(group.Id, 0, 100) groupMembers = res.Data.([]*model.User) - assert.Equal(t, 1, len(groupMembers)) + require.Equal(t, 1, len(groupMembers)) } func testGroupCreateOrRestoreMember(t *testing.T, ss store.Store) { @@ -518,7 +521,7 @@ func testGroupCreateOrRestoreMember(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) group := res1.Data.(*model.Group) // Create user @@ -527,43 +530,43 @@ func testGroupCreateOrRestoreMember(t *testing.T, ss store.Store) { Username: model.NewId(), } res2 := <-ss.User().Save(u1) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) user := res2.Data.(*model.User) // Happy path res3 := <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res3.Err) + require.Nil(t, res3.Err) d2 := res3.Data.(*model.GroupMember) - assert.Equal(t, d2.GroupId, group.Id) - assert.Equal(t, d2.UserId, user.Id) - assert.NotZero(t, d2.CreateAt) - assert.Zero(t, d2.DeleteAt) + require.Equal(t, d2.GroupId, group.Id) + require.Equal(t, d2.UserId, user.Id) + require.NotZero(t, d2.CreateAt) + require.Zero(t, d2.DeleteAt) // Duplicate composite key (GroupId, UserId) res4 := <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Equal(t, res4.Err.Id, "store.sql_group.uniqueness_error") + require.Equal(t, res4.Err.Id, "store.sql_group.uniqueness_error") // Invalid GroupId res6 := <-ss.Group().CreateOrRestoreMember(model.NewId(), user.Id) - assert.Equal(t, res6.Err.Id, "store.insert_error") + require.Equal(t, res6.Err.Id, "store.insert_error") // Restores a deleted member res := <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.NotNil(t, res.Err) + require.NotNil(t, res.Err) res = <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) res = <-ss.Group().GetMemberUsers(group.Id) beforeRestoreCount := len(res.Data.([]*model.User)) res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) res = <-ss.Group().GetMemberUsers(group.Id) afterRestoreCount := len(res.Data.([]*model.User)) - assert.Equal(t, beforeRestoreCount+1, afterRestoreCount) + require.Equal(t, beforeRestoreCount+1, afterRestoreCount) } func testGroupDeleteMember(t *testing.T, ss store.Store) { @@ -575,7 +578,7 @@ func testGroupDeleteMember(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) group := res1.Data.(*model.Group) // Create user @@ -584,44 +587,40 @@ func testGroupDeleteMember(t *testing.T, ss store.Store) { Username: model.NewId(), } res2 := <-ss.User().Save(u1) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) user := res2.Data.(*model.User) // Create member res3 := <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res3.Err) + require.Nil(t, res3.Err) d1 := res3.Data.(*model.GroupMember) // Happy path res4 := <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res4.Err) + require.Nil(t, res4.Err) d2 := res4.Data.(*model.GroupMember) - assert.Equal(t, d2.GroupId, group.Id) - assert.Equal(t, d2.UserId, user.Id) - assert.Equal(t, d2.CreateAt, d1.CreateAt) - assert.NotZero(t, d2.DeleteAt) + require.Equal(t, d2.GroupId, group.Id) + require.Equal(t, d2.UserId, user.Id) + require.Equal(t, d2.CreateAt, d1.CreateAt) + require.NotZero(t, d2.DeleteAt) // Delete an already deleted member res5 := <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Equal(t, res5.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res5.Err.Id, "store.sql_group.no_rows") // Delete with non-existent User res8 := <-ss.Group().DeleteMember(group.Id, model.NewId()) - assert.Equal(t, res8.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res8.Err.Id, "store.sql_group.no_rows") // Delete non-existent Group res9 := <-ss.Group().DeleteMember(model.NewId(), group.Id) - assert.Equal(t, res9.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res9.Err.Id, "store.sql_group.no_rows") } func testCreateGroupSyncable(t *testing.T, ss store.Store) { // Invalid GroupID - res2 := <-ss.Group().CreateGroupSyncable(&model.GroupSyncable{ - GroupId: "x", - SyncableId: string(model.NewId()), - Type: model.GroupSyncableTypeTeam, - }) - assert.Equal(t, res2.Err.Id, "model.group_syncable.group_id.app_error") + res2 := <-ss.Group().CreateGroupSyncable(model.NewGroupTeam("x", model.NewId(), false)) + require.Equal(t, res2.Err.Id, "model.group_syncable.group_id.app_error") // Create Group g1 := &model.Group{ @@ -631,7 +630,7 @@ func testCreateGroupSyncable(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res4 := <-ss.Group().Create(g1) - assert.Nil(t, res4.Err) + require.Nil(t, res4.Err) group := res4.Data.(*model.Group) // Create Team @@ -646,24 +645,19 @@ func testCreateGroupSyncable(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res5 := <-ss.Team().Save(t1) - assert.Nil(t, res5.Err) + require.Nil(t, res5.Err) team := res5.Data.(*model.Team) // New GroupSyncable, happy path - gt1 := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - } + gt1 := model.NewGroupTeam(group.Id, team.Id, false) res6 := <-ss.Group().CreateGroupSyncable(gt1) - assert.Nil(t, res6.Err) + require.Nil(t, res6.Err) d1 := res6.Data.(*model.GroupSyncable) - assert.Equal(t, gt1.SyncableId, d1.SyncableId) - assert.Equal(t, gt1.GroupId, d1.GroupId) - assert.Equal(t, gt1.AutoAdd, d1.AutoAdd) - assert.NotZero(t, d1.CreateAt) - assert.Zero(t, d1.DeleteAt) + require.Equal(t, gt1.SyncableId, d1.SyncableId) + require.Equal(t, gt1.GroupId, d1.GroupId) + require.Equal(t, gt1.AutoAdd, d1.AutoAdd) + require.NotZero(t, d1.CreateAt) + require.Zero(t, d1.DeleteAt) } func testGetGroupSyncable(t *testing.T, ss store.Store) { @@ -676,7 +670,7 @@ func testGetGroupSyncable(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) group := res1.Data.(*model.Group) // Create Team @@ -691,30 +685,25 @@ func testGetGroupSyncable(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res2 := <-ss.Team().Save(t1) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) team := res2.Data.(*model.Team) // Create GroupSyncable - gt1 := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - } + gt1 := model.NewGroupTeam(group.Id, team.Id, false) res3 := <-ss.Group().CreateGroupSyncable(gt1) - assert.Nil(t, res3.Err) + require.Nil(t, res3.Err) groupTeam := res3.Data.(*model.GroupSyncable) // Get GroupSyncable res4 := <-ss.Group().GetGroupSyncable(groupTeam.GroupId, groupTeam.SyncableId, model.GroupSyncableTypeTeam) - assert.Nil(t, res4.Err) + require.Nil(t, res4.Err) dgt := res4.Data.(*model.GroupSyncable) - assert.Equal(t, gt1.GroupId, dgt.GroupId) - assert.Equal(t, gt1.SyncableId, dgt.SyncableId) - assert.Equal(t, gt1.AutoAdd, dgt.AutoAdd) - assert.NotZero(t, gt1.CreateAt) - assert.NotZero(t, gt1.UpdateAt) - assert.Zero(t, gt1.DeleteAt) + require.Equal(t, gt1.GroupId, dgt.GroupId) + require.Equal(t, gt1.SyncableId, dgt.SyncableId) + require.Equal(t, gt1.AutoAdd, dgt.AutoAdd) + require.NotZero(t, gt1.CreateAt) + require.NotZero(t, gt1.UpdateAt) + require.Zero(t, gt1.DeleteAt) } func testGetAllGroupSyncablesByGroup(t *testing.T, ss store.Store) { @@ -729,7 +718,7 @@ func testGetAllGroupSyncablesByGroup(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) group := res1.Data.(*model.Group) groupTeams := []*model.GroupSyncable{} @@ -748,16 +737,12 @@ func testGetAllGroupSyncablesByGroup(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res2 := <-ss.Team().Save(t1) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) team := res2.Data.(*model.Team) // create groupteam - res3 := <-ss.Group().CreateGroupSyncable(&model.GroupSyncable{ - GroupId: group.Id, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - }) - assert.Nil(t, res3.Err) + res3 := <-ss.Group().CreateGroupSyncable(model.NewGroupTeam(group.Id, team.Id, false)) + require.Nil(t, res3.Err) groupTeam := res3.Data.(*model.GroupSyncable) groupTeams = append(groupTeams, groupTeam) } @@ -765,7 +750,7 @@ func testGetAllGroupSyncablesByGroup(t *testing.T, ss store.Store) { // Returns all the group teams res4 := <-ss.Group().GetAllGroupSyncablesByGroupId(group.Id, model.GroupSyncableTypeTeam) d1 := res4.Data.([]*model.GroupSyncable) - assert.Condition(t, func() bool { return len(d1) >= numGroupSyncables }) + require.Condition(t, func() bool { return len(d1) >= numGroupSyncables }) for _, expectedGroupTeam := range groupTeams { present := false for _, dbGroupTeam := range d1 { @@ -774,7 +759,7 @@ func testGetAllGroupSyncablesByGroup(t *testing.T, ss store.Store) { break } } - assert.True(t, present) + require.True(t, present) } } @@ -787,7 +772,7 @@ func testUpdateGroupSyncable(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res4 := <-ss.Group().Create(g1) - assert.Nil(t, res4.Err) + require.Nil(t, res4.Err) group := res4.Data.(*model.Group) // Create Team @@ -802,67 +787,52 @@ func testUpdateGroupSyncable(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res5 := <-ss.Team().Save(t1) - assert.Nil(t, res5.Err) + require.Nil(t, res5.Err) team := res5.Data.(*model.Team) // New GroupSyncable, happy path - gt1 := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - } + gt1 := model.NewGroupTeam(group.Id, team.Id, false) res6 := <-ss.Group().CreateGroupSyncable(gt1) - assert.Nil(t, res6.Err) + require.Nil(t, res6.Err) d1 := res6.Data.(*model.GroupSyncable) // Update existing group team gt1.AutoAdd = true res7 := <-ss.Group().UpdateGroupSyncable(gt1) - assert.Nil(t, res7.Err) + require.Nil(t, res7.Err) d2 := res7.Data.(*model.GroupSyncable) - assert.True(t, d2.AutoAdd) + require.True(t, d2.AutoAdd) // Non-existent Group - gt2 := &model.GroupSyncable{ - GroupId: model.NewId(), - AutoAdd: false, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - } + gt2 := model.NewGroupTeam(model.NewId(), team.Id, false) res9 := <-ss.Group().UpdateGroupSyncable(gt2) - assert.Equal(t, res9.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res9.Err.Id, "store.sql_group.no_rows") // Non-existent Team - gt3 := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: string(model.NewId()), - Type: model.GroupSyncableTypeTeam, - } + gt3 := model.NewGroupTeam(group.Id, model.NewId(), false) res10 := <-ss.Group().UpdateGroupSyncable(gt3) - assert.Equal(t, res10.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res10.Err.Id, "store.sql_group.no_rows") // Cannot update CreateAt or DeleteAt origCreateAt := d1.CreateAt d1.CreateAt = model.GetMillis() d1.AutoAdd = true res11 := <-ss.Group().UpdateGroupSyncable(d1) - assert.Nil(t, res11.Err) + require.Nil(t, res11.Err) d3 := res11.Data.(*model.GroupSyncable) - assert.Equal(t, origCreateAt, d3.CreateAt) + require.Equal(t, origCreateAt, d3.CreateAt) // Cannot update DeleteAt to arbitrary value d1.DeleteAt = 1 res12 := <-ss.Group().UpdateGroupSyncable(d1) - assert.Equal(t, "model.group.delete_at.app_error", res12.Err.Id) + require.Equal(t, "model.group.delete_at.app_error", res12.Err.Id) // Can update DeleteAt to 0 d1.DeleteAt = 0 res13 := <-ss.Group().UpdateGroupSyncable(d1) - assert.Nil(t, res13.Err) + require.Nil(t, res13.Err) d4 := res13.Data.(*model.GroupSyncable) - assert.Zero(t, d4.DeleteAt) + require.Zero(t, d4.DeleteAt) } func testDeleteGroupSyncable(t *testing.T, ss store.Store) { @@ -874,7 +844,7 @@ func testDeleteGroupSyncable(t *testing.T, ss store.Store) { RemoteId: model.NewId(), } res1 := <-ss.Group().Create(g1) - assert.Nil(t, res1.Err) + require.Nil(t, res1.Err) group := res1.Data.(*model.Group) // Create Team @@ -889,54 +859,49 @@ func testDeleteGroupSyncable(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res2 := <-ss.Team().Save(t1) - assert.Nil(t, res2.Err) + require.Nil(t, res2.Err) team := res2.Data.(*model.Team) // Create GroupSyncable - gt1 := &model.GroupSyncable{ - GroupId: group.Id, - AutoAdd: false, - SyncableId: string(team.Id), - Type: model.GroupSyncableTypeTeam, - } + gt1 := model.NewGroupTeam(group.Id, team.Id, false) res7 := <-ss.Group().CreateGroupSyncable(gt1) - assert.Nil(t, res7.Err) + require.Nil(t, res7.Err) groupTeam := res7.Data.(*model.GroupSyncable) // Non-existent Group res5 := <-ss.Group().DeleteGroupSyncable(model.NewId(), groupTeam.SyncableId, model.GroupSyncableTypeTeam) - assert.Equal(t, res5.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res5.Err.Id, "store.sql_group.no_rows") // Non-existent Team res6 := <-ss.Group().DeleteGroupSyncable(groupTeam.GroupId, string(model.NewId()), model.GroupSyncableTypeTeam) - assert.Equal(t, res6.Err.Id, "store.sql_group.no_rows") + require.Equal(t, res6.Err.Id, "store.sql_group.no_rows") // Happy path... res8 := <-ss.Group().DeleteGroupSyncable(groupTeam.GroupId, groupTeam.SyncableId, model.GroupSyncableTypeTeam) - assert.Nil(t, res8.Err) + require.Nil(t, res8.Err) d1 := res8.Data.(*model.GroupSyncable) - assert.NotZero(t, d1.DeleteAt) - assert.Equal(t, d1.GroupId, groupTeam.GroupId) - assert.Equal(t, d1.SyncableId, groupTeam.SyncableId) - assert.Equal(t, d1.AutoAdd, groupTeam.AutoAdd) - assert.Equal(t, d1.CreateAt, groupTeam.CreateAt) - assert.Condition(t, func() bool { return d1.UpdateAt > groupTeam.UpdateAt }) + require.NotZero(t, d1.DeleteAt) + require.Equal(t, d1.GroupId, groupTeam.GroupId) + require.Equal(t, d1.SyncableId, groupTeam.SyncableId) + require.Equal(t, d1.AutoAdd, groupTeam.AutoAdd) + require.Equal(t, d1.CreateAt, groupTeam.CreateAt) + require.Condition(t, func() bool { return d1.UpdateAt > groupTeam.UpdateAt }) // Record already deleted res9 := <-ss.Group().DeleteGroupSyncable(d1.GroupId, d1.SyncableId, d1.Type) - assert.NotNil(t, res9.Err) - assert.Equal(t, res9.Err.Id, "store.sql_group.group_syncable_already_deleted") + require.NotNil(t, res9.Err) + require.Equal(t, res9.Err.Id, "store.sql_group.group_syncable_already_deleted") } func testPendingAutoAddTeamMembers(t *testing.T, ss store.Store) { // Create Group res := <-ss.Group().Create(&model.Group{ Name: model.NewId(), - DisplayName: "PendingAutoAddTeamMembers Test Group", + DisplayName: "TeamMembersToAdd Test Group", RemoteId: model.NewId(), Source: model.GroupSourceLdap, }) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) group := res.Data.(*model.Group) // Create User @@ -945,12 +910,12 @@ func testPendingAutoAddTeamMembers(t *testing.T, ss store.Store) { Username: model.NewId(), } res = <-ss.User().Save(user) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user = res.Data.(*model.User) // Create GroupMember res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Create Team team := &model.Team{ @@ -964,151 +929,146 @@ func testPendingAutoAddTeamMembers(t *testing.T, ss store.Store) { Type: model.TEAM_OPEN, } res = <-ss.Team().Save(team) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) team = res.Data.(*model.Team) // Create GroupTeam - res = <-ss.Group().CreateGroupSyncable(&model.GroupSyncable{ - AutoAdd: true, - SyncableId: team.Id, - Type: model.GroupSyncableTypeTeam, - GroupId: group.Id, - }) - assert.Nil(t, res.Err) + res = <-ss.Group().CreateGroupSyncable(model.NewGroupTeam(group.Id, team.Id, true)) + require.Nil(t, res.Err) syncable := res.Data.(*model.GroupSyncable) // Time before syncable was created - res = <-ss.Group().PendingAutoAddTeamMembers(syncable.CreateAt - 1) - assert.Nil(t, res.Err) - userTeamIDs := res.Data.([]*model.UserTeamIDPair) - assert.Len(t, userTeamIDs, 1) - assert.Equal(t, user.Id, userTeamIDs[0].UserID) - assert.Equal(t, team.Id, userTeamIDs[0].TeamID) + res = <-ss.Group().TeamMembersToAdd(syncable.CreateAt - 1) + require.Nil(t, res.Err) + teamMembers := res.Data.([]*model.UserTeamIDPair) + require.Len(t, teamMembers, 1) + require.Equal(t, user.Id, teamMembers[0].UserID) + require.Equal(t, team.Id, teamMembers[0].TeamID) // Time after syncable was created - res = <-ss.Group().PendingAutoAddTeamMembers(syncable.CreateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + res = <-ss.Group().TeamMembersToAdd(syncable.CreateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Delete and restore GroupMember should return result res = <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(syncable.CreateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(syncable.CreateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) pristineSyncable := *syncable res = <-ss.Group().UpdateGroupSyncable(syncable) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Time before syncable was updated - res = <-ss.Group().PendingAutoAddTeamMembers(syncable.UpdateAt - 1) - assert.Nil(t, res.Err) - userTeamIDs = res.Data.([]*model.UserTeamIDPair) - assert.Len(t, userTeamIDs, 1) - assert.Equal(t, user.Id, userTeamIDs[0].UserID) - assert.Equal(t, team.Id, userTeamIDs[0].TeamID) + res = <-ss.Group().TeamMembersToAdd(syncable.UpdateAt - 1) + require.Nil(t, res.Err) + teamMembers = res.Data.([]*model.UserTeamIDPair) + require.Len(t, teamMembers, 1) + require.Equal(t, user.Id, teamMembers[0].UserID) + require.Equal(t, team.Id, teamMembers[0].TeamID) // Time after syncable was updated - res = <-ss.Group().PendingAutoAddTeamMembers(syncable.UpdateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + res = <-ss.Group().TeamMembersToAdd(syncable.UpdateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Only includes if auto-add syncable.AutoAdd = false res = <-ss.Group().UpdateGroupSyncable(syncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of syncable and verify res = <-ss.Group().UpdateGroupSyncable(&pristineSyncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if Group deleted res = <-ss.Group().Delete(group.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of group and verify group.DeleteAt = 0 res = <-ss.Group().Update(group) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if Team deleted team.DeleteAt = model.GetMillis() res = <-ss.Team().Update(team) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of team and verify team.DeleteAt = 0 res = <-ss.Team().Update(team) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if GroupTeam deleted res = <-ss.Group().DeleteGroupSyncable(group.Id, team.Id, model.GroupSyncableTypeTeam) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset GroupTeam and verify res = <-ss.Group().UpdateGroupSyncable(&pristineSyncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if GroupMember deleted res = <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // restore group member and verify res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // adding team membership stops returning result res = <-ss.Team().SaveMember(&model.TeamMember{ TeamId: team.Id, UserId: user.Id, }, 999) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddTeamMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().TeamMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) } func testPendingAutoAddChannelMembers(t *testing.T, ss store.Store) { // Create Group res := <-ss.Group().Create(&model.Group{ Name: model.NewId(), - DisplayName: "PendingAutoAddChannelMembers Test Group", + DisplayName: "ChannelMembersToAdd Test Group", RemoteId: model.NewId(), Source: model.GroupSourceLdap, }) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) group := res.Data.(*model.Group) // Create User @@ -1117,12 +1077,12 @@ func testPendingAutoAddChannelMembers(t *testing.T, ss store.Store) { Username: model.NewId(), } res = <-ss.User().Save(user) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) user = res.Data.(*model.User) // Create GroupMember res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Create Channel channel := &model.Channel{ @@ -1132,149 +1092,418 @@ func testPendingAutoAddChannelMembers(t *testing.T, ss store.Store) { Type: model.CHANNEL_OPEN, // Query does not look at type so this shouldn't matter. } res = <-ss.Channel().Save(channel, 9999) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) channel = res.Data.(*model.Channel) // Create GroupChannel - res = <-ss.Group().CreateGroupSyncable(&model.GroupSyncable{ - AutoAdd: true, - SyncableId: channel.Id, - Type: model.GroupSyncableTypeChannel, - GroupId: group.Id, - }) - assert.Nil(t, res.Err) + res = <-ss.Group().CreateGroupSyncable(model.NewGroupChannel(group.Id, channel.Id, true)) + require.Nil(t, res.Err) syncable := res.Data.(*model.GroupSyncable) // Time before syncable was created - res = <-ss.Group().PendingAutoAddChannelMembers(syncable.CreateAt - 1) - assert.Nil(t, res.Err) - userChannelIDs := res.Data.([]*model.UserChannelIDPair) - assert.Len(t, userChannelIDs, 1) - assert.Equal(t, user.Id, userChannelIDs[0].UserID) - assert.Equal(t, channel.Id, userChannelIDs[0].ChannelID) + res = <-ss.Group().ChannelMembersToAdd(syncable.CreateAt - 1) + require.Nil(t, res.Err) + channelMembers := res.Data.([]*model.UserChannelIDPair) + require.Len(t, channelMembers, 1) + require.Equal(t, user.Id, channelMembers[0].UserID) + require.Equal(t, channel.Id, channelMembers[0].ChannelID) // Time after syncable was created - res = <-ss.Group().PendingAutoAddChannelMembers(syncable.CreateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + res = <-ss.Group().ChannelMembersToAdd(syncable.CreateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Delete and restore GroupMember should return result res = <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(syncable.CreateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(syncable.CreateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) pristineSyncable := *syncable res = <-ss.Group().UpdateGroupSyncable(syncable) - assert.Nil(t, res.Err) + require.Nil(t, res.Err) // Time before syncable was updated - res = <-ss.Group().PendingAutoAddChannelMembers(syncable.UpdateAt - 1) - assert.Nil(t, res.Err) - userChannelIDs = res.Data.([]*model.UserChannelIDPair) - assert.Len(t, userChannelIDs, 1) - assert.Equal(t, user.Id, userChannelIDs[0].UserID) - assert.Equal(t, channel.Id, userChannelIDs[0].ChannelID) + res = <-ss.Group().ChannelMembersToAdd(syncable.UpdateAt - 1) + require.Nil(t, res.Err) + channelMembers = res.Data.([]*model.UserChannelIDPair) + require.Len(t, channelMembers, 1) + require.Equal(t, user.Id, channelMembers[0].UserID) + require.Equal(t, channel.Id, channelMembers[0].ChannelID) // Time after syncable was updated - res = <-ss.Group().PendingAutoAddChannelMembers(syncable.UpdateAt + 1) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + res = <-ss.Group().ChannelMembersToAdd(syncable.UpdateAt + 1) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Only includes if auto-add syncable.AutoAdd = false res = <-ss.Group().UpdateGroupSyncable(syncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of syncable and verify res = <-ss.Group().UpdateGroupSyncable(&pristineSyncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if Group deleted res = <-ss.Group().Delete(group.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of group and verify group.DeleteAt = 0 res = <-ss.Group().Update(group) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if Channel deleted res = <-ss.Channel().Delete(channel.Id, model.GetMillis()) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset state of channel and verify channel.DeleteAt = 0 res = <-ss.Channel().Update(channel) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if GroupChannel deleted res = <-ss.Group().DeleteGroupSyncable(group.Id, channel.Id, model.GroupSyncableTypeChannel) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // reset GroupChannel and verify res = <-ss.Group().UpdateGroupSyncable(&pristineSyncable) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // No result if GroupMember deleted res = <-ss.Group().DeleteMember(group.Id, user.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // restore group member and verify res = <-ss.Group().CreateOrRestoreMember(group.Id, user.Id) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) // Adding Channel (ChannelMemberHistory) should stop returning result res = <-ss.ChannelMemberHistory().LogJoinEvent(user.Id, channel.Id, model.GetMillis()) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Leaving Channel (ChannelMemberHistory) should still not return result res = <-ss.ChannelMemberHistory().LogLeaveEvent(user.Id, channel.Id, model.GetMillis()) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 0) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 0) // Purging ChannelMemberHistory re-returns the result res = <-ss.ChannelMemberHistory().PermanentDeleteBatch(model.GetMillis()+1, 100) - assert.Nil(t, res.Err) - res = <-ss.Group().PendingAutoAddChannelMembers(0) - assert.Nil(t, res.Err) - assert.Len(t, res.Data, 1) + require.Nil(t, res.Err) + res = <-ss.Group().ChannelMembersToAdd(0) + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) +} + +func testPendingTeamMemberRemovals(t *testing.T, ss store.Store) { + data := pendingMemberRemovalsDataSetup(t, ss) + + // one result when both users are in the group (for user C) + res := <-ss.Group().TeamMembersToRemove() + + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) + teamMembers := res.Data.([]*model.TeamMember) + require.Equal(t, data.UserC.Id, teamMembers[0].UserId) + + res = <-ss.Group().DeleteMember(data.Group.Id, data.UserB.Id) + require.Nil(t, res.Err) + + // user b and c should now be returned + res = <-ss.Group().TeamMembersToRemove() + require.Nil(t, res.Err) + require.Len(t, res.Data, 2) + teamMembers = res.Data.([]*model.TeamMember) + + var userIDs []string + for _, item := range teamMembers { + userIDs = append(userIDs, item.UserId) + } + require.Contains(t, userIDs, data.UserB.Id) + require.Contains(t, userIDs, data.UserC.Id) + require.Equal(t, data.ConstrainedTeam.Id, teamMembers[0].TeamId) + require.Equal(t, data.ConstrainedTeam.Id, teamMembers[1].TeamId) + + res = <-ss.Group().DeleteMember(data.Group.Id, data.UserA.Id) + require.Nil(t, res.Err) + + res = <-ss.Group().TeamMembersToRemove() + require.Nil(t, res.Err) + require.Len(t, res.Data, 3) + + // add users back to groups + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserA.Id) + require.Nil(t, res.Err) + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserB.Id) + require.Nil(t, res.Err) + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserC.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserA.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserB.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserC.Id) + require.Nil(t, res.Err) +} + +func testPendingChannelMemberRemovals(t *testing.T, ss store.Store) { + data := pendingMemberRemovalsDataSetup(t, ss) + + // one result when both users are in the group (for user C) + res := <-ss.Group().ChannelMembersToRemove() + + require.Nil(t, res.Err) + require.Len(t, res.Data, 1) + channelMembers := res.Data.([]*model.ChannelMember) + require.Equal(t, data.UserC.Id, channelMembers[0].UserId) + + res = <-ss.Group().DeleteMember(data.Group.Id, data.UserB.Id) + require.Nil(t, res.Err) + + // user b and c should now be returned + res = <-ss.Group().ChannelMembersToRemove() + require.Nil(t, res.Err) + require.Len(t, res.Data, 2) + channelMembers = res.Data.([]*model.ChannelMember) + + var userIDs []string + for _, item := range channelMembers { + userIDs = append(userIDs, item.UserId) + } + require.Contains(t, userIDs, data.UserB.Id) + require.Contains(t, userIDs, data.UserC.Id) + require.Equal(t, data.ConstrainedChannel.Id, channelMembers[0].ChannelId) + require.Equal(t, data.ConstrainedChannel.Id, channelMembers[1].ChannelId) + + res = <-ss.Group().DeleteMember(data.Group.Id, data.UserA.Id) + require.Nil(t, res.Err) + + res = <-ss.Group().ChannelMembersToRemove() + require.Nil(t, res.Err) + require.Len(t, res.Data, 3) + + // add users back to groups + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserA.Id) + require.Nil(t, res.Err) + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserB.Id) + require.Nil(t, res.Err) + res = <-ss.Team().RemoveMember(data.ConstrainedTeam.Id, data.UserC.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserA.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserB.Id) + require.Nil(t, res.Err) + res = <-ss.Channel().RemoveMember(data.ConstrainedChannel.Id, data.UserC.Id) + require.Nil(t, res.Err) +} + +type removalsData struct { + UserA *model.User + UserB *model.User + UserC *model.User + ConstrainedChannel *model.Channel + UnconstrainedChannel *model.Channel + ConstrainedTeam *model.Team + UnconstrainedTeam *model.Team + Group *model.Group +} + +func pendingMemberRemovalsDataSetup(t *testing.T, ss store.Store) *removalsData { + // create group + res := <-ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: "Pending[Channel|Team]MemberRemovals Test Group", + RemoteId: model.NewId(), + Source: model.GroupSourceLdap, + }) + require.Nil(t, res.Err) + group := res.Data.(*model.Group) + + // create users + // userA will get removed from the group + userA := &model.User{ + Email: MakeEmail(), + Username: model.NewId(), + } + res = <-ss.User().Save(userA) + require.Nil(t, res.Err) + userA = res.Data.(*model.User) + + // userB will not get removed from the group + userB := &model.User{ + Email: MakeEmail(), + Username: model.NewId(), + } + res = <-ss.User().Save(userB) + require.Nil(t, res.Err) + userB = res.Data.(*model.User) + + // userC was never in the group + userC := &model.User{ + Email: MakeEmail(), + Username: model.NewId(), + } + res = <-ss.User().Save(userC) + require.Nil(t, res.Err) + userC = res.Data.(*model.User) + + // add users to group (but not userC) + res = <-ss.Group().CreateOrRestoreMember(group.Id, userA.Id) + require.Nil(t, res.Err) + + res = <-ss.Group().CreateOrRestoreMember(group.Id, userB.Id) + require.Nil(t, res.Err) + + // create channels + channelConstrained := &model.Channel{ + TeamId: model.NewId(), + DisplayName: "A Name", + Name: model.NewId(), + Type: model.CHANNEL_PRIVATE, + GroupConstrained: model.NewBool(true), + } + res = <-ss.Channel().Save(channelConstrained, 9999) + require.Nil(t, res.Err) + channelConstrained = res.Data.(*model.Channel) + + channelUnconstrained := &model.Channel{ + TeamId: model.NewId(), + DisplayName: "A Name", + Name: model.NewId(), + Type: model.CHANNEL_PRIVATE, + } + res = <-ss.Channel().Save(channelUnconstrained, 9999) + require.Nil(t, res.Err) + channelUnconstrained = res.Data.(*model.Channel) + + // create teams + teamConstrained := &model.Team{ + DisplayName: "Name", + Description: "Some description", + CompanyName: "Some company name", + AllowOpenInvite: false, + InviteId: "inviteid0", + Name: "z-z-" + model.NewId() + "a", + Email: "success+" + model.NewId() + "@simulator.amazonses.com", + Type: model.TEAM_INVITE, + GroupConstrained: model.NewBool(true), + } + res = <-ss.Team().Save(teamConstrained) + require.Nil(t, res.Err) + teamConstrained = res.Data.(*model.Team) + + teamUnconstrained := &model.Team{ + DisplayName: "Name", + Description: "Some description", + CompanyName: "Some company name", + AllowOpenInvite: false, + InviteId: "inviteid1", + Name: "z-z-" + model.NewId() + "a", + Email: "success+" + model.NewId() + "@simulator.amazonses.com", + Type: model.TEAM_INVITE, + } + res = <-ss.Team().Save(teamUnconstrained) + require.Nil(t, res.Err) + teamUnconstrained = res.Data.(*model.Team) + + // create groupteams + res = <-ss.Group().CreateGroupSyncable(model.NewGroupTeam(group.Id, teamConstrained.Id, true)) + require.Nil(t, res.Err) + + res = <-ss.Group().CreateGroupSyncable(model.NewGroupTeam(group.Id, teamUnconstrained.Id, true)) + require.Nil(t, res.Err) + + // create groupchannels + res = <-ss.Group().CreateGroupSyncable(model.NewGroupChannel(group.Id, channelConstrained.Id, true)) + require.Nil(t, res.Err) + + res = <-ss.Group().CreateGroupSyncable(model.NewGroupChannel(group.Id, channelUnconstrained.Id, true)) + require.Nil(t, res.Err) + + // add users to teams + userIDTeamIDs := [][]string{ + {userA.Id, teamConstrained.Id}, + {userB.Id, teamConstrained.Id}, + {userC.Id, teamConstrained.Id}, + {userA.Id, teamUnconstrained.Id}, + {userB.Id, teamUnconstrained.Id}, + {userC.Id, teamUnconstrained.Id}, + } + + for _, item := range userIDTeamIDs { + res = <-ss.Team().SaveMember(&model.TeamMember{ + UserId: item[0], + TeamId: item[1], + }, 99) + require.Nil(t, res.Err) + } + + // add users to channels + userIDChannelIDs := [][]string{ + {userA.Id, channelConstrained.Id}, + {userB.Id, channelConstrained.Id}, + {userC.Id, channelConstrained.Id}, + {userA.Id, channelUnconstrained.Id}, + {userB.Id, channelUnconstrained.Id}, + {userC.Id, channelUnconstrained.Id}, + } + + for _, item := range userIDChannelIDs { + res = <-ss.Channel().SaveMember(&model.ChannelMember{ + UserId: item[0], + ChannelId: item[1], + NotifyProps: model.GetDefaultChannelNotifyProps(), + }) + require.Nil(t, res.Err) + } + + return &removalsData{ + UserA: userA, + UserB: userB, + UserC: userC, + ConstrainedChannel: channelConstrained, + UnconstrainedChannel: channelUnconstrained, + ConstrainedTeam: teamConstrained, + UnconstrainedTeam: teamUnconstrained, + Group: group, + } } diff --git a/store/storetest/mocks/GroupStore.go b/store/storetest/mocks/GroupStore.go index 36f8f8787b..6933ffcffd 100644 --- a/store/storetest/mocks/GroupStore.go +++ b/store/storetest/mocks/GroupStore.go @@ -237,13 +237,13 @@ func (_m *GroupStore) GetMemberUsersPage(groupID string, offset int, limit int) return r0 } -// PendingAutoAddChannelMembers provides a mock function with given fields: minGroupMembersCreateAt -func (_m *GroupStore) PendingAutoAddChannelMembers(minGroupMembersCreateAt int64) store.StoreChannel { - ret := _m.Called(minGroupMembersCreateAt) +// ChannelMembersToAdd provides a mock function with given fields: since +func (_m *GroupStore) ChannelMembersToAdd(since int64) store.StoreChannel { + ret := _m.Called(since) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(int64) store.StoreChannel); ok { - r0 = rf(minGroupMembersCreateAt) + r0 = rf(since) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(store.StoreChannel) @@ -253,13 +253,45 @@ func (_m *GroupStore) PendingAutoAddChannelMembers(minGroupMembersCreateAt int64 return r0 } -// PendingAutoAddTeamMembers provides a mock function with given fields: minGroupMembersCreateAt -func (_m *GroupStore) PendingAutoAddTeamMembers(minGroupMembersCreateAt int64) store.StoreChannel { - ret := _m.Called(minGroupMembersCreateAt) +// TeamMembersToAdd provides a mock function with given fields: since +func (_m *GroupStore) TeamMembersToAdd(since int64) store.StoreChannel { + ret := _m.Called(since) var r0 store.StoreChannel if rf, ok := ret.Get(0).(func(int64) store.StoreChannel); ok { - r0 = rf(minGroupMembersCreateAt) + r0 = rf(since) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + +// ChannelMembersToRemove provides a mock function with given fields: +func (_m *GroupStore) ChannelMembersToRemove() store.StoreChannel { + ret := _m.Called() + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func() store.StoreChannel); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(store.StoreChannel) + } + } + + return r0 +} + +// TeamMembersToRemove provides a mock function with given fields: +func (_m *GroupStore) TeamMembersToRemove() store.StoreChannel { + ret := _m.Called() + + var r0 store.StoreChannel + if rf, ok := ret.Get(0).(func() store.StoreChannel); ok { + r0 = rf() } else { if ret.Get(0) != nil { r0 = ret.Get(0).(store.StoreChannel) diff --git a/store/storetest/mocks/LayeredStoreDatabaseLayer.go b/store/storetest/mocks/LayeredStoreDatabaseLayer.go index cb39241e64..167cdc9196 100644 --- a/store/storetest/mocks/LayeredStoreDatabaseLayer.go +++ b/store/storetest/mocks/LayeredStoreDatabaseLayer.go @@ -658,20 +658,20 @@ func (_m *LayeredStoreDatabaseLayer) OAuth() store.OAuthStore { return r0 } -// PendingAutoAddChannelMembers provides a mock function with given fields: ctx, minGroupMembersCreateAt, hints -func (_m *LayeredStoreDatabaseLayer) PendingAutoAddChannelMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +// ChannelMembersToAdd provides a mock function with given fields: ctx, since, hints +func (_m *LayeredStoreDatabaseLayer) ChannelMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) for _i := range hints { _va[_i] = hints[_i] } var _ca []interface{} - _ca = append(_ca, ctx, minGroupMembersCreateAt) + _ca = append(_ca, ctx, since) _ca = append(_ca, _va...) ret := _m.Called(_ca...) var r0 *store.LayeredStoreSupplierResult if rf, ok := ret.Get(0).(func(context.Context, int64, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { - r0 = rf(ctx, minGroupMembersCreateAt, hints...) + r0 = rf(ctx, since, hints...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) @@ -681,20 +681,66 @@ func (_m *LayeredStoreDatabaseLayer) PendingAutoAddChannelMembers(ctx context.Co return r0 } -// PendingAutoAddTeamMembers provides a mock function with given fields: ctx, minGroupMembersCreateAt, hints -func (_m *LayeredStoreDatabaseLayer) PendingAutoAddTeamMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +// TeamMembersToAdd provides a mock function with given fields: ctx, since, hints +func (_m *LayeredStoreDatabaseLayer) TeamMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) for _i := range hints { _va[_i] = hints[_i] } var _ca []interface{} - _ca = append(_ca, ctx, minGroupMembersCreateAt) + _ca = append(_ca, ctx, since) _ca = append(_ca, _va...) ret := _m.Called(_ca...) var r0 *store.LayeredStoreSupplierResult if rf, ok := ret.Get(0).(func(context.Context, int64, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { - r0 = rf(ctx, minGroupMembersCreateAt, hints...) + r0 = rf(ctx, since, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + +// ChannelMembersToRemove provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreDatabaseLayer) ChannelMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + +// TeamMembersToRemove provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreDatabaseLayer) TeamMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) diff --git a/store/storetest/mocks/LayeredStoreSupplier.go b/store/storetest/mocks/LayeredStoreSupplier.go index e6cec590f7..6f37fb5867 100644 --- a/store/storetest/mocks/LayeredStoreSupplier.go +++ b/store/storetest/mocks/LayeredStoreSupplier.go @@ -398,20 +398,20 @@ func (_m *LayeredStoreSupplier) Next() store.LayeredStoreSupplier { return r0 } -// PendingAutoAddChannelMembers provides a mock function with given fields: ctx, minGroupMembersCreateAt, hints -func (_m *LayeredStoreSupplier) PendingAutoAddChannelMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +// ChannelMembersToAdd provides a mock function with given fields: ctx, since, hints +func (_m *LayeredStoreSupplier) ChannelMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) for _i := range hints { _va[_i] = hints[_i] } var _ca []interface{} - _ca = append(_ca, ctx, minGroupMembersCreateAt) + _ca = append(_ca, ctx, since) _ca = append(_ca, _va...) ret := _m.Called(_ca...) var r0 *store.LayeredStoreSupplierResult if rf, ok := ret.Get(0).(func(context.Context, int64, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { - r0 = rf(ctx, minGroupMembersCreateAt, hints...) + r0 = rf(ctx, since, hints...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) @@ -421,20 +421,66 @@ func (_m *LayeredStoreSupplier) PendingAutoAddChannelMembers(ctx context.Context return r0 } -// PendingAutoAddTeamMembers provides a mock function with given fields: ctx, minGroupMembersCreateAt, hints -func (_m *LayeredStoreSupplier) PendingAutoAddTeamMembers(ctx context.Context, minGroupMembersCreateAt int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { +// TeamMembersToAdd provides a mock function with given fields: ctx, since, hints +func (_m *LayeredStoreSupplier) TeamMembersToAdd(ctx context.Context, since int64, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { _va := make([]interface{}, len(hints)) for _i := range hints { _va[_i] = hints[_i] } var _ca []interface{} - _ca = append(_ca, ctx, minGroupMembersCreateAt) + _ca = append(_ca, ctx, since) _ca = append(_ca, _va...) ret := _m.Called(_ca...) var r0 *store.LayeredStoreSupplierResult if rf, ok := ret.Get(0).(func(context.Context, int64, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { - r0 = rf(ctx, minGroupMembersCreateAt, hints...) + r0 = rf(ctx, since, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + +// ChannelMembersToRemove provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreSupplier) ChannelMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) + } + } + + return r0 +} + +// TeamMembersToRemove provides a mock function with given fields: ctx, hints +func (_m *LayeredStoreSupplier) TeamMembersToRemove(ctx context.Context, hints ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult { + _va := make([]interface{}, len(hints)) + for _i := range hints { + _va[_i] = hints[_i] + } + var _ca []interface{} + _ca = append(_ca, ctx) + _ca = append(_ca, _va...) + ret := _m.Called(_ca...) + + var r0 *store.LayeredStoreSupplierResult + if rf, ok := ret.Get(0).(func(context.Context, ...store.LayeredStoreHint) *store.LayeredStoreSupplierResult); ok { + r0 = rf(ctx, hints...) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*store.LayeredStoreSupplierResult) diff --git a/tests/add-groups.ldif b/tests/add-groups.ldif deleted file mode 100644 index e6202871bb..0000000000 --- a/tests/add-groups.ldif +++ /dev/null @@ -1,81 +0,0 @@ -dn: ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: organizationalunit - -# groupOfNames -dn: cn=outsiders,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: uid=board.three,ou=testusers,dc=mm,dc=test,dc=com - -dn: cn=board,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: uid=board.one,ou=testusers,dc=mm,dc=test,dc=com -member: uid=board.two,ou=testusers,dc=mm,dc=test,dc=com -member: cn=outsiders,ou=testgroups,dc=mm,dc=test,dc=com - -dn: cn=executive,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: uid=exec.one,ou=testusers,dc=mm,dc=test,dc=com -member: uid=exec.two,ou=testusers,dc=mm,dc=test,dc=com -member: cn=board,ou=testgroups,dc=mm,dc=test,dc=com - -dn: cn=tgroup-84,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: cn=tgroup-9,ou=testgroups,dc=mm,dc=test,dc=com -member: uid=test.five,ou=testusers,dc=mm,dc=test,dc=com - -dn: cn=tgroup-9,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: cn=tgroup-97,ou=testgroups,dc=mm,dc=test,dc=com - -dn: cn=tgroup-97,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfNames -member: uid=test.four,ou=testusers,dc=mm,dc=test,dc=com - -# groupOfUniqueNames -dn: cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=test.one,ou=testusers,dc=mm,dc=test,dc=com - -dn: cn=ugroup,cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=test.two,ou=testusers,dc=mm,dc=test,dc=com - -dn: cn=vgroup,cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=test.three,ou=testusers,dc=mm,dc=test,dc=com - -# Adds a group with a cycle -dn: cn=team-one-a,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=dev.four,ou=testusers,dc=mm,dc=test,dc=com -uniqueMember: cn=developers,ou=testgroups,dc=mm,dc=test,dc=com - -dn: cn=team-one,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=dev.one,ou=testusers,dc=mm,dc=test,dc=com -uniqueMember: uid=dev.three,ou=testusers,dc=mm,dc=test,dc=com -uniqueMember: cn=team-one-a,ou=testgroups,dc=mm,dc=test,dc=com - -dn: cn=team-two,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=dev.two,ou=testusers,dc=mm,dc=test,dc=com - -dn: cn=developers,ou=testgroups,dc=mm,dc=test,dc=com -changetype: add -objectclass: groupOfUniqueNames -uniqueMember: uid=dev-ops.one,ou=testusers,dc=mm,dc=test,dc=com -uniqueMember: cn=team-one,ou=testgroups,dc=mm,dc=test,dc=com -uniqueMember: cn=team-two,ou=testgroups,dc=mm,dc=test,dc=com \ No newline at end of file diff --git a/tests/add-users.ldif b/tests/test-data.ldif similarity index 50% rename from tests/add-users.ldif rename to tests/test-data.ldif index d96d0e46c1..44d2bb6f5e 100644 --- a/tests/add-users.ldif +++ b/tests/test-data.ldif @@ -127,4 +127,86 @@ objectclass: iNetOrgPerson sn: User cn: Board3 mail: success+boardthree@simulator.amazonses.com -userPassword: Password1 \ No newline at end of file +userPassword: Password1 + +dn: ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: organizationalunit + +# groupOfNames +dn: cn=outsiders,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: uid=board.three,ou=testusers,dc=mm,dc=test,dc=com + +dn: cn=board,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: uid=board.one,ou=testusers,dc=mm,dc=test,dc=com +member: uid=board.two,ou=testusers,dc=mm,dc=test,dc=com +member: cn=outsiders,ou=testgroups,dc=mm,dc=test,dc=com + +dn: cn=executive,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: uid=exec.one,ou=testusers,dc=mm,dc=test,dc=com +member: uid=exec.two,ou=testusers,dc=mm,dc=test,dc=com +member: cn=board,ou=testgroups,dc=mm,dc=test,dc=com + +dn: cn=tgroup-84,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: cn=tgroup-9,ou=testgroups,dc=mm,dc=test,dc=com +member: uid=test.five,ou=testusers,dc=mm,dc=test,dc=com + +dn: cn=tgroup-9,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: cn=tgroup-97,ou=testgroups,dc=mm,dc=test,dc=com + +dn: cn=tgroup-97,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfNames +member: uid=test.four,ou=testusers,dc=mm,dc=test,dc=com + +# groupOfUniqueNames +dn: cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=test.one,ou=testusers,dc=mm,dc=test,dc=com + +dn: cn=ugroup,cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=test.two,ou=testusers,dc=mm,dc=test,dc=com + +dn: cn=vgroup,cn=tgroup,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=test.three,ou=testusers,dc=mm,dc=test,dc=com + +# Adds a group with a cycle +dn: cn=team-one-a,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=dev.four,ou=testusers,dc=mm,dc=test,dc=com +uniqueMember: cn=developers,ou=testgroups,dc=mm,dc=test,dc=com + +dn: cn=team-one,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=dev.one,ou=testusers,dc=mm,dc=test,dc=com +uniqueMember: uid=dev.three,ou=testusers,dc=mm,dc=test,dc=com +uniqueMember: cn=team-one-a,ou=testgroups,dc=mm,dc=test,dc=com + +dn: cn=team-two,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=dev.two,ou=testusers,dc=mm,dc=test,dc=com + +dn: cn=developers,ou=testgroups,dc=mm,dc=test,dc=com +changetype: add +objectclass: groupOfUniqueNames +uniqueMember: uid=dev-ops.one,ou=testusers,dc=mm,dc=test,dc=com +uniqueMember: cn=team-one,ou=testgroups,dc=mm,dc=test,dc=com +uniqueMember: cn=team-two,ou=testgroups,dc=mm,dc=test,dc=com \ No newline at end of file