-
-
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
Conversation
@lunny This is basically functioning and ready for review now. |
Makefile
Outdated
@@ -67,7 +67,8 @@ lint: | |||
for PKG in $(PACKAGES); do golint -set_exit_status $$PKG || exit 1; done; | |||
|
|||
.PHONY: test | |||
test: | |||
test: TAGS=bindata sqlite |
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.
@tboerger maybe you can review this file changed.
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.
For the record, I used to add a new target like xtest:
specifically for the new testing facility but go test
would still look into the directory and keep doing its thing. Another approach to prevent it is to deliberately exclude the /tests/
directory from the PACKAGE
variable for the xtest
target.
Any ideas?
Edit: @lunny @tboerger I've changed it per the aforementioned way.
tests/internal/utils/utils.go
Outdated
} | ||
|
||
// RunTest Helper function for setting up a running Gitea server for functional testing and then gracefully terminating it. | ||
func (c *Config) RunTest(tests ...func(*Config) error) (err error) { |
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.
Would it make sense to have the functions in tests
also take a *testing.T
argument? That way, the tests in tests
can call assert.Equal(..)
and the like.
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.
Agreed. I'll submit a change later for evaluation. And if it works well, I'll then adopt the assert.Equal
way.
Edit: I have submitted the proposed change.
tests/version_test.go
Outdated
|
||
log.Printf("Actual: \"%s\" Expected: \"%s\"\n", string(actual), string(expected)) | ||
if actual != expected { | ||
return fmt.Errorf("do not match") |
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.
This error message isn't very specific; if I see the error message "do not match", I don't know which test failed, why it failed (other than that something didn't match something else).
Like I said above, if we could find a way to pass a *testing.T
into the tests, that would be really nice.
@@ -0,0 +1,11 @@ | |||
package misc |
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.
Need to include copyright info
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. 069155d249b94bb89a84a27002db177c072672c1
tests/internal/utils/utils.go
Outdated
LogFile *os.File | ||
} | ||
|
||
func redirect(cmd *exec.Cmd, f *os.File) error { |
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 f
argument is not used.
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. a68c7ae
tests/install_test.go
Outdated
|
||
// Give the server some amount of time to warm up. | ||
time.Sleep(100 * time.Millisecond) | ||
fmt.Fprintf(os.Stderr, ".") |
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.
Can just use fmt.Fprint(os.Stderr, ".")
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.
Without the sleeps, the retry count would be around ~250 on my laptop. And I think the .
with a fixed amount of timeout can give a rough metric on how the server startup time changes a long the way. If scalability really become an issue, we can change the timeout then.
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.
No, I meant keep the sleep, but replace the call to fmt.Fprintf(..)
(line 50) with fmt.Fprint(..)
. No reason to use fmt.Fprintf(..)
if you're not using any formatting. Sorry for any confusion.
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.
Got it.
tests/install_test.go
Outdated
} | ||
defer resp.Body.Close() | ||
|
||
_ = resp |
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.
Is this line necessary?
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.
Ah, it was for making debugging easier. OK to remove it now.
tests/version_test.go
Outdated
|
||
actual := string(bytes.TrimSpace(buf)) | ||
|
||
log.Printf("Actual: \"%s\" Expected: \"%s\"\n", string(actual), string(expected)) |
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.
actual
and expected
are already strings; they don't need to be casted.
tests/internal/utils/utils.go
Outdated
|
||
workdir := t.Config.WorkDir | ||
if workdir == "" { | ||
workdir, err = filepath.Abs(fmt.Sprintf("%s-%10d", filepath.Base(t.Config.Program), time.Now().UnixNano())) |
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.
I'd prefer something like ioutil.TempDir(os.TempDir(), "gitea_tests")
. Since we're going to discard the contents of workdir
anyways (line 78), we might as well use a temporary directory.
tests/version_test.go
Outdated
//LogFile: os.Stderr, | ||
} | ||
|
||
if err := utils.New(t, &conf).RunTest(install, version); err != nil { |
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.
It would be nice if we could find a way to not have to run install
before every test. Once we start adding more end-to-end tests, this won't scale very well.
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.
I am thinking about adding a method func (t *T) Cleanup()
to do the housekeeping. The tests we currently have would then look like utils.New(t, conf).RunTest(install, version).Cleanup()
.
But when used as follows to 'share' a testing instance across many testing functions:
var globalT *utils.T
func init() {
globalT = utils.New(t.conf).RunTest(install)
}
func TestA(t *testing.T) {
globalT.RunTest(version)
}
func TestB(t *testing.T) {
globalT.RunTest(signup)
}
I have no idea how we can call the cleanup method before quitting.
I don't see any unit-tests for Also please don't call it 'xtest', go for 'integration-test' or 'e2e-test' :) |
@bkcsoft What do you mean by the 'unit-tests'? There isn't any under |
build failed. |
@lunny It's strange. My local copy doesn't have the problem and I can't see how this change could break it. I just renamed a Makefile target irrelevant to the unit tests. |
Please rebase. |
ccbf863
to
c6fcd32
Compare
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.
I didn't go through the tests, but they seem to pass 😉
routers/api/v1/misc/version.go
Outdated
|
||
// ServerVersion shows the version of the Gitea server | ||
func ServerVersion(ctx *context.APIContext) { | ||
ctx.Write([]byte(setting.AppVer)) |
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.
As the entire API is JSON, maybe you should do this instead
type serverVersion struct {
Version string
}
func ServerVersion(ctx *context.APIContext) {
ctx.JSON(200, &serverVersion{Version: setting.AppVer})
}
Preferably the struct should go in code.gitea.io/sdk
🙂 (If you do that just call it api.Version
)
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.
There exists an API named Version
already (https://github.com/go-gitea/gitea/blob/master/vendor/code.gitea.io/sdk/gitea/gitea.go#L17) for library's version.
I am afraid that it would lead to confusion if I have the both called 'Version'.
I did change the function name of the server-side handler to Version
. PTAL.
/api/v1/version
for testing it)
/api/v1/version
for testing it)/api/v1/version
for testing it)
@typeless is this ready to review now? |
@lunny Yes. |
tests/version_test.go
Outdated
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"code.gitea.io/gitea/tests/internal/utils" |
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.
https://github.com/go-gitea/gitea/blob/master/CONTRIBUTING.md#styleguide
import (
// stdlib
"encoding/json"
"fmt"
// local packages
"code.gitea.io/gitea/models"
"code.gitea.io/sdk/gitea"
// external packages
"github.com/foo/bar"
"gopkg.io/baz.v1"
)
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.
tests/version_test.go
Outdated
|
||
fields := strings.Fields(string(out)) | ||
if len(fields) != 3 { | ||
return fmt.Errorf("unexpected version string") |
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.
Minor, but could we include the unexpected version string in the error message; it would make debugging easier in the case where there is unexpected output.
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.
Good idea.
For the record I just found the tests can not pass if using the Go tip, but works fine with Go 1.8. 😮 EDIT: Git bisect shows that it's golang/go@3792db5 |
0188e04
to
f320057
Compare
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.
Could integration tests be put under a specific directory rather than just the generic /test/
one ?
tests/install_test.go
Outdated
|
||
func makeSimpleSettings(user, workdir, port string) map[string][]string { | ||
return map[string][]string{ | ||
"db_type": {"SQLite3"}, |
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.
Doesn't this need a build tag to work ?
Any chance to test other databases too ?
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.
Doesn't this need a build tag to work ?
Yes. Currently we need to have an existing Gitea binary built with SQLite3 to work. I have added a Makefile target named 'e2e-test' to simplify the steps.
Any chance to test other databases too ?
I have not used other databases for Gitea so far and they are much harder to setup. Therefore I would delegate the task to other developers with the skills & experiences.
Also change back the Makefile to use `make integration-test`.
Slightly flattened directory hierarchy is better.
04131a2
to
b022db5
Compare
return map[string][]string{ | ||
"db_type": {"SQLite3"}, | ||
"db_host": {"localhost"}, | ||
"db_path": {workdir + "data/gitea.db"}, |
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.
On Sat, Mar 04, 2017 at 06:14:01AM -0800, Mura Li wrote:
Vendoring configuration has been updated.
Was the PR merged already ? Can you drop a link to the sdk PR here ?
|
|
LGTM Just missing @bkcsoft approval. |
@bkcsoft Please take a look at the PR. |
This will produce |
The primary effort of the PR is to implement a prototype of (poor man's) automated functional tests for Gitea. It currently tests
/install
and/version
only.For #63