From ce98ec55fca7cd82d47b5dede08e925b9ee59b5a Mon Sep 17 00:00:00 2001 From: Miguel de la Cruz Date: Wed, 29 Sep 2021 18:19:34 +0200 Subject: [PATCH] Recovers inactive websockets connections on reconnect in plugin mode (#1324) * Stores a cache of inactive connections so their subscriptions are recovered on reconnections * Adds test for getUserIDsForWorkspace and simplify messages through helpers * Make the plugin websocket client more resilient * Remove missed event callback and limit ws state polling to one at a time * Add read lock for the plugin adapter and guarantee atomic ops on inactiveAt * Add mutex to the plugin adapter client and tests to cover for races * Split plugin adapter mutex in two and use them to lock only on data access * Group plugin adapter fields by the mutex that's guarding them --- server/auth/auth.go | 7 + server/auth/mocks/mockauth_interface.go | 80 + server/ws/helpers_test.go | 57 + server/ws/mocks/mockpluginapi.go | 2468 +++++++++++++++++++++++ server/ws/plugin_adapter.go | 200 +- server/ws/plugin_adapter_client.go | 86 + server/ws/plugin_adapter_test.go | 346 ++++ webapp/src/utils.ts | 9 + webapp/src/wsclient.ts | 54 +- 9 files changed, 3217 insertions(+), 90 deletions(-) create mode 100644 server/auth/mocks/mockauth_interface.go create mode 100644 server/ws/helpers_test.go create mode 100644 server/ws/mocks/mockpluginapi.go create mode 100644 server/ws/plugin_adapter_client.go create mode 100644 server/ws/plugin_adapter_test.go diff --git a/server/auth/auth.go b/server/auth/auth.go index f966f60fd..92a24064a 100644 --- a/server/auth/auth.go +++ b/server/auth/auth.go @@ -1,3 +1,4 @@ +//go:generate mockgen --build_flags=--mod=mod -destination=mocks/mockauth_interface.go -package mocks . AuthInterface package auth import ( @@ -10,6 +11,12 @@ import ( "github.com/pkg/errors" ) +type AuthInterface interface { + GetSession(token string) (*model.Session, error) + IsValidReadToken(c store.Container, blockID string, readToken string) (bool, error) + DoesUserHaveWorkspaceAccess(userID string, workspaceID string) bool +} + // Auth authenticates sessions. type Auth struct { config *config.Configuration diff --git a/server/auth/mocks/mockauth_interface.go b/server/auth/mocks/mockauth_interface.go new file mode 100644 index 000000000..c6ef2e103 --- /dev/null +++ b/server/auth/mocks/mockauth_interface.go @@ -0,0 +1,80 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/mattermost/focalboard/server/auth (interfaces: AuthInterface) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + model "github.com/mattermost/focalboard/server/model" + store "github.com/mattermost/focalboard/server/services/store" +) + +// MockAuthInterface is a mock of AuthInterface interface. +type MockAuthInterface struct { + ctrl *gomock.Controller + recorder *MockAuthInterfaceMockRecorder +} + +// MockAuthInterfaceMockRecorder is the mock recorder for MockAuthInterface. +type MockAuthInterfaceMockRecorder struct { + mock *MockAuthInterface +} + +// NewMockAuthInterface creates a new mock instance. +func NewMockAuthInterface(ctrl *gomock.Controller) *MockAuthInterface { + mock := &MockAuthInterface{ctrl: ctrl} + mock.recorder = &MockAuthInterfaceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAuthInterface) EXPECT() *MockAuthInterfaceMockRecorder { + return m.recorder +} + +// DoesUserHaveWorkspaceAccess mocks base method. +func (m *MockAuthInterface) DoesUserHaveWorkspaceAccess(arg0, arg1 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DoesUserHaveWorkspaceAccess", arg0, arg1) + ret0, _ := ret[0].(bool) + return ret0 +} + +// DoesUserHaveWorkspaceAccess indicates an expected call of DoesUserHaveWorkspaceAccess. +func (mr *MockAuthInterfaceMockRecorder) DoesUserHaveWorkspaceAccess(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DoesUserHaveWorkspaceAccess", reflect.TypeOf((*MockAuthInterface)(nil).DoesUserHaveWorkspaceAccess), arg0, arg1) +} + +// GetSession mocks base method. +func (m *MockAuthInterface) GetSession(arg0 string) (*model.Session, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSession", arg0) + ret0, _ := ret[0].(*model.Session) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetSession indicates an expected call of GetSession. +func (mr *MockAuthInterfaceMockRecorder) GetSession(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSession", reflect.TypeOf((*MockAuthInterface)(nil).GetSession), arg0) +} + +// IsValidReadToken mocks base method. +func (m *MockAuthInterface) IsValidReadToken(arg0 store.Container, arg1, arg2 string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsValidReadToken", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsValidReadToken indicates an expected call of IsValidReadToken. +func (mr *MockAuthInterfaceMockRecorder) IsValidReadToken(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsValidReadToken", reflect.TypeOf((*MockAuthInterface)(nil).IsValidReadToken), arg0, arg1, arg2) +} diff --git a/server/ws/helpers_test.go b/server/ws/helpers_test.go new file mode 100644 index 000000000..2e34d65b3 --- /dev/null +++ b/server/ws/helpers_test.go @@ -0,0 +1,57 @@ +package ws + +import ( + "testing" + + authMocks "github.com/mattermost/focalboard/server/auth/mocks" + wsMocks "github.com/mattermost/focalboard/server/ws/mocks" + + mmModel "github.com/mattermost/mattermost-server/v6/model" + + "github.com/golang/mock/gomock" +) + +type TestHelper struct { + api *wsMocks.MockAPI + auth *authMocks.MockAuthInterface + ctrl *gomock.Controller + pa *PluginAdapter +} + +func SetupTestHelper(t *testing.T) *TestHelper { + ctrl := gomock.NewController(t) + mockAPI := wsMocks.NewMockAPI(ctrl) + mockAuth := authMocks.NewMockAuthInterface(ctrl) + + mockAPI.EXPECT().LogDebug(gomock.Any(), gomock.Any()).AnyTimes() + mockAPI.EXPECT().LogInfo(gomock.Any(), gomock.Any()).AnyTimes() + mockAPI.EXPECT().LogError(gomock.Any(), gomock.Any()).AnyTimes() + mockAPI.EXPECT().LogWarn(gomock.Any(), gomock.Any()).AnyTimes() + + return &TestHelper{ + api: mockAPI, + auth: mockAuth, + ctrl: ctrl, + pa: NewPluginAdapter(mockAPI, mockAuth), + } +} + +func (th *TestHelper) ReceiveWebSocketMessage(webConnID, userID, action string, data map[string]interface{}) { + req := &mmModel.WebSocketRequest{Action: websocketMessagePrefix + action, Data: data} + + th.pa.WebSocketMessageHasBeenPosted(webConnID, userID, req) +} + +func (th *TestHelper) SubscribeWebConnToWorkspace(webConnID, userID, workspaceID string) { + th.auth.EXPECT(). + DoesUserHaveWorkspaceAccess(userID, workspaceID). + Return(true) + + msgData := map[string]interface{}{"workspaceId": workspaceID} + th.ReceiveWebSocketMessage(webConnID, userID, websocketActionSubscribeWorkspace, msgData) +} + +func (th *TestHelper) UnsubscribeWebConnFromWorkspace(webConnID, userID, workspaceID string) { + msgData := map[string]interface{}{"workspaceId": workspaceID} + th.ReceiveWebSocketMessage(webConnID, userID, websocketActionUnsubscribeWorkspace, msgData) +} diff --git a/server/ws/mocks/mockpluginapi.go b/server/ws/mocks/mockpluginapi.go new file mode 100644 index 000000000..f6eacc759 --- /dev/null +++ b/server/ws/mocks/mockpluginapi.go @@ -0,0 +1,2468 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/mattermost/mattermost-server/v6/plugin (interfaces: API) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + io "io" + http "net/http" + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + model "github.com/mattermost/mattermost-server/v6/model" +) + +// MockAPI is a mock of API interface. +type MockAPI struct { + ctrl *gomock.Controller + recorder *MockAPIMockRecorder +} + +// MockAPIMockRecorder is the mock recorder for MockAPI. +type MockAPIMockRecorder struct { + mock *MockAPI +} + +// NewMockAPI creates a new mock instance. +func NewMockAPI(ctrl *gomock.Controller) *MockAPI { + mock := &MockAPI{ctrl: ctrl} + mock.recorder = &MockAPIMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAPI) EXPECT() *MockAPIMockRecorder { + return m.recorder +} + +// AddChannelMember mocks base method. +func (m *MockAPI) AddChannelMember(arg0, arg1 string) (*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddChannelMember", arg0, arg1) + ret0, _ := ret[0].(*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// AddChannelMember indicates an expected call of AddChannelMember. +func (mr *MockAPIMockRecorder) AddChannelMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddChannelMember", reflect.TypeOf((*MockAPI)(nil).AddChannelMember), arg0, arg1) +} + +// AddReaction mocks base method. +func (m *MockAPI) AddReaction(arg0 *model.Reaction) (*model.Reaction, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddReaction", arg0) + ret0, _ := ret[0].(*model.Reaction) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// AddReaction indicates an expected call of AddReaction. +func (mr *MockAPIMockRecorder) AddReaction(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddReaction", reflect.TypeOf((*MockAPI)(nil).AddReaction), arg0) +} + +// AddUserToChannel mocks base method. +func (m *MockAPI) AddUserToChannel(arg0, arg1, arg2 string) (*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddUserToChannel", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// AddUserToChannel indicates an expected call of AddUserToChannel. +func (mr *MockAPIMockRecorder) AddUserToChannel(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUserToChannel", reflect.TypeOf((*MockAPI)(nil).AddUserToChannel), arg0, arg1, arg2) +} + +// CopyFileInfos mocks base method. +func (m *MockAPI) CopyFileInfos(arg0 string, arg1 []string) ([]string, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CopyFileInfos", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CopyFileInfos indicates an expected call of CopyFileInfos. +func (mr *MockAPIMockRecorder) CopyFileInfos(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFileInfos", reflect.TypeOf((*MockAPI)(nil).CopyFileInfos), arg0, arg1) +} + +// CreateBot mocks base method. +func (m *MockAPI) CreateBot(arg0 *model.Bot) (*model.Bot, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateBot", arg0) + ret0, _ := ret[0].(*model.Bot) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateBot indicates an expected call of CreateBot. +func (mr *MockAPIMockRecorder) CreateBot(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBot", reflect.TypeOf((*MockAPI)(nil).CreateBot), arg0) +} + +// CreateChannel mocks base method. +func (m *MockAPI) CreateChannel(arg0 *model.Channel) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateChannel", arg0) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateChannel indicates an expected call of CreateChannel. +func (mr *MockAPIMockRecorder) CreateChannel(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChannel", reflect.TypeOf((*MockAPI)(nil).CreateChannel), arg0) +} + +// CreateChannelSidebarCategory mocks base method. +func (m *MockAPI) CreateChannelSidebarCategory(arg0, arg1 string, arg2 *model.SidebarCategoryWithChannels) (*model.SidebarCategoryWithChannels, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateChannelSidebarCategory", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.SidebarCategoryWithChannels) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateChannelSidebarCategory indicates an expected call of CreateChannelSidebarCategory. +func (mr *MockAPIMockRecorder) CreateChannelSidebarCategory(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChannelSidebarCategory", reflect.TypeOf((*MockAPI)(nil).CreateChannelSidebarCategory), arg0, arg1, arg2) +} + +// CreateCommand mocks base method. +func (m *MockAPI) CreateCommand(arg0 *model.Command) (*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateCommand", arg0) + ret0, _ := ret[0].(*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// CreateCommand indicates an expected call of CreateCommand. +func (mr *MockAPIMockRecorder) CreateCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCommand", reflect.TypeOf((*MockAPI)(nil).CreateCommand), arg0) +} + +// CreateOAuthApp mocks base method. +func (m *MockAPI) CreateOAuthApp(arg0 *model.OAuthApp) (*model.OAuthApp, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateOAuthApp", arg0) + ret0, _ := ret[0].(*model.OAuthApp) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateOAuthApp indicates an expected call of CreateOAuthApp. +func (mr *MockAPIMockRecorder) CreateOAuthApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateOAuthApp", reflect.TypeOf((*MockAPI)(nil).CreateOAuthApp), arg0) +} + +// CreatePost mocks base method. +func (m *MockAPI) CreatePost(arg0 *model.Post) (*model.Post, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreatePost", arg0) + ret0, _ := ret[0].(*model.Post) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreatePost indicates an expected call of CreatePost. +func (mr *MockAPIMockRecorder) CreatePost(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePost", reflect.TypeOf((*MockAPI)(nil).CreatePost), arg0) +} + +// CreateTeam mocks base method. +func (m *MockAPI) CreateTeam(arg0 *model.Team) (*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTeam", arg0) + ret0, _ := ret[0].(*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateTeam indicates an expected call of CreateTeam. +func (mr *MockAPIMockRecorder) CreateTeam(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTeam", reflect.TypeOf((*MockAPI)(nil).CreateTeam), arg0) +} + +// CreateTeamMember mocks base method. +func (m *MockAPI) CreateTeamMember(arg0, arg1 string) (*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTeamMember", arg0, arg1) + ret0, _ := ret[0].(*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateTeamMember indicates an expected call of CreateTeamMember. +func (mr *MockAPIMockRecorder) CreateTeamMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTeamMember", reflect.TypeOf((*MockAPI)(nil).CreateTeamMember), arg0, arg1) +} + +// CreateTeamMembers mocks base method. +func (m *MockAPI) CreateTeamMembers(arg0 string, arg1 []string, arg2 string) ([]*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTeamMembers", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateTeamMembers indicates an expected call of CreateTeamMembers. +func (mr *MockAPIMockRecorder) CreateTeamMembers(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTeamMembers", reflect.TypeOf((*MockAPI)(nil).CreateTeamMembers), arg0, arg1, arg2) +} + +// CreateTeamMembersGracefully mocks base method. +func (m *MockAPI) CreateTeamMembersGracefully(arg0 string, arg1 []string, arg2 string) ([]*model.TeamMemberWithError, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTeamMembersGracefully", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.TeamMemberWithError) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateTeamMembersGracefully indicates an expected call of CreateTeamMembersGracefully. +func (mr *MockAPIMockRecorder) CreateTeamMembersGracefully(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTeamMembersGracefully", reflect.TypeOf((*MockAPI)(nil).CreateTeamMembersGracefully), arg0, arg1, arg2) +} + +// CreateUser mocks base method. +func (m *MockAPI) CreateUser(arg0 *model.User) (*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUser", arg0) + ret0, _ := ret[0].(*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateUser indicates an expected call of CreateUser. +func (mr *MockAPIMockRecorder) CreateUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockAPI)(nil).CreateUser), arg0) +} + +// CreateUserAccessToken mocks base method. +func (m *MockAPI) CreateUserAccessToken(arg0 *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateUserAccessToken", arg0) + ret0, _ := ret[0].(*model.UserAccessToken) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// CreateUserAccessToken indicates an expected call of CreateUserAccessToken. +func (mr *MockAPIMockRecorder) CreateUserAccessToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserAccessToken", reflect.TypeOf((*MockAPI)(nil).CreateUserAccessToken), arg0) +} + +// DeleteChannel mocks base method. +func (m *MockAPI) DeleteChannel(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteChannel", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteChannel indicates an expected call of DeleteChannel. +func (mr *MockAPIMockRecorder) DeleteChannel(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChannel", reflect.TypeOf((*MockAPI)(nil).DeleteChannel), arg0) +} + +// DeleteChannelMember mocks base method. +func (m *MockAPI) DeleteChannelMember(arg0, arg1 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteChannelMember", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteChannelMember indicates an expected call of DeleteChannelMember. +func (mr *MockAPIMockRecorder) DeleteChannelMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChannelMember", reflect.TypeOf((*MockAPI)(nil).DeleteChannelMember), arg0, arg1) +} + +// DeleteCommand mocks base method. +func (m *MockAPI) DeleteCommand(arg0 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteCommand", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteCommand indicates an expected call of DeleteCommand. +func (mr *MockAPIMockRecorder) DeleteCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCommand", reflect.TypeOf((*MockAPI)(nil).DeleteCommand), arg0) +} + +// DeleteEphemeralPost mocks base method. +func (m *MockAPI) DeleteEphemeralPost(arg0, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "DeleteEphemeralPost", arg0, arg1) +} + +// DeleteEphemeralPost indicates an expected call of DeleteEphemeralPost. +func (mr *MockAPIMockRecorder) DeleteEphemeralPost(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteEphemeralPost", reflect.TypeOf((*MockAPI)(nil).DeleteEphemeralPost), arg0, arg1) +} + +// DeleteOAuthApp mocks base method. +func (m *MockAPI) DeleteOAuthApp(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteOAuthApp", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteOAuthApp indicates an expected call of DeleteOAuthApp. +func (mr *MockAPIMockRecorder) DeleteOAuthApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteOAuthApp", reflect.TypeOf((*MockAPI)(nil).DeleteOAuthApp), arg0) +} + +// DeletePost mocks base method. +func (m *MockAPI) DeletePost(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePost", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeletePost indicates an expected call of DeletePost. +func (mr *MockAPIMockRecorder) DeletePost(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePost", reflect.TypeOf((*MockAPI)(nil).DeletePost), arg0) +} + +// DeletePreferencesForUser mocks base method. +func (m *MockAPI) DeletePreferencesForUser(arg0 string, arg1 []model.Preference) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeletePreferencesForUser", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeletePreferencesForUser indicates an expected call of DeletePreferencesForUser. +func (mr *MockAPIMockRecorder) DeletePreferencesForUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeletePreferencesForUser", reflect.TypeOf((*MockAPI)(nil).DeletePreferencesForUser), arg0, arg1) +} + +// DeleteTeam mocks base method. +func (m *MockAPI) DeleteTeam(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteTeam", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteTeam indicates an expected call of DeleteTeam. +func (mr *MockAPIMockRecorder) DeleteTeam(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTeam", reflect.TypeOf((*MockAPI)(nil).DeleteTeam), arg0) +} + +// DeleteTeamMember mocks base method. +func (m *MockAPI) DeleteTeamMember(arg0, arg1, arg2 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteTeamMember", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteTeamMember indicates an expected call of DeleteTeamMember. +func (mr *MockAPIMockRecorder) DeleteTeamMember(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTeamMember", reflect.TypeOf((*MockAPI)(nil).DeleteTeamMember), arg0, arg1, arg2) +} + +// DeleteUser mocks base method. +func (m *MockAPI) DeleteUser(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteUser", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DeleteUser indicates an expected call of DeleteUser. +func (mr *MockAPIMockRecorder) DeleteUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockAPI)(nil).DeleteUser), arg0) +} + +// DisablePlugin mocks base method. +func (m *MockAPI) DisablePlugin(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DisablePlugin", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// DisablePlugin indicates an expected call of DisablePlugin. +func (mr *MockAPIMockRecorder) DisablePlugin(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisablePlugin", reflect.TypeOf((*MockAPI)(nil).DisablePlugin), arg0) +} + +// EnablePlugin mocks base method. +func (m *MockAPI) EnablePlugin(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "EnablePlugin", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// EnablePlugin indicates an expected call of EnablePlugin. +func (mr *MockAPIMockRecorder) EnablePlugin(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnablePlugin", reflect.TypeOf((*MockAPI)(nil).EnablePlugin), arg0) +} + +// ExecuteSlashCommand mocks base method. +func (m *MockAPI) ExecuteSlashCommand(arg0 *model.CommandArgs) (*model.CommandResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ExecuteSlashCommand", arg0) + ret0, _ := ret[0].(*model.CommandResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ExecuteSlashCommand indicates an expected call of ExecuteSlashCommand. +func (mr *MockAPIMockRecorder) ExecuteSlashCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteSlashCommand", reflect.TypeOf((*MockAPI)(nil).ExecuteSlashCommand), arg0) +} + +// GetBot mocks base method. +func (m *MockAPI) GetBot(arg0 string, arg1 bool) (*model.Bot, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBot", arg0, arg1) + ret0, _ := ret[0].(*model.Bot) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetBot indicates an expected call of GetBot. +func (mr *MockAPIMockRecorder) GetBot(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBot", reflect.TypeOf((*MockAPI)(nil).GetBot), arg0, arg1) +} + +// GetBots mocks base method. +func (m *MockAPI) GetBots(arg0 *model.BotGetOptions) ([]*model.Bot, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBots", arg0) + ret0, _ := ret[0].([]*model.Bot) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetBots indicates an expected call of GetBots. +func (mr *MockAPIMockRecorder) GetBots(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBots", reflect.TypeOf((*MockAPI)(nil).GetBots), arg0) +} + +// GetBundlePath mocks base method. +func (m *MockAPI) GetBundlePath() (string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetBundlePath") + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetBundlePath indicates an expected call of GetBundlePath. +func (mr *MockAPIMockRecorder) GetBundlePath() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBundlePath", reflect.TypeOf((*MockAPI)(nil).GetBundlePath)) +} + +// GetChannel mocks base method. +func (m *MockAPI) GetChannel(arg0 string) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannel", arg0) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannel indicates an expected call of GetChannel. +func (mr *MockAPIMockRecorder) GetChannel(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannel", reflect.TypeOf((*MockAPI)(nil).GetChannel), arg0) +} + +// GetChannelByName mocks base method. +func (m *MockAPI) GetChannelByName(arg0, arg1 string, arg2 bool) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelByName", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelByName indicates an expected call of GetChannelByName. +func (mr *MockAPIMockRecorder) GetChannelByName(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelByName", reflect.TypeOf((*MockAPI)(nil).GetChannelByName), arg0, arg1, arg2) +} + +// GetChannelByNameForTeamName mocks base method. +func (m *MockAPI) GetChannelByNameForTeamName(arg0, arg1 string, arg2 bool) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelByNameForTeamName", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelByNameForTeamName indicates an expected call of GetChannelByNameForTeamName. +func (mr *MockAPIMockRecorder) GetChannelByNameForTeamName(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelByNameForTeamName", reflect.TypeOf((*MockAPI)(nil).GetChannelByNameForTeamName), arg0, arg1, arg2) +} + +// GetChannelMember mocks base method. +func (m *MockAPI) GetChannelMember(arg0, arg1 string) (*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelMember", arg0, arg1) + ret0, _ := ret[0].(*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelMember indicates an expected call of GetChannelMember. +func (mr *MockAPIMockRecorder) GetChannelMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelMember", reflect.TypeOf((*MockAPI)(nil).GetChannelMember), arg0, arg1) +} + +// GetChannelMembers mocks base method. +func (m *MockAPI) GetChannelMembers(arg0 string, arg1, arg2 int) (model.ChannelMembers, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelMembers", arg0, arg1, arg2) + ret0, _ := ret[0].(model.ChannelMembers) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelMembers indicates an expected call of GetChannelMembers. +func (mr *MockAPIMockRecorder) GetChannelMembers(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelMembers", reflect.TypeOf((*MockAPI)(nil).GetChannelMembers), arg0, arg1, arg2) +} + +// GetChannelMembersByIds mocks base method. +func (m *MockAPI) GetChannelMembersByIds(arg0 string, arg1 []string) (model.ChannelMembers, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelMembersByIds", arg0, arg1) + ret0, _ := ret[0].(model.ChannelMembers) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelMembersByIds indicates an expected call of GetChannelMembersByIds. +func (mr *MockAPIMockRecorder) GetChannelMembersByIds(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelMembersByIds", reflect.TypeOf((*MockAPI)(nil).GetChannelMembersByIds), arg0, arg1) +} + +// GetChannelMembersForUser mocks base method. +func (m *MockAPI) GetChannelMembersForUser(arg0, arg1 string, arg2, arg3 int) ([]*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelMembersForUser", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelMembersForUser indicates an expected call of GetChannelMembersForUser. +func (mr *MockAPIMockRecorder) GetChannelMembersForUser(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelMembersForUser", reflect.TypeOf((*MockAPI)(nil).GetChannelMembersForUser), arg0, arg1, arg2, arg3) +} + +// GetChannelSidebarCategories mocks base method. +func (m *MockAPI) GetChannelSidebarCategories(arg0, arg1 string) (*model.OrderedSidebarCategories, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelSidebarCategories", arg0, arg1) + ret0, _ := ret[0].(*model.OrderedSidebarCategories) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelSidebarCategories indicates an expected call of GetChannelSidebarCategories. +func (mr *MockAPIMockRecorder) GetChannelSidebarCategories(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelSidebarCategories", reflect.TypeOf((*MockAPI)(nil).GetChannelSidebarCategories), arg0, arg1) +} + +// GetChannelStats mocks base method. +func (m *MockAPI) GetChannelStats(arg0 string) (*model.ChannelStats, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelStats", arg0) + ret0, _ := ret[0].(*model.ChannelStats) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelStats indicates an expected call of GetChannelStats. +func (mr *MockAPIMockRecorder) GetChannelStats(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelStats", reflect.TypeOf((*MockAPI)(nil).GetChannelStats), arg0) +} + +// GetChannelsForTeamForUser mocks base method. +func (m *MockAPI) GetChannelsForTeamForUser(arg0, arg1 string, arg2 bool) ([]*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetChannelsForTeamForUser", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetChannelsForTeamForUser indicates an expected call of GetChannelsForTeamForUser. +func (mr *MockAPIMockRecorder) GetChannelsForTeamForUser(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChannelsForTeamForUser", reflect.TypeOf((*MockAPI)(nil).GetChannelsForTeamForUser), arg0, arg1, arg2) +} + +// GetCommand mocks base method. +func (m *MockAPI) GetCommand(arg0 string) (*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCommand", arg0) + ret0, _ := ret[0].(*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCommand indicates an expected call of GetCommand. +func (mr *MockAPIMockRecorder) GetCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCommand", reflect.TypeOf((*MockAPI)(nil).GetCommand), arg0) +} + +// GetConfig mocks base method. +func (m *MockAPI) GetConfig() *model.Config { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetConfig") + ret0, _ := ret[0].(*model.Config) + return ret0 +} + +// GetConfig indicates an expected call of GetConfig. +func (mr *MockAPIMockRecorder) GetConfig() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConfig", reflect.TypeOf((*MockAPI)(nil).GetConfig)) +} + +// GetDiagnosticId mocks base method. +func (m *MockAPI) GetDiagnosticId() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDiagnosticId") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetDiagnosticId indicates an expected call of GetDiagnosticId. +func (mr *MockAPIMockRecorder) GetDiagnosticId() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDiagnosticId", reflect.TypeOf((*MockAPI)(nil).GetDiagnosticId)) +} + +// GetDirectChannel mocks base method. +func (m *MockAPI) GetDirectChannel(arg0, arg1 string) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetDirectChannel", arg0, arg1) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetDirectChannel indicates an expected call of GetDirectChannel. +func (mr *MockAPIMockRecorder) GetDirectChannel(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDirectChannel", reflect.TypeOf((*MockAPI)(nil).GetDirectChannel), arg0, arg1) +} + +// GetEmoji mocks base method. +func (m *MockAPI) GetEmoji(arg0 string) (*model.Emoji, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEmoji", arg0) + ret0, _ := ret[0].(*model.Emoji) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetEmoji indicates an expected call of GetEmoji. +func (mr *MockAPIMockRecorder) GetEmoji(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEmoji", reflect.TypeOf((*MockAPI)(nil).GetEmoji), arg0) +} + +// GetEmojiByName mocks base method. +func (m *MockAPI) GetEmojiByName(arg0 string) (*model.Emoji, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEmojiByName", arg0) + ret0, _ := ret[0].(*model.Emoji) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetEmojiByName indicates an expected call of GetEmojiByName. +func (mr *MockAPIMockRecorder) GetEmojiByName(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEmojiByName", reflect.TypeOf((*MockAPI)(nil).GetEmojiByName), arg0) +} + +// GetEmojiImage mocks base method. +func (m *MockAPI) GetEmojiImage(arg0 string) ([]byte, string, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEmojiImage", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(string) + ret2, _ := ret[2].(*model.AppError) + return ret0, ret1, ret2 +} + +// GetEmojiImage indicates an expected call of GetEmojiImage. +func (mr *MockAPIMockRecorder) GetEmojiImage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEmojiImage", reflect.TypeOf((*MockAPI)(nil).GetEmojiImage), arg0) +} + +// GetEmojiList mocks base method. +func (m *MockAPI) GetEmojiList(arg0 string, arg1, arg2 int) ([]*model.Emoji, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetEmojiList", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.Emoji) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetEmojiList indicates an expected call of GetEmojiList. +func (mr *MockAPIMockRecorder) GetEmojiList(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEmojiList", reflect.TypeOf((*MockAPI)(nil).GetEmojiList), arg0, arg1, arg2) +} + +// GetFile mocks base method. +func (m *MockAPI) GetFile(arg0 string) ([]byte, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFile", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetFile indicates an expected call of GetFile. +func (mr *MockAPIMockRecorder) GetFile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFile", reflect.TypeOf((*MockAPI)(nil).GetFile), arg0) +} + +// GetFileInfo mocks base method. +func (m *MockAPI) GetFileInfo(arg0 string) (*model.FileInfo, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileInfo", arg0) + ret0, _ := ret[0].(*model.FileInfo) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetFileInfo indicates an expected call of GetFileInfo. +func (mr *MockAPIMockRecorder) GetFileInfo(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileInfo", reflect.TypeOf((*MockAPI)(nil).GetFileInfo), arg0) +} + +// GetFileInfos mocks base method. +func (m *MockAPI) GetFileInfos(arg0, arg1 int, arg2 *model.GetFileInfosOptions) ([]*model.FileInfo, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileInfos", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.FileInfo) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetFileInfos indicates an expected call of GetFileInfos. +func (mr *MockAPIMockRecorder) GetFileInfos(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileInfos", reflect.TypeOf((*MockAPI)(nil).GetFileInfos), arg0, arg1, arg2) +} + +// GetFileLink mocks base method. +func (m *MockAPI) GetFileLink(arg0 string) (string, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetFileLink", arg0) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetFileLink indicates an expected call of GetFileLink. +func (mr *MockAPIMockRecorder) GetFileLink(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetFileLink", reflect.TypeOf((*MockAPI)(nil).GetFileLink), arg0) +} + +// GetGroup mocks base method. +func (m *MockAPI) GetGroup(arg0 string) (*model.Group, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroup", arg0) + ret0, _ := ret[0].(*model.Group) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroup indicates an expected call of GetGroup. +func (mr *MockAPIMockRecorder) GetGroup(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroup", reflect.TypeOf((*MockAPI)(nil).GetGroup), arg0) +} + +// GetGroupByName mocks base method. +func (m *MockAPI) GetGroupByName(arg0 string) (*model.Group, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupByName", arg0) + ret0, _ := ret[0].(*model.Group) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroupByName indicates an expected call of GetGroupByName. +func (mr *MockAPIMockRecorder) GetGroupByName(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupByName", reflect.TypeOf((*MockAPI)(nil).GetGroupByName), arg0) +} + +// GetGroupChannel mocks base method. +func (m *MockAPI) GetGroupChannel(arg0 []string) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupChannel", arg0) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroupChannel indicates an expected call of GetGroupChannel. +func (mr *MockAPIMockRecorder) GetGroupChannel(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupChannel", reflect.TypeOf((*MockAPI)(nil).GetGroupChannel), arg0) +} + +// GetGroupMemberUsers mocks base method. +func (m *MockAPI) GetGroupMemberUsers(arg0 string, arg1, arg2 int) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupMemberUsers", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroupMemberUsers indicates an expected call of GetGroupMemberUsers. +func (mr *MockAPIMockRecorder) GetGroupMemberUsers(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupMemberUsers", reflect.TypeOf((*MockAPI)(nil).GetGroupMemberUsers), arg0, arg1, arg2) +} + +// GetGroupsBySource mocks base method. +func (m *MockAPI) GetGroupsBySource(arg0 model.GroupSource) ([]*model.Group, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsBySource", arg0) + ret0, _ := ret[0].([]*model.Group) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroupsBySource indicates an expected call of GetGroupsBySource. +func (mr *MockAPIMockRecorder) GetGroupsBySource(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsBySource", reflect.TypeOf((*MockAPI)(nil).GetGroupsBySource), arg0) +} + +// GetGroupsForUser mocks base method. +func (m *MockAPI) GetGroupsForUser(arg0 string) ([]*model.Group, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsForUser", arg0) + ret0, _ := ret[0].([]*model.Group) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetGroupsForUser indicates an expected call of GetGroupsForUser. +func (mr *MockAPIMockRecorder) GetGroupsForUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsForUser", reflect.TypeOf((*MockAPI)(nil).GetGroupsForUser), arg0) +} + +// GetLDAPUserAttributes mocks base method. +func (m *MockAPI) GetLDAPUserAttributes(arg0 string, arg1 []string) (map[string]string, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLDAPUserAttributes", arg0, arg1) + ret0, _ := ret[0].(map[string]string) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetLDAPUserAttributes indicates an expected call of GetLDAPUserAttributes. +func (mr *MockAPIMockRecorder) GetLDAPUserAttributes(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLDAPUserAttributes", reflect.TypeOf((*MockAPI)(nil).GetLDAPUserAttributes), arg0, arg1) +} + +// GetLicense mocks base method. +func (m *MockAPI) GetLicense() *model.License { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLicense") + ret0, _ := ret[0].(*model.License) + return ret0 +} + +// GetLicense indicates an expected call of GetLicense. +func (mr *MockAPIMockRecorder) GetLicense() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLicense", reflect.TypeOf((*MockAPI)(nil).GetLicense)) +} + +// GetOAuthApp mocks base method. +func (m *MockAPI) GetOAuthApp(arg0 string) (*model.OAuthApp, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetOAuthApp", arg0) + ret0, _ := ret[0].(*model.OAuthApp) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetOAuthApp indicates an expected call of GetOAuthApp. +func (mr *MockAPIMockRecorder) GetOAuthApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetOAuthApp", reflect.TypeOf((*MockAPI)(nil).GetOAuthApp), arg0) +} + +// GetPluginConfig mocks base method. +func (m *MockAPI) GetPluginConfig() map[string]interface{} { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPluginConfig") + ret0, _ := ret[0].(map[string]interface{}) + return ret0 +} + +// GetPluginConfig indicates an expected call of GetPluginConfig. +func (mr *MockAPIMockRecorder) GetPluginConfig() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginConfig", reflect.TypeOf((*MockAPI)(nil).GetPluginConfig)) +} + +// GetPluginStatus mocks base method. +func (m *MockAPI) GetPluginStatus(arg0 string) (*model.PluginStatus, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPluginStatus", arg0) + ret0, _ := ret[0].(*model.PluginStatus) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPluginStatus indicates an expected call of GetPluginStatus. +func (mr *MockAPIMockRecorder) GetPluginStatus(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPluginStatus", reflect.TypeOf((*MockAPI)(nil).GetPluginStatus), arg0) +} + +// GetPlugins mocks base method. +func (m *MockAPI) GetPlugins() ([]*model.Manifest, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPlugins") + ret0, _ := ret[0].([]*model.Manifest) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPlugins indicates an expected call of GetPlugins. +func (mr *MockAPIMockRecorder) GetPlugins() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPlugins", reflect.TypeOf((*MockAPI)(nil).GetPlugins)) +} + +// GetPost mocks base method. +func (m *MockAPI) GetPost(arg0 string) (*model.Post, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPost", arg0) + ret0, _ := ret[0].(*model.Post) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPost indicates an expected call of GetPost. +func (mr *MockAPIMockRecorder) GetPost(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPost", reflect.TypeOf((*MockAPI)(nil).GetPost), arg0) +} + +// GetPostThread mocks base method. +func (m *MockAPI) GetPostThread(arg0 string) (*model.PostList, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPostThread", arg0) + ret0, _ := ret[0].(*model.PostList) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPostThread indicates an expected call of GetPostThread. +func (mr *MockAPIMockRecorder) GetPostThread(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPostThread", reflect.TypeOf((*MockAPI)(nil).GetPostThread), arg0) +} + +// GetPostsAfter mocks base method. +func (m *MockAPI) GetPostsAfter(arg0, arg1 string, arg2, arg3 int) (*model.PostList, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPostsAfter", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*model.PostList) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPostsAfter indicates an expected call of GetPostsAfter. +func (mr *MockAPIMockRecorder) GetPostsAfter(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPostsAfter", reflect.TypeOf((*MockAPI)(nil).GetPostsAfter), arg0, arg1, arg2, arg3) +} + +// GetPostsBefore mocks base method. +func (m *MockAPI) GetPostsBefore(arg0, arg1 string, arg2, arg3 int) (*model.PostList, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPostsBefore", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*model.PostList) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPostsBefore indicates an expected call of GetPostsBefore. +func (mr *MockAPIMockRecorder) GetPostsBefore(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPostsBefore", reflect.TypeOf((*MockAPI)(nil).GetPostsBefore), arg0, arg1, arg2, arg3) +} + +// GetPostsForChannel mocks base method. +func (m *MockAPI) GetPostsForChannel(arg0 string, arg1, arg2 int) (*model.PostList, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPostsForChannel", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.PostList) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPostsForChannel indicates an expected call of GetPostsForChannel. +func (mr *MockAPIMockRecorder) GetPostsForChannel(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPostsForChannel", reflect.TypeOf((*MockAPI)(nil).GetPostsForChannel), arg0, arg1, arg2) +} + +// GetPostsSince mocks base method. +func (m *MockAPI) GetPostsSince(arg0 string, arg1 int64) (*model.PostList, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPostsSince", arg0, arg1) + ret0, _ := ret[0].(*model.PostList) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPostsSince indicates an expected call of GetPostsSince. +func (mr *MockAPIMockRecorder) GetPostsSince(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPostsSince", reflect.TypeOf((*MockAPI)(nil).GetPostsSince), arg0, arg1) +} + +// GetPreferencesForUser mocks base method. +func (m *MockAPI) GetPreferencesForUser(arg0 string) ([]model.Preference, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPreferencesForUser", arg0) + ret0, _ := ret[0].([]model.Preference) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPreferencesForUser indicates an expected call of GetPreferencesForUser. +func (mr *MockAPIMockRecorder) GetPreferencesForUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPreferencesForUser", reflect.TypeOf((*MockAPI)(nil).GetPreferencesForUser), arg0) +} + +// GetProfileImage mocks base method. +func (m *MockAPI) GetProfileImage(arg0 string) ([]byte, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetProfileImage", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetProfileImage indicates an expected call of GetProfileImage. +func (mr *MockAPIMockRecorder) GetProfileImage(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetProfileImage", reflect.TypeOf((*MockAPI)(nil).GetProfileImage), arg0) +} + +// GetPublicChannelsForTeam mocks base method. +func (m *MockAPI) GetPublicChannelsForTeam(arg0 string, arg1, arg2 int) ([]*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetPublicChannelsForTeam", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetPublicChannelsForTeam indicates an expected call of GetPublicChannelsForTeam. +func (mr *MockAPIMockRecorder) GetPublicChannelsForTeam(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPublicChannelsForTeam", reflect.TypeOf((*MockAPI)(nil).GetPublicChannelsForTeam), arg0, arg1, arg2) +} + +// GetReactions mocks base method. +func (m *MockAPI) GetReactions(arg0 string) ([]*model.Reaction, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetReactions", arg0) + ret0, _ := ret[0].([]*model.Reaction) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetReactions indicates an expected call of GetReactions. +func (mr *MockAPIMockRecorder) GetReactions(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetReactions", reflect.TypeOf((*MockAPI)(nil).GetReactions), arg0) +} + +// GetServerVersion mocks base method. +func (m *MockAPI) GetServerVersion() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetServerVersion") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetServerVersion indicates an expected call of GetServerVersion. +func (mr *MockAPIMockRecorder) GetServerVersion() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetServerVersion", reflect.TypeOf((*MockAPI)(nil).GetServerVersion)) +} + +// GetSession mocks base method. +func (m *MockAPI) GetSession(arg0 string) (*model.Session, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSession", arg0) + ret0, _ := ret[0].(*model.Session) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetSession indicates an expected call of GetSession. +func (mr *MockAPIMockRecorder) GetSession(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSession", reflect.TypeOf((*MockAPI)(nil).GetSession), arg0) +} + +// GetSystemInstallDate mocks base method. +func (m *MockAPI) GetSystemInstallDate() (int64, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetSystemInstallDate") + ret0, _ := ret[0].(int64) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetSystemInstallDate indicates an expected call of GetSystemInstallDate. +func (mr *MockAPIMockRecorder) GetSystemInstallDate() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSystemInstallDate", reflect.TypeOf((*MockAPI)(nil).GetSystemInstallDate)) +} + +// GetTeam mocks base method. +func (m *MockAPI) GetTeam(arg0 string) (*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeam", arg0) + ret0, _ := ret[0].(*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeam indicates an expected call of GetTeam. +func (mr *MockAPIMockRecorder) GetTeam(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeam", reflect.TypeOf((*MockAPI)(nil).GetTeam), arg0) +} + +// GetTeamByName mocks base method. +func (m *MockAPI) GetTeamByName(arg0 string) (*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamByName", arg0) + ret0, _ := ret[0].(*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamByName indicates an expected call of GetTeamByName. +func (mr *MockAPIMockRecorder) GetTeamByName(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamByName", reflect.TypeOf((*MockAPI)(nil).GetTeamByName), arg0) +} + +// GetTeamIcon mocks base method. +func (m *MockAPI) GetTeamIcon(arg0 string) ([]byte, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamIcon", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamIcon indicates an expected call of GetTeamIcon. +func (mr *MockAPIMockRecorder) GetTeamIcon(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamIcon", reflect.TypeOf((*MockAPI)(nil).GetTeamIcon), arg0) +} + +// GetTeamMember mocks base method. +func (m *MockAPI) GetTeamMember(arg0, arg1 string) (*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamMember", arg0, arg1) + ret0, _ := ret[0].(*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamMember indicates an expected call of GetTeamMember. +func (mr *MockAPIMockRecorder) GetTeamMember(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamMember", reflect.TypeOf((*MockAPI)(nil).GetTeamMember), arg0, arg1) +} + +// GetTeamMembers mocks base method. +func (m *MockAPI) GetTeamMembers(arg0 string, arg1, arg2 int) ([]*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamMembers", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamMembers indicates an expected call of GetTeamMembers. +func (mr *MockAPIMockRecorder) GetTeamMembers(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamMembers", reflect.TypeOf((*MockAPI)(nil).GetTeamMembers), arg0, arg1, arg2) +} + +// GetTeamMembersForUser mocks base method. +func (m *MockAPI) GetTeamMembersForUser(arg0 string, arg1, arg2 int) ([]*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamMembersForUser", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamMembersForUser indicates an expected call of GetTeamMembersForUser. +func (mr *MockAPIMockRecorder) GetTeamMembersForUser(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamMembersForUser", reflect.TypeOf((*MockAPI)(nil).GetTeamMembersForUser), arg0, arg1, arg2) +} + +// GetTeamStats mocks base method. +func (m *MockAPI) GetTeamStats(arg0 string) (*model.TeamStats, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamStats", arg0) + ret0, _ := ret[0].(*model.TeamStats) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamStats indicates an expected call of GetTeamStats. +func (mr *MockAPIMockRecorder) GetTeamStats(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamStats", reflect.TypeOf((*MockAPI)(nil).GetTeamStats), arg0) +} + +// GetTeams mocks base method. +func (m *MockAPI) GetTeams() ([]*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeams") + ret0, _ := ret[0].([]*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeams indicates an expected call of GetTeams. +func (mr *MockAPIMockRecorder) GetTeams() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeams", reflect.TypeOf((*MockAPI)(nil).GetTeams)) +} + +// GetTeamsForUser mocks base method. +func (m *MockAPI) GetTeamsForUser(arg0 string) ([]*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamsForUser", arg0) + ret0, _ := ret[0].([]*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamsForUser indicates an expected call of GetTeamsForUser. +func (mr *MockAPIMockRecorder) GetTeamsForUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamsForUser", reflect.TypeOf((*MockAPI)(nil).GetTeamsForUser), arg0) +} + +// GetTeamsUnreadForUser mocks base method. +func (m *MockAPI) GetTeamsUnreadForUser(arg0 string) ([]*model.TeamUnread, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTeamsUnreadForUser", arg0) + ret0, _ := ret[0].([]*model.TeamUnread) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetTeamsUnreadForUser indicates an expected call of GetTeamsUnreadForUser. +func (mr *MockAPIMockRecorder) GetTeamsUnreadForUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeamsUnreadForUser", reflect.TypeOf((*MockAPI)(nil).GetTeamsUnreadForUser), arg0) +} + +// GetTelemetryId mocks base method. +func (m *MockAPI) GetTelemetryId() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetTelemetryId") + ret0, _ := ret[0].(string) + return ret0 +} + +// GetTelemetryId indicates an expected call of GetTelemetryId. +func (mr *MockAPIMockRecorder) GetTelemetryId() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTelemetryId", reflect.TypeOf((*MockAPI)(nil).GetTelemetryId)) +} + +// GetUnsanitizedConfig mocks base method. +func (m *MockAPI) GetUnsanitizedConfig() *model.Config { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUnsanitizedConfig") + ret0, _ := ret[0].(*model.Config) + return ret0 +} + +// GetUnsanitizedConfig indicates an expected call of GetUnsanitizedConfig. +func (mr *MockAPIMockRecorder) GetUnsanitizedConfig() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUnsanitizedConfig", reflect.TypeOf((*MockAPI)(nil).GetUnsanitizedConfig)) +} + +// GetUser mocks base method. +func (m *MockAPI) GetUser(arg0 string) (*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUser", arg0) + ret0, _ := ret[0].(*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUser indicates an expected call of GetUser. +func (mr *MockAPIMockRecorder) GetUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUser", reflect.TypeOf((*MockAPI)(nil).GetUser), arg0) +} + +// GetUserByEmail mocks base method. +func (m *MockAPI) GetUserByEmail(arg0 string) (*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByEmail", arg0) + ret0, _ := ret[0].(*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUserByEmail indicates an expected call of GetUserByEmail. +func (mr *MockAPIMockRecorder) GetUserByEmail(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByEmail", reflect.TypeOf((*MockAPI)(nil).GetUserByEmail), arg0) +} + +// GetUserByUsername mocks base method. +func (m *MockAPI) GetUserByUsername(arg0 string) (*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserByUsername", arg0) + ret0, _ := ret[0].(*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUserByUsername indicates an expected call of GetUserByUsername. +func (mr *MockAPIMockRecorder) GetUserByUsername(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByUsername", reflect.TypeOf((*MockAPI)(nil).GetUserByUsername), arg0) +} + +// GetUserStatus mocks base method. +func (m *MockAPI) GetUserStatus(arg0 string) (*model.Status, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserStatus", arg0) + ret0, _ := ret[0].(*model.Status) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUserStatus indicates an expected call of GetUserStatus. +func (mr *MockAPIMockRecorder) GetUserStatus(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserStatus", reflect.TypeOf((*MockAPI)(nil).GetUserStatus), arg0) +} + +// GetUserStatusesByIds mocks base method. +func (m *MockAPI) GetUserStatusesByIds(arg0 []string) ([]*model.Status, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserStatusesByIds", arg0) + ret0, _ := ret[0].([]*model.Status) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUserStatusesByIds indicates an expected call of GetUserStatusesByIds. +func (mr *MockAPIMockRecorder) GetUserStatusesByIds(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserStatusesByIds", reflect.TypeOf((*MockAPI)(nil).GetUserStatusesByIds), arg0) +} + +// GetUsers mocks base method. +func (m *MockAPI) GetUsers(arg0 *model.UserGetOptions) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsers", arg0) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUsers indicates an expected call of GetUsers. +func (mr *MockAPIMockRecorder) GetUsers(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsers", reflect.TypeOf((*MockAPI)(nil).GetUsers), arg0) +} + +// GetUsersByUsernames mocks base method. +func (m *MockAPI) GetUsersByUsernames(arg0 []string) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsersByUsernames", arg0) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUsersByUsernames indicates an expected call of GetUsersByUsernames. +func (mr *MockAPIMockRecorder) GetUsersByUsernames(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersByUsernames", reflect.TypeOf((*MockAPI)(nil).GetUsersByUsernames), arg0) +} + +// GetUsersInChannel mocks base method. +func (m *MockAPI) GetUsersInChannel(arg0, arg1 string, arg2, arg3 int) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsersInChannel", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUsersInChannel indicates an expected call of GetUsersInChannel. +func (mr *MockAPIMockRecorder) GetUsersInChannel(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersInChannel", reflect.TypeOf((*MockAPI)(nil).GetUsersInChannel), arg0, arg1, arg2, arg3) +} + +// GetUsersInTeam mocks base method. +func (m *MockAPI) GetUsersInTeam(arg0 string, arg1, arg2 int) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUsersInTeam", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// GetUsersInTeam indicates an expected call of GetUsersInTeam. +func (mr *MockAPIMockRecorder) GetUsersInTeam(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUsersInTeam", reflect.TypeOf((*MockAPI)(nil).GetUsersInTeam), arg0, arg1, arg2) +} + +// HasPermissionTo mocks base method. +func (m *MockAPI) HasPermissionTo(arg0 string, arg1 *model.Permission) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasPermissionTo", arg0, arg1) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasPermissionTo indicates an expected call of HasPermissionTo. +func (mr *MockAPIMockRecorder) HasPermissionTo(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasPermissionTo", reflect.TypeOf((*MockAPI)(nil).HasPermissionTo), arg0, arg1) +} + +// HasPermissionToChannel mocks base method. +func (m *MockAPI) HasPermissionToChannel(arg0, arg1 string, arg2 *model.Permission) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasPermissionToChannel", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasPermissionToChannel indicates an expected call of HasPermissionToChannel. +func (mr *MockAPIMockRecorder) HasPermissionToChannel(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasPermissionToChannel", reflect.TypeOf((*MockAPI)(nil).HasPermissionToChannel), arg0, arg1, arg2) +} + +// HasPermissionToTeam mocks base method. +func (m *MockAPI) HasPermissionToTeam(arg0, arg1 string, arg2 *model.Permission) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HasPermissionToTeam", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + return ret0 +} + +// HasPermissionToTeam indicates an expected call of HasPermissionToTeam. +func (mr *MockAPIMockRecorder) HasPermissionToTeam(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasPermissionToTeam", reflect.TypeOf((*MockAPI)(nil).HasPermissionToTeam), arg0, arg1, arg2) +} + +// InstallPlugin mocks base method. +func (m *MockAPI) InstallPlugin(arg0 io.Reader, arg1 bool) (*model.Manifest, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InstallPlugin", arg0, arg1) + ret0, _ := ret[0].(*model.Manifest) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// InstallPlugin indicates an expected call of InstallPlugin. +func (mr *MockAPIMockRecorder) InstallPlugin(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallPlugin", reflect.TypeOf((*MockAPI)(nil).InstallPlugin), arg0, arg1) +} + +// KVCompareAndDelete mocks base method. +func (m *MockAPI) KVCompareAndDelete(arg0 string, arg1 []byte) (bool, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVCompareAndDelete", arg0, arg1) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// KVCompareAndDelete indicates an expected call of KVCompareAndDelete. +func (mr *MockAPIMockRecorder) KVCompareAndDelete(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVCompareAndDelete", reflect.TypeOf((*MockAPI)(nil).KVCompareAndDelete), arg0, arg1) +} + +// KVCompareAndSet mocks base method. +func (m *MockAPI) KVCompareAndSet(arg0 string, arg1, arg2 []byte) (bool, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVCompareAndSet", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// KVCompareAndSet indicates an expected call of KVCompareAndSet. +func (mr *MockAPIMockRecorder) KVCompareAndSet(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVCompareAndSet", reflect.TypeOf((*MockAPI)(nil).KVCompareAndSet), arg0, arg1, arg2) +} + +// KVDelete mocks base method. +func (m *MockAPI) KVDelete(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVDelete", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// KVDelete indicates an expected call of KVDelete. +func (mr *MockAPIMockRecorder) KVDelete(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVDelete", reflect.TypeOf((*MockAPI)(nil).KVDelete), arg0) +} + +// KVDeleteAll mocks base method. +func (m *MockAPI) KVDeleteAll() *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVDeleteAll") + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// KVDeleteAll indicates an expected call of KVDeleteAll. +func (mr *MockAPIMockRecorder) KVDeleteAll() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVDeleteAll", reflect.TypeOf((*MockAPI)(nil).KVDeleteAll)) +} + +// KVGet mocks base method. +func (m *MockAPI) KVGet(arg0 string) ([]byte, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVGet", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// KVGet indicates an expected call of KVGet. +func (mr *MockAPIMockRecorder) KVGet(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVGet", reflect.TypeOf((*MockAPI)(nil).KVGet), arg0) +} + +// KVList mocks base method. +func (m *MockAPI) KVList(arg0, arg1 int) ([]string, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVList", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// KVList indicates an expected call of KVList. +func (mr *MockAPIMockRecorder) KVList(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVList", reflect.TypeOf((*MockAPI)(nil).KVList), arg0, arg1) +} + +// KVSet mocks base method. +func (m *MockAPI) KVSet(arg0 string, arg1 []byte) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVSet", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// KVSet indicates an expected call of KVSet. +func (mr *MockAPIMockRecorder) KVSet(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVSet", reflect.TypeOf((*MockAPI)(nil).KVSet), arg0, arg1) +} + +// KVSetWithExpiry mocks base method. +func (m *MockAPI) KVSetWithExpiry(arg0 string, arg1 []byte, arg2 int64) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVSetWithExpiry", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// KVSetWithExpiry indicates an expected call of KVSetWithExpiry. +func (mr *MockAPIMockRecorder) KVSetWithExpiry(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVSetWithExpiry", reflect.TypeOf((*MockAPI)(nil).KVSetWithExpiry), arg0, arg1, arg2) +} + +// KVSetWithOptions mocks base method. +func (m *MockAPI) KVSetWithOptions(arg0 string, arg1 []byte, arg2 model.PluginKVSetOptions) (bool, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "KVSetWithOptions", arg0, arg1, arg2) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// KVSetWithOptions indicates an expected call of KVSetWithOptions. +func (mr *MockAPIMockRecorder) KVSetWithOptions(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KVSetWithOptions", reflect.TypeOf((*MockAPI)(nil).KVSetWithOptions), arg0, arg1, arg2) +} + +// ListBuiltInCommands mocks base method. +func (m *MockAPI) ListBuiltInCommands() ([]*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListBuiltInCommands") + ret0, _ := ret[0].([]*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListBuiltInCommands indicates an expected call of ListBuiltInCommands. +func (mr *MockAPIMockRecorder) ListBuiltInCommands() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBuiltInCommands", reflect.TypeOf((*MockAPI)(nil).ListBuiltInCommands)) +} + +// ListCommands mocks base method. +func (m *MockAPI) ListCommands(arg0 string) ([]*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListCommands", arg0) + ret0, _ := ret[0].([]*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListCommands indicates an expected call of ListCommands. +func (mr *MockAPIMockRecorder) ListCommands(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCommands", reflect.TypeOf((*MockAPI)(nil).ListCommands), arg0) +} + +// ListCustomCommands mocks base method. +func (m *MockAPI) ListCustomCommands(arg0 string) ([]*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListCustomCommands", arg0) + ret0, _ := ret[0].([]*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListCustomCommands indicates an expected call of ListCustomCommands. +func (mr *MockAPIMockRecorder) ListCustomCommands(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCustomCommands", reflect.TypeOf((*MockAPI)(nil).ListCustomCommands), arg0) +} + +// ListPluginCommands mocks base method. +func (m *MockAPI) ListPluginCommands(arg0 string) ([]*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListPluginCommands", arg0) + ret0, _ := ret[0].([]*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListPluginCommands indicates an expected call of ListPluginCommands. +func (mr *MockAPIMockRecorder) ListPluginCommands(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPluginCommands", reflect.TypeOf((*MockAPI)(nil).ListPluginCommands), arg0) +} + +// LoadPluginConfiguration mocks base method. +func (m *MockAPI) LoadPluginConfiguration(arg0 interface{}) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadPluginConfiguration", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// LoadPluginConfiguration indicates an expected call of LoadPluginConfiguration. +func (mr *MockAPIMockRecorder) LoadPluginConfiguration(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadPluginConfiguration", reflect.TypeOf((*MockAPI)(nil).LoadPluginConfiguration), arg0) +} + +// LogDebug mocks base method. +func (m *MockAPI) LogDebug(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "LogDebug", varargs...) +} + +// LogDebug indicates an expected call of LogDebug. +func (mr *MockAPIMockRecorder) LogDebug(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogDebug", reflect.TypeOf((*MockAPI)(nil).LogDebug), varargs...) +} + +// LogError mocks base method. +func (m *MockAPI) LogError(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "LogError", varargs...) +} + +// LogError indicates an expected call of LogError. +func (mr *MockAPIMockRecorder) LogError(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogError", reflect.TypeOf((*MockAPI)(nil).LogError), varargs...) +} + +// LogInfo mocks base method. +func (m *MockAPI) LogInfo(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "LogInfo", varargs...) +} + +// LogInfo indicates an expected call of LogInfo. +func (mr *MockAPIMockRecorder) LogInfo(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogInfo", reflect.TypeOf((*MockAPI)(nil).LogInfo), varargs...) +} + +// LogWarn mocks base method. +func (m *MockAPI) LogWarn(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "LogWarn", varargs...) +} + +// LogWarn indicates an expected call of LogWarn. +func (mr *MockAPIMockRecorder) LogWarn(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LogWarn", reflect.TypeOf((*MockAPI)(nil).LogWarn), varargs...) +} + +// OpenInteractiveDialog mocks base method. +func (m *MockAPI) OpenInteractiveDialog(arg0 model.OpenDialogRequest) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "OpenInteractiveDialog", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// OpenInteractiveDialog indicates an expected call of OpenInteractiveDialog. +func (mr *MockAPIMockRecorder) OpenInteractiveDialog(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenInteractiveDialog", reflect.TypeOf((*MockAPI)(nil).OpenInteractiveDialog), arg0) +} + +// PatchBot mocks base method. +func (m *MockAPI) PatchBot(arg0 string, arg1 *model.BotPatch) (*model.Bot, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PatchBot", arg0, arg1) + ret0, _ := ret[0].(*model.Bot) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// PatchBot indicates an expected call of PatchBot. +func (mr *MockAPIMockRecorder) PatchBot(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PatchBot", reflect.TypeOf((*MockAPI)(nil).PatchBot), arg0, arg1) +} + +// PermanentDeleteBot mocks base method. +func (m *MockAPI) PermanentDeleteBot(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PermanentDeleteBot", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// PermanentDeleteBot indicates an expected call of PermanentDeleteBot. +func (mr *MockAPIMockRecorder) PermanentDeleteBot(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PermanentDeleteBot", reflect.TypeOf((*MockAPI)(nil).PermanentDeleteBot), arg0) +} + +// PluginHTTP mocks base method. +func (m *MockAPI) PluginHTTP(arg0 *http.Request) *http.Response { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PluginHTTP", arg0) + ret0, _ := ret[0].(*http.Response) + return ret0 +} + +// PluginHTTP indicates an expected call of PluginHTTP. +func (mr *MockAPIMockRecorder) PluginHTTP(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PluginHTTP", reflect.TypeOf((*MockAPI)(nil).PluginHTTP), arg0) +} + +// PublishPluginClusterEvent mocks base method. +func (m *MockAPI) PublishPluginClusterEvent(arg0 model.PluginClusterEvent, arg1 model.PluginClusterEventSendOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PublishPluginClusterEvent", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// PublishPluginClusterEvent indicates an expected call of PublishPluginClusterEvent. +func (mr *MockAPIMockRecorder) PublishPluginClusterEvent(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishPluginClusterEvent", reflect.TypeOf((*MockAPI)(nil).PublishPluginClusterEvent), arg0, arg1) +} + +// PublishUserTyping mocks base method. +func (m *MockAPI) PublishUserTyping(arg0, arg1, arg2 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "PublishUserTyping", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// PublishUserTyping indicates an expected call of PublishUserTyping. +func (mr *MockAPIMockRecorder) PublishUserTyping(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishUserTyping", reflect.TypeOf((*MockAPI)(nil).PublishUserTyping), arg0, arg1, arg2) +} + +// PublishWebSocketEvent mocks base method. +func (m *MockAPI) PublishWebSocketEvent(arg0 string, arg1 map[string]interface{}, arg2 *model.WebsocketBroadcast) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "PublishWebSocketEvent", arg0, arg1, arg2) +} + +// PublishWebSocketEvent indicates an expected call of PublishWebSocketEvent. +func (mr *MockAPIMockRecorder) PublishWebSocketEvent(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PublishWebSocketEvent", reflect.TypeOf((*MockAPI)(nil).PublishWebSocketEvent), arg0, arg1, arg2) +} + +// ReadFile mocks base method. +func (m *MockAPI) ReadFile(arg0 string) ([]byte, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadFile", arg0) + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// ReadFile indicates an expected call of ReadFile. +func (mr *MockAPIMockRecorder) ReadFile(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadFile", reflect.TypeOf((*MockAPI)(nil).ReadFile), arg0) +} + +// RegisterCommand mocks base method. +func (m *MockAPI) RegisterCommand(arg0 *model.Command) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RegisterCommand", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// RegisterCommand indicates an expected call of RegisterCommand. +func (mr *MockAPIMockRecorder) RegisterCommand(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegisterCommand", reflect.TypeOf((*MockAPI)(nil).RegisterCommand), arg0) +} + +// RemovePlugin mocks base method. +func (m *MockAPI) RemovePlugin(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemovePlugin", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// RemovePlugin indicates an expected call of RemovePlugin. +func (mr *MockAPIMockRecorder) RemovePlugin(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemovePlugin", reflect.TypeOf((*MockAPI)(nil).RemovePlugin), arg0) +} + +// RemoveReaction mocks base method. +func (m *MockAPI) RemoveReaction(arg0 *model.Reaction) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveReaction", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// RemoveReaction indicates an expected call of RemoveReaction. +func (mr *MockAPIMockRecorder) RemoveReaction(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveReaction", reflect.TypeOf((*MockAPI)(nil).RemoveReaction), arg0) +} + +// RemoveTeamIcon mocks base method. +func (m *MockAPI) RemoveTeamIcon(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RemoveTeamIcon", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// RemoveTeamIcon indicates an expected call of RemoveTeamIcon. +func (mr *MockAPIMockRecorder) RemoveTeamIcon(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveTeamIcon", reflect.TypeOf((*MockAPI)(nil).RemoveTeamIcon), arg0) +} + +// RequestTrialLicense mocks base method. +func (m *MockAPI) RequestTrialLicense(arg0 string, arg1 int, arg2, arg3 bool) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RequestTrialLicense", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// RequestTrialLicense indicates an expected call of RequestTrialLicense. +func (mr *MockAPIMockRecorder) RequestTrialLicense(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RequestTrialLicense", reflect.TypeOf((*MockAPI)(nil).RequestTrialLicense), arg0, arg1, arg2, arg3) +} + +// RevokeUserAccessToken mocks base method. +func (m *MockAPI) RevokeUserAccessToken(arg0 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RevokeUserAccessToken", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// RevokeUserAccessToken indicates an expected call of RevokeUserAccessToken. +func (mr *MockAPIMockRecorder) RevokeUserAccessToken(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RevokeUserAccessToken", reflect.TypeOf((*MockAPI)(nil).RevokeUserAccessToken), arg0) +} + +// SaveConfig mocks base method. +func (m *MockAPI) SaveConfig(arg0 *model.Config) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SaveConfig", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// SaveConfig indicates an expected call of SaveConfig. +func (mr *MockAPIMockRecorder) SaveConfig(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveConfig", reflect.TypeOf((*MockAPI)(nil).SaveConfig), arg0) +} + +// SavePluginConfig mocks base method. +func (m *MockAPI) SavePluginConfig(arg0 map[string]interface{}) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SavePluginConfig", arg0) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// SavePluginConfig indicates an expected call of SavePluginConfig. +func (mr *MockAPIMockRecorder) SavePluginConfig(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SavePluginConfig", reflect.TypeOf((*MockAPI)(nil).SavePluginConfig), arg0) +} + +// SearchChannels mocks base method. +func (m *MockAPI) SearchChannels(arg0, arg1 string) ([]*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchChannels", arg0, arg1) + ret0, _ := ret[0].([]*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SearchChannels indicates an expected call of SearchChannels. +func (mr *MockAPIMockRecorder) SearchChannels(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchChannels", reflect.TypeOf((*MockAPI)(nil).SearchChannels), arg0, arg1) +} + +// SearchPostsInTeam mocks base method. +func (m *MockAPI) SearchPostsInTeam(arg0 string, arg1 []*model.SearchParams) ([]*model.Post, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchPostsInTeam", arg0, arg1) + ret0, _ := ret[0].([]*model.Post) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SearchPostsInTeam indicates an expected call of SearchPostsInTeam. +func (mr *MockAPIMockRecorder) SearchPostsInTeam(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchPostsInTeam", reflect.TypeOf((*MockAPI)(nil).SearchPostsInTeam), arg0, arg1) +} + +// SearchPostsInTeamForUser mocks base method. +func (m *MockAPI) SearchPostsInTeamForUser(arg0, arg1 string, arg2 model.SearchParameter) (*model.PostSearchResults, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchPostsInTeamForUser", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.PostSearchResults) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SearchPostsInTeamForUser indicates an expected call of SearchPostsInTeamForUser. +func (mr *MockAPIMockRecorder) SearchPostsInTeamForUser(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchPostsInTeamForUser", reflect.TypeOf((*MockAPI)(nil).SearchPostsInTeamForUser), arg0, arg1, arg2) +} + +// SearchTeams mocks base method. +func (m *MockAPI) SearchTeams(arg0 string) ([]*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchTeams", arg0) + ret0, _ := ret[0].([]*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SearchTeams indicates an expected call of SearchTeams. +func (mr *MockAPIMockRecorder) SearchTeams(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchTeams", reflect.TypeOf((*MockAPI)(nil).SearchTeams), arg0) +} + +// SearchUsers mocks base method. +func (m *MockAPI) SearchUsers(arg0 *model.UserSearch) ([]*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SearchUsers", arg0) + ret0, _ := ret[0].([]*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SearchUsers indicates an expected call of SearchUsers. +func (mr *MockAPIMockRecorder) SearchUsers(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUsers", reflect.TypeOf((*MockAPI)(nil).SearchUsers), arg0) +} + +// SendEphemeralPost mocks base method. +func (m *MockAPI) SendEphemeralPost(arg0 string, arg1 *model.Post) *model.Post { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendEphemeralPost", arg0, arg1) + ret0, _ := ret[0].(*model.Post) + return ret0 +} + +// SendEphemeralPost indicates an expected call of SendEphemeralPost. +func (mr *MockAPIMockRecorder) SendEphemeralPost(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendEphemeralPost", reflect.TypeOf((*MockAPI)(nil).SendEphemeralPost), arg0, arg1) +} + +// SendMail mocks base method. +func (m *MockAPI) SendMail(arg0, arg1, arg2 string) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendMail", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// SendMail indicates an expected call of SendMail. +func (mr *MockAPIMockRecorder) SendMail(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendMail", reflect.TypeOf((*MockAPI)(nil).SendMail), arg0, arg1, arg2) +} + +// SetProfileImage mocks base method. +func (m *MockAPI) SetProfileImage(arg0 string, arg1 []byte) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetProfileImage", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// SetProfileImage indicates an expected call of SetProfileImage. +func (mr *MockAPIMockRecorder) SetProfileImage(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProfileImage", reflect.TypeOf((*MockAPI)(nil).SetProfileImage), arg0, arg1) +} + +// SetTeamIcon mocks base method. +func (m *MockAPI) SetTeamIcon(arg0 string, arg1 []byte) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetTeamIcon", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// SetTeamIcon indicates an expected call of SetTeamIcon. +func (mr *MockAPIMockRecorder) SetTeamIcon(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetTeamIcon", reflect.TypeOf((*MockAPI)(nil).SetTeamIcon), arg0, arg1) +} + +// SetUserStatusTimedDND mocks base method. +func (m *MockAPI) SetUserStatusTimedDND(arg0 string, arg1 int64) (*model.Status, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetUserStatusTimedDND", arg0, arg1) + ret0, _ := ret[0].(*model.Status) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// SetUserStatusTimedDND indicates an expected call of SetUserStatusTimedDND. +func (mr *MockAPIMockRecorder) SetUserStatusTimedDND(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetUserStatusTimedDND", reflect.TypeOf((*MockAPI)(nil).SetUserStatusTimedDND), arg0, arg1) +} + +// UnregisterCommand mocks base method. +func (m *MockAPI) UnregisterCommand(arg0, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UnregisterCommand", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UnregisterCommand indicates an expected call of UnregisterCommand. +func (mr *MockAPIMockRecorder) UnregisterCommand(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnregisterCommand", reflect.TypeOf((*MockAPI)(nil).UnregisterCommand), arg0, arg1) +} + +// UpdateBotActive mocks base method. +func (m *MockAPI) UpdateBotActive(arg0 string, arg1 bool) (*model.Bot, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateBotActive", arg0, arg1) + ret0, _ := ret[0].(*model.Bot) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateBotActive indicates an expected call of UpdateBotActive. +func (mr *MockAPIMockRecorder) UpdateBotActive(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateBotActive", reflect.TypeOf((*MockAPI)(nil).UpdateBotActive), arg0, arg1) +} + +// UpdateChannel mocks base method. +func (m *MockAPI) UpdateChannel(arg0 *model.Channel) (*model.Channel, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChannel", arg0) + ret0, _ := ret[0].(*model.Channel) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateChannel indicates an expected call of UpdateChannel. +func (mr *MockAPIMockRecorder) UpdateChannel(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChannel", reflect.TypeOf((*MockAPI)(nil).UpdateChannel), arg0) +} + +// UpdateChannelMemberNotifications mocks base method. +func (m *MockAPI) UpdateChannelMemberNotifications(arg0, arg1 string, arg2 map[string]string) (*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChannelMemberNotifications", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateChannelMemberNotifications indicates an expected call of UpdateChannelMemberNotifications. +func (mr *MockAPIMockRecorder) UpdateChannelMemberNotifications(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChannelMemberNotifications", reflect.TypeOf((*MockAPI)(nil).UpdateChannelMemberNotifications), arg0, arg1, arg2) +} + +// UpdateChannelMemberRoles mocks base method. +func (m *MockAPI) UpdateChannelMemberRoles(arg0, arg1, arg2 string) (*model.ChannelMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChannelMemberRoles", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.ChannelMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateChannelMemberRoles indicates an expected call of UpdateChannelMemberRoles. +func (mr *MockAPIMockRecorder) UpdateChannelMemberRoles(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChannelMemberRoles", reflect.TypeOf((*MockAPI)(nil).UpdateChannelMemberRoles), arg0, arg1, arg2) +} + +// UpdateChannelSidebarCategories mocks base method. +func (m *MockAPI) UpdateChannelSidebarCategories(arg0, arg1 string, arg2 []*model.SidebarCategoryWithChannels) ([]*model.SidebarCategoryWithChannels, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateChannelSidebarCategories", arg0, arg1, arg2) + ret0, _ := ret[0].([]*model.SidebarCategoryWithChannels) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateChannelSidebarCategories indicates an expected call of UpdateChannelSidebarCategories. +func (mr *MockAPIMockRecorder) UpdateChannelSidebarCategories(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateChannelSidebarCategories", reflect.TypeOf((*MockAPI)(nil).UpdateChannelSidebarCategories), arg0, arg1, arg2) +} + +// UpdateCommand mocks base method. +func (m *MockAPI) UpdateCommand(arg0 string, arg1 *model.Command) (*model.Command, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateCommand", arg0, arg1) + ret0, _ := ret[0].(*model.Command) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateCommand indicates an expected call of UpdateCommand. +func (mr *MockAPIMockRecorder) UpdateCommand(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCommand", reflect.TypeOf((*MockAPI)(nil).UpdateCommand), arg0, arg1) +} + +// UpdateEphemeralPost mocks base method. +func (m *MockAPI) UpdateEphemeralPost(arg0 string, arg1 *model.Post) *model.Post { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateEphemeralPost", arg0, arg1) + ret0, _ := ret[0].(*model.Post) + return ret0 +} + +// UpdateEphemeralPost indicates an expected call of UpdateEphemeralPost. +func (mr *MockAPIMockRecorder) UpdateEphemeralPost(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateEphemeralPost", reflect.TypeOf((*MockAPI)(nil).UpdateEphemeralPost), arg0, arg1) +} + +// UpdateOAuthApp mocks base method. +func (m *MockAPI) UpdateOAuthApp(arg0 *model.OAuthApp) (*model.OAuthApp, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateOAuthApp", arg0) + ret0, _ := ret[0].(*model.OAuthApp) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateOAuthApp indicates an expected call of UpdateOAuthApp. +func (mr *MockAPIMockRecorder) UpdateOAuthApp(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateOAuthApp", reflect.TypeOf((*MockAPI)(nil).UpdateOAuthApp), arg0) +} + +// UpdatePost mocks base method. +func (m *MockAPI) UpdatePost(arg0 *model.Post) (*model.Post, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePost", arg0) + ret0, _ := ret[0].(*model.Post) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdatePost indicates an expected call of UpdatePost. +func (mr *MockAPIMockRecorder) UpdatePost(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePost", reflect.TypeOf((*MockAPI)(nil).UpdatePost), arg0) +} + +// UpdatePreferencesForUser mocks base method. +func (m *MockAPI) UpdatePreferencesForUser(arg0 string, arg1 []model.Preference) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePreferencesForUser", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// UpdatePreferencesForUser indicates an expected call of UpdatePreferencesForUser. +func (mr *MockAPIMockRecorder) UpdatePreferencesForUser(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePreferencesForUser", reflect.TypeOf((*MockAPI)(nil).UpdatePreferencesForUser), arg0, arg1) +} + +// UpdateTeam mocks base method. +func (m *MockAPI) UpdateTeam(arg0 *model.Team) (*model.Team, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTeam", arg0) + ret0, _ := ret[0].(*model.Team) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateTeam indicates an expected call of UpdateTeam. +func (mr *MockAPIMockRecorder) UpdateTeam(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTeam", reflect.TypeOf((*MockAPI)(nil).UpdateTeam), arg0) +} + +// UpdateTeamMemberRoles mocks base method. +func (m *MockAPI) UpdateTeamMemberRoles(arg0, arg1, arg2 string) (*model.TeamMember, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTeamMemberRoles", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.TeamMember) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateTeamMemberRoles indicates an expected call of UpdateTeamMemberRoles. +func (mr *MockAPIMockRecorder) UpdateTeamMemberRoles(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTeamMemberRoles", reflect.TypeOf((*MockAPI)(nil).UpdateTeamMemberRoles), arg0, arg1, arg2) +} + +// UpdateUser mocks base method. +func (m *MockAPI) UpdateUser(arg0 *model.User) (*model.User, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUser", arg0) + ret0, _ := ret[0].(*model.User) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateUser indicates an expected call of UpdateUser. +func (mr *MockAPIMockRecorder) UpdateUser(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUser", reflect.TypeOf((*MockAPI)(nil).UpdateUser), arg0) +} + +// UpdateUserActive mocks base method. +func (m *MockAPI) UpdateUserActive(arg0 string, arg1 bool) *model.AppError { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserActive", arg0, arg1) + ret0, _ := ret[0].(*model.AppError) + return ret0 +} + +// UpdateUserActive indicates an expected call of UpdateUserActive. +func (mr *MockAPIMockRecorder) UpdateUserActive(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserActive", reflect.TypeOf((*MockAPI)(nil).UpdateUserActive), arg0, arg1) +} + +// UpdateUserStatus mocks base method. +func (m *MockAPI) UpdateUserStatus(arg0, arg1 string) (*model.Status, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserStatus", arg0, arg1) + ret0, _ := ret[0].(*model.Status) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UpdateUserStatus indicates an expected call of UpdateUserStatus. +func (mr *MockAPIMockRecorder) UpdateUserStatus(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserStatus", reflect.TypeOf((*MockAPI)(nil).UpdateUserStatus), arg0, arg1) +} + +// UploadFile mocks base method. +func (m *MockAPI) UploadFile(arg0 []byte, arg1, arg2 string) (*model.FileInfo, *model.AppError) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UploadFile", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.FileInfo) + ret1, _ := ret[1].(*model.AppError) + return ret0, ret1 +} + +// UploadFile indicates an expected call of UploadFile. +func (mr *MockAPIMockRecorder) UploadFile(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadFile", reflect.TypeOf((*MockAPI)(nil).UploadFile), arg0, arg1, arg2) +} diff --git a/server/ws/plugin_adapter.go b/server/ws/plugin_adapter.go index e8e4f862c..dcb26e416 100644 --- a/server/ws/plugin_adapter.go +++ b/server/ws/plugin_adapter.go @@ -1,9 +1,11 @@ +//go:generate mockgen --build_flags=--mod=mod -destination=mocks/mockpluginapi.go -package mocks github.com/mattermost/mattermost-server/v6/plugin API package ws import ( "fmt" "strings" "sync" + "sync/atomic" "time" "github.com/mattermost/focalboard/server/auth" @@ -17,45 +19,10 @@ const websocketMessagePrefix = "custom_focalboard_" var errMissingWorkspaceInCommand = fmt.Errorf("command doesn't contain workspaceId") -type PluginAdapterClient struct { - webConnID string - userID string - workspaces []string - blocks []string -} - -func (pac *PluginAdapterClient) isSubscribedToWorkspace(workspaceID string) bool { - for _, id := range pac.workspaces { - if id == workspaceID { - return true - } - } - - return false -} - -func (pac *PluginAdapterClient) isSubscribedToBlock(blockID string) bool { - for _, id := range pac.blocks { - if id == blockID { - return true - } - } - - return false -} - type PluginAdapterInterface interface { - addListener(pac *PluginAdapterClient) - removeListener(pac *PluginAdapterClient) - removeListenerFromWorkspace(pac *PluginAdapterClient, workspaceID string) - removeListenerFromBlock(pac *PluginAdapterClient, blockID string) - subscribeListenerToWorkspace(pac *PluginAdapterClient, workspaceID string) - unsubscribeListenerFromWorkspace(pac *PluginAdapterClient, workspaceID string) - unsubscribeListenerFromBlocks(pac *PluginAdapterClient, blockIDs []string) OnWebSocketConnect(webConnID, userID string) OnWebSocketDisconnect(webConnID, userID string) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mmModel.WebSocketRequest) - getUserIDsForWorkspace(workspaceID string) []string BroadcastConfigChange(clientConfig model.ClientConfig) BroadcastBlockChange(workspaceID string, block model.Block) BroadcastBlockDelete(workspaceID, blockID, parentID string) @@ -63,35 +30,73 @@ type PluginAdapterInterface interface { } type PluginAdapter struct { - api plugin.API - auth *auth.Auth + api plugin.API + auth auth.AuthInterface + staleThreshold time.Duration - listeners map[string]*PluginAdapterClient + listenersMU sync.RWMutex + listeners map[string]*PluginAdapterClient + listenersByUserID map[string][]*PluginAdapterClient + + subscriptionsMU sync.RWMutex listenersByWorkspace map[string][]*PluginAdapterClient listenersByBlock map[string][]*PluginAdapterClient - mu sync.RWMutex } -func NewPluginAdapter(api plugin.API, auth *auth.Auth) *PluginAdapter { +func NewPluginAdapter(api plugin.API, auth auth.AuthInterface) *PluginAdapter { return &PluginAdapter{ api: api, auth: auth, + staleThreshold: 5 * time.Minute, listeners: make(map[string]*PluginAdapterClient), + listenersByUserID: make(map[string][]*PluginAdapterClient), listenersByWorkspace: make(map[string][]*PluginAdapterClient), listenersByBlock: make(map[string][]*PluginAdapterClient), - mu: sync.RWMutex{}, + listenersMU: sync.RWMutex{}, + subscriptionsMU: sync.RWMutex{}, } } +func (pa *PluginAdapter) GetListenerByWebConnID(webConnID string) (pac *PluginAdapterClient, ok bool) { + pa.listenersMU.RLock() + defer pa.listenersMU.RUnlock() + + pac, ok = pa.listeners[webConnID] + return +} + +func (pa *PluginAdapter) GetListenersByUserID(userID string) []*PluginAdapterClient { + pa.listenersMU.RLock() + defer pa.listenersMU.RUnlock() + + return pa.listenersByUserID[userID] +} + +func (pa *PluginAdapter) GetListenersByWorkspace(workspaceID string) []*PluginAdapterClient { + pa.subscriptionsMU.RLock() + defer pa.subscriptionsMU.RUnlock() + + return pa.listenersByWorkspace[workspaceID] +} + +func (pa *PluginAdapter) GetListenersByBlock(blockID string) []*PluginAdapterClient { + pa.subscriptionsMU.RLock() + defer pa.subscriptionsMU.RUnlock() + + return pa.listenersByBlock[blockID] +} + func (pa *PluginAdapter) addListener(pac *PluginAdapterClient) { - pa.mu.Lock() - defer pa.mu.Unlock() + pa.listenersMU.Lock() + defer pa.listenersMU.Unlock() + pa.listeners[pac.webConnID] = pac + pa.listenersByUserID[pac.userID] = append(pa.listenersByUserID[pac.userID], pac) } func (pa *PluginAdapter) removeListener(pac *PluginAdapterClient) { - pa.mu.Lock() - defer pa.mu.Unlock() + pa.listenersMU.Lock() + defer pa.listenersMU.Unlock() // workspace subscriptions for _, workspace := range pac.workspaces { @@ -103,43 +108,52 @@ func (pa *PluginAdapter) removeListener(pac *PluginAdapterClient) { pa.removeListenerFromBlock(pac, block) } + // user ID list + newUserListeners := []*PluginAdapterClient{} + for _, listener := range pa.listenersByUserID[pac.userID] { + if listener.webConnID != pac.webConnID { + newUserListeners = append(newUserListeners, listener) + } + } + pa.listenersByUserID[pac.userID] = newUserListeners + delete(pa.listeners, pac.webConnID) } +func (pa *PluginAdapter) removeExpiredForUserID(userID string) { + for _, pac := range pa.GetListenersByUserID(userID) { + if !pac.isActive() && pac.hasExpired(pa.staleThreshold) { + pa.removeListener(pac) + } + } +} + func (pa *PluginAdapter) removeListenerFromWorkspace(pac *PluginAdapterClient, workspaceID string) { newWorkspaceListeners := []*PluginAdapterClient{} - for _, listener := range pa.listenersByWorkspace[workspaceID] { + for _, listener := range pa.GetListenersByWorkspace(workspaceID) { if listener.webConnID != pac.webConnID { newWorkspaceListeners = append(newWorkspaceListeners, listener) } } + pa.subscriptionsMU.Lock() pa.listenersByWorkspace[workspaceID] = newWorkspaceListeners + pa.subscriptionsMU.Unlock() - newClientWorkspaces := []string{} - for _, id := range pac.workspaces { - if id != workspaceID { - newClientWorkspaces = append(newClientWorkspaces, id) - } - } - pac.workspaces = newClientWorkspaces + pac.unsubscribeFromWorkspace(workspaceID) } func (pa *PluginAdapter) removeListenerFromBlock(pac *PluginAdapterClient, blockID string) { newBlockListeners := []*PluginAdapterClient{} - for _, listener := range pa.listenersByBlock[blockID] { + for _, listener := range pa.GetListenersByBlock(blockID) { if listener.webConnID != pac.webConnID { newBlockListeners = append(newBlockListeners, listener) } } + pa.subscriptionsMU.Lock() pa.listenersByBlock[blockID] = newBlockListeners + pa.subscriptionsMU.Unlock() - newClientBlocks := []string{} - for _, id := range pac.blocks { - if id != blockID { - newClientBlocks = append(newClientBlocks, id) - } - } - pac.blocks = newClientBlocks + pac.unsubscribeFromBlock(blockID) } func (pa *PluginAdapter) subscribeListenerToWorkspace(pac *PluginAdapterClient, workspaceID string) { @@ -147,11 +161,11 @@ func (pa *PluginAdapter) subscribeListenerToWorkspace(pac *PluginAdapterClient, return } - pa.mu.Lock() - defer pa.mu.Unlock() - + pa.subscriptionsMU.Lock() pa.listenersByWorkspace[workspaceID] = append(pa.listenersByWorkspace[workspaceID], pac) - pac.workspaces = append(pac.workspaces, workspaceID) + pa.subscriptionsMU.Unlock() + + pac.subscribeToWorkspace(workspaceID) } func (pa *PluginAdapter) unsubscribeListenerFromWorkspace(pac *PluginAdapterClient, workspaceID string) { @@ -159,16 +173,26 @@ func (pa *PluginAdapter) unsubscribeListenerFromWorkspace(pac *PluginAdapterClie return } - pa.mu.Lock() - defer pa.mu.Unlock() - pa.removeListenerFromWorkspace(pac, workspaceID) } -func (pa *PluginAdapter) unsubscribeListenerFromBlocks(pac *PluginAdapterClient, blockIDs []string) { - pa.mu.Lock() - defer pa.mu.Unlock() +func (pa *PluginAdapter) getUserIDsForWorkspace(workspaceID string) []string { + userMap := map[string]bool{} + for _, pac := range pa.GetListenersByWorkspace(workspaceID) { + if pac.isActive() { + userMap[pac.userID] = true + } + } + userIDs := []string{} + for userID := range userMap { + userIDs = append(userIDs, userID) + } + return userIDs +} + +//nolint:unused +func (pa *PluginAdapter) unsubscribeListenerFromBlocks(pac *PluginAdapterClient, blockIDs []string) { for _, blockID := range blockIDs { if pac.isSubscribedToBlock(blockID) { pa.removeListenerFromBlock(pac, blockID) @@ -177,18 +201,29 @@ func (pa *PluginAdapter) unsubscribeListenerFromBlocks(pac *PluginAdapterClient, } func (pa *PluginAdapter) OnWebSocketConnect(webConnID, userID string) { - pac := &PluginAdapterClient{ + if existingPAC, ok := pa.GetListenerByWebConnID(webConnID); ok { + pa.api.LogDebug("inactive connection found for webconn, reusing", + "webConnID", webConnID, + "userID", userID, + ) + atomic.StoreInt64(&existingPAC.inactiveAt, 0) + return + } + + newPAC := &PluginAdapterClient{ + inactiveAt: 0, webConnID: webConnID, userID: userID, workspaces: []string{}, blocks: []string{}, } - pa.addListener(pac) + pa.addListener(newPAC) + pa.removeExpiredForUserID(userID) } func (pa *PluginAdapter) OnWebSocketDisconnect(webConnID, userID string) { - pac, ok := pa.listeners[webConnID] + pac, ok := pa.GetListenerByWebConnID(webConnID) if !ok { pa.api.LogError("received a disconnect for an unregistered webconn", "webConnID", webConnID, @@ -197,7 +232,7 @@ func (pa *PluginAdapter) OnWebSocketDisconnect(webConnID, userID string) { return } - pa.removeListener(pac) + atomic.StoreInt64(&pac.inactiveAt, mmModel.GetMillis()) } func commandFromRequest(req *mmModel.WebSocketRequest) (*WebsocketCommand, error) { @@ -221,7 +256,7 @@ func commandFromRequest(req *mmModel.WebSocketRequest) (*WebsocketCommand, error } func (pa *PluginAdapter) WebSocketMessageHasBeenPosted(webConnID, userID string, req *mmModel.WebSocketRequest) { - pac, ok := pa.listeners[webConnID] + pac, ok := pa.GetListenerByWebConnID(webConnID) if !ok { pa.api.LogError("received a message for an unregistered webconn", "webConnID", webConnID, @@ -282,19 +317,6 @@ func (pa *PluginAdapter) WebSocketMessageHasBeenPosted(webConnID, userID string, } } -func (pa *PluginAdapter) getUserIDsForWorkspace(workspaceID string) []string { - userMap := map[string]bool{} - for _, pac := range pa.listenersByWorkspace[workspaceID] { - userMap[pac.userID] = true - } - - userIDs := []string{} - for userID := range userMap { - userIDs = append(userIDs, userID) - } - return userIDs -} - func (pa *PluginAdapter) sendMessageToAllSkipCluster(payload map[string]interface{}) { // Empty &mmModel.WebsocketBroadcast will send to all users pa.api.PublishWebSocketEvent(websocketActionUpdateConfig, payload, &mmModel.WebsocketBroadcast{}) diff --git a/server/ws/plugin_adapter_client.go b/server/ws/plugin_adapter_client.go new file mode 100644 index 000000000..6a7274d48 --- /dev/null +++ b/server/ws/plugin_adapter_client.go @@ -0,0 +1,86 @@ +package ws + +import ( + "sync" + "sync/atomic" + "time" + + mmModel "github.com/mattermost/mattermost-server/v6/model" +) + +type PluginAdapterClient struct { + inactiveAt int64 + webConnID string + userID string + workspaces []string + blocks []string + mu sync.RWMutex +} + +func (pac *PluginAdapterClient) isActive() bool { + return atomic.LoadInt64(&pac.inactiveAt) == 0 +} + +func (pac *PluginAdapterClient) hasExpired(threshold time.Duration) bool { + return !mmModel.GetTimeForMillis(atomic.LoadInt64(&pac.inactiveAt)).Add(threshold).After(time.Now()) +} + +func (pac *PluginAdapterClient) subscribeToWorkspace(workspaceID string) { + pac.mu.Lock() + defer pac.mu.Unlock() + + pac.workspaces = append(pac.workspaces, workspaceID) +} + +func (pac *PluginAdapterClient) unsubscribeFromWorkspace(workspaceID string) { + pac.mu.Lock() + defer pac.mu.Unlock() + + newClientWorkspaces := []string{} + for _, id := range pac.workspaces { + if id != workspaceID { + newClientWorkspaces = append(newClientWorkspaces, id) + } + } + pac.workspaces = newClientWorkspaces +} + +func (pac *PluginAdapterClient) unsubscribeFromBlock(blockID string) { + pac.mu.Lock() + defer pac.mu.Unlock() + + newClientBlocks := []string{} + for _, id := range pac.blocks { + if id != blockID { + newClientBlocks = append(newClientBlocks, id) + } + } + pac.blocks = newClientBlocks +} + +func (pac *PluginAdapterClient) isSubscribedToWorkspace(workspaceID string) bool { + pac.mu.RLock() + defer pac.mu.RUnlock() + + for _, id := range pac.workspaces { + if id == workspaceID { + return true + } + } + + return false +} + +//nolint:unused +func (pac *PluginAdapterClient) isSubscribedToBlock(blockID string) bool { + pac.mu.RLock() + defer pac.mu.RUnlock() + + for _, id := range pac.blocks { + if id == blockID { + return true + } + } + + return false +} diff --git a/server/ws/plugin_adapter_test.go b/server/ws/plugin_adapter_test.go new file mode 100644 index 000000000..01255949d --- /dev/null +++ b/server/ws/plugin_adapter_test.go @@ -0,0 +1,346 @@ +package ws + +import ( + "sync" + "testing" + + mmModel "github.com/mattermost/mattermost-server/v6/model" + + "github.com/stretchr/testify/require" +) + +func TestPluginAdapterWorkspaceSubscription(t *testing.T) { + th := SetupTestHelper(t) + + webConnID := mmModel.NewId() + userID := mmModel.NewId() + workspaceID := mmModel.NewId() + + var pac *PluginAdapterClient + t.Run("Should correctly add a connection", func(t *testing.T) { + require.Empty(t, th.pa.listeners) + require.Empty(t, th.pa.listenersByWorkspace) + th.pa.OnWebSocketConnect(webConnID, userID) + require.Len(t, th.pa.listeners, 1) + + var ok bool + pac, ok = th.pa.listeners[webConnID] + require.True(t, ok) + require.NotNil(t, pac) + require.Equal(t, userID, pac.userID) + require.Empty(t, th.pa.listenersByWorkspace) + }) + + t.Run("Should correctly subscribe to a workspace", func(t *testing.T) { + require.False(t, pac.isSubscribedToWorkspace(workspaceID)) + + th.SubscribeWebConnToWorkspace(pac.webConnID, pac.userID, workspaceID) + + require.Len(t, th.pa.listenersByWorkspace[workspaceID], 1) + require.Contains(t, th.pa.listenersByWorkspace[workspaceID], pac) + require.Len(t, pac.workspaces, 1) + require.Contains(t, pac.workspaces, workspaceID) + + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Subscribing again to a subscribed workspace would have no effect", func(t *testing.T) { + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + + th.SubscribeWebConnToWorkspace(pac.webConnID, pac.userID, workspaceID) + + require.Len(t, th.pa.listenersByWorkspace[workspaceID], 1) + require.Contains(t, th.pa.listenersByWorkspace[workspaceID], pac) + require.Len(t, pac.workspaces, 1) + require.Contains(t, pac.workspaces, workspaceID) + + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Should correctly unsubscribe to a workspace", func(t *testing.T) { + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + + th.UnsubscribeWebConnFromWorkspace(pac.webConnID, pac.userID, workspaceID) + + require.Empty(t, th.pa.listenersByWorkspace[workspaceID]) + require.Empty(t, pac.workspaces) + + require.False(t, pac.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Unsubscribing again to an unsubscribed workspace would have no effect", func(t *testing.T) { + require.False(t, pac.isSubscribedToWorkspace(workspaceID)) + + th.UnsubscribeWebConnFromWorkspace(pac.webConnID, pac.userID, workspaceID) + + require.Empty(t, th.pa.listenersByWorkspace[workspaceID]) + require.Empty(t, pac.workspaces) + + require.False(t, pac.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Should correctly be marked as inactive if disconnected", func(t *testing.T) { + require.Len(t, th.pa.listeners, 1) + require.True(t, th.pa.listeners[webConnID].isActive()) + + th.pa.OnWebSocketDisconnect(webConnID, userID) + + require.Len(t, th.pa.listeners, 1) + require.False(t, th.pa.listeners[webConnID].isActive()) + }) + + t.Run("Should be marked back as active if reconnect", func(t *testing.T) { + require.Len(t, th.pa.listeners, 1) + require.False(t, th.pa.listeners[webConnID].isActive()) + + th.pa.OnWebSocketConnect(webConnID, userID) + + require.Len(t, th.pa.listeners, 1) + require.True(t, th.pa.listeners[webConnID].isActive()) + }) +} + +func TestPluginAdapterClientReconnect(t *testing.T) { + th := SetupTestHelper(t) + + webConnID := mmModel.NewId() + userID := mmModel.NewId() + workspaceID := mmModel.NewId() + + var pac *PluginAdapterClient + t.Run("A user should be able to reconnect within the accepted threshold and keep their subscriptions", func(t *testing.T) { + // create the connection + require.Len(t, th.pa.listeners, 0) + require.Len(t, th.pa.listenersByUserID[userID], 0) + th.pa.OnWebSocketConnect(webConnID, userID) + require.Len(t, th.pa.listeners, 1) + require.Len(t, th.pa.listenersByUserID[userID], 1) + var ok bool + pac, ok = th.pa.listeners[webConnID] + require.True(t, ok) + require.NotNil(t, pac) + + th.SubscribeWebConnToWorkspace(pac.webConnID, pac.userID, workspaceID) + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + + // disconnect + th.pa.OnWebSocketDisconnect(webConnID, userID) + require.False(t, pac.isActive()) + require.Len(t, th.pa.listeners, 1) + require.Len(t, th.pa.listenersByUserID[userID], 1) + + // reconnect right away. The connection should still be subscribed + th.pa.OnWebSocketConnect(webConnID, userID) + require.Len(t, th.pa.listeners, 1) + require.Len(t, th.pa.listenersByUserID[userID], 1) + require.True(t, pac.isActive()) + require.True(t, pac.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Should remove old inactive connection when user connects with a different ID", func(t *testing.T) { + // we set the stale threshold to zero so inactive connections always get deleted + oldStaleThreshold := th.pa.staleThreshold + th.pa.staleThreshold = 0 + defer func() { th.pa.staleThreshold = oldStaleThreshold }() + th.pa.OnWebSocketDisconnect(webConnID, userID) + require.Len(t, th.pa.listeners, 1) + require.Len(t, th.pa.listenersByUserID[userID], 1) + require.Equal(t, webConnID, th.pa.listenersByUserID[userID][0].webConnID) + + newWebConnID := mmModel.NewId() + th.pa.OnWebSocketConnect(newWebConnID, userID) + + require.Len(t, th.pa.listeners, 1) + require.Len(t, th.pa.listenersByUserID[userID], 1) + require.Contains(t, th.pa.listeners, newWebConnID) + require.NotContains(t, th.pa.listeners, webConnID) + require.Equal(t, newWebConnID, th.pa.listenersByUserID[userID][0].webConnID) + + // if the same ID connects again, it should have no subscriptions + th.pa.OnWebSocketConnect(webConnID, userID) + require.Len(t, th.pa.listeners, 2) + require.Len(t, th.pa.listenersByUserID[userID], 2) + reconnectedPAC, ok := th.pa.listeners[webConnID] + require.True(t, ok) + require.False(t, reconnectedPAC.isSubscribedToWorkspace(workspaceID)) + }) + + t.Run("Should not remove active connections when user connects with a different ID", func(t *testing.T) { + // we set the stale threshold to zero so inactive connections always get deleted + oldStaleThreshold := th.pa.staleThreshold + th.pa.staleThreshold = 0 + defer func() { th.pa.staleThreshold = oldStaleThreshold }() + + // currently we have two listeners for userID, both active + require.Len(t, th.pa.listeners, 2) + + // a new user connects + th.pa.OnWebSocketConnect(mmModel.NewId(), userID) + + // and we should have three connections, all of them active + require.Len(t, th.pa.listeners, 3) + + for _, listener := range th.pa.listeners { + require.True(t, listener.isActive()) + } + }) +} + +func TestGetUserIDsForWorkspace(t *testing.T) { + th := SetupTestHelper(t) + + // we have two workspaces + workspaceID1 := mmModel.NewId() + workspaceID2 := mmModel.NewId() + + // user 1 has two connections + userID1 := mmModel.NewId() + webConnID1 := mmModel.NewId() + webConnID2 := mmModel.NewId() + + // user 2 has one connection + userID2 := mmModel.NewId() + webConnID3 := mmModel.NewId() + + wg := new(sync.WaitGroup) + wg.Add(3) + + go func(wg *sync.WaitGroup) { + th.pa.OnWebSocketConnect(webConnID1, userID1) + th.SubscribeWebConnToWorkspace(webConnID1, userID1, workspaceID1) + wg.Done() + }(wg) + + go func(wg *sync.WaitGroup) { + th.pa.OnWebSocketConnect(webConnID2, userID1) + th.SubscribeWebConnToWorkspace(webConnID2, userID1, workspaceID2) + wg.Done() + }(wg) + + go func(wg *sync.WaitGroup) { + th.pa.OnWebSocketConnect(webConnID3, userID2) + th.SubscribeWebConnToWorkspace(webConnID3, userID2, workspaceID2) + wg.Done() + }(wg) + + wg.Wait() + + t.Run("should find that only user1 is connected to workspace 1", func(t *testing.T) { + userIDs := th.pa.getUserIDsForWorkspace(workspaceID1) + require.ElementsMatch(t, []string{userID1}, userIDs) + }) + + t.Run("should find that both users are connected to workspace 2", func(t *testing.T) { + userIDs := th.pa.getUserIDsForWorkspace(workspaceID2) + require.ElementsMatch(t, []string{userID1, userID2}, userIDs) + }) + + t.Run("should ignore user1 if webConn 2 inactive when getting workspace 2 user ids", func(t *testing.T) { + th.pa.OnWebSocketDisconnect(webConnID2, userID1) + + userIDs := th.pa.getUserIDsForWorkspace(workspaceID2) + require.ElementsMatch(t, []string{userID2}, userIDs) + }) + + t.Run("should still find user 1 in workspace 1 after the webConn 2 disconnection", func(t *testing.T) { + userIDs := th.pa.getUserIDsForWorkspace(workspaceID1) + require.ElementsMatch(t, []string{userID1}, userIDs) + }) + + t.Run("should find again both users if the webConn 2 comes back", func(t *testing.T) { + th.pa.OnWebSocketConnect(webConnID2, userID1) + + userIDs := th.pa.getUserIDsForWorkspace(workspaceID2) + require.ElementsMatch(t, []string{userID1, userID2}, userIDs) + }) +} + +func TestParallelSubscriptionsOnMultipleConnections(t *testing.T) { + th := SetupTestHelper(t) + + workspaceID1 := mmModel.NewId() + workspaceID2 := mmModel.NewId() + workspaceID3 := mmModel.NewId() + workspaceID4 := mmModel.NewId() + + userID := mmModel.NewId() + webConnID1 := mmModel.NewId() + webConnID2 := mmModel.NewId() + + th.pa.OnWebSocketConnect(webConnID1, userID) + pac1, ok := th.pa.GetListenerByWebConnID(webConnID1) + require.True(t, ok) + + th.pa.OnWebSocketConnect(webConnID2, userID) + pac2, ok := th.pa.GetListenerByWebConnID(webConnID2) + require.True(t, ok) + + wg := new(sync.WaitGroup) + wg.Add(4) + + go func(wg *sync.WaitGroup) { + th.SubscribeWebConnToWorkspace(webConnID1, userID, workspaceID1) + require.True(t, pac1.isSubscribedToWorkspace(workspaceID1)) + + th.SubscribeWebConnToWorkspace(webConnID2, userID, workspaceID1) + require.True(t, pac2.isSubscribedToWorkspace(workspaceID1)) + + th.UnsubscribeWebConnFromWorkspace(webConnID1, userID, workspaceID1) + require.False(t, pac1.isSubscribedToWorkspace(workspaceID1)) + + th.UnsubscribeWebConnFromWorkspace(webConnID2, userID, workspaceID1) + require.False(t, pac2.isSubscribedToWorkspace(workspaceID1)) + + wg.Done() + }(wg) + + go func(wg *sync.WaitGroup) { + th.SubscribeWebConnToWorkspace(webConnID1, userID, workspaceID2) + require.True(t, pac1.isSubscribedToWorkspace(workspaceID2)) + + th.SubscribeWebConnToWorkspace(webConnID2, userID, workspaceID2) + require.True(t, pac2.isSubscribedToWorkspace(workspaceID2)) + + th.UnsubscribeWebConnFromWorkspace(webConnID1, userID, workspaceID2) + require.False(t, pac1.isSubscribedToWorkspace(workspaceID2)) + + th.UnsubscribeWebConnFromWorkspace(webConnID2, userID, workspaceID2) + require.False(t, pac2.isSubscribedToWorkspace(workspaceID2)) + + wg.Done() + }(wg) + + go func(wg *sync.WaitGroup) { + th.SubscribeWebConnToWorkspace(webConnID1, userID, workspaceID3) + require.True(t, pac1.isSubscribedToWorkspace(workspaceID3)) + + th.SubscribeWebConnToWorkspace(webConnID2, userID, workspaceID3) + require.True(t, pac2.isSubscribedToWorkspace(workspaceID3)) + + th.UnsubscribeWebConnFromWorkspace(webConnID1, userID, workspaceID3) + require.False(t, pac1.isSubscribedToWorkspace(workspaceID3)) + + th.UnsubscribeWebConnFromWorkspace(webConnID2, userID, workspaceID3) + require.False(t, pac2.isSubscribedToWorkspace(workspaceID3)) + + wg.Done() + }(wg) + + go func(wg *sync.WaitGroup) { + th.SubscribeWebConnToWorkspace(webConnID1, userID, workspaceID4) + require.True(t, pac1.isSubscribedToWorkspace(workspaceID4)) + + th.SubscribeWebConnToWorkspace(webConnID2, userID, workspaceID4) + require.True(t, pac2.isSubscribedToWorkspace(workspaceID4)) + + th.UnsubscribeWebConnFromWorkspace(webConnID1, userID, workspaceID4) + require.False(t, pac1.isSubscribedToWorkspace(workspaceID4)) + + th.UnsubscribeWebConnFromWorkspace(webConnID2, userID, workspaceID4) + require.False(t, pac2.isSubscribedToWorkspace(workspaceID4)) + + wg.Done() + }(wg) + + wg.Wait() +} diff --git a/webapp/src/utils.ts b/webapp/src/utils.ts index aab0974ca..de7f0290d 100644 --- a/webapp/src/utils.ts +++ b/webapp/src/utils.ts @@ -244,6 +244,15 @@ class Utils { /// #!endif } + static logWarn(message: string): void { + /// #!if ENV !== "production" + const timestamp = (Date.now() / 1000).toFixed(2) + // eslint-disable-next-line no-console + console.warn(`[${timestamp}] ${message}`) + + /// #!endif + } + // favicon static setFavicon(icon?: string): void { diff --git a/webapp/src/wsclient.ts b/webapp/src/wsclient.ts index 0cdfb8776..88db7373d 100644 --- a/webapp/src/wsclient.ts +++ b/webapp/src/wsclient.ts @@ -32,7 +32,11 @@ export const ACTION_UPDATE_CLIENT_CONFIG = 'UPDATE_CLIENT_CONFIG' // The Mattermost websocket client interface export interface MMWebSocketClient { + conn: WebSocket | null; sendMessage(action: string, data: any, responseCallback?: () => void): void + setReconnectCallback(callback: () => void): void + setErrorCallback(callback: (event: Event) => void): void + setCloseCallback(callback: (connectFailCount: number) => void): void connectionId: string } @@ -59,6 +63,7 @@ class WSClient { private reopenDelay = 3000 private updatedBlocks: Block[] = [] private updateTimeout?: NodeJS.Timeout + private errorPollId?: NodeJS.Timeout private logged = false @@ -157,16 +162,63 @@ class WSClient { open(): void { if (this.client !== null) { + // configure the Mattermost websocket client callbacks + const onReconnect = () => { + Utils.logWarn('WSClient reconnected') + + this.open() + for (const handler of this.onReconnect) { + handler(this) + } + } + + const onClose = (connectFailCount: number) => { + Utils.logError(`WSClient has been closed, connect fail count: ${connectFailCount}`) + + for (const handler of this.onStateChange) { + handler(this, 'close') + } + this.state = 'close' + + // there is no way to react to a reconnection with the + // reliable websockets schema, so we poll the raw + // websockets client for its state directly until it + // reconnects + if (!this.errorPollId) { + this.errorPollId = setInterval(() => { + Utils.logWarn(`Polling websockets connection for state: ${this.client?.conn?.readyState}`) + if (this.client?.conn?.readyState === 1) { + onReconnect() + clearInterval(this.errorPollId!) + this.errorPollId = undefined + } + }, 500) + } + } + + const onError = (event: Event) => { + Utils.logError(`WSClient websocket onerror. data: ${JSON.stringify(event)}`) + + for (const handler of this.onError) { + handler(this, event) + } + } + + this.client.setErrorCallback(onError) + this.client.setCloseCallback(onClose) + this.client.setReconnectCallback(onReconnect) + // WSClient needs to ensure that the Mattermost client has // correctly stablished the connection before opening let retries = 0 const setPluginOpen = () => { if (this.client?.connectionId !== '') { + Utils.log('WSClient in plugin mode, reusing Mattermost WS connection') + for (const handler of this.onStateChange) { handler(this, 'open') } this.state = 'open' - Utils.log('WSClient in plugin mode, reusing Mattermost WS connection') return }