Этот коммит содержится в:
Chris
2017-10-16 08:09:43 -07:00
коммит произвёл Joram Wilander
родитель adb2b1d6ed
Коммит 34285d8cca
15 изменённых файлов: 302 добавлений и 61 удалений

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

@@ -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 Обычный файл
Просмотреть файл

@@ -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()
}