github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/tools/dashboard/app/build/test.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build appengine 6 7 package build 8 9 // TODO(adg): test authentication 10 // TODO(adg): refactor to use appengine/aetest instead 11 12 import ( 13 "bytes" 14 "encoding/json" 15 "errors" 16 "fmt" 17 "io" 18 "net/http" 19 "net/http/httptest" 20 "net/url" 21 "strings" 22 "time" 23 24 "appengine" 25 "appengine/datastore" 26 ) 27 28 func init() { 29 handleFunc("/buildtest", testHandler) 30 } 31 32 var testEntityKinds = []string{ 33 "Package", 34 "Commit", 35 "CommitRun", 36 "Result", 37 "PerfResult", 38 "PerfMetricRun", 39 "PerfConfig", 40 "PerfTodo", 41 "Log", 42 } 43 44 const testPkg = "golang.org/x/test" 45 46 var testPackage = &Package{Name: "Test", Kind: "subrepo", Path: testPkg} 47 48 var testPackages = []*Package{ 49 {Name: "Go", Path: ""}, 50 testPackage, 51 } 52 53 var tCommitTime = time.Now().Add(-time.Hour * 24 * 7) 54 55 func tCommit(hash, parentHash, path string, bench bool) *Commit { 56 tCommitTime.Add(time.Hour) // each commit should have a different time 57 return &Commit{ 58 PackagePath: path, 59 Hash: hash, 60 ParentHash: parentHash, 61 Time: tCommitTime, 62 User: "adg", 63 Desc: "change description " + hash, 64 NeedsBenchmarking: bench, 65 } 66 } 67 68 var testRequests = []struct { 69 path string 70 vals url.Values 71 req interface{} 72 res interface{} 73 }{ 74 // Packages 75 {"/packages", url.Values{"kind": {"subrepo"}}, nil, []*Package{testPackage}}, 76 77 // Go repo 78 {"/commit", nil, tCommit("0001", "0000", "", true), nil}, 79 {"/commit", nil, tCommit("0002", "0001", "", false), nil}, 80 {"/commit", nil, tCommit("0003", "0002", "", true), nil}, 81 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 82 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 83 {"/result", nil, &Result{Builder: "linux-386", Hash: "0001", OK: true}, nil}, 84 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 85 {"/result", nil, &Result{Builder: "linux-386", Hash: "0002", OK: true}, nil}, 86 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 87 88 // Other builders, to test the UI. 89 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0001", OK: true}, nil}, 90 {"/result", nil, &Result{Builder: "linux-amd64-race", Hash: "0001", OK: true}, nil}, 91 {"/result", nil, &Result{Builder: "netbsd-386", Hash: "0001", OK: true}, nil}, 92 {"/result", nil, &Result{Builder: "plan9-386", Hash: "0001", OK: true}, nil}, 93 {"/result", nil, &Result{Builder: "windows-386", Hash: "0001", OK: true}, nil}, 94 {"/result", nil, &Result{Builder: "windows-amd64", Hash: "0001", OK: true}, nil}, 95 {"/result", nil, &Result{Builder: "windows-amd64-race", Hash: "0001", OK: true}, nil}, 96 {"/result", nil, &Result{Builder: "linux-amd64-temp", Hash: "0001", OK: true}, nil}, 97 98 // multiple builders 99 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 100 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0003", OK: true}, nil}, 101 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 102 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0002"}}}, 103 104 // branches 105 {"/commit", nil, tCommit("0004", "0003", "", false), nil}, 106 {"/commit", nil, tCommit("0005", "0002", "", false), nil}, 107 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}}, 108 {"/result", nil, &Result{Builder: "linux-386", Hash: "0005", OK: true}, nil}, 109 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0004"}}}, 110 {"/result", nil, &Result{Builder: "linux-386", Hash: "0004", OK: false}, nil}, 111 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0003"}}}, 112 113 // logs 114 {"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: "test"}, nil}, 115 {"/log/a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", nil, nil, "test"}, 116 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, nil}, 117 118 // repeat failure (shouldn't re-send mail) 119 {"/result", nil, &Result{Builder: "linux-386", Hash: "0003", OK: false, Log: "test"}, nil}, 120 121 // non-Go repos 122 {"/commit", nil, tCommit("1001", "0000", testPkg, false), nil}, 123 {"/commit", nil, tCommit("1002", "1001", testPkg, false), nil}, 124 {"/commit", nil, tCommit("1003", "1002", testPkg, false), nil}, 125 {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1003"}}}, 126 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0001", OK: true}, nil}, 127 {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1002"}}}, 128 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1002", GoHash: "0001", OK: true}, nil}, 129 {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1001"}}}, 130 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0001", OK: true}, nil}, 131 {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0001"}}, nil, nil}, 132 {"/todo", url.Values{"kind": {"build-package"}, "builder": {"linux-386"}, "packagePath": {testPkg}, "goHash": {"0002"}}, nil, &Todo{Kind: "build-package", Data: &Commit{Hash: "1003"}}}, 133 134 // re-build Go revision for stale subrepos 135 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}}, 136 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0005", OK: false, Log: "boo"}, nil}, 137 {"/todo", url.Values{"kind": {"build-go-commit"}, "builder": {"linux-386"}}, nil, nil}, 138 139 // benchmarks 140 // build-go-commit must have precedence over benchmark-go-commit 141 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0005"}}}, 142 // drain build-go-commit todo 143 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0005", OK: true}, nil}, 144 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0004"}}}, 145 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0004", OK: true}, nil}, 146 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0002"}}}, 147 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0002", OK: true}, nil}, 148 // drain sub-repo todos 149 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1001", GoHash: "0005", OK: false}, nil}, 150 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1002", GoHash: "0005", OK: false}, nil}, 151 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1003", GoHash: "0005", OK: false}, nil}, 152 // now we must get benchmark todo 153 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0003", PerfResults: []string{}}}}, 154 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "http", Hash: "0003", OK: true}, nil}, 155 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0003", PerfResults: []string{"http"}}}}, 156 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "json", Hash: "0003", OK: true}, nil}, 157 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0003", PerfResults: []string{"http", "json"}}}}, 158 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0003", OK: true}, nil}, 159 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0001", PerfResults: []string{}}}}, 160 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "http", Hash: "0001", OK: true}, nil}, 161 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0001", OK: true}, nil}, 162 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, nil}, 163 // create new commit, it must appear in todo 164 {"/commit", nil, tCommit("0006", "0005", "", true), nil}, 165 // drain build-go-commit todo 166 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0006"}}}, 167 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0006", OK: true}, nil}, 168 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1003", GoHash: "0006", OK: false}, nil}, 169 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1002", GoHash: "0006", OK: false}, nil}, 170 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1001", GoHash: "0006", OK: false}, nil}, 171 // now we must get benchmark todo 172 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0006", PerfResults: []string{}}}}, 173 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "http", Hash: "0006", OK: true}, nil}, 174 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0006", OK: true}, nil}, 175 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, nil}, 176 // create new benchmark, all commits must re-appear in todo 177 {"/commit", nil, tCommit("0007", "0006", "", true), nil}, 178 // drain build-go-commit todo 179 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0007"}}}, 180 {"/result", nil, &Result{Builder: "linux-amd64", Hash: "0007", OK: true}, nil}, 181 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1003", GoHash: "0007", OK: false}, nil}, 182 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1002", GoHash: "0007", OK: false}, nil}, 183 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-amd64", Hash: "1001", GoHash: "0007", OK: false}, nil}, 184 // now we must get benchmark todo 185 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0007", PerfResults: []string{}}}}, 186 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "bson", Hash: "0007", OK: true}, nil}, 187 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0007", OK: true}, nil}, 188 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0007", PerfResults: []string{"bson"}}}}, 189 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0007", OK: true}, nil}, 190 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0006", PerfResults: []string{"http"}}}}, 191 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0006", OK: true}, nil}, 192 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0001", PerfResults: []string{"http"}}}}, 193 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0001", OK: true}, nil}, 194 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0003", PerfResults: []string{"http", "json"}}}}, 195 {"/perf-result", nil, &PerfRequest{Builder: "linux-amd64", Benchmark: "meta-done", Hash: "0003", OK: true}, nil}, 196 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-amd64"}}, nil, nil}, 197 // attach second builder 198 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "build-go-commit", Data: &Commit{Hash: "0007"}}}, 199 // drain build-go-commit todo 200 {"/result", nil, &Result{Builder: "linux-386", Hash: "0007", OK: true}, nil}, 201 {"/result", nil, &Result{Builder: "linux-386", Hash: "0006", OK: true}, nil}, 202 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1003", GoHash: "0007", OK: false}, nil}, 203 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1002", GoHash: "0007", OK: false}, nil}, 204 {"/result", nil, &Result{PackagePath: testPkg, Builder: "linux-386", Hash: "1001", GoHash: "0007", OK: false}, nil}, 205 // now we must get benchmark todo 206 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0007"}}}, 207 {"/perf-result", nil, &PerfRequest{Builder: "linux-386", Benchmark: "meta-done", Hash: "0007", OK: true}, nil}, 208 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0006"}}}, 209 {"/perf-result", nil, &PerfRequest{Builder: "linux-386", Benchmark: "meta-done", Hash: "0006", OK: true}, nil}, 210 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0001"}}}, 211 {"/perf-result", nil, &PerfRequest{Builder: "linux-386", Benchmark: "meta-done", Hash: "0001", OK: true}, nil}, 212 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, &Todo{Kind: "benchmark-go-commit", Data: &Commit{Hash: "0003"}}}, 213 {"/perf-result", nil, &PerfRequest{Builder: "linux-386", Benchmark: "meta-done", Hash: "0003", OK: true}, nil}, 214 {"/todo", url.Values{"kind": {"build-go-commit", "benchmark-go-commit"}, "builder": {"linux-386"}}, nil, nil}, 215 } 216 217 func testHandler(w http.ResponseWriter, r *http.Request) { 218 if !appengine.IsDevAppServer() { 219 fmt.Fprint(w, "These tests must be run under the dev_appserver.") 220 return 221 } 222 c := appengine.NewContext(r) 223 if err := nukeEntities(c, testEntityKinds); err != nil { 224 logErr(w, r, err) 225 return 226 } 227 if r.FormValue("nukeonly") != "" { 228 fmt.Fprint(w, "OK") 229 return 230 } 231 232 for _, p := range testPackages { 233 if _, err := datastore.Put(c, p.Key(c), p); err != nil { 234 logErr(w, r, err) 235 return 236 } 237 } 238 239 origReq := *r 240 defer func() { 241 // HACK: We need to clobber the original request (see below) 242 // so make sure we fix it before exiting the handler. 243 *r = origReq 244 }() 245 for i, t := range testRequests { 246 c.Infof("running test %d %s vals='%q' req='%q' res='%q'", i, t.path, t.vals, t.req, t.res) 247 errorf := func(format string, args ...interface{}) { 248 fmt.Fprintf(w, "%d %s: ", i, t.path) 249 fmt.Fprintf(w, format, args...) 250 fmt.Fprintln(w) 251 } 252 var body io.ReadWriter 253 if t.req != nil { 254 body = new(bytes.Buffer) 255 json.NewEncoder(body).Encode(t.req) 256 } 257 url := "http://" + domain + t.path 258 if t.vals != nil { 259 url += "?" + t.vals.Encode() + "&version=2" 260 } else { 261 url += "?version=2" 262 } 263 req, err := http.NewRequest("POST", url, body) 264 if err != nil { 265 logErr(w, r, err) 266 return 267 } 268 if t.req != nil { 269 req.Method = "POST" 270 } 271 req.Header = origReq.Header 272 rec := httptest.NewRecorder() 273 274 // Make the request 275 *r = *req // HACK: App Engine uses the request pointer 276 // as a map key to resolve Contexts. 277 http.DefaultServeMux.ServeHTTP(rec, r) 278 279 if rec.Code != 0 && rec.Code != 200 { 280 errorf(rec.Body.String()) 281 return 282 } 283 c.Infof("response='%v'", rec.Body.String()) 284 resp := new(dashResponse) 285 286 // If we're expecting a *Todo value, 287 // prime the Response field with a Todo and a Commit inside it. 288 if t.path == "/todo" { 289 resp.Response = &Todo{Data: &Commit{}} 290 } 291 292 if strings.HasPrefix(t.path, "/log/") { 293 resp.Response = rec.Body.String() 294 } else { 295 err := json.NewDecoder(rec.Body).Decode(resp) 296 if err != nil { 297 errorf("decoding response: %v", err) 298 return 299 } 300 } 301 if e, ok := t.res.(string); ok { 302 g, ok := resp.Response.(string) 303 if !ok { 304 errorf("Response not string: %T", resp.Response) 305 return 306 } 307 if g != e { 308 errorf("response mismatch: got %q want %q", g, e) 309 return 310 } 311 } 312 if e, ok := t.res.(*Todo); ok { 313 g, ok := resp.Response.(*Todo) 314 if !ok { 315 errorf("Response not *Todo: %T", resp.Response) 316 return 317 } 318 if e.Data == nil && g.Data != nil { 319 errorf("Response.Data should be nil, got: %v", g.Data) 320 return 321 } 322 if g.Data == nil { 323 errorf("Response.Data is nil, want: %v", e.Data) 324 return 325 } 326 gd, ok := g.Data.(*Commit) 327 if !ok { 328 errorf("Response.Data not *Commit: %T", g.Data) 329 return 330 } 331 if g.Kind != e.Kind { 332 errorf("kind don't match: got %q, want %q", g.Kind, e.Kind) 333 return 334 } 335 ed := e.Data.(*Commit) 336 if ed.Hash != gd.Hash { 337 errorf("hashes don't match: got %q, want %q", gd.Hash, ed.Hash) 338 return 339 } 340 if len(gd.PerfResults) != len(ed.PerfResults) { 341 errorf("result data len don't match: got %v, want %v", len(gd.PerfResults), len(ed.PerfResults)) 342 return 343 } 344 for i := range gd.PerfResults { 345 if gd.PerfResults[i] != ed.PerfResults[i] { 346 errorf("result data %v don't match: got %v, want %v", i, gd.PerfResults[i], ed.PerfResults[i]) 347 return 348 } 349 } 350 } 351 if t.res == nil && resp.Response != nil { 352 errorf("response mismatch: got %q expected <nil>", resp.Response) 353 return 354 } 355 } 356 fmt.Fprint(w, "PASS\nYou should see only one mail notification (for 0003/linux-386) in the dev_appserver logs.") 357 } 358 359 func nukeEntities(c appengine.Context, kinds []string) error { 360 if !appengine.IsDevAppServer() { 361 return errors.New("can't nuke production data") 362 } 363 var keys []*datastore.Key 364 for _, kind := range kinds { 365 q := datastore.NewQuery(kind).KeysOnly() 366 for t := q.Run(c); ; { 367 k, err := t.Next(nil) 368 if err == datastore.Done { 369 break 370 } 371 if err != nil { 372 return err 373 } 374 keys = append(keys, k) 375 } 376 } 377 return datastore.DeleteMulti(c, keys) 378 }