-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add basic integration test infrastructure (and new endpoint /api/v1/version
for testing it)
#741
Changes from 59 commits
5a73043
447b802
6ab4622
1f41c0b
4e41eb1
8ab6fb9
1f7a314
fcf470c
86f12e1
8a98268
56c9278
a62c847
1137e7a
f8775f8
a5f9e7d
6b8b09a
b603a31
19a0b63
5a85dd9
4b033b4
78a697f
cec3dee
37591d6
c223dbd
335b41f
7f4e3f4
b0686ee
33a7561
43d973d
235fa4b
662833f
9bcb255
130e725
4a2d00c
c4343c0
240e25b
ae80af3
06c1193
0a6356f
0e161f8
a30aff4
57fc992
fda4cca
ae0dfd5
856a854
a7a98fd
7e1990b
0ef4b44
b4ef83b
f4bbd25
83a4697
a81ef4c
6a60048
175267d
2532c60
3430d3a
6dedc14
e4ad394
b022db5
7fe9959
a7547bf
01a2a73
55e54c3
22a7ad4
3223af5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// Copyright 2017 The Gitea 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 integration | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"os" | ||
"os/user" | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
|
||
"code.gitea.io/gitea/integrations/internal/utils" | ||
) | ||
|
||
// The HTTP port listened by the Gitea server. | ||
const ServerHTTPPort = "3001" | ||
|
||
const _RetryLimit = 10 | ||
|
||
func makeSimpleSettings(user, workdir, port string) map[string][]string { | ||
return map[string][]string{ | ||
"db_type": {"SQLite3"}, | ||
"db_host": {"localhost"}, | ||
"db_path": {workdir + "data/gitea.db"}, | ||
"app_name": {"Gitea: Git with a cup of tea"}, | ||
"repo_root_path": {workdir + "repositories"}, | ||
"run_user": {user}, | ||
"domain": {"localhost"}, | ||
"ssh_port": {"22"}, | ||
"http_port": {port}, | ||
"app_url": {"http://localhost:" + port}, | ||
"log_root_path": {workdir + "log"}, | ||
} | ||
} | ||
|
||
func install(t *utils.T) error { | ||
var r *http.Response | ||
var err error | ||
|
||
for i := 1; i <= _RetryLimit; i++ { | ||
|
||
r, err = http.Get("http://:" + ServerHTTPPort + "/") | ||
if err == nil { | ||
fmt.Fprintln(os.Stderr) | ||
break | ||
} | ||
|
||
// Give the server some amount of time to warm up. | ||
time.Sleep(100 * time.Millisecond) | ||
fmt.Fprint(os.Stderr, ".") | ||
} | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
defer r.Body.Close() | ||
|
||
_user, err := user.Current() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
path, err := filepath.Abs(t.Config.WorkDir) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
settings := makeSimpleSettings(_user.Username, path, ServerHTTPPort) | ||
resp, err := http.PostForm("http://:"+ServerHTTPPort+"/install", settings) | ||
if err != nil { | ||
return err | ||
} | ||
defer resp.Body.Close() | ||
|
||
return nil | ||
} | ||
|
||
func TestInstall(t *testing.T) { | ||
conf := utils.Config{ | ||
Program: "../gitea", | ||
WorkDir: "", | ||
Args: []string{"web", "--port", ServerHTTPPort}, | ||
LogFile: os.Stderr, | ||
} | ||
|
||
if err := utils.New(t, &conf).RunTest(install); err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright 2017 The Gitea 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 utils | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"syscall" | ||
"testing" | ||
) | ||
|
||
// T wraps testing.T and the configurations of the testing instance. | ||
type T struct { | ||
*testing.T | ||
Config *Config | ||
} | ||
|
||
// New create an instance of T | ||
func New(t *testing.T, c *Config) *T { | ||
return &T{T: t, Config: c} | ||
} | ||
|
||
// Config Settings of the testing program | ||
type Config struct { | ||
// The executable path of the tested program. | ||
Program string | ||
// Working directory prepared for the tested program. | ||
// If empty, a directory named with random suffixes is picked, and created under the current directory. | ||
// The directory will be removed when the test finishes. | ||
WorkDir string | ||
// Command-line arguments passed to the tested program. | ||
Args []string | ||
|
||
// Where to redirect the stdout/stderr to. For debugging purposes. | ||
LogFile *os.File | ||
} | ||
|
||
func redirect(cmd *exec.Cmd, f *os.File) error { | ||
stdout, err := cmd.StdoutPipe() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
stderr, err := cmd.StderrPipe() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
go io.Copy(f, stdout) | ||
go io.Copy(f, stderr) | ||
return nil | ||
} | ||
|
||
// RunTest Helper function for setting up a running Gitea server for functional testing and then gracefully terminating it. | ||
func (t *T) RunTest(tests ...func(*T) error) (err error) { | ||
if t.Config.Program == "" { | ||
return errors.New("Need input file") | ||
} | ||
|
||
path, err := filepath.Abs(t.Config.Program) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
workdir := t.Config.WorkDir | ||
if workdir == "" { | ||
workdir, err = ioutil.TempDir(os.TempDir(), "gitea_tests-") | ||
if err != nil { | ||
return err | ||
} | ||
defer os.RemoveAll(workdir) | ||
} | ||
|
||
newpath := filepath.Join(workdir, filepath.Base(path)) | ||
if err := os.Symlink(path, newpath); err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("Starting the server: %s args:%s workdir:%s", newpath, t.Config.Args, workdir) | ||
|
||
cmd := exec.Command(newpath, t.Config.Args...) | ||
cmd.Dir = workdir | ||
|
||
if t.Config.LogFile != nil && testing.Verbose() { | ||
if err := redirect(cmd, t.Config.LogFile); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if err := cmd.Start(); err != nil { | ||
return err | ||
} | ||
|
||
log.Println("Server started.") | ||
|
||
defer func() { | ||
// Do not early return. We have to call Wait anyway. | ||
_ = cmd.Process.Signal(syscall.SIGTERM) | ||
|
||
if _err := cmd.Wait(); _err != nil { | ||
if _err.Error() != "signal: terminated" { | ||
err = _err | ||
return | ||
} | ||
} | ||
|
||
log.Println("Server exited") | ||
}() | ||
|
||
for _, fn := range tests { | ||
if err := fn(t); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
// Note that the return value 'err' may be updated by the 'defer' statement before despite it's returning nil here. | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright 2017 The Gitea 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 integration | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"os" | ||
"os/exec" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"code.gitea.io/gitea/integrations/internal/utils" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func version(t *utils.T) error { | ||
var err error | ||
|
||
path, err := filepath.Abs(t.Config.Program) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
cmd := exec.Command(path, "--version") | ||
out, err := cmd.Output() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fields := strings.Fields(string(out)) | ||
if len(fields) != 3 { | ||
return fmt.Errorf("unexpected version string '%s'", out) | ||
} | ||
|
||
expected := fields[2] | ||
|
||
var r *http.Response | ||
r, err = http.Get("http://:" + ServerHTTPPort + "/api/v1/version") | ||
if err == nil { | ||
return err | ||
} | ||
|
||
defer r.Body.Close() | ||
|
||
buf, err := ioutil.ReadAll(r.Body) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
actual := string(bytes.TrimSpace(buf)) | ||
|
||
log.Printf("Actual: \"%s\" Expected: \"%s\"\n", actual, expected) | ||
assert.Equal(t, expected, actual) | ||
|
||
return nil | ||
} | ||
|
||
func TestVersion(t *testing.T) { | ||
conf := utils.Config{ | ||
Program: "../gitea", | ||
WorkDir: "", | ||
Args: []string{"web", "--port", ServerHTTPPort}, | ||
LogFile: os.Stderr, | ||
} | ||
|
||
if err := utils.New(t, &conf).RunTest(install, version); err != nil { | ||
t.Fatal(err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Copyright 2017 The Gitea 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 misc | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to include copyright info There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. 069155d249b94bb89a84a27002db177c072672c1 |
||
|
||
import ( | ||
"code.gitea.io/gitea/modules/context" | ||
"code.gitea.io/gitea/modules/setting" | ||
"code.gitea.io/sdk/gitea" | ||
) | ||
|
||
// Version shows the version of the Gitea server | ||
func Version(ctx *context.APIContext) { | ||
ctx.JSON(200, &gitea.ServerVersion{Version: setting.AppVer}) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But the test db data will stay with production data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 'workdir' is created by ioutil.TempDir if not specified (that is, an empty string).
My comment regarding the field WorkDir is outdated and does not match with the reality. I'll fix it. Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.