parallel tests (#7629)
Этот коммит содержится в:
коммит произвёл
Joram Wilander
родитель
adb2b1d6ed
Коммит
34285d8cca
2
Makefile
2
Makefile
@@ -312,7 +312,7 @@ test-te: do-cover-file
|
|||||||
@echo Testing TE
|
@echo Testing TE
|
||||||
@echo "Packages to test: "$(TE_PACKAGES)
|
@echo "Packages to test: "$(TE_PACKAGES)
|
||||||
find . -name 'cprofile.out' -exec sh -c 'rm "{}"' \;
|
find . -name 'cprofile.out' -exec sh -c 'rm "{}"' \;
|
||||||
$(GO) test $(GOFLAGS) -run=$(TESTS) $(TESTFLAGS) -p 1 -v -timeout=2000s -covermode=count -coverpkg=$(ALL_PACKAGES_COMMA) -exec $(ROOT)/scripts/test-xprog.sh $(TE_PACKAGES)
|
$(GO) test $(GOFLAGS) -run=$(TESTS) $(TESTFLAGS) -v -timeout=2000s -covermode=count -coverpkg=$(ALL_PACKAGES_COMMA) -exec $(ROOT)/scripts/test-xprog.sh $(TE_PACKAGES)
|
||||||
find . -name 'cprofile.out' -exec sh -c 'tail -n +2 {} >> cover.out ; rm "{}"' \;
|
find . -name 'cprofile.out' -exec sh -c 'tail -n +2 {} >> cover.out ; rm "{}"' \;
|
||||||
|
|
||||||
test-ee: do-cover-file
|
test-ee: do-cover-file
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -69,6 +70,10 @@ func setupTestHelper(enterprise bool) *TestHelper {
|
|||||||
var options []app.Option
|
var options []app.Option
|
||||||
if testStore != nil {
|
if testStore != nil {
|
||||||
options = append(options, app.StoreOverride(testStore))
|
options = append(options, app.StoreOverride(testStore))
|
||||||
|
options = append(options, app.ConfigOverride(func(cfg *model.Config) {
|
||||||
|
cfg.ServiceSettings.ListenAddress = new(string)
|
||||||
|
*cfg.ServiceSettings.ListenAddress = ":0"
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
th := &TestHelper{
|
th := &TestHelper{
|
||||||
@@ -153,8 +158,9 @@ func (me *TestHelper) InitSystemAdmin() *TestHelper {
|
|||||||
|
|
||||||
func (me *TestHelper) waitForConnectivity() {
|
func (me *TestHelper) waitForConnectivity() {
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
_, err := net.Dial("tcp", "localhost"+*utils.Cfg.ServiceSettings.ListenAddress)
|
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", me.App.Srv.ListenAddr.Port))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(time.Millisecond * 20)
|
time.Sleep(time.Millisecond * 20)
|
||||||
@@ -163,11 +169,11 @@ func (me *TestHelper) waitForConnectivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateClient() *model.Client {
|
func (me *TestHelper) CreateClient() *model.Client {
|
||||||
return model.NewClient("http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress)
|
return model.NewClient(fmt.Sprintf("http://localhost:%v", me.App.Srv.ListenAddr.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) {
|
func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) {
|
||||||
return model.NewWebSocketClient("ws://localhost"+*utils.Cfg.ServiceSettings.ListenAddress, me.BasicClient.AuthToken)
|
return model.NewWebSocketClient(fmt.Sprintf("ws://localhost:%v", me.App.Srv.ListenAddr.Port), me.BasicClient.AuthToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateTeam(client *model.Client) *model.Team {
|
func (me *TestHelper) CreateTeam(client *model.Client) *model.Team {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -257,7 +258,7 @@ func TestTestCommand(t *testing.T) {
|
|||||||
*utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost"
|
*utils.Cfg.ServiceSettings.AllowedUntrustedInternalConnections = "localhost"
|
||||||
|
|
||||||
cmd1 := &model.Command{
|
cmd1 := &model.Command{
|
||||||
URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
||||||
Method: model.COMMAND_METHOD_POST,
|
Method: model.COMMAND_METHOD_POST,
|
||||||
Trigger: "testcommand",
|
Trigger: "testcommand",
|
||||||
}
|
}
|
||||||
@@ -290,7 +291,7 @@ func TestTestCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cmd2 := &model.Command{
|
cmd2 := &model.Command{
|
||||||
URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V3 + "/teams/command_test",
|
||||||
Method: model.COMMAND_METHOD_GET,
|
Method: model.COMMAND_METHOD_GET,
|
||||||
Trigger: "test2",
|
Trigger: "test2",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -516,10 +516,7 @@ func TestGetPublicFileOld(t *testing.T) {
|
|||||||
store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
|
store.Must(th.App.Srv.Store.FileInfo().AttachToPost(fileId, th.BasicPost.Id))
|
||||||
|
|
||||||
// reconstruct old style of link
|
// reconstruct old style of link
|
||||||
siteURL := *utils.Cfg.ServiceSettings.SiteURL
|
siteURL := fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port)
|
||||||
if siteURL == "" {
|
|
||||||
siteURL = "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress
|
|
||||||
}
|
|
||||||
link := generatePublicLinkOld(siteURL, th.BasicTeam.Id, channel.Id, th.BasicUser.Id, fileId+"/test.png")
|
link := generatePublicLinkOld(siteURL, th.BasicTeam.Id, channel.Id, th.BasicUser.Id, fileId+"/test.png")
|
||||||
|
|
||||||
// Wait a bit for files to ready
|
// Wait a bit for files to ready
|
||||||
|
|||||||
@@ -1153,20 +1153,31 @@ func TestEmailMention(t *testing.T) {
|
|||||||
if !strings.ContainsAny(resultsMailbox[len(resultsMailbox)-1].To[0], th.BasicUser2.Email) {
|
if !strings.ContainsAny(resultsMailbox[len(resultsMailbox)-1].To[0], th.BasicUser2.Email) {
|
||||||
t.Fatal("Wrong To recipient")
|
t.Fatal("Wrong To recipient")
|
||||||
} else {
|
} else {
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 30; i++ {
|
||||||
if resultsEmail, err := utils.GetMessageFromMailbox(th.BasicUser2.Email, resultsMailbox[len(resultsMailbox)-1].ID); err == nil {
|
for j := len(resultsMailbox) - 1; j >= 0; j-- {
|
||||||
if strings.Contains(resultsEmail.Body.Text, post1.Message) {
|
isUser := false
|
||||||
break
|
for _, to := range resultsMailbox[j].To {
|
||||||
} else if i == 4 {
|
if to == "<"+th.BasicUser2.Email+">" {
|
||||||
t.Log(resultsEmail.Body.Text)
|
isUser = true
|
||||||
t.Fatal("Received wrong Message")
|
}
|
||||||
|
}
|
||||||
|
if !isUser {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if resultsEmail, err := utils.GetMessageFromMailbox(th.BasicUser2.Email, resultsMailbox[j].ID); err == nil {
|
||||||
|
if strings.Contains(resultsEmail.Body.Text, post1.Message) {
|
||||||
|
return
|
||||||
|
} else if i == 4 {
|
||||||
|
t.Log(resultsEmail.Body.Text)
|
||||||
|
t.Fatal("Received wrong Message")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
t.Fatal("Didn't receive message")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFuzzyPosts(t *testing.T) {
|
func TestFuzzyPosts(t *testing.T) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
//"encoding/json"
|
//"encoding/json"
|
||||||
//"net/http"
|
//"net/http"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -323,7 +324,7 @@ func TestWebsocketOriginSecurity(t *testing.T) {
|
|||||||
th := Setup().InitBasic()
|
th := Setup().InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
url := "ws://localhost" + *utils.Cfg.ServiceSettings.ListenAddress
|
url := fmt.Sprintf("ws://localhost:%v", th.App.Srv.ListenAddr.Port)
|
||||||
|
|
||||||
// Should fail because origin doesn't match
|
// Should fail because origin doesn't match
|
||||||
_, _, err := websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
|
_, _, err := websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
|
||||||
@@ -335,7 +336,7 @@ func TestWebsocketOriginSecurity(t *testing.T) {
|
|||||||
|
|
||||||
// We are not a browser so we can spoof this just fine
|
// We are not a browser so we can spoof this just fine
|
||||||
_, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
|
_, _, err = websocket.DefaultDialer.Dial(url+model.API_URL_SUFFIX_V3+"/users/websocket", http.Header{
|
||||||
"Origin": []string{"http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress},
|
"Origin": []string{fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port)},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ func setupTestHelper(enterprise bool) *TestHelper {
|
|||||||
var options []app.Option
|
var options []app.Option
|
||||||
if testStore != nil {
|
if testStore != nil {
|
||||||
options = append(options, app.StoreOverride(testStore))
|
options = append(options, app.StoreOverride(testStore))
|
||||||
|
options = append(options, app.ConfigOverride(func(cfg *model.Config) {
|
||||||
|
cfg.ServiceSettings.ListenAddress = new(string)
|
||||||
|
*cfg.ServiceSettings.ListenAddress = ":0"
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
th := &TestHelper{
|
th := &TestHelper{
|
||||||
@@ -221,8 +225,9 @@ func (me *TestHelper) InitSystemAdmin() *TestHelper {
|
|||||||
|
|
||||||
func (me *TestHelper) waitForConnectivity() {
|
func (me *TestHelper) waitForConnectivity() {
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 1000; i++ {
|
||||||
_, err := net.Dial("tcp", "localhost"+*utils.Cfg.ServiceSettings.ListenAddress)
|
conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%v", me.App.Srv.ListenAddr.Port))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
conn.Close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
time.Sleep(time.Millisecond * 20)
|
time.Sleep(time.Millisecond * 20)
|
||||||
@@ -231,11 +236,11 @@ func (me *TestHelper) waitForConnectivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateClient() *model.Client4 {
|
func (me *TestHelper) CreateClient() *model.Client4 {
|
||||||
return model.NewAPIv4Client("http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress)
|
return model.NewAPIv4Client(fmt.Sprintf("http://localhost:%v", me.App.Srv.ListenAddr.Port))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) {
|
func (me *TestHelper) CreateWebSocketClient() (*model.WebSocketClient, *model.AppError) {
|
||||||
return model.NewWebSocketClient4("ws://localhost"+*utils.Cfg.ServiceSettings.ListenAddress, me.Client.AuthToken)
|
return model.NewWebSocketClient4(fmt.Sprintf("ws://localhost:%v", me.App.Srv.ListenAddr.Port), me.Client.AuthToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *TestHelper) CreateUser() *model.User {
|
func (me *TestHelper) CreateUser() *model.User {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package api4
|
package api4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -399,7 +400,7 @@ func TestExecuteCommand(t *testing.T) {
|
|||||||
postCmd := &model.Command{
|
postCmd := &model.Command{
|
||||||
CreatorId: th.BasicUser.Id,
|
CreatorId: th.BasicUser.Id,
|
||||||
TeamId: th.BasicTeam.Id,
|
TeamId: th.BasicTeam.Id,
|
||||||
URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
||||||
Method: model.COMMAND_METHOD_POST,
|
Method: model.COMMAND_METHOD_POST,
|
||||||
Trigger: "postcommand",
|
Trigger: "postcommand",
|
||||||
}
|
}
|
||||||
@@ -443,7 +444,7 @@ func TestExecuteCommand(t *testing.T) {
|
|||||||
getCmd := &model.Command{
|
getCmd := &model.Command{
|
||||||
CreatorId: th.BasicUser.Id,
|
CreatorId: th.BasicUser.Id,
|
||||||
TeamId: th.BasicTeam.Id,
|
TeamId: th.BasicTeam.Id,
|
||||||
URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
||||||
Method: model.COMMAND_METHOD_GET,
|
Method: model.COMMAND_METHOD_GET,
|
||||||
Trigger: "getcommand",
|
Trigger: "getcommand",
|
||||||
}
|
}
|
||||||
@@ -511,7 +512,7 @@ func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
|
|||||||
postCmd := &model.Command{
|
postCmd := &model.Command{
|
||||||
CreatorId: th.BasicUser.Id,
|
CreatorId: th.BasicUser.Id,
|
||||||
TeamId: team2.Id,
|
TeamId: team2.Id,
|
||||||
URL: "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
URL: fmt.Sprintf("http://localhost:%v", th.App.Srv.ListenAddr.Port) + model.API_URL_SUFFIX_V4 + "/teams/command_test",
|
||||||
Method: model.COMMAND_METHOD_POST,
|
Method: model.COMMAND_METHOD_POST,
|
||||||
Trigger: "postcommand",
|
Trigger: "postcommand",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ type App struct {
|
|||||||
Mfa einterfaces.MfaInterface
|
Mfa einterfaces.MfaInterface
|
||||||
Saml einterfaces.SamlInterface
|
Saml einterfaces.SamlInterface
|
||||||
|
|
||||||
newStore func() store.Store
|
newStore func() store.Store
|
||||||
|
configOverride func(*model.Config) *model.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
var appCount = 0
|
var appCount = 0
|
||||||
@@ -77,7 +78,7 @@ func New(options ...Option) *App {
|
|||||||
|
|
||||||
if app.newStore == nil {
|
if app.newStore == nil {
|
||||||
app.newStore = func() store.Store {
|
app.newStore = func() store.Store {
|
||||||
return store.NewLayeredStore(sqlstore.NewSqlSupplier(utils.Cfg.SqlSettings, app.Metrics), app.Metrics, app.Cluster)
|
return store.NewLayeredStore(sqlstore.NewSqlSupplier(app.Config().SqlSettings, app.Metrics), app.Metrics, app.Cluster)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +234,9 @@ func (a *App) initEnterprise() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Config() *model.Config {
|
func (a *App) Config() *model.Config {
|
||||||
|
if a.configOverride != nil {
|
||||||
|
return a.configOverride(utils.Cfg)
|
||||||
|
}
|
||||||
return utils.Cfg
|
return utils.Cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
48
app/app_test.go
Обычный файл
48
app/app_test.go
Обычный файл
@@ -0,0 +1,48 @@
|
|||||||
|
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
|
||||||
|
// See License.txt for license information.
|
||||||
|
|
||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
l4g "github.com/alecthomas/log4go"
|
||||||
|
|
||||||
|
"github.com/mattermost/mattermost-server/store/storetest"
|
||||||
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
// In the case where a dev just wants to run a single test, it's faster to just use the default
|
||||||
|
// store.
|
||||||
|
if filter := flag.Lookup("test.run").Value.String(); filter != "" && filter != "." {
|
||||||
|
utils.TranslationsPreInit()
|
||||||
|
utils.LoadConfig("config.json")
|
||||||
|
l4g.Info("-test.run used, not creating temporary containers")
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.TranslationsPreInit()
|
||||||
|
utils.LoadConfig("config.json")
|
||||||
|
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
||||||
|
|
||||||
|
status := 0
|
||||||
|
|
||||||
|
container, settings, err := storetest.NewMySQLContainer()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
UseTestStore(container, settings)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
StopTestStore()
|
||||||
|
os.Exit(status)
|
||||||
|
}()
|
||||||
|
|
||||||
|
status = m.Run()
|
||||||
|
}
|
||||||
@@ -7,6 +7,9 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
|
"github.com/mattermost/mattermost-server/store"
|
||||||
|
"github.com/mattermost/mattermost-server/store/sqlstore"
|
||||||
|
"github.com/mattermost/mattermost-server/store/storetest"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
|
|
||||||
l4g "github.com/alecthomas/log4go"
|
l4g "github.com/alecthomas/log4go"
|
||||||
@@ -21,13 +24,47 @@ type TestHelper struct {
|
|||||||
BasicPost *model.Post
|
BasicPost *model.Post
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type persistentTestStore struct {
|
||||||
|
store.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*persistentTestStore) Close() {}
|
||||||
|
|
||||||
|
var testStoreContainer *storetest.RunningContainer
|
||||||
|
var testStore *persistentTestStore
|
||||||
|
|
||||||
|
// UseTestStore sets the container and corresponding settings to use for tests. Once the tests are
|
||||||
|
// complete (e.g. at the end of your TestMain implementation), you should call StopTestStore.
|
||||||
|
func UseTestStore(container *storetest.RunningContainer, settings *model.SqlSettings) {
|
||||||
|
testStoreContainer = container
|
||||||
|
testStore = &persistentTestStore{store.NewLayeredStore(sqlstore.NewSqlSupplier(*settings, nil), nil, nil)}
|
||||||
|
}
|
||||||
|
|
||||||
|
func StopTestStore() {
|
||||||
|
if testStoreContainer != nil {
|
||||||
|
testStoreContainer.Stop()
|
||||||
|
testStoreContainer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setupTestHelper(enterprise bool) *TestHelper {
|
func setupTestHelper(enterprise bool) *TestHelper {
|
||||||
utils.TranslationsPreInit()
|
if utils.T == nil {
|
||||||
|
utils.TranslationsPreInit()
|
||||||
|
}
|
||||||
utils.LoadConfig("config.json")
|
utils.LoadConfig("config.json")
|
||||||
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
||||||
|
|
||||||
|
var options []Option
|
||||||
|
if testStore != nil {
|
||||||
|
options = append(options, StoreOverride(testStore))
|
||||||
|
options = append(options, ConfigOverride(func(cfg *model.Config) {
|
||||||
|
cfg.ServiceSettings.ListenAddress = new(string)
|
||||||
|
*cfg.ServiceSettings.ListenAddress = ":0"
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
th := &TestHelper{
|
th := &TestHelper{
|
||||||
App: New(),
|
App: New(options...),
|
||||||
}
|
}
|
||||||
|
|
||||||
*utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
|
*utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
|
||||||
@@ -188,4 +225,8 @@ func (me *TestHelper) LinkUserToTeam(user *model.User, team *model.Team) {
|
|||||||
|
|
||||||
func (me *TestHelper) TearDown() {
|
func (me *TestHelper) TearDown() {
|
||||||
me.App.Shutdown()
|
me.App.Shutdown()
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
StopTestStore()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,25 +4,53 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/store"
|
"github.com/mattermost/mattermost-server/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Option func(a *App)
|
type Option func(a *App)
|
||||||
|
|
||||||
|
// By default, the app will use a global configuration file. This allows you to override all or part
|
||||||
|
// of that configuration.
|
||||||
|
//
|
||||||
|
// The override parameter must be a *model.Config, func(*model.Config), or func(*model.Config) *model.Config.
|
||||||
|
//
|
||||||
|
// XXX: Most code will not respect this at the moment. (We need to eliminate utils.Cfg first.)
|
||||||
|
func ConfigOverride(override interface{}) Option {
|
||||||
|
return func(a *App) {
|
||||||
|
switch o := override.(type) {
|
||||||
|
case *model.Config:
|
||||||
|
a.configOverride = func(*model.Config) *model.Config {
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
case func(*model.Config):
|
||||||
|
a.configOverride = func(cfg *model.Config) *model.Config {
|
||||||
|
ret := *cfg
|
||||||
|
o(&ret)
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
case func(*model.Config) *model.Config:
|
||||||
|
a.configOverride = o
|
||||||
|
default:
|
||||||
|
panic("invalid ConfigOverride")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// By default, the app will use the store specified by the configuration. This allows you to
|
// By default, the app will use the store specified by the configuration. This allows you to
|
||||||
// construct an app with a different store.
|
// construct an app with a different store.
|
||||||
//
|
//
|
||||||
// The storeOrFactory parameter must be either a store.Store or func(App) store.Store.
|
// The override parameter must be either a store.Store or func(App) store.Store.
|
||||||
func StoreOverride(storeOrFactory interface{}) Option {
|
func StoreOverride(override interface{}) Option {
|
||||||
return func(a *App) {
|
return func(a *App) {
|
||||||
switch s := storeOrFactory.(type) {
|
switch o := override.(type) {
|
||||||
case store.Store:
|
case store.Store:
|
||||||
a.newStore = func() store.Store {
|
a.newStore = func() store.Store {
|
||||||
return s
|
return o
|
||||||
}
|
}
|
||||||
case func(*App) store.Store:
|
case func(*App) store.Store:
|
||||||
a.newStore = func() store.Store {
|
a.newStore = func() store.Store {
|
||||||
return s(a)
|
return o(a)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
panic("invalid StoreOverride")
|
panic("invalid StoreOverride")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -16,7 +17,6 @@ import (
|
|||||||
"github.com/gorilla/handlers"
|
"github.com/gorilla/handlers"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/rsc/letsencrypt"
|
"github.com/rsc/letsencrypt"
|
||||||
"github.com/tylerb/graceful"
|
|
||||||
"gopkg.in/throttled/throttled.v2"
|
"gopkg.in/throttled/throttled.v2"
|
||||||
"gopkg.in/throttled/throttled.v2/store/memstore"
|
"gopkg.in/throttled/throttled.v2/store/memstore"
|
||||||
|
|
||||||
@@ -29,7 +29,8 @@ type Server struct {
|
|||||||
Store store.Store
|
Store store.Store
|
||||||
WebSocketRouter *WebSocketRouter
|
WebSocketRouter *WebSocketRouter
|
||||||
Router *mux.Router
|
Router *mux.Router
|
||||||
GracefulServer *graceful.Server
|
Server *http.Server
|
||||||
|
ListenAddr *net.TCPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowedMethods []string = []string{
|
var allowedMethods []string = []string{
|
||||||
@@ -152,16 +153,29 @@ func (a *App) StartServer() {
|
|||||||
handler = httpRateLimiter.RateLimit(handler)
|
handler = httpRateLimiter.RateLimit(handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
a.Srv.GracefulServer = &graceful.Server{
|
a.Srv.Server = &http.Server{
|
||||||
Timeout: TIME_TO_WAIT_FOR_CONNECTIONS_TO_CLOSE_ON_SERVER_SHUTDOWN,
|
Handler: handlers.RecoveryHandler(handlers.RecoveryLogger(&RecoveryLogger{}), handlers.PrintRecoveryStack(true))(handler),
|
||||||
Server: &http.Server{
|
ReadTimeout: time.Duration(*utils.Cfg.ServiceSettings.ReadTimeout) * time.Second,
|
||||||
Addr: *utils.Cfg.ServiceSettings.ListenAddress,
|
WriteTimeout: time.Duration(*utils.Cfg.ServiceSettings.WriteTimeout) * time.Second,
|
||||||
Handler: handlers.RecoveryHandler(handlers.RecoveryLogger(&RecoveryLogger{}), handlers.PrintRecoveryStack(true))(handler),
|
|
||||||
ReadTimeout: time.Duration(*utils.Cfg.ServiceSettings.ReadTimeout) * time.Second,
|
|
||||||
WriteTimeout: time.Duration(*utils.Cfg.ServiceSettings.WriteTimeout) * time.Second,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
l4g.Info(utils.T("api.server.start_server.listening.info"), *utils.Cfg.ServiceSettings.ListenAddress)
|
|
||||||
|
addr := *a.Config().ServiceSettings.ListenAddress
|
||||||
|
if addr == "" {
|
||||||
|
if *utils.Cfg.ServiceSettings.ConnectionSecurity == model.CONN_SECURITY_TLS {
|
||||||
|
addr = ":https"
|
||||||
|
} else {
|
||||||
|
addr = ":http"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listener, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
a.Srv.ListenAddr = listener.Addr().(*net.TCPAddr)
|
||||||
|
|
||||||
|
l4g.Info(utils.T("api.server.start_server.listening.info"), listener.Addr().String())
|
||||||
|
|
||||||
if *utils.Cfg.ServiceSettings.Forward80To443 {
|
if *utils.Cfg.ServiceSettings.Forward80To443 {
|
||||||
go func() {
|
go func() {
|
||||||
@@ -189,25 +203,55 @@ func (a *App) StartServer() {
|
|||||||
|
|
||||||
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
|
tlsConfig.NextProtos = append(tlsConfig.NextProtos, "h2")
|
||||||
|
|
||||||
err = a.Srv.GracefulServer.ListenAndServeTLSConfig(tlsConfig)
|
a.Srv.Server.TLSConfig = tlsConfig
|
||||||
|
err = a.Srv.Server.ServeTLS(listener, "", "")
|
||||||
} else {
|
} else {
|
||||||
err = a.Srv.GracefulServer.ListenAndServeTLS(*utils.Cfg.ServiceSettings.TLSCertFile, *utils.Cfg.ServiceSettings.TLSKeyFile)
|
err = a.Srv.Server.ServeTLS(listener, *utils.Cfg.ServiceSettings.TLSCertFile, *utils.Cfg.ServiceSettings.TLSKeyFile)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = a.Srv.GracefulServer.ListenAndServe()
|
err = a.Srv.Server.Serve(listener)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil && err != http.ErrServerClosed {
|
||||||
l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
|
l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type tcpKeepAliveListener struct {
|
||||||
|
*net.TCPListener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
|
||||||
|
tc, err := ln.AcceptTCP()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tc.SetKeepAlive(true)
|
||||||
|
tc.SetKeepAlivePeriod(3 * time.Minute)
|
||||||
|
return tc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) Listen(addr string) (net.Listener, error) {
|
||||||
|
if addr == "" {
|
||||||
|
addr = ":http"
|
||||||
|
}
|
||||||
|
ln, err := net.Listen("tcp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tcpKeepAliveListener{ln.(*net.TCPListener)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) StopServer() {
|
func (a *App) StopServer() {
|
||||||
if a.Srv.GracefulServer != nil {
|
if a.Srv.Server != nil {
|
||||||
a.Srv.GracefulServer.Stop(TIME_TO_WAIT_FOR_CONNECTIONS_TO_CLOSE_ON_SERVER_SHUTDOWN)
|
ctx, cancel := context.WithTimeout(context.Background(), TIME_TO_WAIT_FOR_CONNECTIONS_TO_CLOSE_ON_SERVER_SHUTDOWN)
|
||||||
<-a.Srv.GracefulServer.StopChan()
|
defer cancel()
|
||||||
a.Srv.GracefulServer = nil
|
if err := a.Srv.Server.Shutdown(ctx); err != nil {
|
||||||
|
l4g.Warn(err.Error())
|
||||||
|
}
|
||||||
|
a.Srv.Server.Close()
|
||||||
|
a.Srv.Server = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// this pattern allows us to "mock" the underlying l4g code when unit testing
|
// this pattern allows us to "mock" the underlying l4g code when unit testing
|
||||||
|
var logger l4g.Logger
|
||||||
var debugLog = l4g.Debug
|
var debugLog = l4g.Debug
|
||||||
var infoLog = l4g.Info
|
var infoLog = l4g.Info
|
||||||
var errorLog = l4g.Error
|
var errorLog = l4g.Error
|
||||||
@@ -50,10 +51,13 @@ func initL4g(logSettings model.LogSettings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create a logger that writes JSON objects to a file, and override our log methods to use it
|
// create a logger that writes JSON objects to a file, and override our log methods to use it
|
||||||
flw := NewJSONFileLogger(level, utils.GetLogFileLocation(logSettings.FileLocation)+".jsonl")
|
if logger != nil {
|
||||||
debugLog = flw.Debug
|
logger.Close()
|
||||||
infoLog = flw.Info
|
}
|
||||||
errorLog = flw.Error
|
logger = NewJSONFileLogger(level, utils.GetLogFileLocation(logSettings.FileLocation)+".jsonl")
|
||||||
|
debugLog = logger.Debug
|
||||||
|
infoLog = logger.Info
|
||||||
|
errorLog = logger.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
package web
|
package web
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/api"
|
"github.com/mattermost/mattermost-server/api"
|
||||||
@@ -11,23 +13,44 @@ import (
|
|||||||
"github.com/mattermost/mattermost-server/app"
|
"github.com/mattermost/mattermost-server/app"
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/store"
|
"github.com/mattermost/mattermost-server/store"
|
||||||
|
"github.com/mattermost/mattermost-server/store/sqlstore"
|
||||||
|
"github.com/mattermost/mattermost-server/store/storetest"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ApiClient *model.Client
|
var ApiClient *model.Client
|
||||||
var URL string
|
var URL string
|
||||||
|
|
||||||
|
type persistentTestStore struct {
|
||||||
|
store.Store
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*persistentTestStore) Close() {}
|
||||||
|
|
||||||
|
var testStoreContainer *storetest.RunningContainer
|
||||||
|
var testStore *persistentTestStore
|
||||||
|
|
||||||
|
func StopTestStore() {
|
||||||
|
if testStoreContainer != nil {
|
||||||
|
testStoreContainer.Stop()
|
||||||
|
testStoreContainer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Setup() *app.App {
|
func Setup() *app.App {
|
||||||
utils.TranslationsPreInit()
|
utils.TranslationsPreInit()
|
||||||
utils.LoadConfig("config.json")
|
utils.LoadConfig("config.json")
|
||||||
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
||||||
|
|
||||||
a := app.New()
|
a := app.New(app.StoreOverride(testStore), app.ConfigOverride(func(cfg *model.Config) {
|
||||||
|
cfg.ServiceSettings.ListenAddress = new(string)
|
||||||
|
*cfg.ServiceSettings.ListenAddress = ":0"
|
||||||
|
}))
|
||||||
a.StartServer()
|
a.StartServer()
|
||||||
api4.Init(a, a.Srv.Router, false)
|
api4.Init(a, a.Srv.Router, false)
|
||||||
api3 := api.Init(a, a.Srv.Router)
|
api3 := api.Init(a, a.Srv.Router)
|
||||||
Init(api3)
|
Init(api3)
|
||||||
URL = "http://localhost" + *utils.Cfg.ServiceSettings.ListenAddress
|
URL = fmt.Sprintf("http://localhost:%v", a.Srv.ListenAddr.Port)
|
||||||
ApiClient = model.NewClient(URL)
|
ApiClient = model.NewClient(URL)
|
||||||
|
|
||||||
a.Srv.Store.MarkSystemRanUnitTests()
|
a.Srv.Store.MarkSystemRanUnitTests()
|
||||||
@@ -39,6 +62,10 @@ func Setup() *app.App {
|
|||||||
|
|
||||||
func TearDown(a *app.App) {
|
func TearDown(a *app.App) {
|
||||||
a.Shutdown()
|
a.Shutdown()
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
StopTestStore()
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test disabled for now so we don't requrie the client to build. Maybe re-enable after client gets moved out.
|
/* Test disabled for now so we don't requrie the client to build. Maybe re-enable after client gets moved out.
|
||||||
@@ -108,3 +135,26 @@ func TestIncomingWebhook(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
utils.TranslationsPreInit()
|
||||||
|
utils.LoadConfig("config.json")
|
||||||
|
utils.InitTranslations(utils.Cfg.LocalizationSettings)
|
||||||
|
|
||||||
|
status := 0
|
||||||
|
|
||||||
|
container, settings, err := storetest.NewPostgreSQLContainer()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testStoreContainer = container
|
||||||
|
testStore = &persistentTestStore{store.NewLayeredStore(sqlstore.NewSqlSupplier(*settings, nil), nil, nil)}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
StopTestStore()
|
||||||
|
os.Exit(status)
|
||||||
|
}()
|
||||||
|
|
||||||
|
status = m.Run()
|
||||||
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user