mirror of https://github.com/gogs/gogs.git
conf: add unit tests (#5954)
* conf: add tests for utils.go * conf: add tests for static.go * mock os/exec * Run tests on Windows * appveyor: fix gcc not found * computed: add unit tests * log: add unit tests * log: fix tests on Windows * conf: add some tests * Finish adding tests * Cover more cases * Add tests for testutil * Add more testspull/5955/head
parent
17ae0ed3ee
commit
8796df8218
|
@ -11,6 +11,10 @@ build: false
|
|||
deploy: false
|
||||
|
||||
install:
|
||||
- set PATH=C:\msys64\mingw64\bin;%PATH% # Fix "gcc" not found: https://github.com/appveyor/ci/issues/2613
|
||||
- go version
|
||||
- go env
|
||||
- go build -tags "minwinsvc" -v
|
||||
|
||||
test_script:
|
||||
- go test -v -race -cover ./...
|
||||
|
|
|
@ -99,8 +99,8 @@ var (
|
|||
// string when environment variables are not set.
|
||||
func HomeDir() string {
|
||||
homeDirOnce.Do(func() {
|
||||
if !IsWindowsRuntime() {
|
||||
homeDir = os.Getenv("HOME")
|
||||
homeDir = os.Getenv("HOME")
|
||||
if homeDir != "" {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"gogs.io/gogs/internal/testutil"
|
||||
)
|
||||
|
||||
func TestIsProdMode(t *testing.T) {
|
||||
before := App.RunMode
|
||||
defer func() {
|
||||
App.RunMode = before
|
||||
}()
|
||||
|
||||
tests := []struct {
|
||||
mode string
|
||||
want bool
|
||||
}{
|
||||
{mode: "dev", want: false},
|
||||
{mode: "test", want: false},
|
||||
|
||||
{mode: "prod", want: true},
|
||||
{mode: "Prod", want: true},
|
||||
{mode: "PROD", want: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
App.RunMode = test.mode
|
||||
assert.Equal(t, test.want, IsProdMode())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWorkDirHelper(t *testing.T) {
|
||||
if !testutil.WantHelperProcess() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, WorkDir())
|
||||
}
|
||||
|
||||
func TestWorkDir(t *testing.T) {
|
||||
tests := []struct {
|
||||
env string
|
||||
want string
|
||||
}{
|
||||
{env: "GOGS_WORK_DIR=/tmp", want: "/tmp"},
|
||||
{env: "", want: WorkDir()},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
out, err := testutil.Exec("TestWorkDirHelper", test.env)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, test.want, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCustomDirHelper(t *testing.T) {
|
||||
if !testutil.WantHelperProcess() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, CustomDir())
|
||||
}
|
||||
|
||||
func TestCustomDir(t *testing.T) {
|
||||
tests := []struct {
|
||||
env string
|
||||
want string
|
||||
}{
|
||||
{env: "GOGS_CUSTOM=/tmp", want: "/tmp"},
|
||||
{env: "", want: CustomDir()},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
out, err := testutil.Exec("TestCustomDirHelper", test.env)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, test.want, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHomeDirHelper(t *testing.T) {
|
||||
if !testutil.WantHelperProcess() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, HomeDir())
|
||||
}
|
||||
|
||||
func TestHomeDir(t *testing.T) {
|
||||
tests := []struct {
|
||||
envs []string
|
||||
want string
|
||||
}{
|
||||
{envs: []string{"HOME=/tmp"}, want: "/tmp"},
|
||||
{envs: []string{`USERPROFILE=C:\Users\Joe`}, want: `C:\Users\Joe`},
|
||||
{envs: []string{`HOMEDRIVE=C:`, `HOMEPATH=\Users\Joe`}, want: `C:\Users\Joe`},
|
||||
{envs: nil, want: ""},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
out, err := testutil.Exec("TestHomeDirHelper", test.envs...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Equal(t, test.want, out)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -353,7 +353,7 @@ func Init(customConf string) error {
|
|||
// ----- I18n settings -----
|
||||
// *************************
|
||||
|
||||
I18n = new(i18n)
|
||||
I18n = new(i18nConf)
|
||||
if err = File.Section("i18n").MapTo(I18n); err != nil {
|
||||
return errors.Wrap(err, "mapping [i18n] section")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/ini.v1"
|
||||
|
||||
"gogs.io/gogs/internal/testutil"
|
||||
)
|
||||
|
||||
func TestAsset(t *testing.T) {
|
||||
// Make sure it does not blow up
|
||||
_, err := Asset("conf/app.ini")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssetDir(t *testing.T) {
|
||||
// Make sure it does not blow up
|
||||
_, err := AssetDir("conf")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMustAsset(t *testing.T) {
|
||||
// Make sure it does not blow up
|
||||
MustAsset("conf/app.ini")
|
||||
}
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
if IsWindowsRuntime() {
|
||||
return
|
||||
}
|
||||
|
||||
ini.PrettyFormat = false
|
||||
defer func() {
|
||||
MustInit("")
|
||||
ini.PrettyFormat = true
|
||||
}()
|
||||
|
||||
assert.Nil(t, Init(filepath.Join("testdata", "custom.ini")))
|
||||
|
||||
cfg := ini.Empty()
|
||||
cfg.NameMapper = ini.SnackCase
|
||||
|
||||
for _, v := range []struct {
|
||||
section string
|
||||
config interface{}
|
||||
}{
|
||||
{"", &App},
|
||||
{"server", &Server},
|
||||
{"server", &SSH},
|
||||
{"repository", &Repository},
|
||||
{"database", &Database},
|
||||
{"security", &Security},
|
||||
{"email", &Email},
|
||||
{"auth", &Auth},
|
||||
{"user", &User},
|
||||
{"session", &Session},
|
||||
{"attachment", &Attachment},
|
||||
{"time", &Time},
|
||||
{"picture", &Picture},
|
||||
{"mirror", &Mirror},
|
||||
{"i18n", &I18n},
|
||||
} {
|
||||
err := cfg.Section(v.section).ReflectFrom(v.config)
|
||||
if err != nil {
|
||||
t.Fatalf("%s: %v", v.section, err)
|
||||
}
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
_, err := cfg.WriteTo(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testutil.AssertGolden(t, filepath.Join("testdata", "TestInit.golden.ini"), testutil.Update("TestInit"), buf.String())
|
||||
}
|
|
@ -9,28 +9,39 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gopkg.in/ini.v1"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
// Log settings
|
||||
var Log struct {
|
||||
RootPath string
|
||||
Modes []string
|
||||
Configs []interface{}
|
||||
type loggerConf struct {
|
||||
Buffer int64
|
||||
Config interface{}
|
||||
}
|
||||
|
||||
// InitLogging initializes the logging service of the application.
|
||||
func InitLogging() {
|
||||
Log.RootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
|
||||
type logConf struct {
|
||||
RootPath string
|
||||
Modes []string
|
||||
Configs []*loggerConf
|
||||
}
|
||||
|
||||
// Because we always create a console logger as the primary logger at init time,
|
||||
// we need to remove it in case the user doesn't configure to use it after the
|
||||
// logging service is initalized.
|
||||
hasConsole := false
|
||||
// Log settings
|
||||
var Log *logConf
|
||||
|
||||
// initLogConf returns parsed logging configuration from given INI file.
|
||||
// NOTE: Because we always create a console logger as the primary logger at init time,
|
||||
// we need to remove it in case the user doesn't configure to use it after the logging
|
||||
// service is initalized.
|
||||
func initLogConf(cfg *ini.File) (_ *logConf, hasConsole bool, _ error) {
|
||||
rootPath := cfg.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
|
||||
modes := strings.Split(cfg.Section("log").Key("MODE").MustString("console"), ",")
|
||||
lc := &logConf{
|
||||
RootPath: ensureAbs(rootPath),
|
||||
Modes: make([]string, 0, len(modes)),
|
||||
Configs: make([]*loggerConf, 0, len(modes)),
|
||||
}
|
||||
|
||||
// Iterate over [log.*] sections to initialize individual logger.
|
||||
Log.Modes = strings.Split(File.Section("log").Key("MODE").MustString("console"), ",")
|
||||
Log.Configs = make([]interface{}, 0, len(Log.Modes))
|
||||
levelMappings := map[string]log.Level{
|
||||
"trace": log.LevelTrace,
|
||||
"info": log.LevelInfo,
|
||||
|
@ -39,43 +50,30 @@ func InitLogging() {
|
|||
"fatal": log.LevelFatal,
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Buffer int64
|
||||
Config interface{}
|
||||
}
|
||||
for _, mode := range Log.Modes {
|
||||
mode = strings.ToLower(strings.TrimSpace(mode))
|
||||
secName := "log." + mode
|
||||
sec, err := File.GetSection(secName)
|
||||
for i := range modes {
|
||||
modes[i] = strings.ToLower(strings.TrimSpace(modes[i]))
|
||||
secName := "log." + modes[i]
|
||||
sec, err := cfg.GetSection(secName)
|
||||
if err != nil {
|
||||
log.Fatal("Missing configuration section [%s] for %q logger", secName, mode)
|
||||
return
|
||||
return nil, hasConsole, errors.Errorf("missing configuration section [%s] for %q logger", secName, modes[i])
|
||||
}
|
||||
|
||||
level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
|
||||
buffer := sec.Key("BUFFER_LEN").MustInt64(100)
|
||||
var c *config
|
||||
switch mode {
|
||||
var c *loggerConf
|
||||
switch modes[i] {
|
||||
case log.DefaultConsoleName:
|
||||
hasConsole = true
|
||||
c = &config{
|
||||
c = &loggerConf{
|
||||
Buffer: buffer,
|
||||
Config: log.ConsoleConfig{
|
||||
Level: level,
|
||||
},
|
||||
}
|
||||
err = log.NewConsole(c.Buffer, c.Config)
|
||||
|
||||
case log.DefaultFileName:
|
||||
logPath := filepath.Join(Log.RootPath, "gogs.log")
|
||||
logDir := filepath.Dir(logPath)
|
||||
err = os.MkdirAll(logDir, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create log directory %q: %v", logDir, err)
|
||||
return
|
||||
}
|
||||
|
||||
c = &config{
|
||||
logPath := filepath.Join(lc.RootPath, "gogs.log")
|
||||
c = &loggerConf{
|
||||
Buffer: buffer,
|
||||
Config: log.FileConfig{
|
||||
Level: level,
|
||||
|
@ -89,20 +87,18 @@ func InitLogging() {
|
|||
},
|
||||
},
|
||||
}
|
||||
err = log.NewFile(c.Buffer, c.Config)
|
||||
|
||||
case log.DefaultSlackName:
|
||||
c = &config{
|
||||
c = &loggerConf{
|
||||
Buffer: buffer,
|
||||
Config: log.SlackConfig{
|
||||
Level: level,
|
||||
URL: sec.Key("URL").String(),
|
||||
},
|
||||
}
|
||||
err = log.NewSlack(c.Buffer, c.Config)
|
||||
|
||||
case log.DefaultDiscordName:
|
||||
c = &config{
|
||||
c = &loggerConf{
|
||||
Buffer: buffer,
|
||||
Config: log.DiscordConfig{
|
||||
Level: level,
|
||||
|
@ -110,22 +106,62 @@ func InitLogging() {
|
|||
Username: sec.Key("USERNAME").String(),
|
||||
},
|
||||
}
|
||||
err = log.NewDiscord(c.Buffer, c.Config)
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
lc.Modes = append(lc.Modes, modes[i])
|
||||
lc.Configs = append(lc.Configs, c)
|
||||
}
|
||||
|
||||
return lc, hasConsole, nil
|
||||
}
|
||||
|
||||
// InitLogging initializes the logging service of the application.
|
||||
func InitLogging() {
|
||||
logConf, hasConsole, err := initLogConf(File)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to init logging configuration: %v", err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(logConf.RootPath, os.ModePerm)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create log directory: %v", err)
|
||||
}
|
||||
|
||||
for i, mode := range logConf.Modes {
|
||||
c := logConf.Configs[i]
|
||||
|
||||
var err error
|
||||
var level log.Level
|
||||
switch mode {
|
||||
case log.DefaultConsoleName:
|
||||
level = c.Config.(log.ConsoleConfig).Level
|
||||
err = log.NewConsole(c.Buffer, c.Config)
|
||||
case log.DefaultFileName:
|
||||
level = c.Config.(log.FileConfig).Level
|
||||
err = log.NewFile(c.Buffer, c.Config)
|
||||
case log.DefaultSlackName:
|
||||
level = c.Config.(log.SlackConfig).Level
|
||||
err = log.NewSlack(c.Buffer, c.Config)
|
||||
case log.DefaultDiscordName:
|
||||
level = c.Config.(log.DiscordConfig).Level
|
||||
err = log.NewDiscord(c.Buffer, c.Config)
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Fatal("Failed to init %s logger: %v", mode, err)
|
||||
return
|
||||
}
|
||||
|
||||
Log.Configs = append(Log.Configs, c)
|
||||
log.Trace("Log mode: %s (%s)", strings.Title(mode), strings.Title(strings.ToLower(level.String())))
|
||||
}
|
||||
|
||||
if !hasConsole {
|
||||
log.Remove(log.DefaultConsoleName)
|
||||
}
|
||||
|
||||
Log = logConf
|
||||
}
|
||||
|
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"gopkg.in/ini.v1"
|
||||
log "unknwon.dev/clog/v2"
|
||||
)
|
||||
|
||||
func Test_initLogConf(t *testing.T) {
|
||||
t.Run("missing configuration section", func(t *testing.T) {
|
||||
f, err := ini.Load([]byte(`
|
||||
[log]
|
||||
MODE = console
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, hasConsole, err := initLogConf(f)
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, `missing configuration section [log.console] for "console" logger`, err.Error())
|
||||
assert.False(t, hasConsole)
|
||||
assert.Nil(t, got)
|
||||
})
|
||||
|
||||
t.Run("no console logger", func(t *testing.T) {
|
||||
f, err := ini.Load([]byte(`
|
||||
[log]
|
||||
MODE = file
|
||||
|
||||
[log.file]
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, hasConsole, err := initLogConf(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.False(t, hasConsole)
|
||||
assert.NotNil(t, got)
|
||||
})
|
||||
|
||||
f, err := ini.Load([]byte(`
|
||||
[log]
|
||||
ROOT_PATH = log
|
||||
MODE = console, file, slack, discord
|
||||
BUFFER_LEN = 50
|
||||
LEVEL = trace
|
||||
|
||||
[log.console]
|
||||
BUFFER_LEN = 10
|
||||
|
||||
[log.file]
|
||||
LEVEL = INFO
|
||||
LOG_ROTATE = true
|
||||
DAILY_ROTATE = true
|
||||
MAX_SIZE_SHIFT = 20
|
||||
MAX_LINES = 1000
|
||||
MAX_DAYS = 3
|
||||
|
||||
[log.slack]
|
||||
LEVEL = Warn
|
||||
URL = https://slack.com
|
||||
|
||||
[log.discord]
|
||||
LEVEL = error
|
||||
URL = https://discordapp.com
|
||||
USERNAME = yoyo
|
||||
`))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
got, hasConsole, err := initLogConf(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
logConf := &logConf{
|
||||
RootPath: filepath.Join(WorkDir(), "log"),
|
||||
Modes: []string{
|
||||
log.DefaultConsoleName,
|
||||
log.DefaultFileName,
|
||||
log.DefaultSlackName,
|
||||
log.DefaultDiscordName,
|
||||
},
|
||||
Configs: []*loggerConf{
|
||||
{
|
||||
Buffer: 10,
|
||||
Config: log.ConsoleConfig{
|
||||
Level: log.LevelTrace,
|
||||
},
|
||||
}, {
|
||||
Buffer: 50,
|
||||
Config: log.FileConfig{
|
||||
Level: log.LevelInfo,
|
||||
Filename: filepath.Join(WorkDir(), "log", "gogs.log"),
|
||||
FileRotationConfig: log.FileRotationConfig{
|
||||
Rotate: true,
|
||||
Daily: true,
|
||||
MaxSize: 1 << 20,
|
||||
MaxLines: 1000,
|
||||
MaxDays: 3,
|
||||
},
|
||||
},
|
||||
}, {
|
||||
Buffer: 50,
|
||||
Config: log.SlackConfig{
|
||||
Level: log.LevelWarn,
|
||||
URL: "https://slack.com",
|
||||
},
|
||||
}, {
|
||||
Buffer: 50,
|
||||
Config: log.DiscordConfig{
|
||||
Level: log.LevelError,
|
||||
URL: "https://discordapp.com",
|
||||
Username: "yoyo",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.True(t, hasConsole)
|
||||
assert.Equal(t, logConf, got)
|
||||
}
|
|
@ -16,12 +16,12 @@ import (
|
|||
|
||||
// HasMinWinSvc is whether the application is built with Windows Service support.
|
||||
//
|
||||
// ⚠️ WARNING: should only be set by "static_minwinsvc.go".
|
||||
// ⚠️ WARNING: should only be set by "internal/conf/static_minwinsvc.go".
|
||||
var HasMinWinSvc bool
|
||||
|
||||
// Build time and commit information.
|
||||
//
|
||||
// ⚠️ WARNING: should only be set by -ldflags.
|
||||
// ⚠️ WARNING: should only be set by "-ldflags".
|
||||
var (
|
||||
BuildTime string
|
||||
BuildCommit string
|
||||
|
@ -35,7 +35,7 @@ var CustomConf string
|
|||
var (
|
||||
// Application settings
|
||||
App struct {
|
||||
// ⚠️ WARNING: Should only be set by main package (i.e. "gogs.go").
|
||||
// ⚠️ WARNING: Should only be set by the main package (i.e. "gogs.go").
|
||||
Version string `ini:"-"`
|
||||
|
||||
BrandName string
|
||||
|
@ -288,7 +288,7 @@ var (
|
|||
}
|
||||
|
||||
// I18n settings
|
||||
I18n *i18n
|
||||
I18n *i18nConf
|
||||
|
||||
// Webhook settings
|
||||
Webhook struct {
|
||||
|
@ -349,7 +349,9 @@ var (
|
|||
|
||||
// Git settings
|
||||
Git struct {
|
||||
Version string `ini:"-"`
|
||||
// ⚠️ WARNING: Should only be set by "internal/db/repo.go".
|
||||
Version string `ini:"-"`
|
||||
|
||||
DisableDiffHighlight bool
|
||||
MaxGitDiffLines int
|
||||
MaxGitDiffLineCharacters int
|
||||
|
@ -408,15 +410,15 @@ var (
|
|||
HasRobotsTxt bool
|
||||
)
|
||||
|
||||
type i18n struct {
|
||||
Langs []string `delim:","`
|
||||
Names []string `delim:","`
|
||||
dateLangs map[string]string
|
||||
type i18nConf struct {
|
||||
Langs []string `delim:","`
|
||||
Names []string `delim:","`
|
||||
dateLangs map[string]string `ini:"-"`
|
||||
}
|
||||
|
||||
// DateLang transforms standard language locale name to corresponding value in datetime plugin.
|
||||
func (i *i18n) DateLang(lang string) string {
|
||||
name, ok := i.dateLangs[lang]
|
||||
func (c *i18nConf) DateLang(lang string) string {
|
||||
name, ok := c.dateLangs[lang]
|
||||
if ok {
|
||||
return name
|
||||
}
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_i18n_DateLang(t *testing.T) {
|
||||
c := &i18nConf{
|
||||
dateLangs: map[string]string{
|
||||
"en-US": "en",
|
||||
"zh-CN": "zh",
|
||||
},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
lang string
|
||||
want string
|
||||
}{
|
||||
{lang: "en-US", want: "en"},
|
||||
{lang: "zh-CN", want: "zh"},
|
||||
|
||||
{lang: "jp-JP", want: "en"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
assert.Equal(t, test.want, c.DateLang(test.lang))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
BRAND_NAME=Testing
|
||||
RUN_USER=git
|
||||
RUN_MODE=test
|
||||
APP_NAME=
|
||||
|
||||
[server]
|
||||
EXTERNAL_URL=http://localhost:3080/
|
||||
DOMAIN=localhost
|
||||
PROTOCOL=http
|
||||
HTTP_ADDR=0.0.0.0
|
||||
HTTP_PORT=3000
|
||||
CERT_FILE=custom/https/cert.pem
|
||||
KEY_FILE=custom/https/key.pem
|
||||
TLS_MIN_VERSION=TLS12
|
||||
UNIX_SOCKET_PERMISSION=666
|
||||
LOCAL_ROOT_URL=http://0.0.0.0:3000/
|
||||
OFFLINE_MODE=false
|
||||
DISABLE_ROUTER_LOG=true
|
||||
ENABLE_GZIP=false
|
||||
APP_DATA_PATH=/tmp/data
|
||||
LOAD_ASSETS_FROM_DISK=false
|
||||
LANDING_URL=/explore
|
||||
ROOT_URL=
|
||||
LANDING_PAGE=
|
||||
DISABLE_SSH=false
|
||||
SSH_DOMAIN=localhost
|
||||
SSH_PORT=22
|
||||
SSH_ROOT_PATH=/tmp
|
||||
SSH_KEYGEN_PATH=ssh-keygen
|
||||
SSH_KEY_TEST_PATH=/tmp/ssh-key-test
|
||||
MINIMUM_KEY_SIZE_CHECK=true
|
||||
REWRITE_AUTHORIZED_KEYS_AT_START=false
|
||||
START_SSH_SERVER=false
|
||||
SSH_LISTEN_HOST=0.0.0.0
|
||||
SSH_LISTEN_PORT=22
|
||||
SSH_SERVER_CIPHERS=aes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128
|
||||
|
||||
[repository]
|
||||
ROOT=/tmp/gogs-repositories
|
||||
SCRIPT_TYPE=bash
|
||||
ANSI_CHARSET=
|
||||
FORCE_PRIVATE=false
|
||||
MAX_CREATION_LIMIT=-1
|
||||
PREFERRED_LICENSES=Apache License 2.0,MIT License
|
||||
DISABLE_HTTP_GIT=false
|
||||
ENABLE_LOCAL_PATH_MIGRATION=false
|
||||
ENABLE_RAW_FILE_RENDER_MODE=false
|
||||
COMMITS_FETCH_CONCURRENCY=0
|
||||
|
||||
[repository.editor]
|
||||
LINE_WRAP_EXTENSIONS=.txt,.md,.markdown,.mdown,.mkd
|
||||
PREVIEWABLE_FILE_MODES=markdown
|
||||
|
||||
[repository.upload]
|
||||
ENABLED=true
|
||||
TEMP_PATH=/tmp/uploads
|
||||
ALLOWED_TYPES=
|
||||
FILE_MAX_SIZE=3
|
||||
MAX_FILES=5
|
||||
|
||||
[database]
|
||||
TYPE=sqlite
|
||||
HOST=127.0.0.1:5432
|
||||
NAME=gogs
|
||||
USER=gogs
|
||||
PASSWORD=12345678
|
||||
SSL_MODE=disable
|
||||
PATH=/tmp/gogs.db
|
||||
DB_TYPE=
|
||||
PASSWD=
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK=false
|
||||
SECRET_KEY=`!#@FDEWREWR&*(`
|
||||
LOGIN_REMEMBER_DAYS=7
|
||||
COOKIE_REMEMBER_NAME=gogs_incredible
|
||||
COOKIE_USERNAME=gogs_awesome
|
||||
COOKIE_SECURE=false
|
||||
ENABLE_LOGIN_STATUS_COOKIE=false
|
||||
LOGIN_STATUS_COOKIE_NAME=login_status
|
||||
REVERSE_PROXY_AUTHENTICATION_USER=
|
||||
|
||||
[email]
|
||||
ENABLED=true
|
||||
SUBJECT_PREFIX=[Gogs]
|
||||
HOST=smtp.mailgun.org:587
|
||||
FROM=noreply@gogs.localhost
|
||||
USER=noreply@gogs.localhost
|
||||
PASSWORD=87654321
|
||||
DISABLE_HELO=false
|
||||
HELO_HOSTNAME=
|
||||
SKIP_VERIFY=false
|
||||
USE_CERTIFICATE=false
|
||||
CERT_FILE=custom/email/cert.pem
|
||||
KEY_FILE=custom/email/key.pem
|
||||
USE_PLAIN_TEXT=false
|
||||
ADD_PLAIN_TEXT_ALT=false
|
||||
PASSWD=
|
||||
|
||||
[auth]
|
||||
ACTIVATE_CODE_LIVES=10
|
||||
RESET_PASSWORD_CODE_LIVES=10
|
||||
REQUIRE_EMAIL_CONFIRMATION=true
|
||||
REQUIRE_SIGNIN_VIEW=false
|
||||
DISABLE_REGISTRATION=false
|
||||
ENABLE_REGISTRATION_CAPTCHA=true
|
||||
ENABLE_REVERSE_PROXY_AUTHENTICATION=false
|
||||
ENABLE_REVERSE_PROXY_AUTO_REGISTRATION=false
|
||||
REVERSE_PROXY_AUTHENTICATION_HEADER=X-FORWARDED-FOR
|
||||
ACTIVE_CODE_LIVE_MINUTES=0
|
||||
RESET_PASSWD_CODE_LIVE_MINUTES=0
|
||||
REGISTER_EMAIL_CONFIRM=false
|
||||
ENABLE_CAPTCHA=false
|
||||
ENABLE_NOTIFY_MAIL=false
|
||||
|
||||
[user]
|
||||
ENABLE_EMAIL_NOTIFICATION=true
|
||||
|
||||
[session]
|
||||
PROVIDER=memory
|
||||
PROVIDER_CONFIG=data/sessions
|
||||
COOKIE_NAME=i_like_gogs
|
||||
COOKIE_SECURE=false
|
||||
GC_INTERVAL=10
|
||||
MAX_LIFE_TIME=10
|
||||
CSRF_COOKIE_NAME=_csrf
|
||||
GC_INTERVAL_TIME=0
|
||||
SESSION_LIFE_TIME=0
|
||||
|
||||
[attachment]
|
||||
ENABLED=true
|
||||
PATH=/tmp/attachments
|
||||
ALLOWED_TYPES=image/jpeg|image/png
|
||||
MAX_SIZE=4
|
||||
MAX_FILES=5
|
||||
|
||||
[time]
|
||||
FORMAT=RFC1123
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH=/tmp/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH=/tmp/repo-avatars
|
||||
GRAVATAR_SOURCE=https://secure.gravatar.com/avatar/
|
||||
DISABLE_GRAVATAR=false
|
||||
ENABLE_FEDERATED_AVATAR=false
|
||||
|
||||
[mirror]
|
||||
DEFAULT_INTERVAL=8
|
||||
|
||||
[i18n]
|
||||
LANGS=en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,ja-JP,es-ES,pt-BR,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,gl-ES,uk-UA,en-GB,hu-HU,sk-SK,id-ID,fa-IR,vi-VN,pt-PT
|
||||
NAMES=English,简体中文,繁體中文(香港),繁體中文(臺灣),Deutsch,français,Nederlands,latviešu,русский,日本語,español,português do Brasil,polski,български,italiano,suomi,Türkçe,čeština,српски,svenska,한국어,galego,українська,English (United Kingdom),Magyar,Slovenčina,Indonesian,Persian,Vietnamese,Português
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
APP_NAME = Testing
|
||||
RUN_MODE = test
|
||||
|
||||
[server]
|
||||
ROOT_URL = http://localhost:3080/
|
||||
APP_DATA_PATH = /tmp/data
|
||||
SSH_ROOT_PATH = /tmp
|
||||
SSH_KEY_TEST_PATH = /tmp/ssh-key-test
|
||||
MINIMUM_KEY_SIZE_CHECK = true
|
||||
LANDING_PAGE = explore
|
||||
|
||||
[repository]
|
||||
ROOT = /tmp/gogs-repositories
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /tmp/uploads
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite
|
||||
PASSWD = 12345678
|
||||
PATH = /tmp/gogs.db
|
||||
|
||||
[security]
|
||||
REVERSE_PROXY_AUTHENTICATION_USER=X-FORWARDED-FOR
|
||||
|
||||
[email]
|
||||
ENABLED = true
|
||||
PASSWD = 87654321
|
||||
|
||||
[auth]
|
||||
ACTIVE_CODE_LIVE_MINUTES = 10
|
||||
RESET_PASSWD_CODE_LIVE_MINUTES = 10
|
||||
REGISTER_EMAIL_CONFIRM = true
|
||||
ENABLE_CAPTCHA = true
|
||||
ENABLE_NOTIFY_MAIL = true
|
||||
|
||||
[session]
|
||||
GC_INTERVAL_TIME = 10
|
||||
SESSION_LIFE_TIME = 10
|
||||
|
||||
[attachment]
|
||||
PATH = /tmp/attachments
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /tmp/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = /tmp/repo-avatars
|
|
@ -14,6 +14,13 @@ import (
|
|||
"gogs.io/gogs/internal/process"
|
||||
)
|
||||
|
||||
// cleanUpOpenSSHVersion cleans up the raw output of "ssh -V" and returns a clean version string.
|
||||
func cleanUpOpenSSHVersion(raw string) string {
|
||||
v := strings.TrimRight(strings.Fields(raw)[0], ",1234567890")
|
||||
v = strings.TrimSuffix(strings.TrimPrefix(v, "OpenSSH_"), "p")
|
||||
return v
|
||||
}
|
||||
|
||||
// openSSHVersion returns string representation of OpenSSH version via command "ssh -V".
|
||||
func openSSHVersion() (string, error) {
|
||||
// NOTE: Somehow the version is printed to stderr.
|
||||
|
@ -22,10 +29,7 @@ func openSSHVersion() (string, error) {
|
|||
return "", errors.Wrap(err, stderr)
|
||||
}
|
||||
|
||||
// Trim unused information, see https://github.com/gogs/gogs/issues/4507#issuecomment-305150441.
|
||||
v := strings.TrimRight(strings.Fields(stderr)[0], ",1234567890")
|
||||
v = strings.TrimSuffix(strings.TrimPrefix(v, "OpenSSH_"), "p")
|
||||
return v, nil
|
||||
return cleanUpOpenSSHVersion(stderr), nil
|
||||
}
|
||||
|
||||
// ensureAbs prepends the WorkDir to the given path if it is not an absolute path.
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package conf
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_cleanUpOpenSSHVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
raw string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
raw: "OpenSSH_7.4p1 Ubuntu-10, OpenSSL 1.0.2g 1 Mar 2016",
|
||||
want: "7.4",
|
||||
}, {
|
||||
raw: "OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013",
|
||||
want: "5.3",
|
||||
}, {
|
||||
raw: "OpenSSH_4.3p2, OpenSSL 0.9.8e-fips-rhel5 01 Jul 2008",
|
||||
want: "4.3",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
assert.Equal(t, test.want, cleanUpOpenSSHVersion(test.raw))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ensureAbs(t *testing.T) {
|
||||
wd := WorkDir()
|
||||
|
||||
tests := []struct {
|
||||
path string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
path: "data/avatars",
|
||||
want: filepath.Join(wd, "data", "avatars"),
|
||||
}, {
|
||||
path: wd,
|
||||
want: wd,
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
assert.Equal(t, test.want, ensureAbs(test.path))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -25,9 +25,9 @@ func IsExist(path string) bool {
|
|||
|
||||
// CurrentUsername returns the current system user via environment variables.
|
||||
func CurrentUsername() string {
|
||||
curUserName := os.Getenv("USER")
|
||||
if len(curUserName) > 0 {
|
||||
return curUserName
|
||||
username := os.Getenv("USER")
|
||||
if len(username) > 0 {
|
||||
return username
|
||||
}
|
||||
|
||||
return os.Getenv("USERNAME")
|
||||
|
|
|
@ -55,3 +55,8 @@ func TestIsExist(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentUsername(t *testing.T) {
|
||||
// Make sure it does not blow up
|
||||
CurrentUsername()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Exec executes "go test" on given helper with supplied environment variables.
|
||||
// It is useful to mock "os/exec" functions in tests. When succeeded, it returns
|
||||
// the result produced by the test helper.
|
||||
// The test helper should:
|
||||
// 1. Use WantHelperProcess function to determine if it is being called in helper mode.
|
||||
// 2. Call fmt.Fprintln(os.Stdout, ...) to print results for the main test to collect.
|
||||
func Exec(helper string, envs ...string) (string, error) {
|
||||
cmd := exec.Command(os.Args[0], "-test.run="+helper, "--")
|
||||
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
|
||||
cmd.Env = append(cmd.Env, envs...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
str := string(out)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%v - %s", err, str)
|
||||
}
|
||||
|
||||
if strings.Contains(str, "no tests to run") {
|
||||
return "", errors.New("no tests to run")
|
||||
} else if !strings.Contains(str, "PASS") {
|
||||
return "", errors.New(str)
|
||||
}
|
||||
|
||||
// Collect helper result
|
||||
result := str[:strings.Index(str, "PASS")]
|
||||
result = strings.TrimSpace(result)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// WantHelperProcess returns true if current process is in helper mode.
|
||||
func WantHelperProcess() bool {
|
||||
return os.Getenv("GO_WANT_HELPER_PROCESS") == "1"
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestExecHelper(t *testing.T) {
|
||||
if !WantHelperProcess() {
|
||||
return
|
||||
}
|
||||
|
||||
if os.Getenv("PASS") != "1" {
|
||||
fmt.Fprintln(os.Stdout, "tests failed")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stdout, "tests succeed")
|
||||
}
|
||||
|
||||
func TestExec(t *testing.T) {
|
||||
tests := []struct {
|
||||
helper string
|
||||
env string
|
||||
expOut string
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
helper: "NoTestsToRun",
|
||||
expErr: errors.New("no tests to run"),
|
||||
}, {
|
||||
helper: "TestExecHelper",
|
||||
expErr: errors.New("exit status 1 - tests failed\n"),
|
||||
}, {
|
||||
helper: "TestExecHelper",
|
||||
env: "PASS=1",
|
||||
expOut: "tests succeed",
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
out, err := Exec(test.helper, test.env)
|
||||
assert.Equal(t, test.expErr, err)
|
||||
assert.Equal(t, test.expOut, out)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var updateRegex = flag.String("update", "", "Update testdata of tests matching the given regex")
|
||||
|
||||
// Update returns true if update regex mathces given test name.
|
||||
func Update(name string) bool {
|
||||
if updateRegex == nil || *updateRegex == "" {
|
||||
return false
|
||||
}
|
||||
return regexp.MustCompile(*updateRegex).MatchString(name)
|
||||
}
|
||||
|
||||
// AssertGolden compares what's got and what's in the golden file. It updates
|
||||
// the golden file on-demand.
|
||||
func AssertGolden(t testing.TB, path string, update bool, got interface{}) {
|
||||
t.Helper()
|
||||
|
||||
data := marshal(t, got)
|
||||
|
||||
if update {
|
||||
if err := ioutil.WriteFile(path, data, 0640); err != nil {
|
||||
t.Fatalf("update golden file %q: %s", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
golden, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatalf("read golden file %q: %s", path, err)
|
||||
}
|
||||
|
||||
assert.Equal(t, string(golden), string(data))
|
||||
}
|
||||
|
||||
func marshal(t testing.TB, v interface{}) []byte {
|
||||
t.Helper()
|
||||
|
||||
switch v2 := v.(type) {
|
||||
case string:
|
||||
return []byte(v2)
|
||||
case []byte:
|
||||
return v2
|
||||
default:
|
||||
data, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2020 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
before := updateRegex
|
||||
defer func() {
|
||||
updateRegex = before
|
||||
}()
|
||||
|
||||
t.Run("no flag", func(t *testing.T) {
|
||||
updateRegex = nil
|
||||
assert.False(t, Update("TestUpdate"))
|
||||
})
|
||||
|
||||
tests := []struct {
|
||||
regex string
|
||||
name string
|
||||
want bool
|
||||
}{
|
||||
{regex: "", name: "TestUpdate", want: false},
|
||||
{regex: "TestNotFound", name: "TestUpdate", want: false},
|
||||
|
||||
{regex: ".*", name: "TestUpdate", want: true},
|
||||
}
|
||||
for _, test := range tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
updateRegex = &test.regex
|
||||
assert.Equal(t, test.want, Update(test.name))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssertGolden(t *testing.T) {
|
||||
// Make sure it does not blow up
|
||||
AssertGolden(t, filepath.Join("testdata", "golden"), false, "{\n \"Message\": \"This is a golden file.\"\n}")
|
||||
AssertGolden(t, filepath.Join("testdata", "golden"), false, []byte("{\n \"Message\": \"This is a golden file.\"\n}"))
|
||||
|
||||
type T struct {
|
||||
Message string
|
||||
}
|
||||
AssertGolden(t, filepath.Join("testdata", "golden"), false, T{"This is a golden file."})
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"Message": "This is a golden file."
|
||||
}
|
Loading…
Reference in New Issue