2011-11-24 18:53:05 -07:00
|
|
|
// Copyright 2011 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package build
|
|
|
|
|
|
|
|
// TODO(adg): test authentication
|
|
|
|
|
|
|
|
import (
|
|
|
|
"appengine"
|
|
|
|
"appengine/datastore"
|
|
|
|
"bytes"
|
2012-02-05 15:26:32 -07:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2011-11-24 18:53:05 -07:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2012-02-05 15:26:32 -07:00
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"net/url"
|
2011-12-01 22:05:12 -07:00
|
|
|
"strings"
|
2011-12-15 16:48:06 -07:00
|
|
|
"time"
|
2011-11-24 18:53:05 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
http.HandleFunc("/buildtest", testHandler)
|
|
|
|
}
|
|
|
|
|
|
|
|
var testEntityKinds = []string{
|
|
|
|
"Package",
|
|
|
|
"Commit",
|
|
|
|
"Result",
|
|
|
|
"Log",
|
|
|
|
}
|
|
|
|
|
2011-12-04 22:22:14 -07:00
|
|
|
const testPkg = "code.google.com/p/go.test"
|
2011-11-29 01:24:57 -07:00
|
|
|
|
2012-01-29 17:59:06 -07:00
|
|
|
var testPackage = &Package{Name: "Test", Kind: "subrepo", Path: testPkg}
|
2011-11-29 01:24:57 -07:00
|
|
|
|
|
|
|
var testPackages = []*Package{
|
2012-03-08 11:48:51 -07:00
|
|
|
{Name: "Go", Path: ""},
|
2011-11-29 01:24:57 -07:00
|
|
|
testPackage,
|
|
|
|
}
|
|
|
|
|
2012-02-05 15:26:32 -07:00
|
|
|
var tCommitTime = time.Now().Add(-time.Hour * 24 * 7)
|
2011-12-15 16:48:06 -07:00
|
|
|
|
|
|
|
func tCommit(hash, parentHash string) *Commit {
|
2012-02-05 15:26:32 -07:00
|
|
|
tCommitTime.Add(time.Hour) // each commit should have a different time
|
2011-12-15 16:48:06 -07:00
|
|
|
return &Commit{
|
|
|
|
Hash: hash,
|
|
|
|
ParentHash: parentHash,
|
2012-02-05 15:26:32 -07:00
|
|
|
Time: tCommitTime,
|
2011-12-15 16:48:06 -07:00
|
|
|
User: "adg",
|
|
|
|
Desc: "change description",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-24 18:53:05 -07:00
|
|
|
var testRequests = []struct {
|
|
|
|
path string
|
|
|
|
vals url.Values
|
|
|
|
req interface{}
|
|
|
|
res interface{}
|
|
|
|
}{
|
2011-11-29 01:24:57 -07:00
|
|
|
// Packages
|
2012-01-29 17:59:06 -07:00
|
|
|
{"/packages?kind=subrepo", nil, nil, []*Package{testPackage}},
|
2011-11-29 01:24:57 -07:00
|
|
|
|
|
|
|
// Go repo
|
2011-12-15 16:48:06 -07:00
|
|
|
{"/commit", nil, tCommit("0001", "0000"), nil},
|
|
|
|
{"/commit", nil, tCommit("0002", "0001"), nil},
|
|
|
|
{"/commit", nil, tCommit("0003", "0002"), nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
2011-11-24 18:53:05 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0001", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0002", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
2011-11-24 18:53:05 -07:00
|
|
|
|
2011-11-29 01:24:57 -07:00
|
|
|
// multiple builders
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
2011-11-24 18:53:05 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-amd64", Hash: "0003", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0002"}}},
|
2011-11-24 18:53:05 -07:00
|
|
|
|
2011-11-29 01:24:57 -07:00
|
|
|
// branches
|
2011-12-15 16:48:06 -07:00
|
|
|
{"/commit", nil, tCommit("0004", "0003"), nil},
|
|
|
|
{"/commit", nil, tCommit("0005", "0002"), nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0005", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0004"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
|
|
|
|
// logs
|
2011-12-20 18:13:27 -07:00
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: "test"}, nil},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/log/a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", nil, nil, "test"},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, nil},
|
2011-11-29 01:24:57 -07:00
|
|
|
|
2011-12-20 19:16:47 -07:00
|
|
|
// repeat failure (shouldn't re-send mail)
|
|
|
|
{"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: "test"}, nil},
|
|
|
|
|
2011-11-29 01:24:57 -07:00
|
|
|
// non-Go repos
|
|
|
|
{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1001", ParentHash: "1000"}, nil},
|
|
|
|
{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1002", ParentHash: "1001"}, nil},
|
|
|
|
{"/commit", nil, &Commit{PackagePath: testPkg, Hash: "1003", ParentHash: "1002"}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1003"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0001", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1002"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1002", GoHash: "0001", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1001"}}},
|
2011-11-29 01:24:57 -07:00
|
|
|
{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0001", OK: true}, nil},
|
2011-12-19 21:30:11 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, nil},
|
|
|
|
{"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0002"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1003"}}},
|
2012-01-29 20:50:36 -07:00
|
|
|
|
|
|
|
// re-build Go revision for stale subrepos
|
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}},
|
2011-12-20 18:13:27 -07:00
|
|
|
{"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0005", OK: false, Log: "boo"}, nil},
|
2012-01-29 20:50:36 -07:00
|
|
|
{"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, nil},
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func testHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if !appengine.IsDevAppServer() {
|
|
|
|
fmt.Fprint(w, "These tests must be run under the dev_appserver.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
c := appengine.NewContext(r)
|
|
|
|
if err := nukeEntities(c, testEntityKinds); err != nil {
|
|
|
|
logErr(w, r, err)
|
|
|
|
return
|
|
|
|
}
|
2011-12-04 22:22:14 -07:00
|
|
|
if r.FormValue("nukeonly") != "" {
|
|
|
|
fmt.Fprint(w, "OK")
|
|
|
|
return
|
|
|
|
}
|
2011-11-24 18:53:05 -07:00
|
|
|
|
|
|
|
for _, p := range testPackages {
|
|
|
|
if _, err := datastore.Put(c, p.Key(c), p); err != nil {
|
|
|
|
logErr(w, r, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for i, t := range testRequests {
|
2011-12-20 19:16:47 -07:00
|
|
|
c.Infof("running test %d %s", i, t.path)
|
2011-11-24 18:53:05 -07:00
|
|
|
errorf := func(format string, args ...interface{}) {
|
|
|
|
fmt.Fprintf(w, "%d %s: ", i, t.path)
|
|
|
|
fmt.Fprintf(w, format, args...)
|
|
|
|
fmt.Fprintln(w)
|
|
|
|
}
|
|
|
|
var body io.ReadWriter
|
|
|
|
if t.req != nil {
|
|
|
|
body = new(bytes.Buffer)
|
|
|
|
json.NewEncoder(body).Encode(t.req)
|
|
|
|
}
|
2012-01-12 11:42:39 -07:00
|
|
|
url := "http://" + domain + t.path
|
2011-11-24 18:53:05 -07:00
|
|
|
if t.vals != nil {
|
|
|
|
url += "?" + t.vals.Encode()
|
|
|
|
}
|
|
|
|
req, err := http.NewRequest("POST", url, body)
|
|
|
|
if err != nil {
|
|
|
|
logErr(w, r, err)
|
|
|
|
return
|
|
|
|
}
|
2011-12-01 22:05:12 -07:00
|
|
|
if t.req != nil {
|
|
|
|
req.Method = "POST"
|
|
|
|
}
|
2011-11-24 18:53:05 -07:00
|
|
|
req.Header = r.Header
|
|
|
|
rec := httptest.NewRecorder()
|
2011-12-19 21:30:11 -07:00
|
|
|
|
|
|
|
// Make the request
|
2011-11-24 18:53:05 -07:00
|
|
|
http.DefaultServeMux.ServeHTTP(rec, req)
|
2011-12-19 21:30:11 -07:00
|
|
|
|
2011-11-24 18:53:05 -07:00
|
|
|
if rec.Code != 0 && rec.Code != 200 {
|
|
|
|
errorf(rec.Body.String())
|
2011-11-29 01:24:57 -07:00
|
|
|
return
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
2011-12-01 22:05:12 -07:00
|
|
|
resp := new(dashResponse)
|
2011-12-19 21:30:11 -07:00
|
|
|
|
|
|
|
// If we're expecting a *Todo value,
|
|
|
|
// prime the Response field with a Todo and a Commit inside it.
|
|
|
|
if _, ok := t.res.(*Todo); ok {
|
|
|
|
resp.Response = &Todo{Data: &Commit{}}
|
|
|
|
}
|
|
|
|
|
2011-12-01 22:05:12 -07:00
|
|
|
if strings.HasPrefix(t.path, "/log/") {
|
|
|
|
resp.Response = rec.Body.String()
|
|
|
|
} else {
|
|
|
|
err := json.NewDecoder(rec.Body).Decode(resp)
|
|
|
|
if err != nil {
|
|
|
|
errorf("decoding response: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2011-11-24 18:53:05 -07:00
|
|
|
if e, ok := t.res.(string); ok {
|
2011-12-01 22:05:12 -07:00
|
|
|
g, ok := resp.Response.(string)
|
|
|
|
if !ok {
|
|
|
|
errorf("Response not string: %T", resp.Response)
|
|
|
|
return
|
|
|
|
}
|
2011-11-24 18:53:05 -07:00
|
|
|
if g != e {
|
2011-12-01 22:05:12 -07:00
|
|
|
errorf("response mismatch: got %q want %q", g, e)
|
2011-11-29 01:24:57 -07:00
|
|
|
return
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
|
|
|
}
|
2011-12-19 21:30:11 -07:00
|
|
|
if e, ok := t.res.(*Todo); ok {
|
|
|
|
g, ok := resp.Response.(*Todo)
|
|
|
|
if !ok {
|
|
|
|
errorf("Response not *Todo: %T", resp.Response)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if e.Data == nil && g.Data != nil {
|
|
|
|
errorf("Response.Data should be nil, got: %v", g.Data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if g.Data == nil {
|
|
|
|
errorf("Response.Data is nil, want: %v", e.Data)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
gd, ok := g.Data.(*Commit)
|
|
|
|
if !ok {
|
|
|
|
errorf("Response.Data not *Commit: %T", g.Data)
|
|
|
|
return
|
|
|
|
}
|
2012-01-29 20:50:36 -07:00
|
|
|
if eh := e.Data.(*Commit).Hash; eh != gd.Hash {
|
|
|
|
errorf("hashes don't match: got %q, want %q", gd.Hash, eh)
|
2011-12-19 21:30:11 -07:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2011-12-01 22:05:12 -07:00
|
|
|
if t.res == nil && resp.Response != nil {
|
|
|
|
errorf("response mismatch: got %q expected <nil>",
|
|
|
|
resp.Response)
|
|
|
|
return
|
|
|
|
}
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
2011-12-01 22:05:12 -07:00
|
|
|
fmt.Fprint(w, "PASS")
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
|
|
|
|
2012-02-05 15:26:32 -07:00
|
|
|
func nukeEntities(c appengine.Context, kinds []string) error {
|
2011-11-24 18:53:05 -07:00
|
|
|
if !appengine.IsDevAppServer() {
|
2012-02-05 15:26:32 -07:00
|
|
|
return errors.New("can't nuke production data")
|
2011-11-24 18:53:05 -07:00
|
|
|
}
|
|
|
|
var keys []*datastore.Key
|
|
|
|
for _, kind := range kinds {
|
|
|
|
q := datastore.NewQuery(kind).KeysOnly()
|
|
|
|
for t := q.Run(c); ; {
|
|
|
|
k, err := t.Next(nil)
|
|
|
|
if err == datastore.Done {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
keys = append(keys, k)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return datastore.DeleteMulti(c, keys)
|
|
|
|
}
|