From 240e57d58158dae7d522cf7bebbc97cf5a63da7a Mon Sep 17 00:00:00 2001 From: Martin Kraft Date: Thu, 6 Feb 2020 09:25:36 -0500 Subject: [PATCH] MM-21199: Adds groups diagnostics. (#13736) --- app/diagnostics.go | 49 +++++++ store/sqlstore/channel_store.go | 16 +++ store/sqlstore/group_store.go | 40 ++++++ store/sqlstore/team_store.go | 16 +++ store/store.go | 21 +++ store/storetest/channel_store.go | 35 +++++ store/storetest/group_store.go | 198 ++++++++++++++++++++++++++ store/storetest/mocks/ChannelStore.go | 23 +++ store/storetest/mocks/GroupStore.go | 115 +++++++++++++++ store/storetest/mocks/TeamStore.go | 23 +++ store/storetest/team_store.go | 37 +++++ 11 files changed, 573 insertions(+) diff --git a/app/diagnostics.go b/app/diagnostics.go index e4360b627e..937c6a7014 100644 --- a/app/diagnostics.go +++ b/app/diagnostics.go @@ -53,6 +53,7 @@ const ( TRACK_PERMISSIONS_SYSTEM_SCHEME = "permissions_system_scheme" TRACK_PERMISSIONS_TEAM_SCHEMES = "permissions_team_schemes" TRACK_ELASTICSEARCH = "elasticsearch" + TRACK_GROUPS = "groups" TRACK_ACTIVITY = "activity" TRACK_LICENSE = "license" @@ -74,6 +75,7 @@ func (a *App) sendDailyDiagnostics(override bool) { a.trackServer() a.trackPermissions() a.trackElasticsearch() + a.trackGroups() } } @@ -914,3 +916,50 @@ func (a *App) trackElasticsearch() { a.SendDiagnostic(TRACK_ELASTICSEARCH, data) } + +func (a *App) trackGroups() { + groupCount, err := a.Srv.Store.Group().GroupCount() + if err != nil { + mlog.Error(err.Error()) + } + + groupTeamCount, err := a.Srv.Store.Group().GroupTeamCount() + if err != nil { + mlog.Error(err.Error()) + } + + groupChannelCount, err := a.Srv.Store.Group().GroupChannelCount() + if err != nil { + mlog.Error(err.Error()) + } + + groupSyncedTeamCount, err := a.Srv.Store.Team().GroupSyncedTeamCount() + if err != nil { + mlog.Error(err.Error()) + } + + groupSyncedChannelCount, err := a.Srv.Store.Channel().GroupSyncedChannelCount() + if err != nil { + mlog.Error(err.Error()) + } + + groupMemberCount, err := a.Srv.Store.Group().GroupMemberCount() + if err != nil { + mlog.Error(err.Error()) + } + + distinctGroupMemberCount, err := a.Srv.Store.Group().DistinctGroupMemberCount() + if err != nil { + mlog.Error(err.Error()) + } + + a.SendDiagnostic(TRACK_GROUPS, map[string]interface{}{ + "group_count": groupCount, + "group_team_count": groupTeamCount, + "group_channel_count": groupChannelCount, + "group_synced_team_count": groupSyncedTeamCount, + "group_synced_channel_count": groupSyncedChannelCount, + "group_member_count": groupMemberCount, + "distinct_group_member_count": distinctGroupMemberCount, + }) +} diff --git a/store/sqlstore/channel_store.go b/store/sqlstore/channel_store.go index e1527431a4..903f29c10b 100644 --- a/store/sqlstore/channel_store.go +++ b/store/sqlstore/channel_store.go @@ -2854,3 +2854,19 @@ func (s SqlChannelStore) UpdateMembersRole(channelID string, userIDs []string) * return nil } + +func (s SqlChannelStore) GroupSyncedChannelCount() (int64, *model.AppError) { + query := s.getQueryBuilder().Select("COUNT(*)").From("Channels").Where(sq.Eq{"GroupConstrained": true, "DeleteAt": 0}) + + sql, args, err := query.ToSql() + if err != nil { + return 0, model.NewAppError("SqlChannelStore.GroupSyncedChannelCount", "store.sql_group.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + count, err := s.GetReplica().SelectInt(sql, args...) + if err != nil { + return 0, model.NewAppError("SqlChannelStore.GroupSyncedChannelCount", "store.select_error", nil, err.Error(), http.StatusInternalServerError) + } + + return count, nil +} diff --git a/store/sqlstore/group_store.go b/store/sqlstore/group_store.go index 5f80565748..ac106d8e72 100644 --- a/store/sqlstore/group_store.go +++ b/store/sqlstore/group_store.go @@ -1228,3 +1228,43 @@ func (s *SqlGroupStore) PermittedSyncableAdmins(syncableID string, syncableType return userIDs, nil } + +func (s *SqlGroupStore) GroupCount() (int64, *model.AppError) { + return s.countTable("UserGroups") +} + +func (s *SqlGroupStore) GroupTeamCount() (int64, *model.AppError) { + return s.countTable("GroupTeams") +} + +func (s *SqlGroupStore) GroupChannelCount() (int64, *model.AppError) { + return s.countTable("GroupChannels") +} + +func (s *SqlGroupStore) GroupMemberCount() (int64, *model.AppError) { + return s.countTable("GroupMembers") +} + +func (s *SqlGroupStore) DistinctGroupMemberCount() (int64, *model.AppError) { + return s.countTableWithSelect("COUNT(DISTINCT UserId)", "GroupMembers") +} + +func (s *SqlGroupStore) countTable(tableName string) (int64, *model.AppError) { + return s.countTableWithSelect("COUNT(*)", tableName) +} + +func (s *SqlGroupStore) countTableWithSelect(selectStr, tableName string) (int64, *model.AppError) { + query := s.getQueryBuilder().Select(selectStr).From(tableName).Where(sq.Eq{"DeleteAt": 0}) + + sql, args, err := query.ToSql() + if err != nil { + return 0, model.NewAppError("SqlGroupStore.countTableWithSelect", "store.sql_group.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + count, err := s.GetReplica().SelectInt(sql, args...) + if err != nil { + return 0, model.NewAppError("SqlGroupStore.countTableWithSelect", "store.select_error", nil, err.Error(), http.StatusInternalServerError) + } + + return count, nil +} diff --git a/store/sqlstore/team_store.go b/store/sqlstore/team_store.go index 386270f569..41970f83fb 100644 --- a/store/sqlstore/team_store.go +++ b/store/sqlstore/team_store.go @@ -1162,3 +1162,19 @@ func applyTeamMemberViewRestrictionsFilterForStats(query sq.SelectBuilder, teamI return resultQuery } + +func (s SqlTeamStore) GroupSyncedTeamCount() (int64, *model.AppError) { + query := s.getQueryBuilder().Select("COUNT(*)").From("Teams").Where(sq.Eq{"GroupConstrained": true, "DeleteAt": 0}) + + sql, args, err := query.ToSql() + if err != nil { + return 0, model.NewAppError("SqlTeamStore.GroupSyncedTeamCount", "store.sql_group.app_error", nil, err.Error(), http.StatusInternalServerError) + } + + count, err := s.GetReplica().SelectInt(sql, args...) + if err != nil { + return 0, model.NewAppError("SqlTeamStore.GroupSyncedTeamCount", "store.select_error", nil, err.Error(), http.StatusInternalServerError) + } + + return count, nil +} diff --git a/store/store.go b/store/store.go index 4ab9a82219..c0fce55baa 100644 --- a/store/store.go +++ b/store/store.go @@ -110,6 +110,9 @@ type TeamStore interface { // UpdateMembersRole sets all of the given team members to admins and all of the other members of the team to // non-admin members. UpdateMembersRole(teamID string, userIDs []string) *model.AppError + + // GroupSyncedTeamCount returns the count of non-deleted group-constrained teams. + GroupSyncedTeamCount() (int64, *model.AppError) } type ChannelStore interface { @@ -198,6 +201,9 @@ type ChannelStore interface { // UpdateMembersRole sets all of the given team members to admins and all of the other members of the team to // non-admin members. UpdateMembersRole(channelID string, userIDs []string) *model.AppError + + // GroupSyncedChannelCount returns the count of non-deleted group-constrained channels. + GroupSyncedChannelCount() (int64, *model.AppError) } type ChannelMemberHistoryStore interface { @@ -639,6 +645,21 @@ type GroupStore interface { // PermittedSyncableAdmins returns the IDs of all of the user who are permitted by the group syncable to have // the admin role for the given syncable. PermittedSyncableAdmins(syncableID string, syncableType model.GroupSyncableType) ([]string, *model.AppError) + + // GroupCount returns the total count of records in the UserGroups table. + GroupCount() (int64, *model.AppError) + + // GroupTeamCount returns the total count of records in the GroupTeams table. + GroupTeamCount() (int64, *model.AppError) + + // GroupChannelCount returns the total count of records in the GroupChannels table. + GroupChannelCount() (int64, *model.AppError) + + // GroupMemberCount returns the total count of records in the GroupMembers table. + GroupMemberCount() (int64, *model.AppError) + + // DistinctGroupMemberCount returns the count of records in the GroupMembers table with distinct UserId values. + DistinctGroupMemberCount() (int64, *model.AppError) } type LinkMetadataStore interface { diff --git a/store/storetest/channel_store.go b/store/storetest/channel_store.go index d7c4948ab1..bc0f8ca451 100644 --- a/store/storetest/channel_store.go +++ b/store/storetest/channel_store.go @@ -88,6 +88,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlSupplier) { t.Run("ExportAllDirectChannelsExcludePrivateAndPublic", func(t *testing.T) { testChannelStoreExportAllDirectChannelsExcludePrivateAndPublic(t, ss, s) }) t.Run("ExportAllDirectChannelsDeletedChannel", func(t *testing.T) { testChannelStoreExportAllDirectChannelsDeletedChannel(t, ss, s) }) t.Run("GetChannelsBatchForIndexing", func(t *testing.T) { testChannelStoreGetChannelsBatchForIndexing(t, ss) }) + t.Run("GroupSyncedChannelCount", func(t *testing.T) { testGroupSyncedChannelCount(t, ss) }) } func testChannelStoreSave(t *testing.T, ss store.Store) { @@ -4221,3 +4222,37 @@ func testChannelStoreGetChannelsBatchForIndexing(t *testing.T, ss store.Store) { assert.Nil(t, err) assert.ElementsMatch(t, []*model.Channel{c2, c3}, channels) } + +func testGroupSyncedChannelCount(t *testing.T, ss store.Store) { + channel1, err := ss.Channel().Save(&model.Channel{ + DisplayName: model.NewId(), + Name: model.NewId(), + Type: model.CHANNEL_PRIVATE, + GroupConstrained: model.NewBool(true), + }, 999) + require.Nil(t, err) + require.True(t, channel1.IsGroupConstrained()) + defer ss.Channel().PermanentDelete(channel1.Id) + + channel2, err := ss.Channel().Save(&model.Channel{ + DisplayName: model.NewId(), + Name: model.NewId(), + Type: model.CHANNEL_PRIVATE, + }, 999) + require.Nil(t, err) + require.False(t, channel2.IsGroupConstrained()) + defer ss.Channel().PermanentDelete(channel2.Id) + + count, err := ss.Channel().GroupSyncedChannelCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + channel2.GroupConstrained = model.NewBool(true) + channel2, err = ss.Channel().Update(channel2) + require.Nil(t, err) + require.True(t, channel2.IsGroupConstrained()) + + countAfter, err := ss.Channel().GroupSyncedChannelCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +} diff --git a/store/storetest/group_store.go b/store/storetest/group_store.go index 5d9cb49cff..2b128c794b 100644 --- a/store/storetest/group_store.go +++ b/store/storetest/group_store.go @@ -69,6 +69,12 @@ func TestGroupStore(t *testing.T, ss store.Store) { t.Run("PermittedSyncableAdmins_Channel", func(t *testing.T) { groupTestPermittedSyncableAdminsChannel(t, ss) }) t.Run("UpdateMembersRole_Team", func(t *testing.T) { groupTestpUpdateMembersRoleTeam(t, ss) }) t.Run("UpdateMembersRole_Channel", func(t *testing.T) { groupTestpUpdateMembersRoleChannel(t, ss) }) + + t.Run("GroupCount", func(t *testing.T) { groupTestGroupCount(t, ss) }) + t.Run("GroupTeamCount", func(t *testing.T) { groupTestGroupTeamCount(t, ss) }) + t.Run("GroupChannelCount", func(t *testing.T) { groupTestGroupChannelCount(t, ss) }) + t.Run("GroupMemberCount", func(t *testing.T) { groupTestGroupMemberCount(t, ss) }) + t.Run("DistinctGroupMemberCount", func(t *testing.T) { groupTestDistinctGroupMemberCount(t, ss) }) } func testGroupStoreCreate(t *testing.T, ss store.Store) { @@ -3768,3 +3774,195 @@ func groupTestpUpdateMembersRoleChannel(t *testing.T, ss store.Store) { }) } } + +func groupTestGroupCount(t *testing.T, ss store.Store) { + group1, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group1.Id) + + count, err := ss.Group().GroupCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + group2, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group2.Id) + + countAfter, err := ss.Group().GroupCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +} + +func groupTestGroupTeamCount(t *testing.T, ss store.Store) { + team, err := ss.Team().Save(&model.Team{ + DisplayName: model.NewId(), + Description: model.NewId(), + AllowOpenInvite: false, + InviteId: model.NewId(), + Name: model.NewId(), + Email: model.NewId() + "@simulator.amazonses.com", + Type: model.TEAM_OPEN, + }) + require.Nil(t, err) + defer ss.Team().PermanentDelete(team.Id) + + group1, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group1.Id) + + group2, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group2.Id) + + groupSyncable1, err := ss.Group().CreateGroupSyncable(model.NewGroupTeam(group1.Id, team.Id, false)) + require.Nil(t, err) + defer ss.Group().DeleteGroupSyncable(groupSyncable1.GroupId, groupSyncable1.SyncableId, groupSyncable1.Type) + + count, err := ss.Group().GroupTeamCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + groupSyncable2, err := ss.Group().CreateGroupSyncable(model.NewGroupTeam(group2.Id, team.Id, false)) + require.Nil(t, err) + defer ss.Group().DeleteGroupSyncable(groupSyncable2.GroupId, groupSyncable2.SyncableId, groupSyncable2.Type) + + countAfter, err := ss.Group().GroupTeamCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +} + +func groupTestGroupChannelCount(t *testing.T, ss store.Store) { + channel, err := ss.Channel().Save(&model.Channel{ + TeamId: model.NewId(), + DisplayName: model.NewId(), + Name: model.NewId(), + Type: model.CHANNEL_OPEN, + }, 9999) + require.Nil(t, err) + defer ss.Channel().Delete(channel.Id, 0) + + group1, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group1.Id) + + group2, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group2.Id) + + groupSyncable1, err := ss.Group().CreateGroupSyncable(model.NewGroupChannel(group1.Id, channel.Id, false)) + require.Nil(t, err) + defer ss.Group().DeleteGroupSyncable(groupSyncable1.GroupId, groupSyncable1.SyncableId, groupSyncable1.Type) + + count, err := ss.Group().GroupChannelCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + groupSyncable2, err := ss.Group().CreateGroupSyncable(model.NewGroupChannel(group2.Id, channel.Id, false)) + require.Nil(t, err) + defer ss.Group().DeleteGroupSyncable(groupSyncable2.GroupId, groupSyncable2.SyncableId, groupSyncable2.Type) + + countAfter, err := ss.Group().GroupChannelCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +} + +func groupTestGroupMemberCount(t *testing.T, ss store.Store) { + group, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group.Id) + + member1, err := ss.Group().UpsertMember(group.Id, model.NewId()) + require.Nil(t, err) + defer ss.Group().DeleteMember(group.Id, member1.UserId) + + count, err := ss.Group().GroupMemberCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + member2, err := ss.Group().UpsertMember(group.Id, model.NewId()) + require.Nil(t, err) + defer ss.Group().DeleteMember(group.Id, member2.UserId) + + countAfter, err := ss.Group().GroupMemberCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +} + +func groupTestDistinctGroupMemberCount(t *testing.T, ss store.Store) { + group1, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group1.Id) + + group2, err := ss.Group().Create(&model.Group{ + Name: model.NewId(), + DisplayName: model.NewId(), + Source: model.GroupSourceLdap, + RemoteId: model.NewId(), + }) + require.Nil(t, err) + defer ss.Group().Delete(group2.Id) + + member1, err := ss.Group().UpsertMember(group1.Id, model.NewId()) + require.Nil(t, err) + defer ss.Group().DeleteMember(group1.Id, member1.UserId) + + count, err := ss.Group().GroupMemberCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + member2, err := ss.Group().UpsertMember(group1.Id, model.NewId()) + require.Nil(t, err) + defer ss.Group().DeleteMember(group1.Id, member2.UserId) + + countAfter1, err := ss.Group().GroupMemberCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter1, count+1) + + member3, err := ss.Group().UpsertMember(group1.Id, member1.UserId) + require.Nil(t, err) + defer ss.Group().DeleteMember(group1.Id, member3.UserId) + + countAfter2, err := ss.Group().GroupMemberCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter2, countAfter1) +} diff --git a/store/storetest/mocks/ChannelStore.go b/store/storetest/mocks/ChannelStore.go index d28537fc71..23029d9cc2 100644 --- a/store/storetest/mocks/ChannelStore.go +++ b/store/storetest/mocks/ChannelStore.go @@ -1127,6 +1127,29 @@ func (_m *ChannelStore) GetTeamChannels(teamId string) (*model.ChannelList, *mod return r0, r1 } +// GroupSyncedChannelCount provides a mock function with given fields: +func (_m *ChannelStore) GroupSyncedChannelCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // IncrementMentionCount provides a mock function with given fields: channelId, userId func (_m *ChannelStore) IncrementMentionCount(channelId string, userId string) *model.AppError { ret := _m.Called(channelId, userId) diff --git a/store/storetest/mocks/GroupStore.go b/store/storetest/mocks/GroupStore.go index cc618e88bb..ab594635c3 100644 --- a/store/storetest/mocks/GroupStore.go +++ b/store/storetest/mocks/GroupStore.go @@ -331,6 +331,29 @@ func (_m *GroupStore) DeleteMember(groupID string, userID string) (*model.GroupM return r0, r1 } +// DistinctGroupMemberCount provides a mock function with given fields: +func (_m *GroupStore) DistinctGroupMemberCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // Get provides a mock function with given fields: groupID func (_m *GroupStore) Get(groupID string) (*model.Group, *model.AppError) { ret := _m.Called(groupID) @@ -679,6 +702,98 @@ func (_m *GroupStore) GetMemberUsersPage(groupID string, page int, perPage int) return r0, r1 } +// GroupChannelCount provides a mock function with given fields: +func (_m *GroupStore) GroupChannelCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + +// GroupCount provides a mock function with given fields: +func (_m *GroupStore) GroupCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + +// GroupMemberCount provides a mock function with given fields: +func (_m *GroupStore) GroupMemberCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + +// GroupTeamCount provides a mock function with given fields: +func (_m *GroupStore) GroupTeamCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // PermanentDeleteMembersByUser provides a mock function with given fields: userId func (_m *GroupStore) PermanentDeleteMembersByUser(userId string) *model.AppError { ret := _m.Called(userId) diff --git a/store/storetest/mocks/TeamStore.go b/store/storetest/mocks/TeamStore.go index ea0e128f7d..9807d391ff 100644 --- a/store/storetest/mocks/TeamStore.go +++ b/store/storetest/mocks/TeamStore.go @@ -723,6 +723,29 @@ func (_m *TeamStore) GetUserTeamIds(userId string, allowFromCache bool) ([]strin return r0, r1 } +// GroupSyncedTeamCount provides a mock function with given fields: +func (_m *TeamStore) GroupSyncedTeamCount() (int64, *model.AppError) { + ret := _m.Called() + + var r0 int64 + if rf, ok := ret.Get(0).(func() int64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(int64) + } + + var r1 *model.AppError + if rf, ok := ret.Get(1).(func() *model.AppError); ok { + r1 = rf() + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*model.AppError) + } + } + + return r0, r1 +} + // InvalidateAllTeamIdsForUser provides a mock function with given fields: userId func (_m *TeamStore) InvalidateAllTeamIdsForUser(userId string) { _m.Called(userId) diff --git a/store/storetest/team_store.go b/store/storetest/team_store.go index c0d37edaf2..dc8f6efe30 100644 --- a/store/storetest/team_store.go +++ b/store/storetest/team_store.go @@ -61,6 +61,7 @@ func TestTeamStore(t *testing.T, ss store.Store) { t.Run("GetAllForExportAfter", func(t *testing.T) { testTeamStoreGetAllForExportAfter(t, ss) }) t.Run("GetTeamMembersForExport", func(t *testing.T) { testTeamStoreGetTeamMembersForExport(t, ss) }) t.Run("GetTeamsForUserWithPagination", func(t *testing.T) { testTeamMembersWithPagination(t, ss) }) + t.Run("GroupSyncedTeamCount", func(t *testing.T) { testGroupSyncedTeamCount(t, ss) }) } func testTeamStoreSave(t *testing.T, ss store.Store) { @@ -1683,3 +1684,39 @@ func testTeamStoreGetTeamMembersForExport(t *testing.T, ss store.Store) { assert.Equal(t, u1.Id, tmfe1.UserId) assert.Equal(t, t1.Name, tmfe1.TeamName) } + +func testGroupSyncedTeamCount(t *testing.T, ss store.Store) { + team1, err := ss.Team().Save(&model.Team{ + DisplayName: model.NewId(), + Name: model.NewId(), + Email: MakeEmail(), + Type: model.TEAM_INVITE, + GroupConstrained: model.NewBool(true), + }) + require.Nil(t, err) + require.True(t, team1.IsGroupConstrained()) + defer ss.Team().PermanentDelete(team1.Id) + + team2, err := ss.Team().Save(&model.Team{ + DisplayName: model.NewId(), + Name: model.NewId(), + Email: MakeEmail(), + Type: model.TEAM_INVITE, + }) + require.Nil(t, err) + require.False(t, team2.IsGroupConstrained()) + defer ss.Team().PermanentDelete(team2.Id) + + count, err := ss.Team().GroupSyncedTeamCount() + require.Nil(t, err) + require.GreaterOrEqual(t, count, int64(1)) + + team2.GroupConstrained = model.NewBool(true) + team2, err = ss.Team().Update(team2) + require.Nil(t, err) + require.True(t, team2.IsGroupConstrained()) + + countAfter, err := ss.Team().GroupSyncedTeamCount() + require.Nil(t, err) + require.GreaterOrEqual(t, countAfter, count+1) +}