Fix various segfaults when running go test manually (#8448)
* failing to find i18n shouldn't segfault The server was trying to handle the fact that it couldn't find the i18n directory, by emitting a translated log message... * fix utils.FindDir The attempts to find the directory in the parent or grandparent directory don't work if the current working directory was inside `enterprise`, with `enterprise` itself being a symlink as per the usual developer setup. Recurse to the root of the filesystem, cleaning the path along the way to work around this limitation (and allow tests to be run from an arbitrarily deep nesting level.) Fix corresponding usages to employ filepath.Join. * failing to find html templates shouldn't segfault * fail fast if the test user cannot be created * rework utils.FindDir to retain backwards compatibility
Этот коммит содержится в:
коммит произвёл
George Goldberg
родитель
b1b23079c6
Коммит
9d701c7044
@@ -10,6 +10,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -870,7 +871,7 @@ func TestGetInfoForFilename(t *testing.T) {
|
|||||||
|
|
||||||
func readTestFile(name string) ([]byte, error) {
|
func readTestFile(name string) ([]byte, error) {
|
||||||
path, _ := utils.FindDir("tests")
|
path, _ := utils.FindDir("tests")
|
||||||
file, err := os.Open(path + "/" + name)
|
file, err := os.Open(filepath.Join(path, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@@ -778,7 +779,7 @@ func TestUserUploadProfileImage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
path, _ := utils.FindDir("tests")
|
path, _ := utils.FindDir("tests")
|
||||||
file, err := os.Open(path + "/test.png")
|
file, err := os.Open(filepath.Join(path, "test.png"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -302,7 +303,11 @@ func (me *TestHelper) CreateUserWithClient(client *model.Client4) *model.User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
utils.DisableDebugLogForTest()
|
utils.DisableDebugLogForTest()
|
||||||
ruser, _ := client.CreateUser(user)
|
ruser, response := client.CreateUser(user)
|
||||||
|
if response.Error != nil {
|
||||||
|
panic(response.Error)
|
||||||
|
}
|
||||||
|
|
||||||
ruser.Password = "Password1"
|
ruser.Password = "Password1"
|
||||||
store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
|
store.Must(me.App.Srv.Store.User().VerifyEmail(ruser.Id))
|
||||||
utils.EnableDebugLogForTest()
|
utils.EnableDebugLogForTest()
|
||||||
@@ -675,7 +680,7 @@ func CheckInternalErrorStatus(t *testing.T, resp *model.Response) {
|
|||||||
|
|
||||||
func readTestFile(name string) ([]byte, error) {
|
func readTestFile(name string) ([]byte, error) {
|
||||||
path, _ := utils.FindDir("tests")
|
path, _ := utils.FindDir("tests")
|
||||||
file, err := os.Open(path + "/" + name)
|
file, err := os.Open(filepath.Join(path, name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package api4
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
l4g "github.com/alecthomas/log4go"
|
l4g "github.com/alecthomas/log4go"
|
||||||
@@ -375,7 +376,7 @@ func authorizeOAuthPage(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
|
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
|
||||||
|
|
||||||
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
||||||
http.ServeFile(w, r, staticDir+"root.html")
|
http.ServeFile(w, r, filepath.Join(staticDir, "root.html"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
@@ -53,7 +54,7 @@ func TestPlugin(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
path, _ := utils.FindDir("tests")
|
path, _ := utils.FindDir("tests")
|
||||||
file, err := os.Open(path + "/testplugin.tar.gz")
|
file, err := os.Open(filepath.Join(path, "testplugin.tar.gz"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -439,9 +439,13 @@ func (a *App) WaitForGoroutines() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) HTMLTemplates() *template.Template {
|
func (a *App) HTMLTemplates() *template.Template {
|
||||||
|
if a.htmlTemplateWatcher != nil {
|
||||||
return a.htmlTemplateWatcher.Templates()
|
return a.htmlTemplateWatcher.Templates()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) HTTPClient(trustURLs bool) *http.Client {
|
func (a *App) HTTPClient(trustURLs bool) *http.Client {
|
||||||
insecure := a.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *a.Config().ServiceSettings.EnableInsecureOutgoingConnections
|
insecure := a.Config().ServiceSettings.EnableInsecureOutgoingConnections != nil && *a.Config().ServiceSettings.EnableInsecureOutgoingConnections
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
"github.com/mattermost/mattermost-server/utils"
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
@@ -43,7 +44,7 @@ func (cfg *AutoPostCreator) UploadTestFile() ([]string, bool) {
|
|||||||
filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})]
|
filename := cfg.ImageFilenames[utils.RandIntFromRange(utils.Range{Begin: 0, End: len(cfg.ImageFilenames) - 1})]
|
||||||
|
|
||||||
path, _ := utils.FindDir("web/static/images")
|
path, _ := utils.FindDir("web/static/images")
|
||||||
file, err := os.Open(path + "/" + filename)
|
file, err := os.Open(filepath.Join(path, filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path/filepath"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -370,7 +371,7 @@ func TestImportValidateUserImportData(t *testing.T) {
|
|||||||
// Test a valid User with all fields populated.
|
// Test a valid User with all fields populated.
|
||||||
testsDir, _ := utils.FindDir("tests")
|
testsDir, _ := utils.FindDir("tests")
|
||||||
data = UserImportData{
|
data = UserImportData{
|
||||||
ProfileImage: ptrStr(testsDir + "test.png"),
|
ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")),
|
||||||
Username: ptrStr("bob"),
|
Username: ptrStr("bob"),
|
||||||
Email: ptrStr("bob@example.com"),
|
Email: ptrStr("bob@example.com"),
|
||||||
AuthService: ptrStr("ldap"),
|
AuthService: ptrStr("ldap"),
|
||||||
@@ -1487,7 +1488,7 @@ func TestImportImportUser(t *testing.T) {
|
|||||||
username := model.NewId()
|
username := model.NewId()
|
||||||
testsDir, _ := utils.FindDir("tests")
|
testsDir, _ := utils.FindDir("tests")
|
||||||
data = UserImportData{
|
data = UserImportData{
|
||||||
ProfileImage: ptrStr(testsDir + "test.png"),
|
ProfileImage: ptrStr(filepath.Join(testsDir, "test.png")),
|
||||||
Username: &username,
|
Username: &username,
|
||||||
Email: ptrStr(model.NewId() + "@example.com"),
|
Email: ptrStr(model.NewId() + "@example.com"),
|
||||||
Nickname: ptrStr(model.NewId()),
|
Nickname: ptrStr(model.NewId()),
|
||||||
@@ -1543,7 +1544,7 @@ func TestImportImportUser(t *testing.T) {
|
|||||||
|
|
||||||
// Alter all the fields of that user.
|
// Alter all the fields of that user.
|
||||||
data.Email = ptrStr(model.NewId() + "@example.com")
|
data.Email = ptrStr(model.NewId() + "@example.com")
|
||||||
data.ProfileImage = ptrStr(testsDir + "testgif.gif")
|
data.ProfileImage = ptrStr(filepath.Join(testsDir, "testgif.gif"))
|
||||||
data.AuthService = ptrStr("ldap")
|
data.AuthService = ptrStr("ldap")
|
||||||
data.AuthData = &username
|
data.AuthData = &username
|
||||||
data.Nickname = ptrStr(model.NewId())
|
data.Nickname = ptrStr(model.NewId())
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
@@ -42,7 +41,7 @@ func WriteSamlFile(fileData *multipart.FileHeader) *model.AppError {
|
|||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
configDir, _ := utils.FindDir("config")
|
configDir, _ := utils.FindDir("config")
|
||||||
out, err := os.Create(configDir + filename)
|
out, err := os.Create(filepath.Join(configDir, filename))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("AddSamlCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return model.NewAppError("AddSamlCertificate", "api.admin.add_certificate.saving.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -717,7 +718,7 @@ func CreateProfileImage(username string, userId string, initialFont string) ([]b
|
|||||||
initial := string(strings.ToUpper(username)[0])
|
initial := string(strings.ToUpper(username)[0])
|
||||||
|
|
||||||
fontDir, _ := utils.FindDir("fonts")
|
fontDir, _ := utils.FindDir("fonts")
|
||||||
fontBytes, err := ioutil.ReadFile(fontDir + initialFont)
|
fontBytes, err := ioutil.ReadFile(filepath.Join(fontDir, initialFont))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error(), http.StatusInternalServerError)
|
return nil, model.NewAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -51,21 +50,17 @@ func FindConfigFile(fileName string) (path string) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindDir looks for the given directory in nearby ancestors, falling back to `./` if not found.
|
||||||
func FindDir(dir string) (string, bool) {
|
func FindDir(dir string) (string, bool) {
|
||||||
fileName := "."
|
for _, parent := range []string{".", "..", "../.."} {
|
||||||
found := false
|
foundDir, err := filepath.Abs(filepath.Join(parent, dir))
|
||||||
if _, err := os.Stat("./" + dir + "/"); err == nil {
|
if err != nil {
|
||||||
fileName, _ = filepath.Abs("./" + dir + "/")
|
continue
|
||||||
found = true
|
} else if _, err := os.Stat(foundDir); err == nil {
|
||||||
} else if _, err := os.Stat("../" + dir + "/"); err == nil {
|
return foundDir, true
|
||||||
fileName, _ = filepath.Abs("../" + dir + "/")
|
|
||||||
found = true
|
|
||||||
} else if _, err := os.Stat("../../" + dir + "/"); err == nil {
|
|
||||||
fileName, _ = filepath.Abs("../../" + dir + "/")
|
|
||||||
found = true
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return fileName + "/", found
|
return "./", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func DisableDebugLogForTest() {
|
func DisableDebugLogForTest() {
|
||||||
@@ -136,11 +131,10 @@ func ConfigureLog(s *model.LogSettings) {
|
|||||||
|
|
||||||
func GetLogFileLocation(fileLocation string) string {
|
func GetLogFileLocation(fileLocation string) string {
|
||||||
if fileLocation == "" {
|
if fileLocation == "" {
|
||||||
logDir, _ := FindDir("logs")
|
fileLocation, _ = FindDir("logs")
|
||||||
return logDir + LOG_FILENAME
|
|
||||||
} else {
|
|
||||||
return path.Join(fileLocation, LOG_FILENAME)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return filepath.Join(fileLocation, LOG_FILENAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
func SaveConfig(fileName string, config *model.Config) *model.AppError {
|
func SaveConfig(fileName string, config *model.Config) *model.AppError {
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
"io"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
|
if htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html")); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
ret.templates.Store(htmlTemplates)
|
ret.templates.Store(htmlTemplates)
|
||||||
@@ -56,7 +58,7 @@ func NewHTMLTemplateWatcher(directory string) (*HTMLTemplateWatcher, error) {
|
|||||||
case event := <-watcher.Events:
|
case event := <-watcher.Events:
|
||||||
if event.Op&fsnotify.Write == fsnotify.Write {
|
if event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
l4g.Info("Re-parsing templates because of modified file %v", event.Name)
|
l4g.Info("Re-parsing templates because of modified file %v", event.Name)
|
||||||
if htmlTemplates, err := template.ParseGlob(templatesDir + "*.html"); err != nil {
|
if htmlTemplates, err := template.ParseGlob(filepath.Join(templatesDir, "*.html")); err != nil {
|
||||||
l4g.Error("Failed to parse templates %v", err)
|
l4g.Error("Failed to parse templates %v", err)
|
||||||
} else {
|
} else {
|
||||||
ret.templates.Store(htmlTemplates)
|
ret.templates.Store(htmlTemplates)
|
||||||
@@ -103,6 +105,10 @@ func (t *HTMLTemplate) Render() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *HTMLTemplate) RenderToWriter(w io.Writer) error {
|
func (t *HTMLTemplate) RenderToWriter(w io.Writer) error {
|
||||||
|
if t.Templates == nil {
|
||||||
|
return errors.New("no html templates")
|
||||||
|
}
|
||||||
|
|
||||||
if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil {
|
if err := t.Templates.ExecuteTemplate(w, t.TemplateName, t); err != nil {
|
||||||
l4g.Error(T("api.api.render.error"), t.TemplateName, err)
|
l4g.Error(T("api.api.render.error"), t.TemplateName, err)
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -23,13 +23,15 @@ var settings model.LocalizationSettings
|
|||||||
// this functions loads translations from filesystem
|
// this functions loads translations from filesystem
|
||||||
// and assign english while loading server config
|
// and assign english while loading server config
|
||||||
func TranslationsPreInit() error {
|
func TranslationsPreInit() error {
|
||||||
|
// Set T even if we fail to load the translations. Lots of shutdown handling code will
|
||||||
|
// segfault trying to handle the error, and the untranslated IDs are strictly better.
|
||||||
|
T = TfuncWithFallback("en")
|
||||||
|
TDefault = TfuncWithFallback("en")
|
||||||
|
|
||||||
if err := InitTranslationsWithDir("i18n"); err != nil {
|
if err := InitTranslationsWithDir("i18n"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
T = TfuncWithFallback("en")
|
|
||||||
TDefault = TfuncWithFallback("en")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,9 +53,9 @@ func InitTranslationsWithDir(dir string) error {
|
|||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if filepath.Ext(f.Name()) == ".json" {
|
if filepath.Ext(f.Name()) == ".json" {
|
||||||
filename := f.Name()
|
filename := f.Name()
|
||||||
locales[strings.Split(filename, ".")[0]] = i18nDirectory + filename
|
locales[strings.Split(filename, ".")[0]] = filepath.Join(i18nDirectory, filename)
|
||||||
|
|
||||||
if err := i18n.LoadTranslationFile(i18nDirectory + filename); err != nil {
|
if err := i18n.LoadTranslationFile(filepath.Join(i18nDirectory, filename)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ func GetLicenseFileFromDisk(fileName string) []byte {
|
|||||||
func GetLicenseFileLocation(fileLocation string) string {
|
func GetLicenseFileLocation(fileLocation string) string {
|
||||||
if fileLocation == "" {
|
if fileLocation == "" {
|
||||||
configDir, _ := FindDir("config")
|
configDir, _ := FindDir("config")
|
||||||
return configDir + "mattermost.mattermost-license"
|
return filepath.Join(configDir, "mattermost.mattermost-license")
|
||||||
} else {
|
} else {
|
||||||
return fileLocation
|
return fileLocation
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package web
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
@@ -102,5 +103,5 @@ func root(c *api.Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
|
w.Header().Set("Cache-Control", "no-cache, max-age=31556926, public")
|
||||||
|
|
||||||
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
staticDir, _ := utils.FindDir(model.CLIENT_DIR)
|
||||||
http.ServeFile(w, r, staticDir+"root.html")
|
http.ServeFile(w, r, filepath.Join(staticDir, "root.html"))
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user