Merge branch 'master' into mark-as-unread

Этот коммит содержится в:
Harrison Healey
2019-11-07 10:58:09 -05:00
родитель 47409aaa4b 540cfb0239
Коммит 6e6174a9ee
41 изменённых файлов: 1565 добавлений и 1907 удалений

Просмотреть файл

@@ -59,7 +59,7 @@ LDFLAGS += -X "github.com/mattermost/mattermost-server/model.BuildEnterpriseRead
GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1) GO_MAJOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f1)
GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2) GO_MINOR_VERSION = $(shell $(GO) version | cut -c 14- | cut -d' ' -f1 | cut -d'.' -f2)
MINIMUM_SUPPORTED_GO_MAJOR_VERSION = 1 MINIMUM_SUPPORTED_GO_MAJOR_VERSION = 1
MINIMUM_SUPPORTED_GO_MINOR_VERSION = 12 MINIMUM_SUPPORTED_GO_MINOR_VERSION = 13
GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION).$(MINIMUM_SUPPORTED_GO_MINOR_VERSION) GO_VERSION_VALIDATION_ERR_MSG = Golang version is not supported, please update to at least $(MINIMUM_SUPPORTED_GO_MAJOR_VERSION).$(MINIMUM_SUPPORTED_GO_MINOR_VERSION)
# GOOS/GOARCH of the build host, used to determine whether we're cross-compiling or not # GOOS/GOARCH of the build host, used to determine whether we're cross-compiling or not
@@ -81,7 +81,7 @@ TESTFLAGSEE ?= -short
TE_PACKAGES=$(shell $(GO) list ./...) TE_PACKAGES=$(shell $(GO) list ./...)
# Plugins Packages # Plugins Packages
PLUGIN_PACKAGES=mattermost-plugin-zoom-v1.1.1 PLUGIN_PACKAGES=mattermost-plugin-zoom-v1.1.2
PLUGIN_PACKAGES += mattermost-plugin-autolink-v1.1.1 PLUGIN_PACKAGES += mattermost-plugin-autolink-v1.1.1
PLUGIN_PACKAGES += mattermost-plugin-nps-v1.0.3 PLUGIN_PACKAGES += mattermost-plugin-nps-v1.0.3
PLUGIN_PACKAGES += mattermost-plugin-custom-attributes-v1.0.2 PLUGIN_PACKAGES += mattermost-plugin-custom-attributes-v1.0.2

Просмотреть файл

@@ -25,31 +25,26 @@ func TestGetConfig(t *testing.T) {
require.NotEqual(t, "", cfg.TeamSettings.SiteName) require.NotEqual(t, "", cfg.TeamSettings.SiteName)
if *cfg.LdapSettings.BindPassword != model.FAKE_SETTING && len(*cfg.LdapSettings.BindPassword) != 0 { if *cfg.LdapSettings.BindPassword != model.FAKE_SETTING && len(*cfg.LdapSettings.BindPassword) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
}
if *cfg.FileSettings.PublicLinkSalt != model.FAKE_SETTING {
t.Fatal("did not sanitize properly")
} }
require.Equal(t, model.FAKE_SETTING, *cfg.FileSettings.PublicLinkSalt, "did not sanitize properly")
if *cfg.FileSettings.AmazonS3SecretAccessKey != model.FAKE_SETTING && len(*cfg.FileSettings.AmazonS3SecretAccessKey) != 0 { if *cfg.FileSettings.AmazonS3SecretAccessKey != model.FAKE_SETTING && len(*cfg.FileSettings.AmazonS3SecretAccessKey) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
} }
if *cfg.EmailSettings.SMTPPassword != model.FAKE_SETTING && len(*cfg.EmailSettings.SMTPPassword) != 0 { if *cfg.EmailSettings.SMTPPassword != model.FAKE_SETTING && len(*cfg.EmailSettings.SMTPPassword) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
} }
if *cfg.GitLabSettings.Secret != model.FAKE_SETTING && len(*cfg.GitLabSettings.Secret) != 0 { if *cfg.GitLabSettings.Secret != model.FAKE_SETTING && len(*cfg.GitLabSettings.Secret) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
}
if *cfg.SqlSettings.DataSource != model.FAKE_SETTING {
t.Fatal("did not sanitize properly")
}
if *cfg.SqlSettings.AtRestEncryptKey != model.FAKE_SETTING {
t.Fatal("did not sanitize properly")
} }
require.Equal(t, model.FAKE_SETTING, *cfg.SqlSettings.DataSource, "did not sanitize properly")
require.Equal(t, model.FAKE_SETTING, *cfg.SqlSettings.AtRestEncryptKey, "did not sanitize properly")
if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceReplicas) != 0 { if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceReplicas) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
} }
if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceSearchReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceSearchReplicas) != 0 { if !strings.Contains(strings.Join(cfg.SqlSettings.DataSourceSearchReplicas, " "), model.FAKE_SETTING) && len(cfg.SqlSettings.DataSourceSearchReplicas) != 0 {
t.Fatal("did not sanitize properly") require.FailNow(t, "did not sanitize properly")
} }
} }
@@ -61,17 +56,13 @@ func TestReloadConfig(t *testing.T) {
t.Run("as system user", func(t *testing.T) { t.Run("as system user", func(t *testing.T) {
ok, resp := Client.ReloadConfig() ok, resp := Client.ReloadConfig()
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
if ok { require.False(t, ok, "should not Reload the config due no permission.")
t.Fatal("should not Reload the config due no permission.")
}
}) })
t.Run("as system admin", func(t *testing.T) { t.Run("as system admin", func(t *testing.T) {
ok, resp := th.SystemAdminClient.ReloadConfig() ok, resp := th.SystemAdminClient.ReloadConfig()
CheckNoError(t, resp) CheckNoError(t, resp)
if !ok { require.True(t, ok, "should Reload the config")
t.Fatal("should Reload the config")
}
}) })
t.Run("as restricted system admin", func(t *testing.T) { t.Run("as restricted system admin", func(t *testing.T) {
@@ -79,9 +70,7 @@ func TestReloadConfig(t *testing.T) {
ok, resp := Client.ReloadConfig() ok, resp := Client.ReloadConfig()
CheckForbiddenStatus(t, resp) CheckForbiddenStatus(t, resp)
if ok { require.False(t, ok, "should not Reload the config due no permission.")
t.Fatal("should not Reload the config due no permission.")
}
}) })
} }
@@ -245,31 +234,28 @@ func TestGetEnvironmentConfig(t *testing.T) {
envConfig, resp := SystemAdminClient.GetEnvironmentConfig() envConfig, resp := SystemAdminClient.GetEnvironmentConfig()
CheckNoError(t, resp) CheckNoError(t, resp)
if serviceSettings, ok := envConfig["ServiceSettings"]; !ok { serviceSettings, ok := envConfig["ServiceSettings"]
t.Fatal("should've returned ServiceSettings") require.True(t, ok, "should've returned ServiceSettings")
} else if serviceSettingsAsMap, ok := serviceSettings.(map[string]interface{}); !ok {
t.Fatal("should've returned ServiceSettings as a map")
} else {
if siteURL, ok := serviceSettingsAsMap["SiteURL"]; !ok {
t.Fatal("should've returned ServiceSettings.SiteURL")
} else if siteURLAsBool, ok := siteURL.(bool); !ok {
t.Fatal("should've returned ServiceSettings.SiteURL as a boolean")
} else if !siteURLAsBool {
t.Fatal("should've returned ServiceSettings.SiteURL as true")
}
if enableCustomEmoji, ok := serviceSettingsAsMap["EnableCustomEmoji"]; !ok { serviceSettingsAsMap, ok := serviceSettings.(map[string]interface{})
t.Fatal("should've returned ServiceSettings.EnableCustomEmoji") require.True(t, ok, "should've returned ServiceSettings as a map")
} else if enableCustomEmojiAsBool, ok := enableCustomEmoji.(bool); !ok {
t.Fatal("should've returned ServiceSettings.EnableCustomEmoji as a boolean")
} else if !enableCustomEmojiAsBool {
t.Fatal("should've returned ServiceSettings.EnableCustomEmoji as true")
}
}
if _, ok := envConfig["TeamSettings"]; ok { siteURL, ok := serviceSettingsAsMap["SiteURL"]
t.Fatal("should not have returned TeamSettings") require.True(t, ok, "should've returned ServiceSettings.SiteURL")
}
siteURLAsBool, ok := siteURL.(bool)
require.True(t, ok, "should've returned ServiceSettings.SiteURL as a boolean")
require.True(t, siteURLAsBool, "should've returned ServiceSettings.SiteURL as true")
enableCustomEmoji, ok := serviceSettingsAsMap["EnableCustomEmoji"]
require.True(t, ok, "should've returned ServiceSettings.EnableCustomEmoji")
enableCustomEmojiAsBool, ok := enableCustomEmoji.(bool)
require.True(t, ok, "should've returned ServiceSettings.EnableCustomEmoji as a boolean")
require.True(t, enableCustomEmojiAsBool, "should've returned ServiceSettings.EnableCustomEmoji as true")
_, ok = envConfig["TeamSettings"]
require.False(t, ok, "should not have returned TeamSettings")
}) })
t.Run("as team admin", func(t *testing.T) { t.Run("as team admin", func(t *testing.T) {

Просмотреть файл

@@ -21,6 +21,8 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/gorilla/mux"
"io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
@@ -242,19 +244,16 @@ func (a *App) DoPostActionWithCookie(postId, actionId, userId, selectedOption st
// Perform an HTTP POST request to an integration's action endpoint. // Perform an HTTP POST request to an integration's action endpoint.
// Caller must consume and close returned http.Response as necessary. // Caller must consume and close returned http.Response as necessary.
// For internal requests, requests are routed directly to a plugin ServerHTTP hook
func (a *App) DoActionRequest(rawURL string, body []byte) (*http.Response, *model.AppError) { func (a *App) DoActionRequest(rawURL string, body []byte) (*http.Response, *model.AppError) {
inURL, err := url.Parse(rawURL) inURL, err := url.Parse(rawURL)
if err != nil { if err != nil {
return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, err.Error(), http.StatusBadRequest) return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, err.Error(), http.StatusBadRequest)
} }
siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL)
rawURLPath := path.Clean(rawURL) rawURLPath := path.Clean(rawURL)
if siteURL != nil && (strings.HasPrefix(rawURLPath, "/plugins/") || strings.HasPrefix(rawURLPath, "plugins/")) { if strings.HasPrefix(rawURLPath, "/plugins/") || strings.HasPrefix(rawURLPath, "plugins/") {
inURL.Scheme = siteURL.Scheme return a.DoLocalRequest(rawURLPath, body)
inURL.Host = siteURL.Host
inURL.Path = path.Join("/", siteURL.Path, rawURLPath)
rawURL = inURL.String()
} }
req, err := http.NewRequest("POST", rawURL, bytes.NewReader(body)) req, err := http.NewRequest("POST", rawURL, bytes.NewReader(body))
@@ -267,6 +266,7 @@ func (a *App) DoActionRequest(rawURL string, body []byte) (*http.Response, *mode
// Allow access to plugin routes for action buttons // Allow access to plugin routes for action buttons
var httpClient *http.Client var httpClient *http.Client
subpath, _ := utils.GetSubpathFromConfig(a.Config()) subpath, _ := utils.GetSubpathFromConfig(a.Config())
siteURL, _ := url.Parse(*a.Config().ServiceSettings.SiteURL)
if (inURL.Hostname() == "localhost" || inURL.Hostname() == "127.0.0.1" || inURL.Hostname() == siteURL.Hostname()) && strings.HasPrefix(inURL.Path, path.Join(subpath, "plugins")) { if (inURL.Hostname() == "localhost" || inURL.Hostname() == "127.0.0.1" || inURL.Hostname() == siteURL.Hostname()) && strings.HasPrefix(inURL.Path, path.Join(subpath, "plugins")) {
req.Header.Set(model.HEADER_AUTH, "Bearer "+a.Session.Token) req.Header.Set(model.HEADER_AUTH, "Bearer "+a.Session.Token)
httpClient = a.HTTPService.MakeClient(true) httpClient = a.HTTPService.MakeClient(true)
@@ -286,6 +286,74 @@ func (a *App) DoActionRequest(rawURL string, body []byte) (*http.Response, *mode
return resp, nil return resp, nil
} }
type LocalResponseWriter struct {
data []byte
headers http.Header
status int
}
func (w *LocalResponseWriter) Header() http.Header {
if w.headers == nil {
w.headers = make(http.Header)
}
return w.headers
}
func (w *LocalResponseWriter) Write(bytes []byte) (int, error) {
w.data = make([]byte, len(bytes))
copy(w.data, bytes)
return len(w.data), nil
}
func (w *LocalResponseWriter) WriteHeader(statusCode int) {
w.status = statusCode
}
func (a *App) DoLocalRequest(rawURL string, body []byte) (*http.Response, *model.AppError) {
rawURL = strings.TrimPrefix(rawURL, "/")
inURL, err := url.Parse(rawURL)
if err != nil {
return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, "err="+err.Error(), http.StatusBadRequest)
}
result := strings.Split(inURL.Path, "/")
if len(result) < 2 {
return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, "err=Unable to find pluginId", http.StatusBadRequest)
}
if result[0] != "plugins" {
return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, "err=plugins not in path", http.StatusBadRequest)
}
pluginId := result[1]
path := strings.TrimPrefix(inURL.Path, "plugins/"+pluginId)
w := &LocalResponseWriter{}
r, err := http.NewRequest("POST", path, bytes.NewReader(body))
if err != nil {
return nil, model.NewAppError("DoActionRequest", "api.post.do_action.action_integration.app_error", nil, "err="+err.Error(), http.StatusBadRequest)
}
r.Header.Set("Mattermost-User-Id", a.Session.UserId)
r.Header.Set(model.HEADER_AUTH, "Bearer "+a.Session.Token)
params := make(map[string]string)
params["plugin_id"] = pluginId
r = mux.SetURLVars(r, params)
a.ServePluginRequest(w, r)
resp := &http.Response{
StatusCode: w.status,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: w.headers,
Body: ioutil.NopCloser(bytes.NewReader(w.data)),
}
if resp.StatusCode == 0 {
resp.StatusCode = http.StatusOK
}
return resp, nil
}
func (a *App) OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError { func (a *App) OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError {
clientTriggerId, userId, err := request.DecodeAndVerifyTriggerId(a.AsymmetricSigningKey()) clientTriggerId, userId, err := request.DecodeAndVerifyTriggerId(a.AsymmetricSigningKey())
if err != nil { if err != nil {

Просмотреть файл

@@ -443,6 +443,37 @@ func TestSubmitInteractiveDialog(t *testing.T) {
})) }))
defer ts.Close() defer ts.Close()
setupPluginApiTest(t,
`
package main
import (
"net/http"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/model"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func (p *MyPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
response := &model.SubmitDialogResponse{
Errors: map[string]string{"name1": "some error"},
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write(response.ToJson())
}
func main() {
plugin.ClientMain(&MyPlugin{})
}
`, `{"id": "myplugin", "backend": {"executable": "backend.exe"}}`, "myplugin", th.App)
hooks, err2 := th.App.GetPluginsEnvironment().HooksForPlugin("myplugin")
require.Nil(t, err2)
require.NotNil(t, hooks)
submit.URL = ts.URL submit.URL = ts.URL
resp, err := th.App.SubmitInteractiveDialog(submit) resp, err := th.App.SubmitInteractiveDialog(submit)
@@ -601,7 +632,8 @@ func TestPostActionRelativeURL(t *testing.T) {
require.NotEmpty(t, attachments[0].Actions[0].Id) require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "") _, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err) require.NotNil(t, err)
}) })
t.Run("valid (but dirty) relative URL with SiteURL set", func(t *testing.T) { t.Run("valid (but dirty) relative URL with SiteURL set", func(t *testing.T) {
@@ -641,7 +673,7 @@ func TestPostActionRelativeURL(t *testing.T) {
require.NotEmpty(t, attachments[0].Actions[0].Id) require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "") _, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err) require.NotNil(t, err)
}) })
t.Run("valid relative URL with SiteURL set and no leading slash", func(t *testing.T) { t.Run("valid relative URL with SiteURL set and no leading slash", func(t *testing.T) {
@@ -680,6 +712,200 @@ func TestPostActionRelativeURL(t *testing.T) {
require.NotEmpty(t, attachments[0].Actions) require.NotEmpty(t, attachments[0].Actions)
require.NotEmpty(t, attachments[0].Actions[0].Id) require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.NotNil(t, err)
})
}
func TestPostActionRelativePluginURL(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
setupPluginApiTest(t,
`
package main
import (
"net/http"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/model"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func (p *MyPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
response := &model.PostActionIntegrationResponse{}
w.WriteHeader(http.StatusOK)
_, _ = w.Write(response.ToJson())
}
func main() {
plugin.ClientMain(&MyPlugin{})
}
`, `{"id": "myplugin", "backend": {"executable": "backend.exe"}}`, "myplugin", th.App)
hooks, err2 := th.App.GetPluginsEnvironment().HooksForPlugin("myplugin")
require.Nil(t, err2)
require.NotNil(t, hooks)
t.Run("invalid relative URL", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = ""
*cfg.ServiceSettings.SiteURL = ""
})
interactivePost := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
URL: "/notaplugin/some/path",
},
Name: "action",
Type: "some_type",
},
},
},
},
},
}
post, err := th.App.CreatePostAsUser(&interactivePost, "")
require.Nil(t, err)
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
require.NotEmpty(t, attachments[0].Actions)
require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.NotNil(t, err)
})
t.Run("valid relative URL", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = ""
*cfg.ServiceSettings.SiteURL = ""
})
interactivePost := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
URL: "/plugins/myplugin/myaction",
},
Name: "action",
Type: "some_type",
},
},
},
},
},
}
post, err := th.App.CreatePostAsUser(&interactivePost, "")
require.Nil(t, err)
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
require.NotEmpty(t, attachments[0].Actions)
require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err)
})
t.Run("valid (but dirty) relative URL", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = ""
*cfg.ServiceSettings.SiteURL = ""
})
interactivePost := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
URL: "//plugins/myplugin///myaction",
},
Name: "action",
Type: "some_type",
},
},
},
},
},
}
post, err := th.App.CreatePostAsUser(&interactivePost, "")
require.Nil(t, err)
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
require.NotEmpty(t, attachments[0].Actions)
require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err)
})
t.Run("valid relative URL and no leading slash", func(t *testing.T) {
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.AllowedUntrustedInternalConnections = ""
*cfg.ServiceSettings.SiteURL = ""
})
interactivePost := model.Post{
Message: "Interactive post",
ChannelId: th.BasicChannel.Id,
PendingPostId: model.NewId() + ":" + fmt.Sprint(model.GetMillis()),
UserId: th.BasicUser.Id,
Props: model.StringInterface{
"attachments": []*model.SlackAttachment{
{
Text: "hello",
Actions: []*model.PostAction{
{
Integration: &model.PostActionIntegration{
URL: "plugins/myplugin/myaction",
},
Name: "action",
Type: "some_type",
},
},
},
},
},
}
post, err := th.App.CreatePostAsUser(&interactivePost, "")
require.Nil(t, err)
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
require.True(t, ok)
require.NotEmpty(t, attachments[0].Actions)
require.NotEmpty(t, attachments[0].Actions[0].Id)
_, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "") _, err = th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
require.Nil(t, err) require.Nil(t, err)
}) })

Просмотреть файл

@@ -10,6 +10,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -825,3 +826,29 @@ func (api *PluginAPI) DeleteBotIconImage(userId string) *model.AppError {
return api.app.DeleteBotIconImage(userId) return api.app.DeleteBotIconImage(userId)
} }
func (api *PluginAPI) PluginHTTP(request *http.Request) *http.Response {
split := strings.SplitN(request.URL.Path, "/", 3)
if len(split) != 3 {
return &http.Response{
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(bytes.NewBufferString("Not enough URL. Form of URL should be /<pluginid>/*")),
}
}
destinationPluginId := split[1]
newURL, err := url.Parse("/" + split[2])
request.URL = newURL
if destinationPluginId == "" || err != nil {
message := "No plugin specified. Form of URL should be /<pluginid>/*"
if err != nil {
message = "Form of URL should be /<pluginid>/* Error: " + err.Error()
}
return &http.Response{
StatusCode: http.StatusBadRequest,
Body: ioutil.NopCloser(bytes.NewBufferString(message)),
}
}
responseTransfer := &PluginResponseWriter{}
api.app.ServeInterPluginRequest(responseTransfer, request, api.id, destinationPluginId)
return responseTransfer.GenerateResponse()
}

Просмотреть файл

@@ -26,7 +26,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string, pluginId string, app *App) string { func setupMultiPluginApiTest(t *testing.T, pluginCodes []string, pluginManifests []string, pluginIds []string, app *App) string {
pluginDir, err := ioutil.TempDir("", "") pluginDir, err := ioutil.TempDir("", "")
require.NoError(t, err) require.NoError(t, err)
webappPluginDir, err := ioutil.TempDir("", "") webappPluginDir, err := ioutil.TempDir("", "")
@@ -37,20 +37,29 @@ func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string,
env, err := plugin.NewEnvironment(app.NewPluginAPI, pluginDir, webappPluginDir, app.Log) env, err := plugin.NewEnvironment(app.NewPluginAPI, pluginDir, webappPluginDir, app.Log)
require.NoError(t, err) require.NoError(t, err)
backend := filepath.Join(pluginDir, pluginId, "backend.exe") require.Equal(t, len(pluginCodes), len(pluginIds))
utils.CompileGo(t, pluginCode, backend) require.Equal(t, len(pluginManifests), len(pluginIds))
ioutil.WriteFile(filepath.Join(pluginDir, pluginId, "plugin.json"), []byte(pluginManifest), 0600) for i, pluginId := range pluginIds {
manifest, activated, reterr := env.Activate(pluginId) backend := filepath.Join(pluginDir, pluginId, "backend.exe")
require.Nil(t, reterr) utils.CompileGo(t, pluginCodes[i], backend)
require.NotNil(t, manifest)
require.True(t, activated) ioutil.WriteFile(filepath.Join(pluginDir, pluginId, "plugin.json"), []byte(pluginManifests[i]), 0600)
manifest, activated, reterr := env.Activate(pluginId)
require.Nil(t, reterr)
require.NotNil(t, manifest)
require.True(t, activated)
}
app.SetPluginsEnvironment(env) app.SetPluginsEnvironment(env)
return pluginDir return pluginDir
} }
func setupPluginApiTest(t *testing.T, pluginCode string, pluginManifest string, pluginId string, app *App) string {
return setupMultiPluginApiTest(t, []string{pluginCode}, []string{pluginManifest}, []string{pluginId}, app)
}
func TestPublicFilesPathConfiguration(t *testing.T) { func TestPublicFilesPathConfiguration(t *testing.T) {
th := Setup(t).InitBasic() th := Setup(t).InitBasic()
defer th.TearDown() defer th.TearDown()
@@ -1462,3 +1471,98 @@ func TestPluginAddUserToChannel(t *testing.T) {
require.Equal(t, th.BasicChannel.Id, member.ChannelId) require.Equal(t, th.BasicChannel.Id, member.ChannelId)
require.Equal(t, th.BasicUser.Id, member.UserId) require.Equal(t, th.BasicUser.Id, member.UserId)
} }
func TestInterpluginPluginHTTP(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
setupMultiPluginApiTest(t,
[]string{`
package main
import (
"github.com/mattermost/mattermost-server/plugin"
"bytes"
"net/http"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func (p *MyPlugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/v2/test" {
return
}
buf := bytes.Buffer{}
buf.ReadFrom(r.Body)
resp := "we got:" + buf.String()
w.WriteHeader(598)
w.Write([]byte(resp))
}
func main() {
plugin.ClientMain(&MyPlugin{})
}
`,
`
package main
import (
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/model"
"bytes"
"net/http"
"io/ioutil"
)
type MyPlugin struct {
plugin.MattermostPlugin
}
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
buf := bytes.Buffer{}
buf.WriteString("This is the request")
req, err := http.NewRequest("GET", "/testplugininterserver/api/v2/test", &buf)
if err != nil {
return nil, err.Error()
}
req.Header.Add("Mattermost-User-Id", "userid")
resp := p.API.PluginHTTP(req)
if resp == nil {
return nil, "Nil resp"
}
if resp.Body == nil {
return nil, "Nil body"
}
respbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err.Error()
}
if resp.StatusCode != 598 {
return nil, "wrong status " + string(respbody)
}
return nil, string(respbody)
}
func main() {
plugin.ClientMain(&MyPlugin{})
}
`,
},
[]string{
`{"id": "testplugininterserver", "backend": {"executable": "backend.exe"}}`,
`{"id": "testplugininterclient", "backend": {"executable": "backend.exe"}}`,
},
[]string{
"testplugininterserver",
"testplugininterclient",
},
th.App,
)
hooks, err := th.App.GetPluginsEnvironment().HooksForPlugin("testplugininterclient")
require.NoError(t, err)
_, ret := hooks.MessageWillBePosted(nil, nil)
assert.Equal(t, "we got:This is the request", ret)
}

Просмотреть файл

@@ -42,6 +42,37 @@ func (a *App) ServePluginRequest(w http.ResponseWriter, r *http.Request) {
a.servePluginRequest(w, r, hooks.ServeHTTP) a.servePluginRequest(w, r, hooks.ServeHTTP)
} }
func (a *App) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string) {
pluginsEnvironment := a.GetPluginsEnvironment()
if pluginsEnvironment == nil {
err := model.NewAppError("ServeInterPluginRequest", "app.plugin.disabled.app_error", nil, "Plugin enviroment not found.", http.StatusNotImplemented)
a.Log.Error(err.Error())
w.WriteHeader(err.StatusCode)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(err.ToJson()))
return
}
hooks, err := pluginsEnvironment.HooksForPlugin(destinationPluginId)
if err != nil {
a.Log.Error("Access to route for non-existent plugin in inter plugin request",
mlog.String("sourse_plugin_id", sourcePluginId),
mlog.String("destination_plugin_id", destinationPluginId),
mlog.Err(err),
)
http.NotFound(w, r)
return
}
context := &plugin.Context{
RequestId: model.NewId(),
UserAgent: r.UserAgent(),
SourcePluginId: sourcePluginId,
}
hooks.ServeHTTP(context, w, r)
}
// ServePluginPublicRequest serves public plugin files // ServePluginPublicRequest serves public plugin files
// at the URL http(s)://$SITE_URL/plugins/$PLUGIN_ID/public/{anything} // at the URL http(s)://$SITE_URL/plugins/$PLUGIN_ID/public/{anything}
func (a *App) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request) { func (a *App) ServePluginPublicRequest(w http.ResponseWriter, r *http.Request) {

70
app/response_transfer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,70 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package app
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
)
type PluginResponseWriter struct {
bytes.Buffer
headers http.Header
statusCode int
}
func (rt *PluginResponseWriter) Header() http.Header {
if rt.headers == nil {
rt.headers = make(http.Header)
}
return rt.headers
}
func (rt *PluginResponseWriter) WriteHeader(statusCode int) {
rt.statusCode = statusCode
}
// From net/http/httptest/recorder.go
func parseContentLength(cl string) int64 {
cl = strings.TrimSpace(cl)
if cl == "" {
return -1
}
n, err := strconv.ParseInt(cl, 10, 64)
if err != nil {
return -1
}
return n
}
func (rt *PluginResponseWriter) GenerateResponse() *http.Response {
res := &http.Response{
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
StatusCode: rt.statusCode,
Header: rt.headers.Clone(),
}
if res.StatusCode == 0 {
res.StatusCode = http.StatusOK
}
res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode))
if rt.Len() > 0 {
res.Body = ioutil.NopCloser(rt)
} else {
res.Body = http.NoBody
}
res.ContentLength = parseContentLength(rt.headers.Get("Content-Length"))
return res
}

Просмотреть файл

@@ -61,7 +61,7 @@ func (s *Server) RunOldAppInitalization() error {
if s.FakeApp().Srv.newStore == nil { if s.FakeApp().Srv.newStore == nil {
s.FakeApp().Srv.newStore = func() store.Store { s.FakeApp().Srv.newStore = func() store.Store {
return store.NewTimerLayer(localcachelayer.NewLocalCacheLayer(store.NewLayeredStore(sqlstore.NewSqlSupplier(s.FakeApp().Config().SqlSettings, s.Metrics), s.Metrics, s.Cluster), s.Metrics, s.Cluster), s.Metrics) return store.NewTimerLayer(localcachelayer.NewLocalCacheLayer(sqlstore.NewSqlSupplier(s.FakeApp().Config().SqlSettings, s.Metrics), s.Metrics, s.Cluster), s.Metrics)
} }
} }

Просмотреть файл

@@ -4,8 +4,6 @@
package app package app
import ( import (
"fmt"
"github.com/mattermost/mattermost-server/mlog" "github.com/mattermost/mattermost-server/mlog"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/utils" "github.com/mattermost/mattermost-server/utils"
@@ -215,11 +213,11 @@ func (a *App) SetStatusOnline(userId string, manual bool) {
if status.Status != oldStatus || status.Manual != oldManual || status.LastActivityAt-oldTime > model.STATUS_MIN_UPDATE_TIME { if status.Status != oldStatus || status.Manual != oldManual || status.LastActivityAt-oldTime > model.STATUS_MIN_UPDATE_TIME {
if broadcast { if broadcast {
if err := a.Srv.Store.Status().SaveOrUpdate(status); err != nil { if err := a.Srv.Store.Status().SaveOrUpdate(status); err != nil {
mlog.Error(fmt.Sprintf("Failed to save status for user_id=%v, err=%v", userId, err), mlog.String("user_id", userId)) mlog.Error("Failed to save status", mlog.String("user_id", userId), mlog.Err(err), mlog.String("user_id", userId))
} }
} else { } else {
if err := a.Srv.Store.Status().UpdateLastActivityAt(status.UserId, status.LastActivityAt); err != nil { if err := a.Srv.Store.Status().UpdateLastActivityAt(status.UserId, status.LastActivityAt); err != nil {
mlog.Error(fmt.Sprintf("Failed to save status for user_id=%v, err=%v", userId, err), mlog.String("user_id", userId)) mlog.Error("Failed to save status", mlog.String("user_id", userId), mlog.Err(err), mlog.String("user_id", userId))
} }
} }
} }
@@ -304,7 +302,7 @@ func (a *App) SaveAndBroadcastStatus(status *model.Status) {
a.AddStatusCache(status) a.AddStatusCache(status)
if err := a.Srv.Store.Status().SaveOrUpdate(status); err != nil { if err := a.Srv.Store.Status().SaveOrUpdate(status); err != nil {
mlog.Error(fmt.Sprintf("Failed to save status for user_id=%v, err=%v", status.UserId, err)) mlog.Error("Failed to save status", mlog.String("user_id", status.UserId), mlog.Err(err))
} }
a.BroadcastStatus(status) a.BroadcastStatus(status)

Просмотреть файл

@@ -91,6 +91,9 @@ type PluginSettingsSchema struct {
// "id": "com.mycompany.myplugin", // "id": "com.mycompany.myplugin",
// "name": "My Plugin", // "name": "My Plugin",
// "description": "This is my plugin", // "description": "This is my plugin",
// "homepage_url": "https://example.com",
// "support_url": "https://example.com/support",
// "icon_path": "assets/logo.svg",
// "version": "0.1.0", // "version": "0.1.0",
// "min_server_version": "5.6.0", // "min_server_version": "5.6.0",
// "server": { // "server": {

Просмотреть файл

@@ -5,6 +5,7 @@ package plugin
import ( import (
"io" "io"
"net/http"
plugin "github.com/hashicorp/go-plugin" plugin "github.com/hashicorp/go-plugin"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/model"
@@ -19,17 +20,20 @@ type API interface {
// LoadPluginConfiguration loads the plugin's configuration. dest should be a pointer to a // LoadPluginConfiguration loads the plugin's configuration. dest should be a pointer to a
// struct that the configuration JSON can be unmarshalled to. // struct that the configuration JSON can be unmarshalled to.
// //
// @tag Plugin
// Minimum server version: 5.2 // Minimum server version: 5.2
LoadPluginConfiguration(dest interface{}) error LoadPluginConfiguration(dest interface{}) error
// RegisterCommand registers a custom slash command. When the command is triggered, your plugin // RegisterCommand registers a custom slash command. When the command is triggered, your plugin
// can fulfill it via the ExecuteCommand hook. // can fulfill it via the ExecuteCommand hook.
// //
// @tag Command
// Minimum server version: 5.2 // Minimum server version: 5.2
RegisterCommand(command *model.Command) error RegisterCommand(command *model.Command) error
// UnregisterCommand unregisters a command previously registered via RegisterCommand. // UnregisterCommand unregisters a command previously registered via RegisterCommand.
// //
// @tag Command
// Minimum server version: 5.2 // Minimum server version: 5.2
UnregisterCommand(teamId, trigger string) error UnregisterCommand(teamId, trigger string) error
@@ -40,139 +44,168 @@ type API interface {
// GetConfig fetches the currently persisted config // GetConfig fetches the currently persisted config
// //
// @tag Configuration
// Minimum server version: 5.2 // Minimum server version: 5.2
GetConfig() *model.Config GetConfig() *model.Config
// GetUnsanitizedConfig fetches the currently persisted config without removing secrets. // GetUnsanitizedConfig fetches the currently persisted config without removing secrets.
// //
// @tag Configuration
// Minimum server version: 5.16 // Minimum server version: 5.16
GetUnsanitizedConfig() *model.Config GetUnsanitizedConfig() *model.Config
// SaveConfig sets the given config and persists the changes // SaveConfig sets the given config and persists the changes
// //
// @tag Configuration
// Minimum server version: 5.2 // Minimum server version: 5.2
SaveConfig(config *model.Config) *model.AppError SaveConfig(config *model.Config) *model.AppError
// GetPluginConfig fetches the currently persisted config of plugin // GetPluginConfig fetches the currently persisted config of plugin
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPluginConfig() map[string]interface{} GetPluginConfig() map[string]interface{}
// SavePluginConfig sets the given config for plugin and persists the changes // SavePluginConfig sets the given config for plugin and persists the changes
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
SavePluginConfig(config map[string]interface{}) *model.AppError SavePluginConfig(config map[string]interface{}) *model.AppError
// GetBundlePath returns the absolute path where the plugin's bundle was unpacked. // GetBundlePath returns the absolute path where the plugin's bundle was unpacked.
// //
// @tag Plugin
// Minimum server version: 5.10 // Minimum server version: 5.10
GetBundlePath() (string, error) GetBundlePath() (string, error)
// GetLicense returns the current license used by the Mattermost server. Returns nil if the // GetLicense returns the current license used by the Mattermost server. Returns nil if the
// the server does not have a license. // the server does not have a license.
// //
// @tag Server
// Minimum server version: 5.10 // Minimum server version: 5.10
GetLicense() *model.License GetLicense() *model.License
// GetServerVersion return the current Mattermost server version // GetServerVersion return the current Mattermost server version
// //
// @tag Server
// Minimum server version: 5.4 // Minimum server version: 5.4
GetServerVersion() string GetServerVersion() string
// GetSystemInstallDate returns the time that Mattermost was first installed and ran. // GetSystemInstallDate returns the time that Mattermost was first installed and ran.
// //
// @tag Server
// Minimum server version: 5.10 // Minimum server version: 5.10
GetSystemInstallDate() (int64, *model.AppError) GetSystemInstallDate() (int64, *model.AppError)
// GetDiagnosticId returns a unique identifier used by the server for diagnostic reports. // GetDiagnosticId returns a unique identifier used by the server for diagnostic reports.
// //
// @tag Server
// Minimum server version: 5.10 // Minimum server version: 5.10
GetDiagnosticId() string GetDiagnosticId() string
// CreateUser creates a user. // CreateUser creates a user.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
CreateUser(user *model.User) (*model.User, *model.AppError) CreateUser(user *model.User) (*model.User, *model.AppError)
// DeleteUser deletes a user. // DeleteUser deletes a user.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteUser(userId string) *model.AppError DeleteUser(userId string) *model.AppError
// GetUsers a list of users based on search options. // GetUsers a list of users based on search options.
// //
// @tag User
// Minimum server version: 5.10 // Minimum server version: 5.10
GetUsers(options *model.UserGetOptions) ([]*model.User, *model.AppError) GetUsers(options *model.UserGetOptions) ([]*model.User, *model.AppError)
// GetUser gets a user. // GetUser gets a user.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetUser(userId string) (*model.User, *model.AppError) GetUser(userId string) (*model.User, *model.AppError)
// GetUserByEmail gets a user by their email address. // GetUserByEmail gets a user by their email address.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetUserByEmail(email string) (*model.User, *model.AppError) GetUserByEmail(email string) (*model.User, *model.AppError)
// GetUserByUsername gets a user by their username. // GetUserByUsername gets a user by their username.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetUserByUsername(name string) (*model.User, *model.AppError) GetUserByUsername(name string) (*model.User, *model.AppError)
// GetUsersByUsernames gets users by their usernames. // GetUsersByUsernames gets users by their usernames.
// //
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetUsersByUsernames(usernames []string) ([]*model.User, *model.AppError) GetUsersByUsernames(usernames []string) ([]*model.User, *model.AppError)
// GetUsersInTeam gets users in team. // GetUsersInTeam gets users in team.
// //
// @tag User
// @tag Team
// Minimum server version: 5.6 // Minimum server version: 5.6
GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError) GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError)
// GetTeamIcon gets the team icon. // GetTeamIcon gets the team icon.
// //
// @tag Team
// Minimum server version: 5.6 // Minimum server version: 5.6
GetTeamIcon(teamId string) ([]byte, *model.AppError) GetTeamIcon(teamId string) ([]byte, *model.AppError)
// SetTeamIcon sets the team icon. // SetTeamIcon sets the team icon.
// //
// @tag Team
// Minimum server version: 5.6 // Minimum server version: 5.6
SetTeamIcon(teamId string, data []byte) *model.AppError SetTeamIcon(teamId string, data []byte) *model.AppError
// RemoveTeamIcon removes the team icon. // RemoveTeamIcon removes the team icon.
// //
// @tag Team
// Minimum server version: 5.6 // Minimum server version: 5.6
RemoveTeamIcon(teamId string) *model.AppError RemoveTeamIcon(teamId string) *model.AppError
// UpdateUser updates a user. // UpdateUser updates a user.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateUser(user *model.User) (*model.User, *model.AppError) UpdateUser(user *model.User) (*model.User, *model.AppError)
// GetUserStatus will get a user's status. // GetUserStatus will get a user's status.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetUserStatus(userId string) (*model.Status, *model.AppError) GetUserStatus(userId string) (*model.Status, *model.AppError)
// GetUserStatusesByIds will return a list of user statuses based on the provided slice of user IDs. // GetUserStatusesByIds will return a list of user statuses based on the provided slice of user IDs.
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetUserStatusesByIds(userIds []string) ([]*model.Status, *model.AppError) GetUserStatusesByIds(userIds []string) ([]*model.Status, *model.AppError)
// UpdateUserStatus will set a user's status until the user, or another integration/plugin, sets it back to online. // UpdateUserStatus will set a user's status until the user, or another integration/plugin, sets it back to online.
// The status parameter can be: "online", "away", "dnd", or "offline". // The status parameter can be: "online", "away", "dnd", or "offline".
// //
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateUserStatus(userId, status string) (*model.Status, *model.AppError) UpdateUserStatus(userId, status string) (*model.Status, *model.AppError)
// UpdateUserActive deactivates or reactivates an user. // UpdateUserActive deactivates or reactivates an user.
// //
// @tag User
// Minimum server version: 5.8 // Minimum server version: 5.8
UpdateUserActive(userId string, active bool) *model.AppError UpdateUserActive(userId string, active bool) *model.AppError
// GetUsersInChannel returns a page of users in a channel. Page counting starts at 0. // GetUsersInChannel returns a page of users in a channel. Page counting starts at 0.
// The sortBy parameter can be: "username" or "status". // The sortBy parameter can be: "username" or "status".
// //
// @tag User
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetUsersInChannel(channelId, sortBy string, page, perPage int) ([]*model.User, *model.AppError) GetUsersInChannel(channelId, sortBy string, page, perPage int) ([]*model.User, *model.AppError)
@@ -181,312 +214,403 @@ type API interface {
// Returns a map with attribute names as keys and the user's attributes as values. // Returns a map with attribute names as keys and the user's attributes as values.
// Requires an enterprise license, LDAP to be configured and for the user to use LDAP as an authentication method. // Requires an enterprise license, LDAP to be configured and for the user to use LDAP as an authentication method.
// //
// @tag User
// Minimum server version: 5.3 // Minimum server version: 5.3
GetLDAPUserAttributes(userId string, attributes []string) (map[string]string, *model.AppError) GetLDAPUserAttributes(userId string, attributes []string) (map[string]string, *model.AppError)
// CreateTeam creates a team. // CreateTeam creates a team.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
CreateTeam(team *model.Team) (*model.Team, *model.AppError) CreateTeam(team *model.Team) (*model.Team, *model.AppError)
// DeleteTeam deletes a team. // DeleteTeam deletes a team.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteTeam(teamId string) *model.AppError DeleteTeam(teamId string) *model.AppError
// GetTeam gets all teams. // GetTeam gets all teams.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
GetTeams() ([]*model.Team, *model.AppError) GetTeams() ([]*model.Team, *model.AppError)
// GetTeam gets a team. // GetTeam gets a team.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
GetTeam(teamId string) (*model.Team, *model.AppError) GetTeam(teamId string) (*model.Team, *model.AppError)
// GetTeamByName gets a team by its name. // GetTeamByName gets a team by its name.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
GetTeamByName(name string) (*model.Team, *model.AppError) GetTeamByName(name string) (*model.Team, *model.AppError)
// GetTeamsUnreadForUser gets the unread message and mention counts for each team to which the given user belongs. // GetTeamsUnreadForUser gets the unread message and mention counts for each team to which the given user belongs.
// //
// @tag Team
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetTeamsUnreadForUser(userId string) ([]*model.TeamUnread, *model.AppError) GetTeamsUnreadForUser(userId string) ([]*model.TeamUnread, *model.AppError)
// UpdateTeam updates a team. // UpdateTeam updates a team.
// //
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateTeam(team *model.Team) (*model.Team, *model.AppError) UpdateTeam(team *model.Team) (*model.Team, *model.AppError)
// SearchTeams search a team. // SearchTeams search a team.
// //
// @tag Team
// Minimum server version: 5.8 // Minimum server version: 5.8
SearchTeams(term string) ([]*model.Team, *model.AppError) SearchTeams(term string) ([]*model.Team, *model.AppError)
// GetTeamsForUser returns list of teams of given user ID. // GetTeamsForUser returns list of teams of given user ID.
// //
// @tag Team
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetTeamsForUser(userId string) ([]*model.Team, *model.AppError) GetTeamsForUser(userId string) ([]*model.Team, *model.AppError)
// CreateTeamMember creates a team membership. // CreateTeamMember creates a team membership.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
CreateTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) CreateTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError)
// CreateTeamMember creates a team membership for all provided user ids. // CreateTeamMembers creates a team membership for all provided user ids.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError) CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError)
// DeleteTeamMember deletes a team membership. // DeleteTeamMember deletes a team membership.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteTeamMember(teamId, userId, requestorId string) *model.AppError DeleteTeamMember(teamId, userId, requestorId string) *model.AppError
// GetTeamMembers returns the memberships of a specific team. // GetTeamMembers returns the memberships of a specific team.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetTeamMembers(teamId string, page, perPage int) ([]*model.TeamMember, *model.AppError) GetTeamMembers(teamId string, page, perPage int) ([]*model.TeamMember, *model.AppError)
// GetTeamMember returns a specific membership. // GetTeamMember returns a specific membership.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError)
// GetTeamMembersForUser returns all team memberships for a user. // GetTeamMembersForUser returns all team memberships for a user.
// //
// @tag Team
// @tag User
// Minimum server version: 5.10 // Minimum server version: 5.10
GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError) GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError)
// UpdateTeamMemberRoles updates the role for a team membership. // UpdateTeamMemberRoles updates the role for a team membership.
// //
// @tag Team
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateTeamMemberRoles(teamId, userId, newRoles string) (*model.TeamMember, *model.AppError) UpdateTeamMemberRoles(teamId, userId, newRoles string) (*model.TeamMember, *model.AppError)
// CreateChannel creates a channel. // CreateChannel creates a channel.
// //
// @tag Channel
// Minimum server version: 5.2 // Minimum server version: 5.2
CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError)
// DeleteChannel deletes a channel. // DeleteChannel deletes a channel.
// //
// @tag Channel
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteChannel(channelId string) *model.AppError DeleteChannel(channelId string) *model.AppError
// GetPublicChannelsForTeam gets a list of all channels. // GetPublicChannelsForTeam gets a list of all channels.
// //
// @tag Channel
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
GetPublicChannelsForTeam(teamId string, page, perPage int) ([]*model.Channel, *model.AppError) GetPublicChannelsForTeam(teamId string, page, perPage int) ([]*model.Channel, *model.AppError)
// GetChannel gets a channel. // GetChannel gets a channel.
// //
// @tag Channel
// Minimum server version: 5.2 // Minimum server version: 5.2
GetChannel(channelId string) (*model.Channel, *model.AppError) GetChannel(channelId string) (*model.Channel, *model.AppError)
// GetChannelByName gets a channel by its name, given a team id. // GetChannelByName gets a channel by its name, given a team id.
// //
// @tag Channel
// Minimum server version: 5.2 // Minimum server version: 5.2
GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError) GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError)
// GetChannelByNameForTeamName gets a channel by its name, given a team name. // GetChannelByNameForTeamName gets a channel by its name, given a team name.
// //
// @tag Channel
// @tag Team
// Minimum server version: 5.2 // Minimum server version: 5.2
GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError) GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError)
// GetChannelsForTeamForUser gets a list of channels for given user ID in given team ID. // GetChannelsForTeamForUser gets a list of channels for given user ID in given team ID.
// //
// @tag Channel
// @tag Team
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError)
// GetChannelStats gets statistics for a channel. // GetChannelStats gets statistics for a channel.
// //
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetChannelStats(channelId string) (*model.ChannelStats, *model.AppError) GetChannelStats(channelId string) (*model.ChannelStats, *model.AppError)
// GetDirectChannel gets a direct message channel. // GetDirectChannel gets a direct message channel.
// If the channel does not exist it will create it. // If the channel does not exist it will create it.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError) GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError)
// GetGroupChannel gets a group message channel. // GetGroupChannel gets a group message channel.
// If the channel does not exist it will create it. // If the channel does not exist it will create it.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError)
// UpdateChannel updates a channel. // UpdateChannel updates a channel.
// //
// @tag Channel
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError)
// SearchChannels returns the channels on a team matching the provided search term. // SearchChannels returns the channels on a team matching the provided search term.
// //
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError)
// SearchUsers returns a list of users based on some search criteria. // SearchUsers returns a list of users based on some search criteria.
// //
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
SearchUsers(search *model.UserSearch) ([]*model.User, *model.AppError) SearchUsers(search *model.UserSearch) ([]*model.User, *model.AppError)
// SearchPostsInTeam returns a list of posts in a specific team that match the given params. // SearchPostsInTeam returns a list of posts in a specific team that match the given params.
// //
// @tag Post
// @tag Team
// Minimum server version: 5.10 // Minimum server version: 5.10
SearchPostsInTeam(teamId string, paramsList []*model.SearchParams) ([]*model.Post, *model.AppError) SearchPostsInTeam(teamId string, paramsList []*model.SearchParams) ([]*model.Post, *model.AppError)
// AddChannelMember joins a user to a channel (as if they joined themselves) // AddChannelMember joins a user to a channel (as if they joined themselves)
// This means the user will not receive notifications for joining the channel. // This means the user will not receive notifications for joining the channel.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError)
// AddUserToChannel adds a user to a channel as if the specified user had invited them. // AddUserToChannel adds a user to a channel as if the specified user had invited them.
// This means the user will receive the regular notifications for being added to the channel. // This means the user will receive the regular notifications for being added to the channel.
// //
// @tag User
// @tag Channel
// Minimum server version: 5.18 // Minimum server version: 5.18
AddUserToChannel(channelId, userId, asUserId string) (*model.ChannelMember, *model.AppError) AddUserToChannel(channelId, userId, asUserId string) (*model.ChannelMember, *model.AppError)
// GetChannelMember gets a channel membership for a user. // GetChannelMember gets a channel membership for a user.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError)
// GetChannelMembers gets a channel membership for all users. // GetChannelMembers gets a channel membership for all users.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetChannelMembers(channelId string, page, perPage int) (*model.ChannelMembers, *model.AppError) GetChannelMembers(channelId string, page, perPage int) (*model.ChannelMembers, *model.AppError)
// GetChannelMembersByIds gets a channel membership for a particular User // GetChannelMembersByIds gets a channel membership for a particular User
// //
// @tag Channel
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetChannelMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError) GetChannelMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError)
// GetChannelMembersForUser returns all channel memberships on a team for a user. // GetChannelMembersForUser returns all channel memberships on a team for a user.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.10 // Minimum server version: 5.10
GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError) GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError)
// UpdateChannelMemberRoles updates a user's roles for a channel. // UpdateChannelMemberRoles updates a user's roles for a channel.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError)
// UpdateChannelMemberNotifications updates a user's notification properties for a channel. // UpdateChannelMemberNotifications updates a user's notification properties for a channel.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError)
// GetGroup gets a group by ID. // GetGroup gets a group by ID.
// //
// @tag Group
// Minimum server version: 5.18 // Minimum server version: 5.18
GetGroup(groupId string) (*model.Group, *model.AppError) GetGroup(groupId string) (*model.Group, *model.AppError)
// GetGroupByName gets a group by name. // GetGroupByName gets a group by name.
// //
// @tag Group
// Minimum server version: 5.18 // Minimum server version: 5.18
GetGroupByName(name string) (*model.Group, *model.AppError) GetGroupByName(name string) (*model.Group, *model.AppError)
// GetGroupsForUser gets the groups a user is in. // GetGroupsForUser gets the groups a user is in.
// //
// @tag Group
// @tag User
// Minimum server version: 5.18 // Minimum server version: 5.18
GetGroupsForUser(userId string) ([]*model.Group, *model.AppError) GetGroupsForUser(userId string) ([]*model.Group, *model.AppError)
// DeleteChannelMember deletes a channel membership for a user. // DeleteChannelMember deletes a channel membership for a user.
// //
// @tag Channel
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteChannelMember(channelId, userId string) *model.AppError DeleteChannelMember(channelId, userId string) *model.AppError
// CreatePost creates a post. // CreatePost creates a post.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
CreatePost(post *model.Post) (*model.Post, *model.AppError) CreatePost(post *model.Post) (*model.Post, *model.AppError)
// AddReaction add a reaction to a post. // AddReaction add a reaction to a post.
// //
// @tag Post
// Minimum server version: 5.3 // Minimum server version: 5.3
AddReaction(reaction *model.Reaction) (*model.Reaction, *model.AppError) AddReaction(reaction *model.Reaction) (*model.Reaction, *model.AppError)
// RemoveReaction remove a reaction from a post. // RemoveReaction remove a reaction from a post.
// //
// @tag Post
// Minimum server version: 5.3 // Minimum server version: 5.3
RemoveReaction(reaction *model.Reaction) *model.AppError RemoveReaction(reaction *model.Reaction) *model.AppError
// GetReaction get the reactions of a post. // GetReaction get the reactions of a post.
// //
// @tag Post
// Minimum server version: 5.3 // Minimum server version: 5.3
GetReactions(postId string) ([]*model.Reaction, *model.AppError) GetReactions(postId string) ([]*model.Reaction, *model.AppError)
// SendEphemeralPost creates an ephemeral post. // SendEphemeralPost creates an ephemeral post.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
SendEphemeralPost(userId string, post *model.Post) *model.Post SendEphemeralPost(userId string, post *model.Post) *model.Post
// UpdateEphemeralPost updates an ephemeral message previously sent to the user. // UpdateEphemeralPost updates an ephemeral message previously sent to the user.
// EXPERIMENTAL: This API is experimental and can be changed without advance notice. // EXPERIMENTAL: This API is experimental and can be changed without advance notice.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdateEphemeralPost(userId string, post *model.Post) *model.Post UpdateEphemeralPost(userId string, post *model.Post) *model.Post
// DeleteEphemeralPost deletes an ephemeral message previously sent to the user. // DeleteEphemeralPost deletes an ephemeral message previously sent to the user.
// EXPERIMENTAL: This API is experimental and can be changed without advance notice. // EXPERIMENTAL: This API is experimental and can be changed without advance notice.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
DeleteEphemeralPost(userId, postId string) DeleteEphemeralPost(userId, postId string)
// DeletePost deletes a post. // DeletePost deletes a post.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
DeletePost(postId string) *model.AppError DeletePost(postId string) *model.AppError
// GetPostThread gets a post with all the other posts in the same thread. // GetPostThread gets a post with all the other posts in the same thread.
// //
// @tag Post
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPostThread(postId string) (*model.PostList, *model.AppError) GetPostThread(postId string) (*model.PostList, *model.AppError)
// GetPost gets a post. // GetPost gets a post.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
GetPost(postId string) (*model.Post, *model.AppError) GetPost(postId string) (*model.Post, *model.AppError)
// GetPostsSince gets posts created after a specified time as Unix time in milliseconds. // GetPostsSince gets posts created after a specified time as Unix time in milliseconds.
// //
// @tag Post
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPostsSince(channelId string, time int64) (*model.PostList, *model.AppError) GetPostsSince(channelId string, time int64) (*model.PostList, *model.AppError)
// GetPostsAfter gets a page of posts that were posted after the post provided. // GetPostsAfter gets a page of posts that were posted after the post provided.
// //
// @tag Post
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPostsAfter(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) GetPostsAfter(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError)
// GetPostsBefore gets a page of posts that were posted before the post provided. // GetPostsBefore gets a page of posts that were posted before the post provided.
// //
// @tag Post
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPostsBefore(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) GetPostsBefore(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError)
// GetPostsForChannel gets a list of posts for a channel. // GetPostsForChannel gets a list of posts for a channel.
// //
// @tag Post
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPostsForChannel(channelId string, page, perPage int) (*model.PostList, *model.AppError) GetPostsForChannel(channelId string, page, perPage int) (*model.PostList, *model.AppError)
// GetTeamStats gets a team's statistics // GetTeamStats gets a team's statistics
// //
// @tag Team
// Minimum server version: 5.8 // Minimum server version: 5.8
GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) GetTeamStats(teamId string) (*model.TeamStats, *model.AppError)
// UpdatePost updates a post. // UpdatePost updates a post.
// //
// @tag Post
// Minimum server version: 5.2 // Minimum server version: 5.2
UpdatePost(post *model.Post) (*model.Post, *model.AppError) UpdatePost(post *model.Post) (*model.Post, *model.AppError)
// GetProfileImage gets user's profile image. // GetProfileImage gets user's profile image.
// //
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
GetProfileImage(userId string) ([]byte, *model.AppError) GetProfileImage(userId string) ([]byte, *model.AppError)
// SetProfileImage sets a user's profile image. // SetProfileImage sets a user's profile image.
// //
// @tag User
// Minimum server version: 5.6 // Minimum server version: 5.6
SetProfileImage(userId string, data []byte) *model.AppError SetProfileImage(userId string, data []byte) *model.AppError
@@ -494,16 +618,19 @@ type API interface {
// //
// The sortBy parameter can be: "name". // The sortBy parameter can be: "name".
// //
// @tag Emoji
// Minimum server version: 5.6 // Minimum server version: 5.6
GetEmojiList(sortBy string, page, perPage int) ([]*model.Emoji, *model.AppError) GetEmojiList(sortBy string, page, perPage int) ([]*model.Emoji, *model.AppError)
// GetEmojiByName gets an emoji by it's name. // GetEmojiByName gets an emoji by it's name.
// //
// @tag Emoji
// Minimum server version: 5.6 // Minimum server version: 5.6
GetEmojiByName(name string) (*model.Emoji, *model.AppError) GetEmojiByName(name string) (*model.Emoji, *model.AppError)
// GetEmoji returns a custom emoji based on the emojiId string. // GetEmoji returns a custom emoji based on the emojiId string.
// //
// @tag Emoji
// Minimum server version: 5.6 // Minimum server version: 5.6
GetEmoji(emojiId string) (*model.Emoji, *model.AppError) GetEmoji(emojiId string) (*model.Emoji, *model.AppError)
@@ -514,36 +641,45 @@ type API interface {
// to CreatePost. Use this API to duplicate a post and its file attachments without // to CreatePost. Use this API to duplicate a post and its file attachments without
// actually duplicating the uploaded files. // actually duplicating the uploaded files.
// //
// @tag File
// @tag User
// Minimum server version: 5.2 // Minimum server version: 5.2
CopyFileInfos(userId string, fileIds []string) ([]string, *model.AppError) CopyFileInfos(userId string, fileIds []string) ([]string, *model.AppError)
// GetFileInfo gets a File Info for a specific fileId // GetFileInfo gets a File Info for a specific fileId
// //
// @tag File
// Minimum server version: 5.3 // Minimum server version: 5.3
GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) GetFileInfo(fileId string) (*model.FileInfo, *model.AppError)
// GetFile gets content of a file by it's ID // GetFile gets content of a file by it's ID
// //
// @tag File
// Minimum server version: 5.8 // Minimum server version: 5.8
GetFile(fileId string) ([]byte, *model.AppError) GetFile(fileId string) ([]byte, *model.AppError)
// GetFileLink gets the public link to a file by fileId. // GetFileLink gets the public link to a file by fileId.
// //
// @tag File
// Minimum server version: 5.6 // Minimum server version: 5.6
GetFileLink(fileId string) (string, *model.AppError) GetFileLink(fileId string) (string, *model.AppError)
// ReadFileAtPath reads the file from the backend for a specific path // ReadFileAtPath reads the file from the backend for a specific path
// //
// @tag File
// Minimum server version: 5.3 // Minimum server version: 5.3
ReadFile(path string) ([]byte, *model.AppError) ReadFile(path string) ([]byte, *model.AppError)
// GetEmojiImage returns the emoji image. // GetEmojiImage returns the emoji image.
// //
// @tag Emoji
// Minimum server version: 5.6 // Minimum server version: 5.6
GetEmojiImage(emojiId string) ([]byte, string, *model.AppError) GetEmojiImage(emojiId string) ([]byte, string, *model.AppError)
// UploadFile will upload a file to a channel using a multipart request, to be later attached to a post. // UploadFile will upload a file to a channel using a multipart request, to be later attached to a post.
// //
// @tag File
// @tag Channel
// Minimum server version: 5.6 // Minimum server version: 5.6
UploadFile(data []byte, channelId string, filename string) (*model.FileInfo, *model.AppError) UploadFile(data []byte, channelId string, filename string) (*model.FileInfo, *model.AppError)
@@ -558,32 +694,38 @@ type API interface {
// GetPlugins will return a list of plugin manifests for currently active plugins. // GetPlugins will return a list of plugin manifests for currently active plugins.
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPlugins() ([]*model.Manifest, *model.AppError) GetPlugins() ([]*model.Manifest, *model.AppError)
// EnablePlugin will enable an plugin installed. // EnablePlugin will enable an plugin installed.
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
EnablePlugin(id string) *model.AppError EnablePlugin(id string) *model.AppError
// DisablePlugin will disable an enabled plugin. // DisablePlugin will disable an enabled plugin.
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
DisablePlugin(id string) *model.AppError DisablePlugin(id string) *model.AppError
// RemovePlugin will disable and delete a plugin. // RemovePlugin will disable and delete a plugin.
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
RemovePlugin(id string) *model.AppError RemovePlugin(id string) *model.AppError
// GetPluginStatus will return the status of a plugin. // GetPluginStatus will return the status of a plugin.
// //
// @tag Plugin
// Minimum server version: 5.6 // Minimum server version: 5.6
GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError)
// InstallPlugin will upload another plugin with tar.gz file. // InstallPlugin will upload another plugin with tar.gz file.
// Previous version will be replaced on replace true. // Previous version will be replaced on replace true.
// //
// @tag Plugin
// Minimum server version: 5.18 // Minimum server version: 5.18
InstallPlugin(file io.Reader, replace bool) (*model.Manifest, *model.AppError) InstallPlugin(file io.Reader, replace bool) (*model.Manifest, *model.AppError)
@@ -592,6 +734,7 @@ type API interface {
// KVSet stores a key-value pair, unique per plugin. // KVSet stores a key-value pair, unique per plugin.
// Provided helper functions and internal plugin code will use the prefix `mmi_` before keys. Do not use this prefix. // Provided helper functions and internal plugin code will use the prefix `mmi_` before keys. Do not use this prefix.
// //
// @tag KeyValueStore
// Minimum server version: 5.2 // Minimum server version: 5.2
KVSet(key string, value []byte) *model.AppError KVSet(key string, value []byte) *model.AppError
@@ -601,6 +744,7 @@ type API interface {
// Returns (false, nil) if current value != oldValue or key already exists when inserting // Returns (false, nil) if current value != oldValue or key already exists when inserting
// Returns (true, nil) if current value == oldValue or new key is inserted // Returns (true, nil) if current value == oldValue or new key is inserted
// //
// @tag KeyValueStore
// Minimum server version: 5.12 // Minimum server version: 5.12
KVCompareAndSet(key string, oldValue, newValue []byte) (bool, *model.AppError) KVCompareAndSet(key string, oldValue, newValue []byte) (bool, *model.AppError)
@@ -609,6 +753,7 @@ type API interface {
// Returns (false, nil) if current value != oldValue or key does not exist when deleting // Returns (false, nil) if current value != oldValue or key does not exist when deleting
// Returns (true, nil) if current value == oldValue and the key was deleted // Returns (true, nil) if current value == oldValue and the key was deleted
// //
// @tag KeyValueStore
// Minimum server version: 5.16 // Minimum server version: 5.16
KVCompareAndDelete(key string, oldValue []byte) (bool, *model.AppError) KVCompareAndDelete(key string, oldValue []byte) (bool, *model.AppError)
@@ -623,26 +768,31 @@ type API interface {
// KVSet stores a key-value pair with an expiry time, unique per plugin. // KVSet stores a key-value pair with an expiry time, unique per plugin.
// //
// @tag KeyValueStore
// Minimum server version: 5.6 // Minimum server version: 5.6
KVSetWithExpiry(key string, value []byte, expireInSeconds int64) *model.AppError KVSetWithExpiry(key string, value []byte, expireInSeconds int64) *model.AppError
// KVGet retrieves a value based on the key, unique per plugin. Returns nil for non-existent keys. // KVGet retrieves a value based on the key, unique per plugin. Returns nil for non-existent keys.
// //
// @tag KeyValueStore
// Minimum server version: 5.2 // Minimum server version: 5.2
KVGet(key string) ([]byte, *model.AppError) KVGet(key string) ([]byte, *model.AppError)
// KVDelete removes a key-value pair, unique per plugin. Returns nil for non-existent keys. // KVDelete removes a key-value pair, unique per plugin. Returns nil for non-existent keys.
// //
// @tag KeyValueStore
// Minimum server version: 5.2 // Minimum server version: 5.2
KVDelete(key string) *model.AppError KVDelete(key string) *model.AppError
// KVDeleteAll removes all key-value pairs for a plugin. // KVDeleteAll removes all key-value pairs for a plugin.
// //
// @tag KeyValueStore
// Minimum server version: 5.6 // Minimum server version: 5.6
KVDeleteAll() *model.AppError KVDeleteAll() *model.AppError
// KVList lists all keys for a plugin. // KVList lists all keys for a plugin.
// //
// @tag KeyValueStore
// Minimum server version: 5.6 // Minimum server version: 5.6
KVList(page, perPage int) ([]string, *model.AppError) KVList(page, perPage int) ([]string, *model.AppError)
@@ -656,16 +806,21 @@ type API interface {
// HasPermissionTo check if the user has the permission at system scope. // HasPermissionTo check if the user has the permission at system scope.
// //
// @tag User
// Minimum server version: 5.3 // Minimum server version: 5.3
HasPermissionTo(userId string, permission *model.Permission) bool HasPermissionTo(userId string, permission *model.Permission) bool
// HasPermissionToTeam check if the user has the permission at team scope. // HasPermissionToTeam check if the user has the permission at team scope.
// //
// @tag User
// @tag Team
// Minimum server version: 5.3 // Minimum server version: 5.3
HasPermissionToTeam(userId, teamId string, permission *model.Permission) bool HasPermissionToTeam(userId, teamId string, permission *model.Permission) bool
// HasPermissionToChannel check if the user has the permission at channel scope. // HasPermissionToChannel check if the user has the permission at channel scope.
// //
// @tag User
// @tag Channel
// Minimum server version: 5.3 // Minimum server version: 5.3
HasPermissionToChannel(userId, channelId string, permission *model.Permission) bool HasPermissionToChannel(userId, channelId string, permission *model.Permission) bool
@@ -673,6 +828,7 @@ type API interface {
// Appropriate context such as the plugin name will already be added as fields so plugins // Appropriate context such as the plugin name will already be added as fields so plugins
// do not need to add that info. // do not need to add that info.
// //
// @tag Logging
// Minimum server version: 5.2 // Minimum server version: 5.2
LogDebug(msg string, keyValuePairs ...interface{}) LogDebug(msg string, keyValuePairs ...interface{})
@@ -680,6 +836,7 @@ type API interface {
// Appropriate context such as the plugin name will already be added as fields so plugins // Appropriate context such as the plugin name will already be added as fields so plugins
// do not need to add that info. // do not need to add that info.
// //
// @tag Logging
// Minimum server version: 5.2 // Minimum server version: 5.2
LogInfo(msg string, keyValuePairs ...interface{}) LogInfo(msg string, keyValuePairs ...interface{})
@@ -687,6 +844,7 @@ type API interface {
// Appropriate context such as the plugin name will already be added as fields so plugins // Appropriate context such as the plugin name will already be added as fields so plugins
// do not need to add that info. // do not need to add that info.
// //
// @tag Logging
// Minimum server version: 5.2 // Minimum server version: 5.2
LogError(msg string, keyValuePairs ...interface{}) LogError(msg string, keyValuePairs ...interface{})
@@ -694,6 +852,7 @@ type API interface {
// Appropriate context such as the plugin name will already be added as fields so plugins // Appropriate context such as the plugin name will already be added as fields so plugins
// do not need to add that info. // do not need to add that info.
// //
// @tag Logging
// Minimum server version: 5.2 // Minimum server version: 5.2
LogWarn(msg string, keyValuePairs ...interface{}) LogWarn(msg string, keyValuePairs ...interface{})
@@ -704,49 +863,63 @@ type API interface {
// CreateBot creates the given bot and corresponding user. // CreateBot creates the given bot and corresponding user.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
CreateBot(bot *model.Bot) (*model.Bot, *model.AppError) CreateBot(bot *model.Bot) (*model.Bot, *model.AppError)
// PatchBot applies the given patch to the bot and corresponding user. // PatchBot applies the given patch to the bot and corresponding user.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
PatchBot(botUserId string, botPatch *model.BotPatch) (*model.Bot, *model.AppError) PatchBot(botUserId string, botPatch *model.BotPatch) (*model.Bot, *model.AppError)
// GetBot returns the given bot. // GetBot returns the given bot.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.AppError) GetBot(botUserId string, includeDeleted bool) (*model.Bot, *model.AppError)
// GetBots returns the requested page of bots. // GetBots returns the requested page of bots.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
GetBots(options *model.BotGetOptions) ([]*model.Bot, *model.AppError) GetBots(options *model.BotGetOptions) ([]*model.Bot, *model.AppError)
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user. // UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
UpdateBotActive(botUserId string, active bool) (*model.Bot, *model.AppError) UpdateBotActive(botUserId string, active bool) (*model.Bot, *model.AppError)
// PermanentDeleteBot permanently deletes a bot and its corresponding user. // PermanentDeleteBot permanently deletes a bot and its corresponding user.
// //
// @tag Bot
// Minimum server version: 5.10 // Minimum server version: 5.10
PermanentDeleteBot(botUserId string) *model.AppError PermanentDeleteBot(botUserId string) *model.AppError
// GetBotIconImage gets LHS bot icon image. // GetBotIconImage gets LHS bot icon image.
// //
// @tag Bot
// Minimum server version: 5.14 // Minimum server version: 5.14
GetBotIconImage(botUserId string) ([]byte, *model.AppError) GetBotIconImage(botUserId string) ([]byte, *model.AppError)
// SetBotIconImage sets LHS bot icon image. // SetBotIconImage sets LHS bot icon image.
// Icon image must be SVG format, all other formats are rejected. // Icon image must be SVG format, all other formats are rejected.
// //
// @tag Bot
// Minimum server version: 5.14 // Minimum server version: 5.14
SetBotIconImage(botUserId string, data []byte) *model.AppError SetBotIconImage(botUserId string, data []byte) *model.AppError
// DeleteBotIconImage deletes LHS bot icon image. // DeleteBotIconImage deletes LHS bot icon image.
// //
// @tag Bot
// Minimum server version: 5.14 // Minimum server version: 5.14
DeleteBotIconImage(botUserId string) *model.AppError DeleteBotIconImage(botUserId string) *model.AppError
// PluginHTTP allows inter-plugin requests to plugin APIs.
//
// Minimum server version: 5.18
PluginHTTP(request *http.Request) *http.Response
} }
var handshake = plugin.HandshakeConfig{ var handshake = plugin.HandshakeConfig{

Просмотреть файл

@@ -56,11 +56,13 @@ func (p *hooksPlugin) Client(b *plugin.MuxBroker, client *rpc.Client) (interface
} }
type apiRPCClient struct { type apiRPCClient struct {
client *rpc.Client client *rpc.Client
muxBroker *plugin.MuxBroker
} }
type apiRPCServer struct { type apiRPCServer struct {
impl API impl API
muxBroker *plugin.MuxBroker
} }
// ErrorString is a fallback for sending unregistered implementations of the error interface across // ErrorString is a fallback for sending unregistered implementations of the error interface across
@@ -171,7 +173,8 @@ type Z_OnActivateReturns struct {
func (g *hooksRPCClient) OnActivate() error { func (g *hooksRPCClient) OnActivate() error {
muxId := g.muxBroker.NextId() muxId := g.muxBroker.NextId()
go g.muxBroker.AcceptAndServe(muxId, &apiRPCServer{ go g.muxBroker.AcceptAndServe(muxId, &apiRPCServer{
impl: g.apiImpl, impl: g.apiImpl,
muxBroker: g.muxBroker,
}) })
_args := &Z_OnActivateArgs{ _args := &Z_OnActivateArgs{
@@ -192,7 +195,8 @@ func (s *hooksRPCServer) OnActivate(args *Z_OnActivateArgs, returns *Z_OnActivat
} }
s.apiRPCClient = &apiRPCClient{ s.apiRPCClient = &apiRPCClient{
client: rpc.NewClient(connection), client: rpc.NewClient(connection),
muxBroker: s.muxBroker,
} }
if mmplugin, ok := s.impl.(interface { if mmplugin, ok := s.impl.(interface {
@@ -363,6 +367,76 @@ func (s *hooksRPCServer) ServeHTTP(args *Z_ServeHTTPArgs, returns *struct{}) err
return nil return nil
} }
type Z_PluginHTTPArgs struct {
Request *http.Request
RequestBody []byte
}
type Z_PluginHTTPReturns struct {
Response *http.Response
ResponseBody []byte
}
func (g *apiRPCClient) PluginHTTP(request *http.Request) *http.Response {
forwardedRequest := &http.Request{
Method: request.Method,
URL: request.URL,
Proto: request.Proto,
ProtoMajor: request.ProtoMajor,
ProtoMinor: request.ProtoMinor,
Header: request.Header,
Host: request.Host,
RemoteAddr: request.RemoteAddr,
RequestURI: request.RequestURI,
}
requestBody, err := ioutil.ReadAll(request.Body)
if err != nil {
log.Printf("RPC call to PluginHTTP API failed: %s", err.Error())
return nil
}
request.Body.Close()
request.Body = nil
_args := &Z_PluginHTTPArgs{
Request: forwardedRequest,
RequestBody: requestBody,
}
_returns := &Z_PluginHTTPReturns{}
if err := g.client.Call("Plugin.PluginHTTP", _args, _returns); err != nil {
log.Printf("RPC call to PluginHTTP API failed: %s", err.Error())
return nil
}
_returns.Response.Body = ioutil.NopCloser(bytes.NewBuffer(_returns.ResponseBody))
return _returns.Response
}
func (s *apiRPCServer) PluginHTTP(args *Z_PluginHTTPArgs, returns *Z_PluginHTTPReturns) error {
args.Request.Body = ioutil.NopCloser(bytes.NewBuffer(args.RequestBody))
if hook, ok := s.impl.(interface {
PluginHTTP(request *http.Request) *http.Response
}); ok {
response := hook.PluginHTTP(args.Request)
responseBody, err := ioutil.ReadAll(response.Body)
if err != nil {
return encodableError(fmt.Errorf("RPC call to PluginHTTP API failed: %s", err.Error()))
}
response.Body.Close()
response.Body = nil
returns.Response = response
returns.ResponseBody = responseBody
} else {
return encodableError(fmt.Errorf("API PluginHTTP called but not implemented."))
}
return nil
}
func init() { func init() {
hookNameToId["FileWillBeUploaded"] = FileWillBeUploadedId hookNameToId["FileWillBeUploaded"] = FileWillBeUploadedId
} }

Просмотреть файл

@@ -12,4 +12,5 @@ type Context struct {
IpAddress string IpAddress string
AcceptLanguage string AcceptLanguage string
UserAgent string UserAgent string
SourcePluginId string
} }

Просмотреть файл

@@ -3,7 +3,11 @@
package plugin package plugin
import "github.com/mattermost/mattermost-server/model" import (
"github.com/blang/semver"
"github.com/mattermost/mattermost-server/model"
"github.com/pkg/errors"
)
type Helpers interface { type Helpers interface {
// EnsureBot either returns an existing bot user matching the given bot, or creates a bot user from the given bot. // EnsureBot either returns an existing bot user matching the given bot, or creates a bot user from the given bot.
@@ -54,3 +58,14 @@ type Helpers interface {
type HelpersImpl struct { type HelpersImpl struct {
API API API API
} }
func (p *HelpersImpl) ensureServerVersion(required string) error {
serverVersion := p.API.GetServerVersion()
currentVersion := semver.MustParse(serverVersion)
requiredVersion := semver.MustParse(required)
if currentVersion.LT(requiredVersion) {
return errors.Errorf("incompatible server version for plugin, minimum required version: %s, current version: %s", required, serverVersion)
}
return nil
}

Просмотреть файл

@@ -10,6 +10,11 @@ import (
) )
func (p *HelpersImpl) EnsureBot(bot *model.Bot) (retBotId string, retErr error) { func (p *HelpersImpl) EnsureBot(bot *model.Bot) (retBotId string, retErr error) {
err := p.ensureServerVersion("5.10.0")
if err != nil {
return "", errors.Wrap(err, "failed to ensure bot")
}
// Must provide a bot with a username // Must provide a bot with a username
if bot == nil || len(bot.Username) < 1 { if bot == nil || len(bot.Username) < 1 {
return "", errors.New("passed a bad bot, nil or no username") return "", errors.New("passed a bad bot, nil or no username")

Просмотреть файл

@@ -24,15 +24,37 @@ func TestEnsureBot(t *testing.T) {
Description: "testbotdescription", Description: "testbotdescription",
} }
t.Run("server version incompatible", func(t *testing.T) {
api := setupAPI()
api.On("GetServerVersion").Return("5.9.0")
defer api.AssertExpectations(t)
p := &plugin.HelpersImpl{}
p.API = api
_, retErr := p.EnsureBot(nil)
assert.NotNil(t, retErr)
assert.Equal(t, "failed to ensure bot: incompatible server version for plugin, minimum required version: 5.10.0, current version: 5.9.0", retErr.Error())
})
t.Run("bad parameters", func(t *testing.T) { t.Run("bad parameters", func(t *testing.T) {
t.Run("no bot", func(t *testing.T) { t.Run("no bot", func(t *testing.T) {
api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
p.API = api
botId, err := p.EnsureBot(nil) botId, err := p.EnsureBot(nil)
assert.Equal(t, "", botId) assert.Equal(t, "", botId)
assert.NotNil(t, err) assert.NotNil(t, err)
}) })
t.Run("bad username", func(t *testing.T) { t.Run("bad username", func(t *testing.T) {
api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
p.API = api
botId, err := p.EnsureBot(&model.Bot{ botId, err := p.EnsureBot(&model.Bot{
Username: "", Username: "",
}) })
@@ -46,6 +68,7 @@ func TestEnsureBot(t *testing.T) {
expectedBotId := model.NewId() expectedBotId := model.NewId()
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return([]byte(expectedBotId), nil) api.On("KVGet", plugin.BOT_USER_KEY).Return([]byte(expectedBotId), nil)
defer api.AssertExpectations(t) defer api.AssertExpectations(t)
@@ -60,6 +83,7 @@ func TestEnsureBot(t *testing.T) {
t.Run("should return an error if unable to get bot", func(t *testing.T) { t.Run("should return an error if unable to get bot", func(t *testing.T) {
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, &model.AppError{}) api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, &model.AppError{})
defer api.AssertExpectations(t) defer api.AssertExpectations(t)
@@ -78,6 +102,7 @@ func TestEnsureBot(t *testing.T) {
expectedBotId := model.NewId() expectedBotId := model.NewId()
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil) api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil)
api.On("GetUserByUsername", testbot.Username).Return(nil, nil) api.On("GetUserByUsername", testbot.Username).Return(nil, nil)
api.On("CreateBot", testbot).Return(&model.Bot{ api.On("CreateBot", testbot).Return(&model.Bot{
@@ -99,6 +124,7 @@ func TestEnsureBot(t *testing.T) {
expectedBotId := model.NewId() expectedBotId := model.NewId()
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil) api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil)
api.On("GetUserByUsername", testbot.Username).Return(&model.User{ api.On("GetUserByUsername", testbot.Username).Return(&model.User{
Id: expectedBotId, Id: expectedBotId,
@@ -119,6 +145,7 @@ func TestEnsureBot(t *testing.T) {
t.Run("should return the non-bot account but log a message if user exists with the same name and is not a bot", func(t *testing.T) { t.Run("should return the non-bot account but log a message if user exists with the same name and is not a bot", func(t *testing.T) {
expectedBotId := model.NewId() expectedBotId := model.NewId()
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil) api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil)
api.On("GetUserByUsername", testbot.Username).Return(&model.User{ api.On("GetUserByUsername", testbot.Username).Return(&model.User{
Id: expectedBotId, Id: expectedBotId,
@@ -138,6 +165,7 @@ func TestEnsureBot(t *testing.T) {
t.Run("should fail if create bot fails", func(t *testing.T) { t.Run("should fail if create bot fails", func(t *testing.T) {
api := setupAPI() api := setupAPI()
api.On("GetServerVersion").Return("5.10.0")
api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil) api.On("KVGet", plugin.BOT_USER_KEY).Return(nil, nil)
api.On("GetUserByUsername", testbot.Username).Return(nil, nil) api.On("GetUserByUsername", testbot.Username).Return(nil, nil)
api.On("CreateBot", testbot).Return(nil, &model.AppError{}) api.On("CreateBot", testbot).Return(nil, &model.AppError{})

Просмотреть файл

@@ -11,6 +11,11 @@ import (
// KVSetJSON implements Helpers.KVSetJSON. // KVSetJSON implements Helpers.KVSetJSON.
func (p *HelpersImpl) KVSetJSON(key string, value interface{}) error { func (p *HelpersImpl) KVSetJSON(key string, value interface{}) error {
err := p.ensureServerVersion("5.2.0")
if err != nil {
return err
}
data, err := json.Marshal(value) data, err := json.Marshal(value)
if err != nil { if err != nil {
return err return err
@@ -26,9 +31,14 @@ func (p *HelpersImpl) KVSetJSON(key string, value interface{}) error {
// KVCompareAndSetJSON implements Helpers.KVCompareAndSetJSON. // KVCompareAndSetJSON implements Helpers.KVCompareAndSetJSON.
func (p *HelpersImpl) KVCompareAndSetJSON(key string, oldValue interface{}, newValue interface{}) (bool, error) { func (p *HelpersImpl) KVCompareAndSetJSON(key string, oldValue interface{}, newValue interface{}) (bool, error) {
var oldData, newData []byte
var err error var err error
err = p.ensureServerVersion("5.12.0")
if err != nil {
return false, err
}
var oldData, newData []byte
if oldValue != nil { if oldValue != nil {
oldData, err = json.Marshal(oldValue) oldData, err = json.Marshal(oldValue)
if err != nil { if err != nil {
@@ -53,9 +63,15 @@ func (p *HelpersImpl) KVCompareAndSetJSON(key string, oldValue interface{}, newV
// KVCompareAndDeleteJSON implements Helpers.KVCompareAndDeleteJSON. // KVCompareAndDeleteJSON implements Helpers.KVCompareAndDeleteJSON.
func (p *HelpersImpl) KVCompareAndDeleteJSON(key string, oldValue interface{}) (bool, error) { func (p *HelpersImpl) KVCompareAndDeleteJSON(key string, oldValue interface{}) (bool, error) {
var oldData []byte
var err error var err error
err = p.ensureServerVersion("5.16.0")
if err != nil {
return false, err
}
var oldData []byte
if oldValue != nil { if oldValue != nil {
oldData, err = json.Marshal(oldValue) oldData, err = json.Marshal(oldValue)
if err != nil { if err != nil {
@@ -73,6 +89,11 @@ func (p *HelpersImpl) KVCompareAndDeleteJSON(key string, oldValue interface{}) (
// KVGetJSON implements Helpers.KVGetJSON. // KVGetJSON implements Helpers.KVGetJSON.
func (p *HelpersImpl) KVGetJSON(key string, value interface{}) (bool, error) { func (p *HelpersImpl) KVGetJSON(key string, value interface{}) (bool, error) {
err := p.ensureServerVersion("5.2.0")
if err != nil {
return false, err
}
data, appErr := p.API.KVGet(key) data, appErr := p.API.KVGet(key)
if appErr != nil { if appErr != nil {
return false, appErr return false, appErr
@@ -81,7 +102,7 @@ func (p *HelpersImpl) KVGetJSON(key string, value interface{}) (bool, error) {
return false, nil return false, nil
} }
err := json.Unmarshal(data, value) err = json.Unmarshal(data, value)
if err != nil { if err != nil {
return false, err return false, err
} }
@@ -89,8 +110,13 @@ func (p *HelpersImpl) KVGetJSON(key string, value interface{}) (bool, error) {
return true, nil return true, nil
} }
// KVSetWithExpiryJSON implements Helpers.KVSetWithExpiryJSON. // KVSetWithExpiryJSON is a wrapper around KVSetWithExpiry to simplify atomically writing a JSON object with expiry to the key value store.
func (p *HelpersImpl) KVSetWithExpiryJSON(key string, value interface{}, expireInSeconds int64) error { func (p *HelpersImpl) KVSetWithExpiryJSON(key string, value interface{}, expireInSeconds int64) error {
err := p.ensureServerVersion("5.6.0")
if err != nil {
return err
}
data, err := json.Marshal(value) data, err := json.Marshal(value)
if err != nil { if err != nil {
return err return err

Просмотреть файл

@@ -10,10 +10,26 @@ import (
) )
func TestKVGetJSON(t *testing.T) { func TestKVGetJSON(t *testing.T) {
t.Run("incompatible server version", func(t *testing.T) {
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.1.0")
p := &plugin.HelpersImpl{API: api}
var dat map[string]interface{}
ok, err := p.KVGetJSON("test-key", dat)
api.AssertExpectations(t)
assert.False(t, ok)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.2.0, current version: 5.1.0", err.Error())
})
t.Run("KVGet error", func(t *testing.T) { t.Run("KVGet error", func(t *testing.T) {
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.2.0")
api.On("KVGet", "test-key").Return(nil, &model.AppError{}) api.On("KVGet", "test-key").Return(nil, &model.AppError{})
p.API = api p.API = api
@@ -30,6 +46,7 @@ func TestKVGetJSON(t *testing.T) {
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.2.0")
api.On("KVGet", "test-key").Return(nil, nil) api.On("KVGet", "test-key").Return(nil, nil)
p.API = api p.API = api
@@ -46,6 +63,7 @@ func TestKVGetJSON(t *testing.T) {
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.2.0")
api.On("KVGet", "test-key").Return([]byte(`{{:}"val-a": 10}`), nil) api.On("KVGet", "test-key").Return([]byte(`{{:}"val-a": 10}`), nil)
p.API = api p.API = api
@@ -62,6 +80,7 @@ func TestKVGetJSON(t *testing.T) {
p := &plugin.HelpersImpl{} p := &plugin.HelpersImpl{}
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.2.0")
api.On("KVGet", "test-key").Return([]byte(`{"val-a": 10}`), nil) api.On("KVGet", "test-key").Return([]byte(`{"val-a": 10}`), nil)
p.API = api p.API = api
@@ -78,9 +97,25 @@ func TestKVGetJSON(t *testing.T) {
} }
func TestKVSetJSON(t *testing.T) { func TestKVSetJSON(t *testing.T) {
t.Run("incompatible server version", func(t *testing.T) {
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.1.0")
p := &plugin.HelpersImpl{API: api}
err := p.KVSetJSON("test-key", map[string]interface{}{
"val-a": float64(10),
})
api.AssertExpectations(t)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.2.0, current version: 5.1.0", err.Error())
})
t.Run("JSON marshal error", func(t *testing.T) { t.Run("JSON marshal error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.AssertNotCalled(t, "KVSet") api.AssertNotCalled(t, "KVSet")
api.On("GetServerVersion").Return("5.2.0")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -92,6 +127,7 @@ func TestKVSetJSON(t *testing.T) {
t.Run("KVSet error", func(t *testing.T) { t.Run("KVSet error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("KVSet", "test-key", []byte(`{"val-a":10}`)).Return(&model.AppError{}) api.On("KVSet", "test-key", []byte(`{"val-a":10}`)).Return(&model.AppError{})
api.On("GetServerVersion").Return("5.2.0")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -106,6 +142,7 @@ func TestKVSetJSON(t *testing.T) {
t.Run("marshallable struct", func(t *testing.T) { t.Run("marshallable struct", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("KVSet", "test-key", []byte(`{"val-a":10}`)).Return(nil) api.On("KVSet", "test-key", []byte(`{"val-a":10}`)).Return(nil)
api.On("GetServerVersion").Return("5.2.0")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -119,9 +156,24 @@ func TestKVSetJSON(t *testing.T) {
} }
func TestKVCompareAndSetJSON(t *testing.T) { func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("incompatible server version", func(t *testing.T) {
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.10.0")
p := &plugin.HelpersImpl{API: api}
ok, err := p.KVCompareAndSetJSON("test-key", nil, map[string]interface{}{
"val-b": 20,
})
assert.Equal(t, false, ok)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.12.0, current version: 5.10.0", err.Error())
})
t.Run("old value JSON marshal error", func(t *testing.T) { t.Run("old value JSON marshal error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.AssertNotCalled(t, "KVCompareAndSet") api.AssertNotCalled(t, "KVCompareAndSet")
api.On("GetServerVersion").Return("5.12.0")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
ok, err := p.KVCompareAndSetJSON("test-key", func() {}, map[string]interface{}{}) ok, err := p.KVCompareAndSetJSON("test-key", func() {}, map[string]interface{}{})
@@ -133,6 +185,7 @@ func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("new value JSON marshal error", func(t *testing.T) { t.Run("new value JSON marshal error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.12.0")
api.AssertNotCalled(t, "KVCompareAndSet") api.AssertNotCalled(t, "KVCompareAndSet")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -146,6 +199,7 @@ func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("KVCompareAndSet error", func(t *testing.T) { t.Run("KVCompareAndSet error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.12.0")
api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(`{"val-b":20}`)).Return(false, &model.AppError{}) api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(`{"val-b":20}`)).Return(false, &model.AppError{})
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -162,6 +216,7 @@ func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("old value nil", func(t *testing.T) { t.Run("old value nil", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.12.0")
api.On("KVCompareAndSet", "test-key", []byte(nil), []byte(`{"val-b":20}`)).Return(true, nil) api.On("KVCompareAndSet", "test-key", []byte(nil), []byte(`{"val-b":20}`)).Return(true, nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -176,6 +231,7 @@ func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("old value non-nil", func(t *testing.T) { t.Run("old value non-nil", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.12.0")
api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(`{"val-b":20}`)).Return(true, nil) api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(`{"val-b":20}`)).Return(true, nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -192,6 +248,7 @@ func TestKVCompareAndSetJSON(t *testing.T) {
t.Run("new value nil", func(t *testing.T) { t.Run("new value nil", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.12.0")
api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(nil)).Return(true, nil) api.On("KVCompareAndSet", "test-key", []byte(`{"val-a":10}`), []byte(nil)).Return(true, nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -206,8 +263,23 @@ func TestKVCompareAndSetJSON(t *testing.T) {
} }
func TestKVCompareAndDeleteJSON(t *testing.T) { func TestKVCompareAndDeleteJSON(t *testing.T) {
t.Run("incompatible server version", func(t *testing.T) {
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.10.0")
p := &plugin.HelpersImpl{API: api}
ok, err := p.KVCompareAndDeleteJSON("test-key", map[string]interface{}{
"val-a": 10,
})
assert.Equal(t, false, ok)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.16.0, current version: 5.10.0", err.Error())
})
t.Run("old value JSON marshal error", func(t *testing.T) { t.Run("old value JSON marshal error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.16.0")
api.AssertNotCalled(t, "KVCompareAndDelete") api.AssertNotCalled(t, "KVCompareAndDelete")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -220,6 +292,7 @@ func TestKVCompareAndDeleteJSON(t *testing.T) {
t.Run("KVCompareAndDelete error", func(t *testing.T) { t.Run("KVCompareAndDelete error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.16.0")
api.On("KVCompareAndDelete", "test-key", []byte(`{"val-a":10}`)).Return(false, &model.AppError{}) api.On("KVCompareAndDelete", "test-key", []byte(`{"val-a":10}`)).Return(false, &model.AppError{})
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -234,6 +307,7 @@ func TestKVCompareAndDeleteJSON(t *testing.T) {
t.Run("old value nil", func(t *testing.T) { t.Run("old value nil", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.16.0")
api.On("KVCompareAndDelete", "test-key", []byte(nil)).Return(true, nil) api.On("KVCompareAndDelete", "test-key", []byte(nil)).Return(true, nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -246,6 +320,7 @@ func TestKVCompareAndDeleteJSON(t *testing.T) {
t.Run("old value non-nil", func(t *testing.T) { t.Run("old value non-nil", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.16.0")
api.On("KVCompareAndDelete", "test-key", []byte(`{"val-a":10}`)).Return(true, nil) api.On("KVCompareAndDelete", "test-key", []byte(`{"val-a":10}`)).Return(true, nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -260,8 +335,24 @@ func TestKVCompareAndDeleteJSON(t *testing.T) {
} }
func TestKVSetWithExpiryJSON(t *testing.T) { func TestKVSetWithExpiryJSON(t *testing.T) {
t.Run("incompatible server version", func(t *testing.T) {
api := &plugintest.API{}
api.On("GetServerVersion").Return("5.4.0")
p := &plugin.HelpersImpl{API: api}
err := p.KVSetWithExpiryJSON("test-key", map[string]interface{}{
"val-a": float64(10),
}, 100)
api.AssertExpectations(t)
assert.Error(t, err)
assert.Equal(t, "incompatible server version for plugin, minimum required version: 5.6.0, current version: 5.4.0", err.Error())
})
t.Run("JSON marshal error", func(t *testing.T) { t.Run("JSON marshal error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.6.0")
api.AssertNotCalled(t, "KVSetWithExpiry") api.AssertNotCalled(t, "KVSetWithExpiry")
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -274,6 +365,7 @@ func TestKVSetWithExpiryJSON(t *testing.T) {
t.Run("KVSetWithExpiry error", func(t *testing.T) { t.Run("KVSetWithExpiry error", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.6.0")
api.On("KVSetWithExpiry", "test-key", []byte(`{"val-a":10}`), int64(100)).Return(&model.AppError{}) api.On("KVSetWithExpiry", "test-key", []byte(`{"val-a":10}`), int64(100)).Return(&model.AppError{})
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}
@@ -287,6 +379,7 @@ func TestKVSetWithExpiryJSON(t *testing.T) {
t.Run("wellformed JSON", func(t *testing.T) { t.Run("wellformed JSON", func(t *testing.T) {
api := &plugintest.API{} api := &plugintest.API{}
api.On("GetServerVersion").Return("5.6.0")
api.On("KVSetWithExpiry", "test-key", []byte(`{"val-a":10}`), int64(100)).Return(nil) api.On("KVSetWithExpiry", "test-key", []byte(`{"val-a":10}`), int64(100)).Return(nil)
p := &plugin.HelpersImpl{API: api} p := &plugin.HelpersImpl{API: api}

Просмотреть файл

@@ -392,17 +392,18 @@ func getPluginPackageDir() string {
func removeExcluded(info *PluginInterfaceInfo) *PluginInterfaceInfo { func removeExcluded(info *PluginInterfaceInfo) *PluginInterfaceInfo {
toBeExcluded := func(item string) bool { toBeExcluded := func(item string) bool {
excluded := []string{ excluded := []string{
"OnActivate", "FileWillBeUploaded",
"Implemented", "Implemented",
"LoadPluginConfiguration", "LoadPluginConfiguration",
"ServeHTTP",
"FileWillBeUploaded",
"MessageWillBePosted",
"MessageWillBeUpdated",
"LogDebug", "LogDebug",
"LogError",
"LogInfo", "LogInfo",
"LogWarn", "LogWarn",
"LogError", "MessageWillBePosted",
"MessageWillBeUpdated",
"OnActivate",
"PluginHTTP",
"ServeHTTP",
} }
for _, exclusion := range excluded { for _, exclusion := range excluded {
if exclusion == item { if exclusion == item {

Просмотреть файл

@@ -6,9 +6,11 @@ package plugintest
import ( import (
io "io" io "io"
http "net/http"
mock "github.com/stretchr/testify/mock"
model "github.com/mattermost/mattermost-server/model" model "github.com/mattermost/mattermost-server/model"
mock "github.com/stretchr/testify/mock"
) )
// API is an autogenerated mock type for the API type // API is an autogenerated mock type for the API type
@@ -2334,6 +2336,22 @@ func (_m *API) PermanentDeleteBot(botUserId string) *model.AppError {
return r0 return r0
} }
// PluginHTTP provides a mock function with given fields: request
func (_m *API) PluginHTTP(request *http.Request) *http.Response {
ret := _m.Called(request)
var r0 *http.Response
if rf, ok := ret.Get(0).(func(*http.Request) *http.Response); ok {
r0 = rf(request)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*http.Response)
}
}
return r0
}
// PublishWebSocketEvent provides a mock function with given fields: event, payload, broadcast // PublishWebSocketEvent provides a mock function with given fields: event, payload, broadcast
func (_m *API) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) { func (_m *API) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) {
_m.Called(event, payload, broadcast) _m.Called(event, payload, broadcast)

Просмотреть файл

@@ -19,7 +19,7 @@ check_prereq()
if check_version $installed_version $required_version; then if check_version $installed_version $required_version; then
echo "$dependency minimum requirement met. Required: $required_version, Found: $installed_version" echo "$dependency minimum requirement met. Required: $required_version, Found: $installed_version"
else else
echo "WARNING! Mattermost did not find the minimum supported version of '$dependency' installed. Required: $required_version, Found: $installed_version" echo "WARNING! Mattermost did not find the minimum supported version of '$dependency' installed. Required: $required_version, Found: $installed_version"
echo "We highly recommend stopping installation and updating dependencies before continuing" echo "We highly recommend stopping installation and updating dependencies before continuing"
read -p "Enter Y to continue anyway (not recommended)." -n 1 -r read -p "Enter Y to continue anyway (not recommended)." -n 1 -r
@@ -35,7 +35,7 @@ echo "Checking prerequisites"
REQUIREDNODEVERSION=8.9.0 REQUIREDNODEVERSION=8.9.0
REQUIREDNPMVERSION=5.6.0 REQUIREDNPMVERSION=5.6.0
REQUIREDGOVERSION=1.12.0 REQUIREDGOVERSION=1.13.0
REQUIREDDOCKERVERSION=17.0 REQUIREDDOCKERVERSION=17.0
NODEVERSION=$(sed 's/v//' <<< $(node -v)) NODEVERSION=$(sed 's/v//' <<< $(node -v))

Просмотреть файл

@@ -1,203 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"context"
"github.com/mattermost/mattermost-server/einterfaces"
)
type LayeredStoreDatabaseLayer interface {
LayeredStoreSupplier
Store
}
type LayeredStore struct {
TmpContext context.Context
DatabaseLayer LayeredStoreDatabaseLayer
LocalCacheLayer *LocalCacheSupplier
LayerChainHead LayeredStoreSupplier
}
func NewLayeredStore(db LayeredStoreDatabaseLayer, metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface) Store {
store := &LayeredStore{
TmpContext: context.TODO(),
DatabaseLayer: db,
LocalCacheLayer: NewLocalCacheSupplier(metrics, cluster),
}
// Setup the chain
store.LocalCacheLayer.SetChainNext(store.DatabaseLayer)
store.LayerChainHead = store.LocalCacheLayer
return store
}
type QueryFunction func(LayeredStoreSupplier) *LayeredStoreSupplierResult
func (s *LayeredStore) GetCurrentSchemaVersion() string {
return s.DatabaseLayer.GetCurrentSchemaVersion()
}
func (s *LayeredStore) Team() TeamStore {
return s.DatabaseLayer.Team()
}
func (s *LayeredStore) Channel() ChannelStore {
return s.DatabaseLayer.Channel()
}
func (s *LayeredStore) Post() PostStore {
return s.DatabaseLayer.Post()
}
func (s *LayeredStore) User() UserStore {
return s.DatabaseLayer.User()
}
func (s *LayeredStore) Bot() BotStore {
return s.DatabaseLayer.Bot()
}
func (s *LayeredStore) Audit() AuditStore {
return s.DatabaseLayer.Audit()
}
func (s *LayeredStore) ClusterDiscovery() ClusterDiscoveryStore {
return s.DatabaseLayer.ClusterDiscovery()
}
func (s *LayeredStore) Compliance() ComplianceStore {
return s.DatabaseLayer.Compliance()
}
func (s *LayeredStore) Session() SessionStore {
return s.DatabaseLayer.Session()
}
func (s *LayeredStore) OAuth() OAuthStore {
return s.DatabaseLayer.OAuth()
}
func (s *LayeredStore) System() SystemStore {
return s.DatabaseLayer.System()
}
func (s *LayeredStore) Webhook() WebhookStore {
return s.DatabaseLayer.Webhook()
}
func (s *LayeredStore) Command() CommandStore {
return s.DatabaseLayer.Command()
}
func (s *LayeredStore) CommandWebhook() CommandWebhookStore {
return s.DatabaseLayer.CommandWebhook()
}
func (s *LayeredStore) Preference() PreferenceStore {
return s.DatabaseLayer.Preference()
}
func (s *LayeredStore) License() LicenseStore {
return s.DatabaseLayer.License()
}
func (s *LayeredStore) Token() TokenStore {
return s.DatabaseLayer.Token()
}
func (s *LayeredStore) Emoji() EmojiStore {
return s.DatabaseLayer.Emoji()
}
func (s *LayeredStore) Status() StatusStore {
return s.DatabaseLayer.Status()
}
func (s *LayeredStore) FileInfo() FileInfoStore {
return s.DatabaseLayer.FileInfo()
}
func (s *LayeredStore) Reaction() ReactionStore {
return s.DatabaseLayer.Reaction()
}
func (s *LayeredStore) Job() JobStore {
return s.DatabaseLayer.Job()
}
func (s *LayeredStore) UserAccessToken() UserAccessTokenStore {
return s.DatabaseLayer.UserAccessToken()
}
func (s *LayeredStore) ChannelMemberHistory() ChannelMemberHistoryStore {
return s.DatabaseLayer.ChannelMemberHistory()
}
func (s *LayeredStore) Plugin() PluginStore {
return s.DatabaseLayer.Plugin()
}
func (s *LayeredStore) Role() RoleStore {
return s.DatabaseLayer.Role()
}
func (s *LayeredStore) TermsOfService() TermsOfServiceStore {
return s.DatabaseLayer.TermsOfService()
}
func (s *LayeredStore) UserTermsOfService() UserTermsOfServiceStore {
return s.DatabaseLayer.UserTermsOfService()
}
func (s *LayeredStore) Scheme() SchemeStore {
return s.DatabaseLayer.Scheme()
}
func (s *LayeredStore) Group() GroupStore {
return s.DatabaseLayer.Group()
}
func (s *LayeredStore) LinkMetadata() LinkMetadataStore {
return s.DatabaseLayer.LinkMetadata()
}
func (s *LayeredStore) MarkSystemRanUnitTests() {
s.DatabaseLayer.MarkSystemRanUnitTests()
}
func (s *LayeredStore) Close() {
s.DatabaseLayer.Close()
}
func (s *LayeredStore) LockToMaster() {
s.DatabaseLayer.LockToMaster()
}
func (s *LayeredStore) UnlockFromMaster() {
s.DatabaseLayer.UnlockFromMaster()
}
func (s *LayeredStore) DropAllTables() {
defer s.LocalCacheLayer.Invalidate()
s.DatabaseLayer.DropAllTables()
}
func (s *LayeredStore) TotalMasterDbConnections() int {
return s.DatabaseLayer.TotalMasterDbConnections()
}
func (s *LayeredStore) TotalReadDbConnections() int {
return s.DatabaseLayer.TotalReadDbConnections()
}
func (s *LayeredStore) TotalSearchDbConnections() int {
return s.DatabaseLayer.TotalSearchDbConnections()
}
func (s *LayeredStore) CheckIntegrity() <-chan IntegrityCheckResult {
return s.DatabaseLayer.CheckIntegrity()
}

Просмотреть файл

@@ -1,11 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package store
type LayeredStoreHint int
const (
LSH_NO_CACHE LayeredStoreHint = iota
LSH_MASTER_ONLY
)

Просмотреть файл

@@ -1,20 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package store
type LayeredStoreSupplierResult struct {
StoreResult
}
func NewSupplierResult() *LayeredStoreSupplierResult {
return &LayeredStoreSupplierResult{}
}
type LayeredStoreSupplier interface {
//
// Control
//
SetChainNext(LayeredStoreSupplier)
Next() LayeredStoreSupplier
}

Просмотреть файл

@@ -1,83 +0,0 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package store
import (
"context"
"github.com/mattermost/mattermost-server/einterfaces"
"github.com/mattermost/mattermost-server/model"
)
const (
CLEAR_CACHE_MESSAGE_DATA = ""
)
type LocalCacheSupplier struct {
next LayeredStoreSupplier
metrics einterfaces.MetricsInterface
cluster einterfaces.ClusterInterface
}
// Caching Interface
type ObjectCache interface {
AddWithExpiresInSecs(key, value interface{}, expireAtSecs int64)
AddWithDefaultExpires(key, value interface{})
Purge()
Get(key interface{}) (value interface{}, ok bool)
Remove(key interface{})
Len() int
Name() string
GetInvalidateClusterEvent() string
}
func NewLocalCacheSupplier(metrics einterfaces.MetricsInterface, cluster einterfaces.ClusterInterface) *LocalCacheSupplier {
supplier := &LocalCacheSupplier{
metrics: metrics,
cluster: cluster,
}
return supplier
}
func (s *LocalCacheSupplier) SetChainNext(next LayeredStoreSupplier) {
s.next = next
}
func (s *LocalCacheSupplier) Next() LayeredStoreSupplier {
return s.next
}
func (s *LocalCacheSupplier) doStandardAddToCache(ctx context.Context, cache ObjectCache, key string, result *LayeredStoreSupplierResult, hints ...LayeredStoreHint) {
if result.Err == nil && result.Data != nil {
cache.AddWithDefaultExpires(key, result.Data)
}
}
func (s *LocalCacheSupplier) doInvalidateCacheCluster(cache ObjectCache, key string) {
cache.Remove(key)
if s.cluster != nil {
msg := &model.ClusterMessage{
Event: cache.GetInvalidateClusterEvent(),
SendType: model.CLUSTER_SEND_BEST_EFFORT,
Data: key,
}
s.cluster.SendClusterMessage(msg)
}
}
func (s *LocalCacheSupplier) doClearCacheCluster(cache ObjectCache) {
cache.Purge()
if s.cluster != nil {
msg := &model.ClusterMessage{
Event: cache.GetInvalidateClusterEvent(),
SendType: model.CLUSTER_SEND_BEST_EFFORT,
Data: CLEAR_CACHE_MESSAGE_DATA,
}
s.cluster.SendClusterMessage(msg)
}
}
func (s *LocalCacheSupplier) Invalidate() {
}

Просмотреть файл

@@ -58,7 +58,7 @@ func initStores() {
go func() { go func() {
defer wg.Done() defer wg.Done()
st.SqlSupplier = sqlstore.NewSqlSupplier(*st.SqlSettings, nil) st.SqlSupplier = sqlstore.NewSqlSupplier(*st.SqlSettings, nil)
st.Store = NewLocalCacheLayer(store.NewLayeredStore(st.SqlSupplier, nil, nil), nil, nil) st.Store = NewLocalCacheLayer(st.SqlSupplier, nil, nil)
st.Store.DropAllTables() st.Store.DropAllTables()
st.Store.MarkSystemRanUnitTests() st.Store.MarkSystemRanUnitTests()
}() }()

Просмотреть файл

@@ -362,7 +362,7 @@ func TestCheckIntegrity(t *testing.T) {
func TestCheckParentChildIntegrity(t *testing.T) { func TestCheckParentChildIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
t.Run("should receive an error", func(t *testing.T) { t.Run("should receive an error", func(t *testing.T) {
config := relationalCheckConfig{ config := relationalCheckConfig{
parentName: "NotValid", parentName: "NotValid",
@@ -379,7 +379,7 @@ func TestCheckParentChildIntegrity(t *testing.T) {
func TestCheckChannelsCommandWebhooksIntegrity(t *testing.T) { func TestCheckChannelsCommandWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -407,7 +407,7 @@ func TestCheckChannelsCommandWebhooksIntegrity(t *testing.T) {
func TestCheckChannelsChannelMemberHistoryIntegrity(t *testing.T) { func TestCheckChannelsChannelMemberHistoryIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -437,7 +437,7 @@ func TestCheckChannelsChannelMemberHistoryIntegrity(t *testing.T) {
func TestCheckChannelsChannelMembersIntegrity(t *testing.T) { func TestCheckChannelsChannelMembersIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -465,7 +465,7 @@ func TestCheckChannelsChannelMembersIntegrity(t *testing.T) {
func TestCheckChannelsIncomingWebhooksIntegrity(t *testing.T) { func TestCheckChannelsIncomingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -493,7 +493,7 @@ func TestCheckChannelsIncomingWebhooksIntegrity(t *testing.T) {
func TestCheckChannelsOutgoingWebhooksIntegrity(t *testing.T) { func TestCheckChannelsOutgoingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -523,7 +523,7 @@ func TestCheckChannelsOutgoingWebhooksIntegrity(t *testing.T) {
func TestCheckChannelsPostsIntegrity(t *testing.T) { func TestCheckChannelsPostsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -550,7 +550,7 @@ func TestCheckChannelsPostsIntegrity(t *testing.T) {
func TestCheckCommandsCommandWebhooksIntegrity(t *testing.T) { func TestCheckCommandsCommandWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -578,7 +578,7 @@ func TestCheckCommandsCommandWebhooksIntegrity(t *testing.T) {
func TestCheckPostsFileInfoIntegrity(t *testing.T) { func TestCheckPostsFileInfoIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -605,7 +605,7 @@ func TestCheckPostsFileInfoIntegrity(t *testing.T) {
func TestCheckPostsPostsParentIdIntegrity(t *testing.T) { func TestCheckPostsPostsParentIdIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -637,7 +637,7 @@ func TestCheckPostsPostsParentIdIntegrity(t *testing.T) {
func TestCheckPostsPostsRootIdIntegrity(t *testing.T) { func TestCheckPostsPostsRootIdIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -667,7 +667,7 @@ func TestCheckPostsPostsRootIdIntegrity(t *testing.T) {
func TestCheckPostsReactionsIntegrity(t *testing.T) { func TestCheckPostsReactionsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -694,7 +694,7 @@ func TestCheckPostsReactionsIntegrity(t *testing.T) {
func TestCheckSchemesChannelsIntegrity(t *testing.T) { func TestCheckSchemesChannelsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -725,7 +725,7 @@ func TestCheckSchemesChannelsIntegrity(t *testing.T) {
func TestCheckSchemesTeamsIntegrity(t *testing.T) { func TestCheckSchemesTeamsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -756,7 +756,7 @@ func TestCheckSchemesTeamsIntegrity(t *testing.T) {
func TestCheckSessionsAuditsIntegrity(t *testing.T) { func TestCheckSessionsAuditsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -787,7 +787,7 @@ func TestCheckSessionsAuditsIntegrity(t *testing.T) {
func TestCheckTeamsChannelsIntegrity(t *testing.T) { func TestCheckTeamsChannelsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -814,7 +814,7 @@ func TestCheckTeamsChannelsIntegrity(t *testing.T) {
func TestCheckTeamsCommandsIntegrity(t *testing.T) { func TestCheckTeamsCommandsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -842,7 +842,7 @@ func TestCheckTeamsCommandsIntegrity(t *testing.T) {
func TestCheckTeamsIncomingWebhooksIntegrity(t *testing.T) { func TestCheckTeamsIncomingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -870,7 +870,7 @@ func TestCheckTeamsIncomingWebhooksIntegrity(t *testing.T) {
func TestCheckTeamsOutgoingWebhooksIntegrity(t *testing.T) { func TestCheckTeamsOutgoingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -898,7 +898,7 @@ func TestCheckTeamsOutgoingWebhooksIntegrity(t *testing.T) {
func TestCheckTeamsTeamMembersIntegrity(t *testing.T) { func TestCheckTeamsTeamMembersIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -926,7 +926,7 @@ func TestCheckTeamsTeamMembersIntegrity(t *testing.T) {
func TestCheckUsersAuditsIntegrity(t *testing.T) { func TestCheckUsersAuditsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -956,7 +956,7 @@ func TestCheckUsersAuditsIntegrity(t *testing.T) {
func TestCheckUsersCommandWebhooksIntegrity(t *testing.T) { func TestCheckUsersCommandWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -984,7 +984,7 @@ func TestCheckUsersCommandWebhooksIntegrity(t *testing.T) {
func TestCheckUsersChannelsIntegrity(t *testing.T) { func TestCheckUsersChannelsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1011,7 +1011,7 @@ func TestCheckUsersChannelsIntegrity(t *testing.T) {
func TestCheckUsersChannelMemberHistoryIntegrity(t *testing.T) { func TestCheckUsersChannelMemberHistoryIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1041,7 +1041,7 @@ func TestCheckUsersChannelMemberHistoryIntegrity(t *testing.T) {
func TestCheckUsersChannelMembersIntegrity(t *testing.T) { func TestCheckUsersChannelMembersIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1071,7 +1071,7 @@ func TestCheckUsersChannelMembersIntegrity(t *testing.T) {
func TestCheckUsersCommandsIntegrity(t *testing.T) { func TestCheckUsersCommandsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1099,7 +1099,7 @@ func TestCheckUsersCommandsIntegrity(t *testing.T) {
func TestCheckUsersCompliancesIntegrity(t *testing.T) { func TestCheckUsersCompliancesIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1129,7 +1129,7 @@ func TestCheckUsersCompliancesIntegrity(t *testing.T) {
func TestCheckUsersEmojiIntegrity(t *testing.T) { func TestCheckUsersEmojiIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1159,7 +1159,7 @@ func TestCheckUsersEmojiIntegrity(t *testing.T) {
func TestCheckUsersFileInfoIntegrity(t *testing.T) { func TestCheckUsersFileInfoIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1188,7 +1188,7 @@ func TestCheckUsersFileInfoIntegrity(t *testing.T) {
func TestCheckUsersIncomingWebhooksIntegrity(t *testing.T) { func TestCheckUsersIncomingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1216,7 +1216,7 @@ func TestCheckUsersIncomingWebhooksIntegrity(t *testing.T) {
func TestCheckUsersOAuthAccessDataIntegrity(t *testing.T) { func TestCheckUsersOAuthAccessDataIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1246,7 +1246,7 @@ func TestCheckUsersOAuthAccessDataIntegrity(t *testing.T) {
func TestCheckUsersOAuthAppsIntegrity(t *testing.T) { func TestCheckUsersOAuthAppsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1276,7 +1276,7 @@ func TestCheckUsersOAuthAppsIntegrity(t *testing.T) {
func TestCheckUsersOAuthAuthDataIntegrity(t *testing.T) { func TestCheckUsersOAuthAuthDataIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1306,7 +1306,7 @@ func TestCheckUsersOAuthAuthDataIntegrity(t *testing.T) {
func TestCheckUsersOutgoingWebhooksIntegrity(t *testing.T) { func TestCheckUsersOutgoingWebhooksIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1334,7 +1334,7 @@ func TestCheckUsersOutgoingWebhooksIntegrity(t *testing.T) {
func TestCheckUsersPostsIntegrity(t *testing.T) { func TestCheckUsersPostsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1361,7 +1361,7 @@ func TestCheckUsersPostsIntegrity(t *testing.T) {
func TestCheckUsersPreferencesIntegrity(t *testing.T) { func TestCheckUsersPreferencesIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1390,7 +1390,7 @@ func TestCheckUsersPreferencesIntegrity(t *testing.T) {
func TestCheckUsersReactionsIntegrity(t *testing.T) { func TestCheckUsersReactionsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1419,7 +1419,7 @@ func TestCheckUsersReactionsIntegrity(t *testing.T) {
func TestCheckUsersSessionsIntegrity(t *testing.T) { func TestCheckUsersSessionsIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1447,7 +1447,7 @@ func TestCheckUsersSessionsIntegrity(t *testing.T) {
func TestCheckUsersStatusIntegrity(t *testing.T) { func TestCheckUsersStatusIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1476,7 +1476,7 @@ func TestCheckUsersStatusIntegrity(t *testing.T) {
func TestCheckUsersTeamMembersIntegrity(t *testing.T) { func TestCheckUsersTeamMembersIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {
@@ -1506,7 +1506,7 @@ func TestCheckUsersTeamMembersIntegrity(t *testing.T) {
func TestCheckUsersUserAccessTokensIntegrity(t *testing.T) { func TestCheckUsersUserAccessTokensIntegrity(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
supplier := ss.(*store.LayeredStore).DatabaseLayer.(*SqlSupplier) supplier := ss.(*SqlSupplier)
dbmap := supplier.GetMaster() dbmap := supplier.GetMaster()
t.Run("should generate a report with no records", func(t *testing.T) { t.Run("should generate a report with no records", func(t *testing.T) {

Просмотреть файл

@@ -70,7 +70,7 @@ func initStores() {
go func() { go func() {
defer wg.Done() defer wg.Done()
st.SqlSupplier = NewSqlSupplier(*st.SqlSettings, nil) st.SqlSupplier = NewSqlSupplier(*st.SqlSettings, nil)
st.Store = store.NewLayeredStore(st.SqlSupplier, nil, nil) st.Store = st.SqlSupplier
st.Store.DropAllTables() st.Store.DropAllTables()
st.Store.MarkSystemRanUnitTests() st.Store.MarkSystemRanUnitTests()
}() }()

Просмотреть файл

@@ -67,7 +67,7 @@ const (
EXIT_DOES_COLUMN_EXISTS_SQLITE = 138 EXIT_DOES_COLUMN_EXISTS_SQLITE = 138
) )
type SqlSupplierOldStores struct { type SqlSupplierStores struct {
team store.TeamStore team store.TeamStore
channel store.ChannelStore channel store.ChannelStore
post store.PostStore post store.PostStore
@@ -106,11 +106,10 @@ type SqlSupplier struct {
// See https://github.com/mattermost/mattermost-server/pull/7281 // See https://github.com/mattermost/mattermost-server/pull/7281
rrCounter int64 rrCounter int64
srCounter int64 srCounter int64
next store.LayeredStoreSupplier
master *gorp.DbMap master *gorp.DbMap
replicas []*gorp.DbMap replicas []*gorp.DbMap
searchReplicas []*gorp.DbMap searchReplicas []*gorp.DbMap
oldStores SqlSupplierOldStores stores SqlSupplierStores
settings *model.SqlSettings settings *model.SqlSettings
lockedToMaster bool lockedToMaster bool
} }
@@ -124,37 +123,37 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
supplier.initConnection() supplier.initConnection()
supplier.oldStores.team = NewSqlTeamStore(supplier, metrics) supplier.stores.team = NewSqlTeamStore(supplier, metrics)
supplier.oldStores.channel = NewSqlChannelStore(supplier, metrics) supplier.stores.channel = NewSqlChannelStore(supplier, metrics)
supplier.oldStores.post = NewSqlPostStore(supplier, metrics) supplier.stores.post = NewSqlPostStore(supplier, metrics)
supplier.oldStores.user = NewSqlUserStore(supplier, metrics) supplier.stores.user = NewSqlUserStore(supplier, metrics)
supplier.oldStores.bot = NewSqlBotStore(supplier, metrics) supplier.stores.bot = NewSqlBotStore(supplier, metrics)
supplier.oldStores.audit = NewSqlAuditStore(supplier) supplier.stores.audit = NewSqlAuditStore(supplier)
supplier.oldStores.cluster = NewSqlClusterDiscoveryStore(supplier) supplier.stores.cluster = NewSqlClusterDiscoveryStore(supplier)
supplier.oldStores.compliance = NewSqlComplianceStore(supplier) supplier.stores.compliance = NewSqlComplianceStore(supplier)
supplier.oldStores.session = NewSqlSessionStore(supplier) supplier.stores.session = NewSqlSessionStore(supplier)
supplier.oldStores.oauth = NewSqlOAuthStore(supplier) supplier.stores.oauth = NewSqlOAuthStore(supplier)
supplier.oldStores.system = NewSqlSystemStore(supplier) supplier.stores.system = NewSqlSystemStore(supplier)
supplier.oldStores.webhook = NewSqlWebhookStore(supplier, metrics) supplier.stores.webhook = NewSqlWebhookStore(supplier, metrics)
supplier.oldStores.command = NewSqlCommandStore(supplier) supplier.stores.command = NewSqlCommandStore(supplier)
supplier.oldStores.commandWebhook = NewSqlCommandWebhookStore(supplier) supplier.stores.commandWebhook = NewSqlCommandWebhookStore(supplier)
supplier.oldStores.preference = NewSqlPreferenceStore(supplier) supplier.stores.preference = NewSqlPreferenceStore(supplier)
supplier.oldStores.license = NewSqlLicenseStore(supplier) supplier.stores.license = NewSqlLicenseStore(supplier)
supplier.oldStores.token = NewSqlTokenStore(supplier) supplier.stores.token = NewSqlTokenStore(supplier)
supplier.oldStores.emoji = NewSqlEmojiStore(supplier, metrics) supplier.stores.emoji = NewSqlEmojiStore(supplier, metrics)
supplier.oldStores.status = NewSqlStatusStore(supplier) supplier.stores.status = NewSqlStatusStore(supplier)
supplier.oldStores.fileInfo = NewSqlFileInfoStore(supplier, metrics) supplier.stores.fileInfo = NewSqlFileInfoStore(supplier, metrics)
supplier.oldStores.job = NewSqlJobStore(supplier) supplier.stores.job = NewSqlJobStore(supplier)
supplier.oldStores.userAccessToken = NewSqlUserAccessTokenStore(supplier) supplier.stores.userAccessToken = NewSqlUserAccessTokenStore(supplier)
supplier.oldStores.channelMemberHistory = NewSqlChannelMemberHistoryStore(supplier) supplier.stores.channelMemberHistory = NewSqlChannelMemberHistoryStore(supplier)
supplier.oldStores.plugin = NewSqlPluginStore(supplier) supplier.stores.plugin = NewSqlPluginStore(supplier)
supplier.oldStores.TermsOfService = NewSqlTermsOfServiceStore(supplier, metrics) supplier.stores.TermsOfService = NewSqlTermsOfServiceStore(supplier, metrics)
supplier.oldStores.UserTermsOfService = NewSqlUserTermsOfServiceStore(supplier) supplier.stores.UserTermsOfService = NewSqlUserTermsOfServiceStore(supplier)
supplier.oldStores.linkMetadata = NewSqlLinkMetadataStore(supplier) supplier.stores.linkMetadata = NewSqlLinkMetadataStore(supplier)
supplier.oldStores.reaction = NewSqlReactionStore(supplier) supplier.stores.reaction = NewSqlReactionStore(supplier)
supplier.oldStores.role = NewSqlRoleStore(supplier) supplier.stores.role = NewSqlRoleStore(supplier)
supplier.oldStores.scheme = NewSqlSchemeStore(supplier) supplier.stores.scheme = NewSqlSchemeStore(supplier)
supplier.oldStores.group = NewSqlGroupStore(supplier) supplier.stores.group = NewSqlGroupStore(supplier)
err := supplier.GetMaster().CreateTablesIfNotExists() err := supplier.GetMaster().CreateTablesIfNotExists()
if err != nil { if err != nil {
@@ -170,46 +169,37 @@ func NewSqlSupplier(settings model.SqlSettings, metrics einterfaces.MetricsInter
os.Exit(EXIT_GENERIC_FAILURE) os.Exit(EXIT_GENERIC_FAILURE)
} }
supplier.oldStores.team.(*SqlTeamStore).CreateIndexesIfNotExists() supplier.stores.team.(*SqlTeamStore).CreateIndexesIfNotExists()
supplier.oldStores.channel.(*SqlChannelStore).CreateIndexesIfNotExists() supplier.stores.channel.(*SqlChannelStore).CreateIndexesIfNotExists()
supplier.oldStores.post.(*SqlPostStore).CreateIndexesIfNotExists() supplier.stores.post.(*SqlPostStore).CreateIndexesIfNotExists()
supplier.oldStores.user.(*SqlUserStore).CreateIndexesIfNotExists() supplier.stores.user.(*SqlUserStore).CreateIndexesIfNotExists()
supplier.oldStores.bot.(*SqlBotStore).CreateIndexesIfNotExists() supplier.stores.bot.(*SqlBotStore).CreateIndexesIfNotExists()
supplier.oldStores.audit.(*SqlAuditStore).CreateIndexesIfNotExists() supplier.stores.audit.(*SqlAuditStore).CreateIndexesIfNotExists()
supplier.oldStores.compliance.(*SqlComplianceStore).CreateIndexesIfNotExists() supplier.stores.compliance.(*SqlComplianceStore).CreateIndexesIfNotExists()
supplier.oldStores.session.(*SqlSessionStore).CreateIndexesIfNotExists() supplier.stores.session.(*SqlSessionStore).CreateIndexesIfNotExists()
supplier.oldStores.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists() supplier.stores.oauth.(*SqlOAuthStore).CreateIndexesIfNotExists()
supplier.oldStores.system.(*SqlSystemStore).CreateIndexesIfNotExists() supplier.stores.system.(*SqlSystemStore).CreateIndexesIfNotExists()
supplier.oldStores.webhook.(*SqlWebhookStore).CreateIndexesIfNotExists() supplier.stores.webhook.(*SqlWebhookStore).CreateIndexesIfNotExists()
supplier.oldStores.command.(*SqlCommandStore).CreateIndexesIfNotExists() supplier.stores.command.(*SqlCommandStore).CreateIndexesIfNotExists()
supplier.oldStores.commandWebhook.(*SqlCommandWebhookStore).CreateIndexesIfNotExists() supplier.stores.commandWebhook.(*SqlCommandWebhookStore).CreateIndexesIfNotExists()
supplier.oldStores.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists() supplier.stores.preference.(*SqlPreferenceStore).CreateIndexesIfNotExists()
supplier.oldStores.license.(*SqlLicenseStore).CreateIndexesIfNotExists() supplier.stores.license.(*SqlLicenseStore).CreateIndexesIfNotExists()
supplier.oldStores.token.(*SqlTokenStore).CreateIndexesIfNotExists() supplier.stores.token.(*SqlTokenStore).CreateIndexesIfNotExists()
supplier.oldStores.emoji.(*SqlEmojiStore).CreateIndexesIfNotExists() supplier.stores.emoji.(*SqlEmojiStore).CreateIndexesIfNotExists()
supplier.oldStores.status.(*SqlStatusStore).CreateIndexesIfNotExists() supplier.stores.status.(*SqlStatusStore).CreateIndexesIfNotExists()
supplier.oldStores.fileInfo.(*SqlFileInfoStore).CreateIndexesIfNotExists() supplier.stores.fileInfo.(*SqlFileInfoStore).CreateIndexesIfNotExists()
supplier.oldStores.job.(*SqlJobStore).CreateIndexesIfNotExists() supplier.stores.job.(*SqlJobStore).CreateIndexesIfNotExists()
supplier.oldStores.userAccessToken.(*SqlUserAccessTokenStore).CreateIndexesIfNotExists() supplier.stores.userAccessToken.(*SqlUserAccessTokenStore).CreateIndexesIfNotExists()
supplier.oldStores.plugin.(*SqlPluginStore).CreateIndexesIfNotExists() supplier.stores.plugin.(*SqlPluginStore).CreateIndexesIfNotExists()
supplier.oldStores.TermsOfService.(SqlTermsOfServiceStore).CreateIndexesIfNotExists() supplier.stores.TermsOfService.(SqlTermsOfServiceStore).CreateIndexesIfNotExists()
supplier.oldStores.UserTermsOfService.(SqlUserTermsOfServiceStore).CreateIndexesIfNotExists() supplier.stores.UserTermsOfService.(SqlUserTermsOfServiceStore).CreateIndexesIfNotExists()
supplier.oldStores.linkMetadata.(*SqlLinkMetadataStore).CreateIndexesIfNotExists() supplier.stores.linkMetadata.(*SqlLinkMetadataStore).CreateIndexesIfNotExists()
supplier.oldStores.group.(*SqlGroupStore).CreateIndexesIfNotExists() supplier.stores.group.(*SqlGroupStore).CreateIndexesIfNotExists()
supplier.stores.preference.(*SqlPreferenceStore).DeleteUnusedFeatures()
supplier.oldStores.preference.(*SqlPreferenceStore).DeleteUnusedFeatures()
return supplier return supplier
} }
func (s *SqlSupplier) SetChainNext(next store.LayeredStoreSupplier) {
s.next = next
}
func (s *SqlSupplier) Next() store.LayeredStoreSupplier {
return s.next
}
func setupConnection(con_type string, dataSource string, settings *model.SqlSettings) *gorp.DbMap { func setupConnection(con_type string, dataSource string, settings *model.SqlSettings) *gorp.DbMap {
db, err := dbsql.Open(*settings.DriverName, dataSource) db, err := dbsql.Open(*settings.DriverName, dataSource)
if err != nil { if err != nil {
@@ -930,127 +920,127 @@ func (ss *SqlSupplier) UnlockFromMaster() {
} }
func (ss *SqlSupplier) Team() store.TeamStore { func (ss *SqlSupplier) Team() store.TeamStore {
return ss.oldStores.team return ss.stores.team
} }
func (ss *SqlSupplier) Channel() store.ChannelStore { func (ss *SqlSupplier) Channel() store.ChannelStore {
return ss.oldStores.channel return ss.stores.channel
} }
func (ss *SqlSupplier) Post() store.PostStore { func (ss *SqlSupplier) Post() store.PostStore {
return ss.oldStores.post return ss.stores.post
} }
func (ss *SqlSupplier) User() store.UserStore { func (ss *SqlSupplier) User() store.UserStore {
return ss.oldStores.user return ss.stores.user
} }
func (ss *SqlSupplier) Bot() store.BotStore { func (ss *SqlSupplier) Bot() store.BotStore {
return ss.oldStores.bot return ss.stores.bot
} }
func (ss *SqlSupplier) Session() store.SessionStore { func (ss *SqlSupplier) Session() store.SessionStore {
return ss.oldStores.session return ss.stores.session
} }
func (ss *SqlSupplier) Audit() store.AuditStore { func (ss *SqlSupplier) Audit() store.AuditStore {
return ss.oldStores.audit return ss.stores.audit
} }
func (ss *SqlSupplier) ClusterDiscovery() store.ClusterDiscoveryStore { func (ss *SqlSupplier) ClusterDiscovery() store.ClusterDiscoveryStore {
return ss.oldStores.cluster return ss.stores.cluster
} }
func (ss *SqlSupplier) Compliance() store.ComplianceStore { func (ss *SqlSupplier) Compliance() store.ComplianceStore {
return ss.oldStores.compliance return ss.stores.compliance
} }
func (ss *SqlSupplier) OAuth() store.OAuthStore { func (ss *SqlSupplier) OAuth() store.OAuthStore {
return ss.oldStores.oauth return ss.stores.oauth
} }
func (ss *SqlSupplier) System() store.SystemStore { func (ss *SqlSupplier) System() store.SystemStore {
return ss.oldStores.system return ss.stores.system
} }
func (ss *SqlSupplier) Webhook() store.WebhookStore { func (ss *SqlSupplier) Webhook() store.WebhookStore {
return ss.oldStores.webhook return ss.stores.webhook
} }
func (ss *SqlSupplier) Command() store.CommandStore { func (ss *SqlSupplier) Command() store.CommandStore {
return ss.oldStores.command return ss.stores.command
} }
func (ss *SqlSupplier) CommandWebhook() store.CommandWebhookStore { func (ss *SqlSupplier) CommandWebhook() store.CommandWebhookStore {
return ss.oldStores.commandWebhook return ss.stores.commandWebhook
} }
func (ss *SqlSupplier) Preference() store.PreferenceStore { func (ss *SqlSupplier) Preference() store.PreferenceStore {
return ss.oldStores.preference return ss.stores.preference
} }
func (ss *SqlSupplier) License() store.LicenseStore { func (ss *SqlSupplier) License() store.LicenseStore {
return ss.oldStores.license return ss.stores.license
} }
func (ss *SqlSupplier) Token() store.TokenStore { func (ss *SqlSupplier) Token() store.TokenStore {
return ss.oldStores.token return ss.stores.token
} }
func (ss *SqlSupplier) Emoji() store.EmojiStore { func (ss *SqlSupplier) Emoji() store.EmojiStore {
return ss.oldStores.emoji return ss.stores.emoji
} }
func (ss *SqlSupplier) Status() store.StatusStore { func (ss *SqlSupplier) Status() store.StatusStore {
return ss.oldStores.status return ss.stores.status
} }
func (ss *SqlSupplier) FileInfo() store.FileInfoStore { func (ss *SqlSupplier) FileInfo() store.FileInfoStore {
return ss.oldStores.fileInfo return ss.stores.fileInfo
} }
func (ss *SqlSupplier) Reaction() store.ReactionStore { func (ss *SqlSupplier) Reaction() store.ReactionStore {
return ss.oldStores.reaction return ss.stores.reaction
} }
func (ss *SqlSupplier) Job() store.JobStore { func (ss *SqlSupplier) Job() store.JobStore {
return ss.oldStores.job return ss.stores.job
} }
func (ss *SqlSupplier) UserAccessToken() store.UserAccessTokenStore { func (ss *SqlSupplier) UserAccessToken() store.UserAccessTokenStore {
return ss.oldStores.userAccessToken return ss.stores.userAccessToken
} }
func (ss *SqlSupplier) ChannelMemberHistory() store.ChannelMemberHistoryStore { func (ss *SqlSupplier) ChannelMemberHistory() store.ChannelMemberHistoryStore {
return ss.oldStores.channelMemberHistory return ss.stores.channelMemberHistory
} }
func (ss *SqlSupplier) Plugin() store.PluginStore { func (ss *SqlSupplier) Plugin() store.PluginStore {
return ss.oldStores.plugin return ss.stores.plugin
} }
func (ss *SqlSupplier) Role() store.RoleStore { func (ss *SqlSupplier) Role() store.RoleStore {
return ss.oldStores.role return ss.stores.role
} }
func (ss *SqlSupplier) TermsOfService() store.TermsOfServiceStore { func (ss *SqlSupplier) TermsOfService() store.TermsOfServiceStore {
return ss.oldStores.TermsOfService return ss.stores.TermsOfService
} }
func (ss *SqlSupplier) UserTermsOfService() store.UserTermsOfServiceStore { func (ss *SqlSupplier) UserTermsOfService() store.UserTermsOfServiceStore {
return ss.oldStores.UserTermsOfService return ss.stores.UserTermsOfService
} }
func (ss *SqlSupplier) Scheme() store.SchemeStore { func (ss *SqlSupplier) Scheme() store.SchemeStore {
return ss.oldStores.scheme return ss.stores.scheme
} }
func (ss *SqlSupplier) Group() store.GroupStore { func (ss *SqlSupplier) Group() store.GroupStore {
return ss.oldStores.group return ss.stores.group
} }
func (ss *SqlSupplier) LinkMetadata() store.LinkMetadataStore { func (ss *SqlSupplier) LinkMetadata() store.LinkMetadataStore {
return ss.oldStores.linkMetadata return ss.stores.linkMetadata
} }
func (ss *SqlSupplier) DropAllTables() { func (ss *SqlSupplier) DropAllTables() {

Просмотреть файл

@@ -12,7 +12,7 @@ import (
func TestStoreUpgrade(t *testing.T) { func TestStoreUpgrade(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
sqlStore := ss.(*store.LayeredStore).DatabaseLayer.(SqlStore) sqlStore := ss.(SqlStore)
t.Run("invalid currentModelVersion", func(t *testing.T) { t.Run("invalid currentModelVersion", func(t *testing.T) {
err := UpgradeDatabase(sqlStore, "notaversion") err := UpgradeDatabase(sqlStore, "notaversion")
@@ -81,7 +81,7 @@ func TestStoreUpgrade(t *testing.T) {
func TestSaveSchemaVersion(t *testing.T) { func TestSaveSchemaVersion(t *testing.T) {
StoreTest(t, func(t *testing.T, ss store.Store) { StoreTest(t, func(t *testing.T, ss store.Store) {
sqlStore := ss.(*store.LayeredStore).DatabaseLayer.(SqlStore) sqlStore := ss.(SqlStore)
t.Run("set earliest version", func(t *testing.T) { t.Run("set earliest version", func(t *testing.T) {
saveSchemaVersion(sqlStore, VERSION_3_0_0) saveSchemaVersion(sqlStore, VERSION_3_0_0)

Просмотреть файл

@@ -30,33 +30,26 @@ func testEmojiSaveDelete(t *testing.T, ss store.Store) {
Name: model.NewId(), Name: model.NewId(),
} }
if _, err := ss.Emoji().Save(emoji1); err != nil { _, err := ss.Emoji().Save(emoji1)
t.Fatal(err) require.Nil(t, err)
}
if len(emoji1.Id) != 26 { assert.Len(t, emoji1.Id, 26, "should've set id for emoji")
t.Fatal("should've set id for emoji")
}
emoji2 := model.Emoji{ emoji2 := model.Emoji{
CreatorId: model.NewId(), CreatorId: model.NewId(),
Name: emoji1.Name, Name: emoji1.Name,
} }
if _, err := ss.Emoji().Save(&emoji2); err == nil { _, err = ss.Emoji().Save(&emoji2)
t.Fatal("shouldn't be able to save emoji with duplicate name") require.NotNil(t, err, "shouldn't be able to save emoji with duplicate name")
}
if err := ss.Emoji().Delete(emoji1, time.Now().Unix()); err != nil { err = ss.Emoji().Delete(emoji1, time.Now().Unix())
t.Fatal(err) require.Nil(t, err)
}
if _, err := ss.Emoji().Save(&emoji2); err != nil { _, err = ss.Emoji().Save(&emoji2)
t.Fatal("should be able to save emoji with duplicate name now that original has been deleted", err) require.Nil(t, err, "should be able to save emoji with duplicate name now that original has been deleted")
}
if err := ss.Emoji().Delete(&emoji2, time.Now().Unix()+1); err != nil { err = ss.Emoji().Delete(&emoji2, time.Now().Unix()+1)
t.Fatal(err) require.Nil(t, err)
}
} }
func testEmojiGet(t *testing.T, ss store.Store) { func testEmojiGet(t *testing.T, ss store.Store) {
@@ -88,15 +81,13 @@ func testEmojiGet(t *testing.T, ss store.Store) {
}() }()
for _, emoji := range emojis { for _, emoji := range emojis {
if _, err := ss.Emoji().Get(emoji.Id, false); err != nil { _, err := ss.Emoji().Get(emoji.Id, false)
t.Fatalf("failed to get emoji with id %v: %v", emoji.Id, err) require.Nilf(t, err, "failed to get emoji with id %v", emoji.Id)
}
} }
for _, emoji := range emojis { for _, emoji := range emojis {
if _, err := ss.Emoji().Get(emoji.Id, true); err != nil { _, err := ss.Emoji().Get(emoji.Id, true)
t.Fatalf("failed to get emoji with id %v: %v", emoji.Id, err) require.Nilf(t, err, "failed to get emoji with id %v", emoji.Id)
}
} }
} }
@@ -184,9 +175,8 @@ func testEmojiGetByName(t *testing.T, ss store.Store) {
}() }()
for _, emoji := range emojis { for _, emoji := range emojis {
if _, err := ss.Emoji().GetByName(emoji.Name, true); err != nil { _, err := ss.Emoji().GetByName(emoji.Name, true)
t.Fatalf("failed to get emoji with name %v: %v", emoji.Name, err) require.Nilf(t, err, "failed to get emoji with name %v", emoji.Name)
}
} }
} }
@@ -219,35 +209,28 @@ func testEmojiGetMultipleByName(t *testing.T, ss store.Store) {
}() }()
t.Run("one emoji", func(t *testing.T) { t.Run("one emoji", func(t *testing.T) {
if received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name}); err != nil { received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name})
t.Fatal("could not get emoji", err) require.Nilf(t, err, "could not get emoji")
} else if len(received) != 1 || *received[0] != emojis[0] { require.Len(t, received, 1, "got incorrect emoji")
t.Fatal("got incorrect emoji") require.Equal(t, *received[0], emojis[0], "got incorrect emoji")
}
}) })
t.Run("multiple emojis", func(t *testing.T) { t.Run("multiple emojis", func(t *testing.T) {
if received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name, emojis[1].Name, emojis[2].Name}); err != nil { received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name, emojis[1].Name, emojis[2].Name})
t.Fatal("could not get emojis", err) require.Nil(t, err, "could not get emojis")
} else if len(received) != 3 { require.Len(t, received, 3, "got incorrect emojis")
t.Fatal("got incorrect emojis")
}
}) })
t.Run("one nonexistent emoji", func(t *testing.T) { t.Run("one nonexistent emoji", func(t *testing.T) {
if received, err := ss.Emoji().GetMultipleByName([]string{"ab"}); err != nil { received, err := ss.Emoji().GetMultipleByName([]string{"ab"})
t.Fatal("could not get emoji", err) require.Nilf(t, err, "%v, could not get emoji", err)
} else if len(received) != 0 { require.Len(t, received, 0, "got incorrect emoji")
t.Fatal("got incorrect emoji")
}
}) })
t.Run("multiple emojis with nonexistent names", func(t *testing.T) { t.Run("multiple emojis with nonexistent names", func(t *testing.T) {
if received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name, emojis[1].Name, emojis[2].Name, "abcd", "1234"}); err != nil { received, err := ss.Emoji().GetMultipleByName([]string{emojis[0].Name, emojis[1].Name, emojis[2].Name, "abcd", "1234"})
t.Fatal("could not get emojis", err) require.Nil(t, err, "could not get emojis")
} else if len(received) != 3 { require.Len(t, received, 3, "got incorrect emojis")
t.Fatal("got incorrect emojis")
}
}) })
} }
@@ -292,9 +275,7 @@ func testEmojiGetList(t *testing.T, ss store.Store) {
} }
} }
if !found { require.Truef(t, found, "failed to get emoji with id %v", emoji.Id)
t.Fatalf("failed to get emoji with id %v", emoji.Id)
}
} }
} }
@@ -347,38 +328,34 @@ func testEmojiSearch(t *testing.T, ss store.Store) {
shouldFind := []bool{true, false, false, false} shouldFind := []bool{true, false, false, false}
if result, err := ss.Emoji().Search("blargh", true, 100); err != nil { result, err := ss.Emoji().Search("blargh", true, 100)
t.Fatal(err) require.Nil(t, err)
} else { for i, emoji := range emojis {
for i, emoji := range emojis { found := false
found := false
for _, savedEmoji := range result { for _, savedEmoji := range result {
if emoji.Id == savedEmoji.Id { if emoji.Id == savedEmoji.Id {
found = true found = true
break break
}
} }
assert.Equal(t, shouldFind[i], found, emoji.Name)
} }
assert.Equal(t, shouldFind[i], found, emoji.Name)
} }
shouldFind = []bool{true, true, true, false} shouldFind = []bool{true, true, true, false}
if result, err := ss.Emoji().Search("blargh", false, 100); err != nil { result, err = ss.Emoji().Search("blargh", false, 100)
t.Fatal(err) require.Nil(t, err)
} else { for i, emoji := range emojis {
for i, emoji := range emojis { found := false
found := false
for _, savedEmoji := range result { for _, savedEmoji := range result {
if emoji.Id == savedEmoji.Id { if emoji.Id == savedEmoji.Id {
found = true found = true
break break
}
} }
assert.Equal(t, shouldFind[i], found, emoji.Name)
} }
assert.Equal(t, shouldFind[i], found, emoji.Name)
} }
} }

Просмотреть файл

@@ -1,629 +0,0 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.
package mocks
import (
store "github.com/mattermost/mattermost-server/store"
mock "github.com/stretchr/testify/mock"
)
// LayeredStoreDatabaseLayer is an autogenerated mock type for the LayeredStoreDatabaseLayer type
type LayeredStoreDatabaseLayer struct {
mock.Mock
}
// Audit provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Audit() store.AuditStore {
ret := _m.Called()
var r0 store.AuditStore
if rf, ok := ret.Get(0).(func() store.AuditStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.AuditStore)
}
}
return r0
}
// Bot provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Bot() store.BotStore {
ret := _m.Called()
var r0 store.BotStore
if rf, ok := ret.Get(0).(func() store.BotStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.BotStore)
}
}
return r0
}
// Channel provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Channel() store.ChannelStore {
ret := _m.Called()
var r0 store.ChannelStore
if rf, ok := ret.Get(0).(func() store.ChannelStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ChannelStore)
}
}
return r0
}
// ChannelMemberHistory provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) ChannelMemberHistory() store.ChannelMemberHistoryStore {
ret := _m.Called()
var r0 store.ChannelMemberHistoryStore
if rf, ok := ret.Get(0).(func() store.ChannelMemberHistoryStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ChannelMemberHistoryStore)
}
}
return r0
}
// CheckIntegrity provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) CheckIntegrity() <-chan store.IntegrityCheckResult {
ret := _m.Called()
var r0 <-chan store.IntegrityCheckResult
if rf, ok := ret.Get(0).(func() <-chan store.IntegrityCheckResult); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(<-chan store.IntegrityCheckResult)
}
}
return r0
}
// Close provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Close() {
_m.Called()
}
// ClusterDiscovery provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) ClusterDiscovery() store.ClusterDiscoveryStore {
ret := _m.Called()
var r0 store.ClusterDiscoveryStore
if rf, ok := ret.Get(0).(func() store.ClusterDiscoveryStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ClusterDiscoveryStore)
}
}
return r0
}
// Command provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Command() store.CommandStore {
ret := _m.Called()
var r0 store.CommandStore
if rf, ok := ret.Get(0).(func() store.CommandStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.CommandStore)
}
}
return r0
}
// CommandWebhook provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) CommandWebhook() store.CommandWebhookStore {
ret := _m.Called()
var r0 store.CommandWebhookStore
if rf, ok := ret.Get(0).(func() store.CommandWebhookStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.CommandWebhookStore)
}
}
return r0
}
// Compliance provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Compliance() store.ComplianceStore {
ret := _m.Called()
var r0 store.ComplianceStore
if rf, ok := ret.Get(0).(func() store.ComplianceStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ComplianceStore)
}
}
return r0
}
// DropAllTables provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) DropAllTables() {
_m.Called()
}
// Emoji provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Emoji() store.EmojiStore {
ret := _m.Called()
var r0 store.EmojiStore
if rf, ok := ret.Get(0).(func() store.EmojiStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.EmojiStore)
}
}
return r0
}
// FileInfo provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) FileInfo() store.FileInfoStore {
ret := _m.Called()
var r0 store.FileInfoStore
if rf, ok := ret.Get(0).(func() store.FileInfoStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.FileInfoStore)
}
}
return r0
}
// GetCurrentSchemaVersion provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) GetCurrentSchemaVersion() string {
ret := _m.Called()
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// Group provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Group() store.GroupStore {
ret := _m.Called()
var r0 store.GroupStore
if rf, ok := ret.Get(0).(func() store.GroupStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.GroupStore)
}
}
return r0
}
// Job provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Job() store.JobStore {
ret := _m.Called()
var r0 store.JobStore
if rf, ok := ret.Get(0).(func() store.JobStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.JobStore)
}
}
return r0
}
// License provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) License() store.LicenseStore {
ret := _m.Called()
var r0 store.LicenseStore
if rf, ok := ret.Get(0).(func() store.LicenseStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.LicenseStore)
}
}
return r0
}
// LinkMetadata provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) LinkMetadata() store.LinkMetadataStore {
ret := _m.Called()
var r0 store.LinkMetadataStore
if rf, ok := ret.Get(0).(func() store.LinkMetadataStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.LinkMetadataStore)
}
}
return r0
}
// LockToMaster provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) LockToMaster() {
_m.Called()
}
// MarkSystemRanUnitTests provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) MarkSystemRanUnitTests() {
_m.Called()
}
// Next provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Next() store.LayeredStoreSupplier {
ret := _m.Called()
var r0 store.LayeredStoreSupplier
if rf, ok := ret.Get(0).(func() store.LayeredStoreSupplier); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.LayeredStoreSupplier)
}
}
return r0
}
// OAuth provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) OAuth() store.OAuthStore {
ret := _m.Called()
var r0 store.OAuthStore
if rf, ok := ret.Get(0).(func() store.OAuthStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.OAuthStore)
}
}
return r0
}
// Plugin provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Plugin() store.PluginStore {
ret := _m.Called()
var r0 store.PluginStore
if rf, ok := ret.Get(0).(func() store.PluginStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.PluginStore)
}
}
return r0
}
// Post provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Post() store.PostStore {
ret := _m.Called()
var r0 store.PostStore
if rf, ok := ret.Get(0).(func() store.PostStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.PostStore)
}
}
return r0
}
// Preference provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Preference() store.PreferenceStore {
ret := _m.Called()
var r0 store.PreferenceStore
if rf, ok := ret.Get(0).(func() store.PreferenceStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.PreferenceStore)
}
}
return r0
}
// Reaction provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Reaction() store.ReactionStore {
ret := _m.Called()
var r0 store.ReactionStore
if rf, ok := ret.Get(0).(func() store.ReactionStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.ReactionStore)
}
}
return r0
}
// Role provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Role() store.RoleStore {
ret := _m.Called()
var r0 store.RoleStore
if rf, ok := ret.Get(0).(func() store.RoleStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.RoleStore)
}
}
return r0
}
// Scheme provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Scheme() store.SchemeStore {
ret := _m.Called()
var r0 store.SchemeStore
if rf, ok := ret.Get(0).(func() store.SchemeStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SchemeStore)
}
}
return r0
}
// Session provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Session() store.SessionStore {
ret := _m.Called()
var r0 store.SessionStore
if rf, ok := ret.Get(0).(func() store.SessionStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SessionStore)
}
}
return r0
}
// SetChainNext provides a mock function with given fields: _a0
func (_m *LayeredStoreDatabaseLayer) SetChainNext(_a0 store.LayeredStoreSupplier) {
_m.Called(_a0)
}
// Status provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Status() store.StatusStore {
ret := _m.Called()
var r0 store.StatusStore
if rf, ok := ret.Get(0).(func() store.StatusStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.StatusStore)
}
}
return r0
}
// System provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) System() store.SystemStore {
ret := _m.Called()
var r0 store.SystemStore
if rf, ok := ret.Get(0).(func() store.SystemStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.SystemStore)
}
}
return r0
}
// Team provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Team() store.TeamStore {
ret := _m.Called()
var r0 store.TeamStore
if rf, ok := ret.Get(0).(func() store.TeamStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.TeamStore)
}
}
return r0
}
// TermsOfService provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) TermsOfService() store.TermsOfServiceStore {
ret := _m.Called()
var r0 store.TermsOfServiceStore
if rf, ok := ret.Get(0).(func() store.TermsOfServiceStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.TermsOfServiceStore)
}
}
return r0
}
// Token provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Token() store.TokenStore {
ret := _m.Called()
var r0 store.TokenStore
if rf, ok := ret.Get(0).(func() store.TokenStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.TokenStore)
}
}
return r0
}
// TotalMasterDbConnections provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) TotalMasterDbConnections() int {
ret := _m.Called()
var r0 int
if rf, ok := ret.Get(0).(func() int); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int)
}
return r0
}
// TotalReadDbConnections provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) TotalReadDbConnections() int {
ret := _m.Called()
var r0 int
if rf, ok := ret.Get(0).(func() int); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int)
}
return r0
}
// TotalSearchDbConnections provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) TotalSearchDbConnections() int {
ret := _m.Called()
var r0 int
if rf, ok := ret.Get(0).(func() int); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(int)
}
return r0
}
// UnlockFromMaster provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) UnlockFromMaster() {
_m.Called()
}
// User provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) User() store.UserStore {
ret := _m.Called()
var r0 store.UserStore
if rf, ok := ret.Get(0).(func() store.UserStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.UserStore)
}
}
return r0
}
// UserAccessToken provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) UserAccessToken() store.UserAccessTokenStore {
ret := _m.Called()
var r0 store.UserAccessTokenStore
if rf, ok := ret.Get(0).(func() store.UserAccessTokenStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.UserAccessTokenStore)
}
}
return r0
}
// UserTermsOfService provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) UserTermsOfService() store.UserTermsOfServiceStore {
ret := _m.Called()
var r0 store.UserTermsOfServiceStore
if rf, ok := ret.Get(0).(func() store.UserTermsOfServiceStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.UserTermsOfServiceStore)
}
}
return r0
}
// Webhook provides a mock function with given fields:
func (_m *LayeredStoreDatabaseLayer) Webhook() store.WebhookStore {
ret := _m.Called()
var r0 store.WebhookStore
if rf, ok := ret.Get(0).(func() store.WebhookStore); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.WebhookStore)
}
}
return r0
}

Просмотреть файл

@@ -1,36 +0,0 @@
// Code generated by mockery v1.0.0. DO NOT EDIT.
// Regenerate this file using `make store-mocks`.
package mocks
import (
store "github.com/mattermost/mattermost-server/store"
mock "github.com/stretchr/testify/mock"
)
// LayeredStoreSupplier is an autogenerated mock type for the LayeredStoreSupplier type
type LayeredStoreSupplier struct {
mock.Mock
}
// Next provides a mock function with given fields:
func (_m *LayeredStoreSupplier) Next() store.LayeredStoreSupplier {
ret := _m.Called()
var r0 store.LayeredStoreSupplier
if rf, ok := ret.Get(0).(func() store.LayeredStoreSupplier); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(store.LayeredStoreSupplier)
}
}
return r0
}
// SetChainNext provides a mock function with given fields: _a0
func (_m *LayeredStoreSupplier) SetChainNext(_a0 store.LayeredStoreSupplier) {
_m.Called(_a0)
}

Просмотреть файл

@@ -69,18 +69,15 @@ func testTeamStoreSave(t *testing.T, ss store.Store) {
o1.Email = MakeEmail() o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN o1.Type = model.TEAM_OPEN
if _, err := ss.Team().Save(&o1); err != nil { _, err := ss.Team().Save(&o1)
t.Fatal("couldn't save item", err) require.Nil(t, err, "couldn't save item")
}
if _, err := ss.Team().Save(&o1); err == nil { _, err = ss.Team().Save(&o1)
t.Fatal("shouldn't be able to update from save") require.NotNil(t, err, "shouldn't be able to update from save")
}
o1.Id = "" o1.Id = ""
if _, err := ss.Team().Save(&o1); err == nil { _, err = ss.Team().Save(&o1)
t.Fatal("should be unique domain") require.NotNil(t, err, "should be unique domain")
}
} }
func testTeamStoreUpdate(t *testing.T, ss store.Store) { func testTeamStoreUpdate(t *testing.T, ss store.Store) {
@@ -89,25 +86,21 @@ func testTeamStoreUpdate(t *testing.T, ss store.Store) {
o1.Name = "z-z-z" + model.NewId() + "b" o1.Name = "z-z-z" + model.NewId() + "b"
o1.Email = MakeEmail() o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN o1.Type = model.TEAM_OPEN
if _, err := ss.Team().Save(&o1); err != nil { _, err := ss.Team().Save(&o1)
t.Fatal(err) require.Nil(t, err)
}
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
if _, err := ss.Team().Update(&o1); err != nil { _, err = ss.Team().Update(&o1)
t.Fatal(err) require.Nil(t, err)
}
o1.Id = "missing" o1.Id = "missing"
if _, err := ss.Team().Update(&o1); err == nil { _, err = ss.Team().Update(&o1)
t.Fatal("Update should have failed because of missing key") require.NotNil(t, err, "Update should have failed because of missing key")
}
o1.Id = model.NewId() o1.Id = model.NewId()
if _, err := ss.Team().Update(&o1); err == nil { _, err = ss.Team().Update(&o1)
t.Fatal("Update should have faile because id change") require.NotNil(t, err, "Update should have faile because id change")
}
} }
func testTeamStoreGet(t *testing.T, ss store.Store) { func testTeamStoreGet(t *testing.T, ss store.Store) {
@@ -134,21 +127,15 @@ func testTeamStoreGetByName(t *testing.T, ss store.Store) {
o1.Email = MakeEmail() o1.Email = MakeEmail()
o1.Type = model.TEAM_OPEN o1.Type = model.TEAM_OPEN
if _, err := ss.Team().Save(&o1); err != nil { _, err := ss.Team().Save(&o1)
t.Fatal(err) require.Nil(t, err)
}
if team, err := ss.Team().GetByName(o1.Name); err != nil { team, err := ss.Team().GetByName(o1.Name)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, *team, o1, "invalid returned team")
if team.ToJson() != o1.ToJson() {
t.Fatal("invalid returned team")
}
}
if _, err := ss.Team().GetByName(""); err == nil { _, err = ss.Team().GetByName("")
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testTeamStoreSearchAll(t *testing.T, ss store.Store) { func testTeamStoreSearchAll(t *testing.T, ss store.Store) {
@@ -363,9 +350,7 @@ func testTeamStoreGetByInviteId(t *testing.T, ss store.Store) {
o1.InviteId = model.NewId() o1.InviteId = model.NewId()
save1, err := ss.Team().Save(&o1) save1, err := ss.Team().Save(&o1)
if err != nil { require.Nil(t, err)
t.Fatal(err)
}
o2 := model.Team{} o2 := model.Team{}
o2.DisplayName = "DisplayName" o2.DisplayName = "DisplayName"
@@ -373,17 +358,12 @@ func testTeamStoreGetByInviteId(t *testing.T, ss store.Store) {
o2.Email = MakeEmail() o2.Email = MakeEmail()
o2.Type = model.TEAM_OPEN o2.Type = model.TEAM_OPEN
if r1, err := ss.Team().GetByInviteId(save1.InviteId); err != nil { r1, err := ss.Team().GetByInviteId(save1.InviteId)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, *r1, o1, "invalid returned team")
if r1.ToJson() != o1.ToJson() {
t.Fatal("invalid returned team")
}
}
if _, err := ss.Team().GetByInviteId(""); err == nil { _, err = ss.Team().GetByInviteId("")
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testTeamStoreByUserId(t *testing.T, ss store.Store) { func testTeamStoreByUserId(t *testing.T, ss store.Store) {
@@ -400,18 +380,10 @@ func testTeamStoreByUserId(t *testing.T, ss store.Store) {
_, err = ss.Team().SaveMember(m1, -1) _, err = ss.Team().SaveMember(m1, -1)
require.Nil(t, err) require.Nil(t, err)
if teams, err := ss.Team().GetTeamsByUserId(m1.UserId); err != nil { teams, err := ss.Team().GetTeamsByUserId(m1.UserId)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, teams, 1, "Should return a team")
if len(teams) == 0 { require.Equal(t, teams[0].Id, o1.Id, "should be a member")
t.Fatal("Should return a team")
}
if teams[0].Id != o1.Id {
t.Fatal("should be a member")
}
}
} }
func testGetAllTeamListing(t *testing.T, ss store.Store) { func testGetAllTeamListing(t *testing.T, ss store.Store) {
@@ -449,19 +421,13 @@ func testGetAllTeamListing(t *testing.T, ss store.Store) {
_, err = ss.Team().Save(&o4) _, err = ss.Team().Save(&o4)
require.Nil(t, err) require.Nil(t, err)
if teams, err := ss.Team().GetAllTeamListing(); err != nil { teams, err := ss.Team().GetAllTeamListing()
t.Fatal(err) require.Nil(t, err)
} else { for _, team := range teams {
for _, team := range teams { require.True(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as true")
if !team.AllowOpenInvite {
t.Fatal("should have returned team with AllowOpenInvite as true")
}
}
if len(teams) == 0 {
t.Fatal("failed team listing")
}
} }
require.NotEmpty(t, teams, "failed team listing")
} }
func testGetAllTeamPageListing(t *testing.T, ss store.Store) { func testGetAllTeamPageListing(t *testing.T, ss store.Store) {
@@ -505,14 +471,10 @@ func testGetAllTeamPageListing(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
for _, team := range teams { for _, team := range teams {
if !team.AllowOpenInvite { require.True(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as true")
t.Fatal("should have returned team with AllowOpenInvite as true")
}
} }
if len(teams) > 10 { require.LessOrEqual(t, len(teams), 10, "should have returned max of 10 teams")
t.Fatal("should have returned max of 10 teams")
}
o5 := model.Team{} o5 := model.Team{}
o5.DisplayName = "DisplayName" o5.DisplayName = "DisplayName"
@@ -527,27 +489,19 @@ func testGetAllTeamPageListing(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
for _, team := range teams { for _, team := range teams {
if !team.AllowOpenInvite { require.True(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as true")
t.Fatal("should have returned team with AllowOpenInvite as true")
}
} }
if len(teams) > 4 { require.LessOrEqual(t, len(teams), 4, "should have returned max of 4 teams")
t.Fatal("should have returned max of 4 teams")
}
teams, err = ss.Team().GetAllTeamPageListing(1, 1) teams, err = ss.Team().GetAllTeamPageListing(1, 1)
require.Nil(t, err) require.Nil(t, err)
for _, team := range teams { for _, team := range teams {
if !team.AllowOpenInvite { require.True(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as true")
t.Fatal("should have returned team with AllowOpenInvite as true")
}
} }
if len(teams) > 1 { require.LessOrEqual(t, len(teams), 1, "should have returned max of 1 team")
t.Fatal("should have returned max of 1 team")
}
} }
func testGetAllPrivateTeamListing(t *testing.T, ss store.Store) { func testGetAllPrivateTeamListing(t *testing.T, ss store.Store) {
@@ -585,18 +539,12 @@ func testGetAllPrivateTeamListing(t *testing.T, ss store.Store) {
_, err = ss.Team().Save(&o4) _, err = ss.Team().Save(&o4)
require.Nil(t, err) require.Nil(t, err)
if teams, err := ss.Team().GetAllPrivateTeamListing(); err != nil { teams, err := ss.Team().GetAllPrivateTeamListing()
t.Fatal(err) require.Nil(t, err)
} else { require.NotEmpty(t, teams, "failed team listing")
for _, team := range teams {
if team.AllowOpenInvite {
t.Fatal("should have returned team with AllowOpenInvite as false")
}
}
if len(teams) == 0 { for _, team := range teams {
t.Fatal("failed team listing") require.False(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as false")
}
} }
} }
@@ -637,20 +585,14 @@ func testGetAllPrivateTeamPageListing(t *testing.T, ss store.Store) {
_, err = ss.Team().Save(&o4) _, err = ss.Team().Save(&o4)
require.Nil(t, err) require.Nil(t, err)
if teams, listErr := ss.Team().GetAllPrivateTeamPageListing(0, 10); listErr != nil { teams, listErr := ss.Team().GetAllPrivateTeamPageListing(0, 10)
t.Fatal(listErr) require.Nil(t, listErr)
} else { for _, team := range teams {
for _, team := range teams { require.False(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as false")
if team.AllowOpenInvite {
t.Fatal("should have returned team with AllowOpenInvite as false")
}
}
if len(teams) > 10 {
t.Fatal("should have returned max of 10 teams")
}
} }
require.LessOrEqual(t, len(teams), 10, "should have returned max of 10 teams")
o5 := model.Team{} o5 := model.Team{}
o5.DisplayName = "DisplayName" o5.DisplayName = "DisplayName"
o5.Name = "z-z-z" + model.NewId() + "b" o5.Name = "z-z-z" + model.NewId() + "b"
@@ -660,33 +602,21 @@ func testGetAllPrivateTeamPageListing(t *testing.T, ss store.Store) {
_, err = ss.Team().Save(&o5) _, err = ss.Team().Save(&o5)
require.Nil(t, err) require.Nil(t, err)
if teams, listErr := ss.Team().GetAllPrivateTeamPageListing(0, 4); listErr != nil { teams, listErr = ss.Team().GetAllPrivateTeamPageListing(0, 4)
t.Fatal(listErr) require.Nil(t, listErr)
} else { for _, team := range teams {
for _, team := range teams { require.False(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as false")
if team.AllowOpenInvite {
t.Fatal("should have returned team with AllowOpenInvite as false")
}
}
if len(teams) > 4 {
t.Fatal("should have returned max of 4 teams")
}
} }
if teams, listErr := ss.Team().GetAllPrivateTeamPageListing(1, 1); listErr != nil { require.LessOrEqual(t, len(teams), 4, "should have returned max of 4 teams")
t.Fatal(listErr)
} else {
for _, team := range teams {
if team.AllowOpenInvite {
t.Fatal("should have returned team with AllowOpenInvite as false")
}
}
if len(teams) > 1 { teams, listErr = ss.Team().GetAllPrivateTeamPageListing(1, 1)
t.Fatal("should have returned max of 1 team") require.Nil(t, listErr)
} for _, team := range teams {
require.False(t, team.AllowOpenInvite, "should have returned team with AllowOpenInvite as false")
} }
require.LessOrEqual(t, len(teams), 1, "should have returned max of 1 team")
} }
func testGetAllPublicTeamPageListing(t *testing.T, ss store.Store) { func testGetAllPublicTeamPageListing(t *testing.T, ss store.Store) {
@@ -767,9 +697,8 @@ func testDelete(t *testing.T, ss store.Store) {
_, err = ss.Team().Save(&o2) _, err = ss.Team().Save(&o2)
require.Nil(t, err) require.Nil(t, err)
if r1 := ss.Team().PermanentDelete(o1.Id); r1 != nil { r1 := ss.Team().PermanentDelete(o1.Id)
t.Fatal(r1) require.Nil(t, r1)
}
} }
func testPublicTeamCount(t *testing.T, ss store.Store) { func testPublicTeamCount(t *testing.T, ss store.Store) {
@@ -852,13 +781,9 @@ func testTeamCount(t *testing.T, ss store.Store) {
_, err := ss.Team().Save(&o1) _, err := ss.Team().Save(&o1)
require.Nil(t, err) require.Nil(t, err)
if teamCount, err := ss.Team().AnalyticsTeamCount(); err != nil { teamCount, err := ss.Team().AnalyticsTeamCount()
t.Fatal(err) require.Nil(t, err)
} else { require.NotEqual(t, 0, int(teamCount), "should be at least 1 team")
if teamCount == 0 {
t.Fatal("should be at least 1 team")
}
}
} }
func testTeamMembers(t *testing.T, ss store.Store) { func testTeamMembers(t *testing.T, ss store.Store) {
@@ -880,47 +805,33 @@ func testTeamMembers(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
assert.Len(t, ms, 2) assert.Len(t, ms, 2)
if ms, err = ss.Team().GetMembers(teamId2, 0, 100, nil); err != nil { ms, err = ss.Team().GetMembers(teamId2, 0, 100, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, ms, 1)
require.Equal(t, m3.UserId, ms[0].UserId)
require.Len(t, ms, 1) ms, err = ss.Team().GetTeamsForUser(m1.UserId)
require.Equal(t, m3.UserId, ms[0].UserId) require.Nil(t, err)
} require.Len(t, ms, 1)
require.Equal(t, m1.TeamId, ms[0].TeamId)
if ms, err = ss.Team().GetTeamsForUser(m1.UserId); err != nil { err = ss.Team().RemoveMember(teamId1, m1.UserId)
t.Fatal(err) require.Nil(t, err)
} else {
require.Len(t, ms, 1) ms, err = ss.Team().GetMembers(teamId1, 0, 100, nil)
require.Equal(t, m1.TeamId, ms[0].TeamId) require.Nil(t, err)
} require.Len(t, ms, 1)
require.Equal(t, m2.UserId, ms[0].UserId)
if err = ss.Team().RemoveMember(teamId1, m1.UserId); err != nil {
t.Fatal(err)
}
if ms, err = ss.Team().GetMembers(teamId1, 0, 100, nil); err != nil {
t.Fatal(err)
} else {
require.Len(t, ms, 1)
require.Equal(t, m2.UserId, ms[0].UserId)
}
_, err = ss.Team().SaveMember(m1, -1) _, err = ss.Team().SaveMember(m1, -1)
require.Nil(t, err) require.Nil(t, err)
if err = ss.Team().RemoveAllMembersByTeam(teamId1); err != nil { err = ss.Team().RemoveAllMembersByTeam(teamId1)
t.Fatal(err) require.Nil(t, err)
}
if ms, err = ss.Team().GetMembers(teamId1, 0, 100, nil); err != nil { ms, err = ss.Team().GetMembers(teamId1, 0, 100, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, ms, 0)
require.Len(t, ms, 0)
}
uid := model.NewId() uid := model.NewId()
m4 := &model.TeamMember{TeamId: teamId1, UserId: uid} m4 := &model.TeamMember{TeamId: teamId1, UserId: uid}
@@ -930,23 +841,16 @@ func testTeamMembers(t *testing.T, ss store.Store) {
_, err = ss.Team().SaveMember(m5, -1) _, err = ss.Team().SaveMember(m5, -1)
require.Nil(t, err) require.Nil(t, err)
if ms, err = ss.Team().GetTeamsForUser(uid); err != nil { ms, err = ss.Team().GetTeamsForUser(uid)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, ms, 2)
require.Len(t, ms, 2) err = ss.Team().RemoveAllMembersByUser(uid)
} require.Nil(t, err)
if err = ss.Team().RemoveAllMembersByUser(uid); err != nil { ms, err = ss.Team().GetTeamsForUser(m1.UserId)
t.Fatal(err) require.Nil(t, err)
} require.Len(t, ms, 0)
if ms, err = ss.Team().GetTeamsForUser(m1.UserId); err != nil {
t.Fatal(err)
} else {
require.Len(t, ms, 0)
}
} }
func testTeamMembersWithPagination(t *testing.T, ss store.Store) { func testTeamMembersWithPagination(t *testing.T, ss store.Store) {
@@ -1044,11 +948,9 @@ func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
}(userIds[i]) }(userIds[i])
} }
if totalMemberCount, err := ss.Team().GetTotalMemberCount(team.Id, nil); err != nil { totalMemberCount, err := ss.Team().GetTotalMemberCount(team.Id, nil)
t.Fatal(err) require.Nil(t, err)
} else if int(totalMemberCount) != maxUsersPerTeam { require.Equal(t, int(totalMemberCount), maxUsersPerTeam, "should start with 5 team members, had %v instead", totalMemberCount)
t.Fatalf("should start with 5 team members, had %v instead", totalMemberCount)
}
user, err := ss.User().Save(&model.User{ user, err := ss.User().Save(&model.User{
Username: model.NewId(), Username: model.NewId(),
@@ -1060,47 +962,36 @@ func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
ss.User().PermanentDelete(newUserId) ss.User().PermanentDelete(newUserId)
}() }()
if _, err = ss.Team().SaveMember(&model.TeamMember{ _, err = ss.Team().SaveMember(&model.TeamMember{
TeamId: team.Id, TeamId: team.Id,
UserId: newUserId, UserId: newUserId,
}, maxUsersPerTeam); err == nil { }, maxUsersPerTeam)
t.Fatal("shouldn't be able to save member when at maximum members per team") require.NotNil(t, err, "shouldn't be able to save member when at maximum members per team")
}
if totalMemberCount, teamErr := ss.Team().GetTotalMemberCount(team.Id, nil); teamErr != nil { totalMemberCount, teamErr := ss.Team().GetTotalMemberCount(team.Id, nil)
t.Fatal(teamErr) require.Nil(t, teamErr)
} else if int(totalMemberCount) != maxUsersPerTeam { require.Equal(t, maxUsersPerTeam, int(totalMemberCount), "should still have 5 team members, had %v instead", totalMemberCount)
t.Fatalf("should still have 5 team members, had %v instead", totalMemberCount)
}
// Leaving the team from the UI sets DeleteAt instead of using TeamStore.RemoveMember // Leaving the team from the UI sets DeleteAt instead of using TeamStore.RemoveMember
if _, teamErr := ss.Team().UpdateMember(&model.TeamMember{ _, teamErr = ss.Team().UpdateMember(&model.TeamMember{
TeamId: team.Id, TeamId: team.Id,
UserId: userIds[0], UserId: userIds[0],
DeleteAt: 1234, DeleteAt: 1234,
}); teamErr != nil { })
panic(teamErr) require.Nil(t, teamErr)
}
if totalMemberCount, teamErr := ss.Team().GetTotalMemberCount(team.Id, nil); teamErr != nil { totalMemberCount, teamErr = ss.Team().GetTotalMemberCount(team.Id, nil)
t.Fatal(teamErr) require.Nil(t, teamErr)
} else if int(totalMemberCount) != maxUsersPerTeam-1 { require.Equal(t, maxUsersPerTeam-1, int(totalMemberCount), "should now only have 4 team members, had %v instead", totalMemberCount)
t.Fatalf("should now only have 4 team members, had %v instead", totalMemberCount)
}
if _, err = ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId}, maxUsersPerTeam); err != nil { _, err = ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId}, maxUsersPerTeam)
t.Fatal("should've been able to save new member after deleting one", err) require.Nil(t, err, "should've been able to save new member after deleting one")
} else {
defer func(userId string) {
ss.Team().RemoveMember(team.Id, userId)
}(newUserId)
}
if totalMemberCount, teamErr := ss.Team().GetTotalMemberCount(team.Id, nil); teamErr != nil { defer ss.Team().RemoveMember(team.Id, newUserId)
t.Fatal(teamErr)
} else if int(totalMemberCount) != maxUsersPerTeam { totalMemberCount, teamErr = ss.Team().GetTotalMemberCount(team.Id, nil)
t.Fatalf("should have 5 team members again, had %v instead", totalMemberCount) require.Nil(t, teamErr)
} require.Equal(t, maxUsersPerTeam, int(totalMemberCount), "should have 5 team members again, had %v instead", totalMemberCount)
// Deactivating a user should make them stop counting against max members // Deactivating a user should make them stop counting against max members
user2, err := ss.User().Get(userIds[1]) user2, err := ss.User().Get(userIds[1])
@@ -1115,13 +1006,10 @@ func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
}) })
require.Nil(t, err) require.Nil(t, err)
newUserId2 := user.Id newUserId2 := user.Id
if _, err := ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId2}, maxUsersPerTeam); err != nil { _, err = ss.Team().SaveMember(&model.TeamMember{TeamId: team.Id, UserId: newUserId2}, maxUsersPerTeam)
t.Fatal("should've been able to save new member after deleting one", err) require.Nil(t, err, "should've been able to save new member after deleting one")
} else {
defer func(userId string) { defer ss.Team().RemoveMember(team.Id, newUserId2)
ss.Team().RemoveMember(team.Id, userId)
}(newUserId2)
}
} }
func testGetTeamMember(t *testing.T, ss store.Store) { func testGetTeamMember(t *testing.T, ss store.Store) {
@@ -1132,26 +1020,18 @@ func testGetTeamMember(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
var rm1 *model.TeamMember var rm1 *model.TeamMember
if rm1, err = ss.Team().GetMember(m1.TeamId, m1.UserId); err != nil { rm1, err = ss.Team().GetMember(m1.TeamId, m1.UserId)
t.Fatal(err) require.Nil(t, err)
} else {
if rm1.TeamId != m1.TeamId { require.Equal(t, rm1.TeamId, m1.TeamId, "bad team id")
t.Fatal("bad team id")
}
if rm1.UserId != m1.UserId { require.Equal(t, rm1.UserId, m1.UserId, "bad user id")
t.Fatal("bad user id")
}
}
if _, err = ss.Team().GetMember(m1.TeamId, ""); err == nil { _, err = ss.Team().GetMember(m1.TeamId, "")
t.Fatal("empty user id - should have failed") require.NotNil(t, err, "empty user id - should have failed")
}
if _, err = ss.Team().GetMember("", m1.UserId); err == nil { _, err = ss.Team().GetMember("", m1.UserId)
t.Fatal("empty team id - should have failed") require.NotNil(t, err, "empty team id - should have failed")
}
// Test with a custom team scheme. // Test with a custom team scheme.
s2 := &model.Scheme{ s2 := &model.Scheme{
@@ -1204,36 +1084,24 @@ func testGetTeamMembersByIds(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
var r []*model.TeamMember var r []*model.TeamMember
if r, err = ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId}, nil); err != nil { r, err = ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId}, nil)
t.Fatal(err) require.Nil(t, err)
} else { rm1 := r[0]
rm1 := r[0]
if rm1.TeamId != m1.TeamId { require.Equal(t, rm1.TeamId, m1.TeamId, "bad team id")
t.Fatal("bad team id") require.Equal(t, rm1.UserId, m1.UserId, "bad user id")
}
if rm1.UserId != m1.UserId {
t.Fatal("bad user id")
}
}
m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()} m2 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
_, err = ss.Team().SaveMember(m2, -1) _, err = ss.Team().SaveMember(m2, -1)
require.Nil(t, err) require.Nil(t, err)
if rm, err := ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId, m2.UserId, model.NewId()}, nil); err != nil { rm, err := ss.Team().GetMembersByIds(m1.TeamId, []string{m1.UserId, m2.UserId, model.NewId()}, nil)
t.Fatal(err) require.Nil(t, err)
} else {
if len(rm) != 2 { require.Len(t, rm, 2, "return wrong number of results")
t.Fatal("return wrong number of results")
}
}
if _, err := ss.Team().GetMembersByIds(m1.TeamId, []string{}, nil); err == nil { _, err = ss.Team().GetMembersByIds(m1.TeamId, []string{}, nil)
t.Fatal("empty user ids - should have failed") require.NotNil(t, err, "empty user ids - should have failed")
}
} }
func testTeamStoreMemberCount(t *testing.T, ss store.Store) { func testTeamStoreMemberCount(t *testing.T, ss store.Store) {
@@ -1258,42 +1126,26 @@ func testTeamStoreMemberCount(t *testing.T, ss store.Store) {
require.Nil(t, err) require.Nil(t, err)
var totalMemberCount int64 var totalMemberCount int64
if totalMemberCount, err = ss.Team().GetTotalMemberCount(teamId1, nil); err != nil { totalMemberCount, err = ss.Team().GetTotalMemberCount(teamId1, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, int(totalMemberCount), 2, "wrong count")
if totalMemberCount != 2 {
t.Fatal("wrong count")
}
}
var result int64 var result int64
if result, err = ss.Team().GetActiveMemberCount(teamId1, nil); err != nil { result, err = ss.Team().GetActiveMemberCount(teamId1, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, 1, int(result), "wrong count")
if result != 1 {
t.Fatal("wrong count")
}
}
m3 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()} m3 := &model.TeamMember{TeamId: teamId1, UserId: model.NewId()}
_, err = ss.Team().SaveMember(m3, -1) _, err = ss.Team().SaveMember(m3, -1)
require.Nil(t, err) require.Nil(t, err)
if totalMemberCount, err := ss.Team().GetTotalMemberCount(teamId1, nil); err != nil { totalMemberCount, err = ss.Team().GetTotalMemberCount(teamId1, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, 2, int(totalMemberCount), "wrong count")
if totalMemberCount != 2 {
t.Fatal("wrong count")
}
}
if result, err := ss.Team().GetActiveMemberCount(teamId1, nil); err != nil { result, err = ss.Team().GetActiveMemberCount(teamId1, nil)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, 1, int(result), "wrong count")
if result != 1 {
t.Fatal("wrong count")
}
}
} }
func testGetChannelUnreadsForAllTeams(t *testing.T, ss store.Store) { func testGetChannelUnreadsForAllTeams(t *testing.T, ss store.Store) {
@@ -1323,48 +1175,35 @@ func testGetChannelUnreadsForAllTeams(t *testing.T, ss store.Store) {
_, err = ss.Channel().SaveMember(cm2) _, err = ss.Channel().SaveMember(cm2)
require.Nil(t, err) require.Nil(t, err)
if ms1, err := ss.Team().GetChannelUnreadsForAllTeams("", uid); err != nil { ms1, err := ss.Team().GetChannelUnreadsForAllTeams("", uid)
t.Fatal(err) require.Nil(t, err)
} else { membersMap := make(map[string]bool)
membersMap := make(map[string]bool) for i := range ms1 {
for i := range ms1 { id := ms1[i].TeamId
id := ms1[i].TeamId if _, ok := membersMap[id]; !ok {
if _, ok := membersMap[id]; !ok { membersMap[id] = true
membersMap[id] = true
}
}
if len(membersMap) != 2 {
t.Fatal("Should be the unreads for all the teams")
} }
}
require.Len(t, membersMap, 2, "Should be the unreads for all the teams")
if ms1[0].MsgCount != 10 { require.Equal(t, 10, int(ms1[0].MsgCount), "subtraction failed")
t.Fatal("subtraction failed")
ms2, err := ss.Team().GetChannelUnreadsForAllTeams(teamId1, uid)
require.Nil(t, err)
membersMap = make(map[string]bool)
for i := range ms2 {
id := ms2[i].TeamId
if _, ok := membersMap[id]; !ok {
membersMap[id] = true
} }
} }
if ms2, err := ss.Team().GetChannelUnreadsForAllTeams(teamId1, uid); err != nil { require.Len(t, membersMap, 1, "Should be the unreads for just one team")
t.Fatal(err)
} else {
membersMap := make(map[string]bool)
for i := range ms2 {
id := ms2[i].TeamId
if _, ok := membersMap[id]; !ok {
membersMap[id] = true
}
}
if len(membersMap) != 1 { require.Equal(t, 10, int(ms2[0].MsgCount), "subtraction failed")
t.Fatal("Should be the unreads for just one team")
}
if ms2[0].MsgCount != 10 { err = ss.Team().RemoveAllMembersByUser(uid)
t.Fatal("subtraction failed") require.Nil(t, err)
}
}
if err := ss.Team().RemoveAllMembersByUser(uid); err != nil {
t.Fatal(err)
}
} }
func testGetChannelUnreadsForTeam(t *testing.T, ss store.Store) { func testGetChannelUnreadsForTeam(t *testing.T, ss store.Store) {
@@ -1390,17 +1229,11 @@ func testGetChannelUnreadsForTeam(t *testing.T, ss store.Store) {
_, err = ss.Channel().SaveMember(cm2) _, err = ss.Channel().SaveMember(cm2)
require.Nil(t, err) require.Nil(t, err)
if ms, err := ss.Team().GetChannelUnreadsForTeam(m1.TeamId, m1.UserId); err != nil { ms, err := ss.Team().GetChannelUnreadsForTeam(m1.TeamId, m1.UserId)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, ms, 2, "wrong length")
if len(ms) != 2 {
t.Fatal("wrong length")
}
if ms[0].MsgCount != 10 { require.Equal(t, 10, int(ms[0].MsgCount), "subtraction failed")
t.Fatal("subtraction failed")
}
}
} }
func testUpdateLastTeamIconUpdate(t *testing.T, ss store.Store) { func testUpdateLastTeamIconUpdate(t *testing.T, ss store.Store) {
@@ -1419,16 +1252,13 @@ func testUpdateLastTeamIconUpdate(t *testing.T, ss store.Store) {
curTime := model.GetMillis() curTime := model.GetMillis()
if err = ss.Team().UpdateLastTeamIconUpdate(o1.Id, curTime); err != nil { err = ss.Team().UpdateLastTeamIconUpdate(o1.Id, curTime)
t.Fatal(err) require.Nil(t, err)
}
ro1, err := ss.Team().Get(o1.Id) ro1, err := ss.Team().Get(o1.Id)
require.Nil(t, err) require.Nil(t, err)
if ro1.LastTeamIconUpdate <= lastTeamIconUpdateInitial { require.Greater(t, ro1.LastTeamIconUpdate, lastTeamIconUpdateInitial, "LastTeamIconUpdate not updated")
t.Fatal("LastTeamIconUpdate not updated")
}
} }
func testGetTeamsByScheme(t *testing.T, ss store.Store) { func testGetTeamsByScheme(t *testing.T, ss store.Store) {

Просмотреть файл

@@ -43,13 +43,11 @@ func TestWebhookStore(t *testing.T, ss store.Store) {
func testWebhookStoreSaveIncoming(t *testing.T, ss store.Store) { func testWebhookStoreSaveIncoming(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
if _, err := ss.Webhook().SaveIncoming(o1); err != nil { _, err := ss.Webhook().SaveIncoming(o1)
t.Fatal("couldn't save item", err) require.Nil(t, err, "couldn't save item")
}
if _, err := ss.Webhook().SaveIncoming(o1); err == nil { _, err = ss.Webhook().SaveIncoming(o1)
t.Fatal("shouldn't be able to update from save") require.NotNil(t, err, "shouldn't be able to update from save")
}
} }
func testWebhookStoreUpdateIncoming(t *testing.T, ss store.Store) { func testWebhookStoreUpdateIncoming(t *testing.T, ss store.Store) {
@@ -58,9 +56,7 @@ func testWebhookStoreUpdateIncoming(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
previousUpdatedAt := o1.UpdateAt previousUpdatedAt := o1.UpdateAt
@@ -70,14 +66,9 @@ func testWebhookStoreUpdateIncoming(t *testing.T, ss store.Store) {
webhook, err := ss.Webhook().UpdateIncoming(o1) webhook, err := ss.Webhook().UpdateIncoming(o1)
require.Nil(t, err) require.Nil(t, err)
if webhook.UpdateAt == previousUpdatedAt { require.NotEqual(t, webhook.UpdateAt, previousUpdatedAt, "should have updated the UpdatedAt of the hook")
t.Fatal("should have updated the UpdatedAt of the hook")
}
if webhook.DisplayName != "TestHook" {
t.Fatal("display name is not updated")
}
require.Equal(t, "TestHook", webhook.DisplayName, "display name is not updated")
} }
func testWebhookStoreGetIncoming(t *testing.T, ss store.Store) { func testWebhookStoreGetIncoming(t *testing.T, ss store.Store) {
@@ -85,33 +76,25 @@ func testWebhookStoreGetIncoming(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
webhook, err := ss.Webhook().GetIncoming(o1.Id, false) webhook, err := ss.Webhook().GetIncoming(o1.Id, false)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
webhook, err = ss.Webhook().GetIncoming(o1.Id, true) webhook, err = ss.Webhook().GetIncoming(o1.Id, true)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if _, err = ss.Webhook().GetIncoming("123", false); err == nil { _, err = ss.Webhook().GetIncoming("123", false)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
if _, err = ss.Webhook().GetIncoming("123", true); err == nil { _, err = ss.Webhook().GetIncoming("123", true)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
if _, err = ss.Webhook().GetIncoming("123", true); err.StatusCode != http.StatusNotFound { _, err = ss.Webhook().GetIncoming("123", true)
t.Fatal("Should have set the status as not found for missing id") require.NotNil(t, err)
} require.Equal(t, err.StatusCode, http.StatusNotFound, "Should have set the status as not found for missing id")
} }
func testWebhookStoreGetIncomingList(t *testing.T, ss store.Store) { func testWebhookStoreGetIncomingList(t *testing.T, ss store.Store) {
@@ -122,31 +105,22 @@ func testWebhookStoreGetIncomingList(t *testing.T, ss store.Store) {
var err *model.AppError var err *model.AppError
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
if hooks, err := ss.Webhook().GetIncomingList(0, 1000); err != nil { hooks, err := ss.Webhook().GetIncomingList(0, 1000)
t.Fatal(err) require.Nil(t, err)
} else {
found := false
for _, hook := range hooks {
if hook.Id == o1.Id {
found = true
}
}
if !found {
t.Fatal("missing webhook")
}
}
if hooks, err := ss.Webhook().GetIncomingList(0, 1); err != nil { found := false
t.Fatal(err) for _, hook := range hooks {
} else { if hook.Id == o1.Id {
if len(hooks) != 1 { found = true
t.Fatal("only 1 should be returned")
} }
} }
require.True(t, found, "missing webhook")
hooks, err = ss.Webhook().GetIncomingList(0, 1)
require.Nil(t, err)
require.Len(t, hooks, 1, "only 1 should be returned")
} }
func testWebhookStoreGetIncomingListByUser(t *testing.T, ss store.Store) { func testWebhookStoreGetIncomingListByUser(t *testing.T, ss store.Store) {
@@ -179,21 +153,13 @@ func testWebhookStoreGetIncomingByTeam(t *testing.T, ss store.Store) {
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
require.Nil(t, err) require.Nil(t, err)
if hooks, err := ss.Webhook().GetIncomingByTeam(o1.TeamId, 0, 100); err != nil { hooks, err := ss.Webhook().GetIncomingByTeam(o1.TeamId, 0, 100)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, hooks[0].CreateAt, o1.CreateAt, "invalid returned webhook")
if hooks[0].CreateAt != o1.CreateAt {
t.Fatal("invalid returned webhook")
}
}
if hooks, err := ss.Webhook().GetIncomingByTeam("123", 0, 100); err != nil { hooks, err = ss.Webhook().GetIncomingByTeam("123", 0, 100)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, hooks, 0, "no webhooks should have returned")
if len(hooks) != 0 {
t.Fatal("no webhooks should have returned")
}
}
} }
func TestWebhookStoreGetIncomingByTeamByUser(t *testing.T, ss store.Store) { func TestWebhookStoreGetIncomingByTeamByUser(t *testing.T, ss store.Store) {
@@ -232,23 +198,15 @@ func TestWebhookStoreGetIncomingByChannel(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err := ss.Webhook().SaveIncoming(o1) o1, err := ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook")
}
webhooks, err := ss.Webhook().GetIncomingByChannel(o1.ChannelId) webhooks, err := ss.Webhook().GetIncomingByChannel(o1.ChannelId)
require.Nil(t, err) require.Nil(t, err)
if webhooks[0].CreateAt != o1.CreateAt { require.Equal(t, webhooks[0].CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if webhooks, err = ss.Webhook().GetIncomingByChannel("123"); err != nil { webhooks, err = ss.Webhook().GetIncomingByChannel("123")
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, webhooks, 0, "no webhooks should have returned")
if len(webhooks) != 0 {
t.Fatal("no webhooks should have returned")
}
}
} }
func testWebhookStoreDeleteIncoming(t *testing.T, ss store.Store) { func testWebhookStoreDeleteIncoming(t *testing.T, ss store.Store) {
@@ -256,19 +214,14 @@ func testWebhookStoreDeleteIncoming(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
webhook, err := ss.Webhook().GetIncoming(o1.Id, true) webhook, err := ss.Webhook().GetIncoming(o1.Id, true)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err = ss.Webhook().DeleteIncoming(o1.Id, model.GetMillis()); err != nil { err = ss.Webhook().DeleteIncoming(o1.Id, model.GetMillis())
t.Fatal(err) require.Nil(t, err)
}
webhook, err = ss.Webhook().GetIncoming(o1.Id, true) webhook, err = ss.Webhook().GetIncoming(o1.Id, true)
require.NotNil(t, err) require.NotNil(t, err)
@@ -279,23 +232,17 @@ func testWebhookStoreDeleteIncomingByChannel(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
webhook, err := ss.Webhook().GetIncoming(o1.Id, true) webhook, err := ss.Webhook().GetIncoming(o1.Id, true)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err = ss.Webhook().PermanentDeleteIncomingByChannel(o1.ChannelId); err != nil { err = ss.Webhook().PermanentDeleteIncomingByChannel(o1.ChannelId)
t.Fatal(err) require.Nil(t, err)
}
if _, err = ss.Webhook().GetIncoming(o1.Id, true); err == nil { _, err = ss.Webhook().GetIncoming(o1.Id, true)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testWebhookStoreDeleteIncomingByUser(t *testing.T, ss store.Store) { func testWebhookStoreDeleteIncomingByUser(t *testing.T, ss store.Store) {
@@ -303,23 +250,17 @@ func testWebhookStoreDeleteIncomingByUser(t *testing.T, ss store.Store) {
o1 := buildIncomingWebhook() o1 := buildIncomingWebhook()
o1, err = ss.Webhook().SaveIncoming(o1) o1, err = ss.Webhook().SaveIncoming(o1)
if err != nil { require.Nil(t, err, "unable to save webhook")
t.Fatal("unable to save webhook", err)
}
webhook, err := ss.Webhook().GetIncoming(o1.Id, true) webhook, err := ss.Webhook().GetIncoming(o1.Id, true)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err = ss.Webhook().PermanentDeleteIncomingByUser(o1.UserId); err != nil { err = ss.Webhook().PermanentDeleteIncomingByUser(o1.UserId)
t.Fatal(err) require.Nil(t, err)
}
if _, err = ss.Webhook().GetIncoming(o1.Id, true); err == nil { _, err = ss.Webhook().GetIncoming(o1.Id, true)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func buildIncomingWebhook() *model.IncomingWebhook { func buildIncomingWebhook() *model.IncomingWebhook {
@@ -340,13 +281,11 @@ func testWebhookStoreSaveOutgoing(t *testing.T, ss store.Store) {
o1.Username = "test-user-name" o1.Username = "test-user-name"
o1.IconURL = "http://nowhere.com/icon" o1.IconURL = "http://nowhere.com/icon"
if _, err := ss.Webhook().SaveOutgoing(&o1); err != nil { _, err := ss.Webhook().SaveOutgoing(&o1)
t.Fatal("couldn't save item", err) require.Nil(t, err, "couldn't save item")
}
if _, err := ss.Webhook().SaveOutgoing(&o1); err == nil { _, err = ss.Webhook().SaveOutgoing(&o1)
t.Fatal("shouldn't be able to update from save") require.NotNil(t, err, "shouldn't be able to update from save")
}
} }
func testWebhookStoreGetOutgoing(t *testing.T, ss store.Store) { func testWebhookStoreGetOutgoing(t *testing.T, ss store.Store) {
@@ -362,13 +301,10 @@ func testWebhookStoreGetOutgoing(t *testing.T, ss store.Store) {
webhook, err := ss.Webhook().GetOutgoing(o1.Id) webhook, err := ss.Webhook().GetOutgoing(o1.Id)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if _, err := ss.Webhook().GetOutgoing("123"); err == nil { _, err = ss.Webhook().GetOutgoing("123")
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testWebhookStoreGetOutgoingListByUser(t *testing.T, ss store.Store) { func testWebhookStoreGetOutgoingListByUser(t *testing.T, ss store.Store) {
@@ -412,38 +348,28 @@ func testWebhookStoreGetOutgoingList(t *testing.T, ss store.Store) {
o2, _ = ss.Webhook().SaveOutgoing(o2) o2, _ = ss.Webhook().SaveOutgoing(o2)
if r1, err := ss.Webhook().GetOutgoingList(0, 1000); err != nil { r1, err := ss.Webhook().GetOutgoingList(0, 1000)
t.Fatal(err) require.Nil(t, err)
} else { hooks := r1
hooks := r1 found1 := false
found1 := false found2 := false
found2 := false
for _, hook := range hooks { for _, hook := range hooks {
if hook.CreateAt != o1.CreateAt { if hook.CreateAt != o1.CreateAt {
found1 = true found1 = true
}
if hook.CreateAt != o2.CreateAt {
found2 = true
}
} }
if !found1 { if hook.CreateAt != o2.CreateAt {
t.Fatal("missing hook1") found2 = true
}
if !found2 {
t.Fatal("missing hook2")
} }
} }
if result, err := ss.Webhook().GetOutgoingList(0, 2); err != nil { require.True(t, found1, "missing hook1")
t.Fatal(err) require.True(t, found2, "missing hook2")
} else {
if len(result) != 2 { result, err := ss.Webhook().GetOutgoingList(0, 2)
t.Fatal("wrong number of hooks returned") require.Nil(t, err)
} require.Len(t, result, 2, "wrong number of hooks returned")
}
} }
func testWebhookStoreGetOutgoingByChannel(t *testing.T, ss store.Store) { func testWebhookStoreGetOutgoingByChannel(t *testing.T, ss store.Store) {
@@ -455,21 +381,13 @@ func testWebhookStoreGetOutgoingByChannel(t *testing.T, ss store.Store) {
o1, _ = ss.Webhook().SaveOutgoing(o1) o1, _ = ss.Webhook().SaveOutgoing(o1)
if r1, err := ss.Webhook().GetOutgoingByChannel(o1.ChannelId, 0, 100); err != nil { r1, err := ss.Webhook().GetOutgoingByChannel(o1.ChannelId, 0, 100)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, r1[0].CreateAt, o1.CreateAt, "invalid returned webhook")
if r1[0].CreateAt != o1.CreateAt {
t.Fatal("invalid returned webhook")
}
}
if result, err := ss.Webhook().GetOutgoingByChannel("123", -1, -1); err != nil { result, err := ss.Webhook().GetOutgoingByChannel("123", -1, -1)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, result, 0, "no webhooks should have returned")
if len(result) != 0 {
t.Fatal("no webhooks should have returned")
}
}
} }
func testWebhookStoreGetOutgoingByChannelByUser(t *testing.T, ss store.Store) { func testWebhookStoreGetOutgoingByChannelByUser(t *testing.T, ss store.Store) {
@@ -520,21 +438,13 @@ func testWebhookStoreGetOutgoingByTeam(t *testing.T, ss store.Store) {
o1, _ = ss.Webhook().SaveOutgoing(o1) o1, _ = ss.Webhook().SaveOutgoing(o1)
if r1, err := ss.Webhook().GetOutgoingByTeam(o1.TeamId, 0, 100); err != nil { r1, err := ss.Webhook().GetOutgoingByTeam(o1.TeamId, 0, 100)
t.Fatal(err) require.Nil(t, err)
} else { require.Equal(t, r1[0].CreateAt, o1.CreateAt, "invalid returned webhook")
if r1[0].CreateAt != o1.CreateAt {
t.Fatal("invalid returned webhook")
}
}
if result, err := ss.Webhook().GetOutgoingByTeam("123", -1, -1); err != nil { result, err := ss.Webhook().GetOutgoingByTeam("123", -1, -1)
t.Fatal(err) require.Nil(t, err)
} else { require.Len(t, result, 0, "no webhooks should have returned")
if len(result) != 0 {
t.Fatal("no webhooks should have returned")
}
}
} }
func testWebhookStoreGetOutgoingByTeamByUser(t *testing.T, ss store.Store) { func testWebhookStoreGetOutgoingByTeamByUser(t *testing.T, ss store.Store) {
@@ -589,17 +499,13 @@ func testWebhookStoreDeleteOutgoing(t *testing.T, ss store.Store) {
webhook, err := ss.Webhook().GetOutgoing(o1.Id) webhook, err := ss.Webhook().GetOutgoing(o1.Id)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err := ss.Webhook().DeleteOutgoing(o1.Id, model.GetMillis()); err != nil { err = ss.Webhook().DeleteOutgoing(o1.Id, model.GetMillis())
t.Fatal(err) require.Nil(t, err)
}
if _, err := ss.Webhook().GetOutgoing(o1.Id); err == nil { _, err = ss.Webhook().GetOutgoing(o1.Id)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testWebhookStoreDeleteOutgoingByChannel(t *testing.T, ss store.Store) { func testWebhookStoreDeleteOutgoingByChannel(t *testing.T, ss store.Store) {
@@ -613,17 +519,13 @@ func testWebhookStoreDeleteOutgoingByChannel(t *testing.T, ss store.Store) {
webhook, err := ss.Webhook().GetOutgoing(o1.Id) webhook, err := ss.Webhook().GetOutgoing(o1.Id)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err := ss.Webhook().PermanentDeleteOutgoingByChannel(o1.ChannelId); err != nil { err = ss.Webhook().PermanentDeleteOutgoingByChannel(o1.ChannelId)
t.Fatal(err) require.Nil(t, err)
}
if _, err := ss.Webhook().GetOutgoing(o1.Id); err == nil { _, err = ss.Webhook().GetOutgoing(o1.Id)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testWebhookStoreDeleteOutgoingByUser(t *testing.T, ss store.Store) { func testWebhookStoreDeleteOutgoingByUser(t *testing.T, ss store.Store) {
@@ -637,17 +539,13 @@ func testWebhookStoreDeleteOutgoingByUser(t *testing.T, ss store.Store) {
webhook, err := ss.Webhook().GetOutgoing(o1.Id) webhook, err := ss.Webhook().GetOutgoing(o1.Id)
require.Nil(t, err) require.Nil(t, err)
if webhook.CreateAt != o1.CreateAt { require.Equal(t, webhook.CreateAt, o1.CreateAt, "invalid returned webhook")
t.Fatal("invalid returned webhook")
}
if err := ss.Webhook().PermanentDeleteOutgoingByUser(o1.CreatorId); err != nil { err = ss.Webhook().PermanentDeleteOutgoingByUser(o1.CreatorId)
t.Fatal(err) require.Nil(t, err)
}
if _, err := ss.Webhook().GetOutgoing(o1.Id); err == nil { _, err = ss.Webhook().GetOutgoing(o1.Id)
t.Fatal("Missing id should have failed") require.NotNil(t, err, "Missing id should have failed")
}
} }
func testWebhookStoreUpdateOutgoing(t *testing.T, ss store.Store) { func testWebhookStoreUpdateOutgoing(t *testing.T, ss store.Store) {
@@ -664,9 +562,8 @@ func testWebhookStoreUpdateOutgoing(t *testing.T, ss store.Store) {
o1.Token = model.NewId() o1.Token = model.NewId()
o1.Username = "another-test-user-name" o1.Username = "another-test-user-name"
if _, err := ss.Webhook().UpdateOutgoing(o1); err != nil { _, err := ss.Webhook().UpdateOutgoing(o1)
t.Fatal(err) require.Nil(t, err)
}
} }
func testWebhookStoreCountIncoming(t *testing.T, ss store.Store) { func testWebhookStoreCountIncoming(t *testing.T, ss store.Store) {
@@ -678,13 +575,9 @@ func testWebhookStoreCountIncoming(t *testing.T, ss store.Store) {
_, _ = ss.Webhook().SaveIncoming(o1) _, _ = ss.Webhook().SaveIncoming(o1)
c, err := ss.Webhook().AnalyticsIncomingCount("") c, err := ss.Webhook().AnalyticsIncomingCount("")
if err != nil { require.Nil(t, err)
t.Fatal(err)
}
if c == 0 { require.NotEqual(t, 0, c, "should have at least 1 incoming hook")
t.Fatal("should have at least 1 incoming hook")
}
} }
func testWebhookStoreCountOutgoing(t *testing.T, ss store.Store) { func testWebhookStoreCountOutgoing(t *testing.T, ss store.Store) {
@@ -696,11 +589,7 @@ func testWebhookStoreCountOutgoing(t *testing.T, ss store.Store) {
ss.Webhook().SaveOutgoing(o1) ss.Webhook().SaveOutgoing(o1)
if r, err := ss.Webhook().AnalyticsOutgoingCount(""); err != nil { r, err := ss.Webhook().AnalyticsOutgoingCount("")
t.Fatal(err) require.Nil(t, err)
} else { require.NotEqual(t, 0, r, "should have at least 1 outgoing hook")
if r == 0 {
t.Fatal("should have at least 1 outgoing hook")
}
}
} }

Просмотреть файл

@@ -103,7 +103,7 @@ func (h *MainHelper) setupStore() {
h.ClusterInterface = &FakeClusterInterface{} h.ClusterInterface = &FakeClusterInterface{}
h.SqlSupplier = sqlstore.NewSqlSupplier(*h.Settings, nil) h.SqlSupplier = sqlstore.NewSqlSupplier(*h.Settings, nil)
h.Store = &TestStore{ h.Store = &TestStore{
store.NewLayeredStore(h.SqlSupplier, nil, h.ClusterInterface), h.SqlSupplier,
} }
} }

Просмотреть файл

@@ -27,6 +27,8 @@ const (
actionSymlink actionSymlink
) )
const root = "___mattermost-server"
type testResourceDetails struct { type testResourceDetails struct {
src string src string
dest string dest string
@@ -50,6 +52,15 @@ func findFile(path string) string {
} }
func findDir(dir string) (string, bool) { func findDir(dir string) (string, bool) {
if dir == root {
srcPath := findFile("go.mod")
if srcPath == "" {
return "./", false
}
return path.Dir(srcPath), true
}
found := fileutils.FindPath(dir, commonBaseSearchPaths, func(fileInfo os.FileInfo) bool { found := fileutils.FindPath(dir, commonBaseSearchPaths, func(fileInfo os.FileInfo) bool {
return fileInfo.IsDir() return fileInfo.IsDir()
}) })
@@ -65,7 +76,7 @@ func getTestResourcesToSetup() []testResourceDetails {
var found bool var found bool
var testResourcesToSetup = []testResourceDetails{ var testResourcesToSetup = []testResourceDetails{
{"mattermost-server", "mattermost-server", resourceTypeFolder, actionSymlink}, {root, "mattermost-server", resourceTypeFolder, actionSymlink},
{"i18n", "i18n", resourceTypeFolder, actionSymlink}, {"i18n", "i18n", resourceTypeFolder, actionSymlink},
{"templates", "templates", resourceTypeFolder, actionSymlink}, {"templates", "templates", resourceTypeFolder, actionSymlink},
{"tests", "tests", resourceTypeFolder, actionSymlink}, {"tests", "tests", resourceTypeFolder, actionSymlink},

15
testlib/resources_test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,15 @@
package testlib
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestFindDir(t *testing.T) {
t.Run("find root", func(t *testing.T) {
path, found := findDir(root)
assert.True(t, found, "failed to find root")
assert.NotEmpty(t, path)
})
}

Просмотреть файл

@@ -12,6 +12,7 @@ import (
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestLRU(t *testing.T) { func TestLRU(t *testing.T) {
@@ -20,50 +21,39 @@ func TestLRU(t *testing.T) {
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
l.Add(i, i) l.Add(i, i)
} }
if l.Len() != 128 { require.Equalf(t, l.Len(), 128, "bad len: %v", l.Len())
t.Fatalf("bad len: %v", l.Len())
}
for i, k := range l.Keys() { for i, k := range l.Keys() {
if v, ok := l.Get(k); !ok || v != k || v != i+128 { v, ok := l.Get(k)
t.Fatalf("bad key: %v", k) require.True(t, ok, "bad key: %v", k)
} require.Equalf(t, v, k, "bad key: %v", k)
require.Equalf(t, i+128, v, "bad key: %v", k)
} }
for i := 0; i < 128; i++ { for i := 0; i < 128; i++ {
_, ok := l.Get(i) _, ok := l.Get(i)
if ok { require.False(t, ok, "should be evicted")
t.Fatalf("should be evicted")
}
} }
for i := 128; i < 256; i++ { for i := 128; i < 256; i++ {
_, ok := l.Get(i) _, ok := l.Get(i)
if !ok { require.True(t, ok, "should not be evicted")
t.Fatalf("should not be evicted")
}
} }
for i := 128; i < 192; i++ { for i := 128; i < 192; i++ {
l.Remove(i) l.Remove(i)
_, ok := l.Get(i) _, ok := l.Get(i)
if ok { require.False(t, ok, "should be deleted")
t.Fatalf("should be deleted")
}
} }
l.Get(192) // expect 192 to be last key in l.Keys() l.Get(192) // expect 192 to be last key in l.Keys()
for i, k := range l.Keys() { for i, k := range l.Keys() {
if (i < 63 && k != i+193) || (i == 63 && k != 192) { require.Falsef(t, (i < 63 && k != i+193), "out of order key: %v", k)
t.Fatalf("out of order key: %v", k) require.Falsef(t, (i == 63 && k != 192), "out of order key: %v", k)
}
} }
l.Purge() l.Purge()
if l.Len() != 0 { require.Equalf(t, l.Len(), 0, "bad len: %v", l.Len())
t.Fatalf("bad len: %v", l.Len()) _, ok := l.Get(200)
} require.False(t, ok, "should contain nothing")
if _, ok := l.Get(200); ok {
t.Fatalf("should contain nothing")
}
} }
func TestLRUExpire(t *testing.T) { func TestLRUExpire(t *testing.T) {
@@ -75,13 +65,11 @@ func TestLRUExpire(t *testing.T) {
time.Sleep(time.Millisecond * 2100) time.Sleep(time.Millisecond * 2100)
if r1, ok := l.Get(1); ok { r1, ok := l.Get(1)
t.Fatal(r1) require.False(t, ok, r1)
}
if _, ok2 := l.Get(3); !ok2 { _, ok2 := l.Get(3)
t.Fatal("should exist") require.True(t, ok2, "should exist")
}
} }
func TestLRUGetOrAdd(t *testing.T) { func TestLRUGetOrAdd(t *testing.T) {

Просмотреть файл

@@ -12,8 +12,6 @@ import (
"path/filepath" "path/filepath"
"testing" "testing"
"github.com/mattermost/mattermost-server/testlib"
"github.com/mattermost/mattermost-server/app" "github.com/mattermost/mattermost-server/app"
"github.com/mattermost/mattermost-server/config" "github.com/mattermost/mattermost-server/config"
"github.com/mattermost/mattermost-server/model" "github.com/mattermost/mattermost-server/model"
@@ -97,11 +95,6 @@ func Setup() *TestHelper {
} }
func (th *TestHelper) InitPlugins() *TestHelper { func (th *TestHelper) InitPlugins() *TestHelper {
if th.tempWorkspace == "" {
th.tempWorkspace, _ = testlib.SetupTestResources()
}
pluginDir := filepath.Join(th.tempWorkspace, "plugins") pluginDir := filepath.Join(th.tempWorkspace, "plugins")
webappDir := filepath.Join(th.tempWorkspace, "webapp") webappDir := filepath.Join(th.tempWorkspace, "webapp")