golang.org/x/playground@v0.0.0-20230418134305-14ebe15bcd59/tests.go (about) 1 // Copyright 2014 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 // Test tests are linked into the main binary and are run as part of 6 // the Docker build step. 7 8 package main 9 10 import ( 11 "context" 12 "fmt" 13 stdlog "log" 14 "net" 15 "os" 16 "reflect" 17 "strings" 18 "time" 19 ) 20 21 type compileTest struct { 22 name string // test name 23 prog, want, errors string 24 wantFunc func(got string) error // alternative to want 25 withVet bool 26 wantEvents []Event 27 wantVetErrors string 28 } 29 30 func (s *server) test() { 31 if _, err := net.ResolveIPAddr("ip", "sandbox_dev.sandnet."); err != nil { 32 log.Fatalf("sandbox_dev.sandnet not available") 33 } 34 os.Setenv("DEBUG_FORCE_GVISOR", "1") 35 os.Setenv("SANDBOX_BACKEND_URL", "http://sandbox_dev.sandnet/run") 36 s.runTests() 37 } 38 39 func (s *server) runTests() { 40 if err := s.healthCheck(context.Background()); err != nil { 41 stdlog.Fatal(err) 42 } 43 44 failed := false 45 for i, t := range tests { 46 stdlog.Printf("testing case %d (%q)...\n", i, t.name) 47 resp, err := compileAndRun(context.Background(), &request{Body: t.prog, WithVet: t.withVet}) 48 if err != nil { 49 stdlog.Fatal(err) 50 } 51 if t.wantEvents != nil { 52 if !reflect.DeepEqual(resp.Events, t.wantEvents) { 53 stdlog.Printf("resp.Events = %q, want %q", resp.Events, t.wantEvents) 54 failed = true 55 } 56 continue 57 } 58 if t.errors != "" { 59 if resp.Errors != t.errors { 60 stdlog.Printf("resp.Errors = %q, want %q", resp.Errors, t.errors) 61 failed = true 62 } 63 continue 64 } 65 if resp.Errors != "" { 66 stdlog.Printf("resp.Errors = %q, want %q", resp.Errors, t.errors) 67 failed = true 68 continue 69 } 70 if resp.VetErrors != t.wantVetErrors { 71 stdlog.Printf("resp.VetErrs = %q, want %q", resp.VetErrors, t.wantVetErrors) 72 failed = true 73 continue 74 } 75 if t.withVet && (resp.VetErrors != "") == resp.VetOK { 76 stdlog.Printf("resp.VetErrs & VetOK inconsistent; VetErrs = %q; VetOK = %v", resp.VetErrors, resp.VetOK) 77 failed = true 78 continue 79 } 80 if len(resp.Events) == 0 { 81 stdlog.Printf("unexpected output: %q, want %q", "", t.want) 82 failed = true 83 continue 84 } 85 var b strings.Builder 86 for _, e := range resp.Events { 87 b.WriteString(e.Message) 88 } 89 if t.wantFunc != nil { 90 if err := t.wantFunc(b.String()); err != nil { 91 stdlog.Printf("%v\n", err) 92 failed = true 93 } 94 } else { 95 if !strings.Contains(b.String(), t.want) { 96 stdlog.Printf("unexpected output: %q, want %q", b.String(), t.want) 97 failed = true 98 } 99 } 100 } 101 if failed { 102 stdlog.Fatalf("FAILED") 103 } 104 fmt.Println("OK") 105 } 106 107 var tests = []compileTest{ 108 { 109 name: "timezones_available", 110 prog: ` 111 package main 112 113 import "time" 114 115 func main() { 116 loc, err := time.LoadLocation("America/New_York") 117 if err != nil { 118 panic(err.Error()) 119 } 120 println(loc.String()) 121 } 122 `, want: "America/New_York"}, 123 124 { 125 name: "faketime_works", 126 prog: ` 127 package main 128 129 import ( 130 "fmt" 131 "time" 132 ) 133 134 func main() { 135 fmt.Println(time.Now()) 136 } 137 `, want: "2009-11-10 23:00:00 +0000 UTC"}, 138 139 { 140 name: "faketime_tickers", 141 prog: ` 142 package main 143 144 import ( 145 "fmt" 146 "time" 147 ) 148 149 func main() { 150 t1 := time.Tick(time.Second * 3) 151 t2 := time.Tick(time.Second * 7) 152 t3 := time.Tick(time.Second * 11) 153 end := time.After(time.Second * 19) 154 want := "112131211" 155 var got []byte 156 for { 157 var c byte 158 select { 159 case <-t1: 160 c = '1' 161 case <-t2: 162 c = '2' 163 case <-t3: 164 c = '3' 165 case <-end: 166 if g := string(got); g != want { 167 fmt.Printf("got %q, want %q\n", g, want) 168 } else { 169 fmt.Println("timers fired as expected") 170 } 171 return 172 } 173 got = append(got, c) 174 } 175 } 176 `, want: "timers fired as expected"}, 177 { 178 name: "must_be_package_main", 179 prog: ` 180 package test 181 182 func main() { 183 println("test") 184 } 185 `, want: "", errors: "package name must be main"}, 186 { 187 name: "filesystem_contents", 188 prog: ` 189 package main 190 191 import ( 192 "fmt" 193 "os" 194 "path/filepath" 195 ) 196 197 func main() { 198 filepath.Walk("/", func(path string, info os.FileInfo, err error) error { 199 if path == "/proc" || path == "/sys" { 200 return filepath.SkipDir 201 } 202 fmt.Println(path) 203 return nil 204 }) 205 } 206 `, wantFunc: func(got string) error { 207 // The environment for the old nacl sandbox: 208 if strings.TrimSpace(got) == `/ 209 /dev 210 /dev/null 211 /dev/random 212 /dev/urandom 213 /dev/zero 214 /etc 215 /etc/group 216 /etc/hosts 217 /etc/passwd 218 /etc/resolv.conf 219 /tmp 220 /usr 221 /usr/local 222 /usr/local/go 223 /usr/local/go/lib 224 /usr/local/go/lib/time 225 /usr/local/go/lib/time/zoneinfo.zip` { 226 return nil 227 } 228 have := map[string]bool{} 229 for _, f := range strings.Split(got, "\n") { 230 have[f] = true 231 } 232 for _, expect := range []string{ 233 "/.dockerenv", 234 "/etc/hostname", 235 "/dev/zero", 236 "/lib/ld-linux-x86-64.so.2", 237 "/lib/libc.so.6", 238 "/etc/nsswitch.conf", 239 "/bin/env", 240 "/tmpfs", 241 } { 242 if !have[expect] { 243 return fmt.Errorf("missing expected sandbox file %q; got:\n%s", expect, got) 244 } 245 } 246 return nil 247 }, 248 }, 249 { 250 name: "test_passes", 251 prog: ` 252 package main 253 254 import "testing" 255 256 func TestSanity(t *testing.T) { 257 if 1+1 != 2 { 258 t.Error("uhh...") 259 } 260 } 261 `, want: `=== RUN TestSanity 262 --- PASS: TestSanity (0.00s) 263 PASS`}, 264 265 { 266 name: "test_without_import", 267 prog: ` 268 package main 269 270 func TestSanity(t *testing.T) { 271 t.Error("uhh...") 272 } 273 274 func ExampleNotExecuted() { 275 // Output: it should not run 276 } 277 `, want: "", errors: "./prog_test.go:4:20: undefined: testing\n"}, 278 279 { 280 name: "test_with_import_ignored", 281 prog: ` 282 package main 283 284 import ( 285 "fmt" 286 "testing" 287 ) 288 289 func TestSanity(t *testing.T) { 290 t.Error("uhh...") 291 } 292 293 func main() { 294 fmt.Println("test") 295 } 296 `, want: "test"}, 297 298 { 299 name: "example_runs", 300 prog: ` 301 package main//comment 302 303 import "fmt" 304 305 func ExampleOutput() { 306 fmt.Println("The output") 307 // Output: The output 308 } 309 `, want: `=== RUN ExampleOutput 310 --- PASS: ExampleOutput (0.00s) 311 PASS`}, 312 313 { 314 name: "example_unordered", 315 prog: ` 316 package main//comment 317 318 import "fmt" 319 320 func ExampleUnorderedOutput() { 321 fmt.Println("2") 322 fmt.Println("1") 323 fmt.Println("3") 324 // Unordered output: 3 325 // 2 326 // 1 327 } 328 `, want: `=== RUN ExampleUnorderedOutput 329 --- PASS: ExampleUnorderedOutput (0.00s) 330 PASS`}, 331 332 { 333 name: "example_fail", 334 prog: ` 335 package main 336 337 import "fmt" 338 339 func ExampleEmptyOutput() { 340 // Output: 341 } 342 343 func ExampleEmptyOutputFail() { 344 fmt.Println("1") 345 // Output: 346 } 347 `, want: `=== RUN ExampleEmptyOutput 348 --- PASS: ExampleEmptyOutput (0.00s) 349 === RUN ExampleEmptyOutputFail 350 --- FAIL: ExampleEmptyOutputFail (0.00s) 351 got: 352 1 353 want: 354 355 FAIL`}, 356 357 // Run program without executing this example function. 358 { 359 name: "example_no_output_skips_run", 360 prog: ` 361 package main 362 363 func ExampleNoOutput() { 364 panic(1) 365 } 366 `, want: `testing: warning: no tests to run 367 PASS`}, 368 369 { 370 name: "example_output", 371 prog: ` 372 package main 373 374 import "fmt" 375 376 func ExampleShouldNotRun() { 377 fmt.Println("The output") 378 // Output: The output 379 } 380 381 func main() { 382 fmt.Println("Main") 383 } 384 `, want: "Main"}, 385 386 { 387 name: "stdout_stderr_merge", 388 prog: ` 389 package main 390 391 import ( 392 "fmt" 393 "os" 394 ) 395 396 func main() { 397 fmt.Fprintln(os.Stdout, "A") 398 fmt.Fprintln(os.Stderr, "B") 399 fmt.Fprintln(os.Stdout, "A") 400 fmt.Fprintln(os.Stdout, "A") 401 } 402 `, want: "A\nB\nA\nA\n"}, 403 404 // Integration test for runtime.write fake timestamps. 405 { 406 name: "faketime_write_interaction", 407 prog: ` 408 package main 409 410 import ( 411 "fmt" 412 "os" 413 "time" 414 ) 415 416 func main() { 417 fmt.Fprintln(os.Stdout, "A") 418 fmt.Fprintln(os.Stderr, "B") 419 fmt.Fprintln(os.Stdout, "A") 420 fmt.Fprintln(os.Stdout, "A") 421 time.Sleep(time.Second) 422 fmt.Fprintln(os.Stderr, "B") 423 time.Sleep(time.Second) 424 fmt.Fprintln(os.Stdout, "A") 425 } 426 `, wantEvents: []Event{ 427 {"A\n", "stdout", 0}, 428 {"B\n", "stderr", time.Nanosecond}, 429 {"A\nA\n", "stdout", time.Nanosecond}, 430 {"B\n", "stderr", time.Second - 2*time.Nanosecond}, 431 {"A\n", "stdout", time.Second}, 432 }}, 433 434 { 435 name: "third_party_imports", 436 prog: ` 437 package main 438 import ("fmt"; "github.com/bradfitz/iter") 439 func main() { for i := range iter.N(5) { fmt.Println(i) } } 440 `, 441 want: "0\n1\n2\n3\n4\n", 442 }, 443 444 { 445 name: "compile_with_vet", 446 withVet: true, 447 wantVetErrors: "./prog.go:5:2: fmt.Printf format %v reads arg #1, but call has 0 args\n", 448 prog: ` 449 package main 450 import "fmt" 451 func main() { 452 fmt.Printf("hi %v") 453 } 454 `, 455 }, 456 457 { 458 name: "compile_without_vet", 459 withVet: false, 460 prog: ` 461 package main 462 import "fmt" 463 func main() { 464 fmt.Printf("hi %v") 465 } 466 `, 467 }, 468 469 { 470 name: "compile_modules_with_vet", 471 withVet: true, 472 wantVetErrors: "./prog.go:6:2: fmt.Printf format %v reads arg #1, but call has 0 args\n", 473 prog: ` 474 package main 475 import ("fmt"; "github.com/bradfitz/iter") 476 func main() { 477 for i := range iter.N(5) { fmt.Println(i) } 478 fmt.Printf("hi %v") 479 } 480 `, 481 }, 482 483 { 484 name: "multi_file_basic", 485 prog: ` 486 package main 487 const foo = "bar" 488 489 -- two.go -- 490 package main 491 func main() { 492 println(foo) 493 } 494 `, 495 wantEvents: []Event{ 496 {"bar\n", "stderr", 0}, 497 }, 498 }, 499 500 { 501 name: "multi_file_use_package", 502 withVet: true, 503 prog: ` 504 package main 505 506 import "play.test/foo" 507 508 func main() { 509 foo.Hello() 510 } 511 512 -- go.mod -- 513 module play.test 514 515 -- foo/foo.go -- 516 package foo 517 518 import "fmt" 519 520 func Hello() { fmt.Println("hello world") } 521 `, 522 }, 523 { 524 name: "timeouts_handled_gracefully", 525 prog: ` 526 package main 527 528 import ( 529 "time" 530 ) 531 532 func main() { 533 c := make(chan struct{}) 534 535 go func() { 536 defer close(c) 537 for { 538 time.Sleep(10 * time.Millisecond) 539 } 540 }() 541 542 <-c 543 } 544 `, want: "timeout running program"}, 545 { 546 name: "timezone_info_exists", 547 prog: ` 548 package main 549 550 import ( 551 "fmt" 552 "time" 553 ) 554 555 func main() { 556 loc, _ := time.LoadLocation("Europe/Berlin") 557 558 // This will look for the name CEST in the Europe/Berlin time zone. 559 const longForm = "Jan 2, 2006 at 3:04pm (MST)" 560 t, _ := time.ParseInLocation(longForm, "Jul 9, 2012 at 5:02am (CEST)", loc) 561 fmt.Println(t) 562 563 // Note: without explicit zone, returns time in given location. 564 const shortForm = "2006-Jan-02" 565 t, _ = time.ParseInLocation(shortForm, "2012-Jul-09", loc) 566 fmt.Println(t) 567 568 } 569 `, want: "2012-07-09 05:02:00 +0200 CEST\n2012-07-09 00:00:00 +0200 CEST\n"}, 570 { 571 name: "cgo_enabled_0", 572 prog: ` 573 package main 574 575 import ( 576 "fmt" 577 "net" 578 ) 579 580 func main() { 581 fmt.Println(net.ParseIP("1.2.3.4")) 582 } 583 `, want: "1.2.3.4\n"}, 584 { 585 name: "fuzz_executed", 586 prog: ` 587 package main 588 589 import "testing" 590 591 func FuzzSanity(f *testing.F) { 592 f.Add("a") 593 f.Fuzz(func(t *testing.T, v string) { 594 }) 595 } 596 `, want: `=== RUN FuzzSanity 597 === RUN FuzzSanity/seed#0 598 --- PASS: FuzzSanity (0.00s) 599 --- PASS: FuzzSanity/seed#0 (0.00s) 600 PASS`}, 601 { 602 name: "test_main", 603 prog: ` 604 package main 605 606 import ( 607 "os" 608 "testing" 609 ) 610 611 func TestMain(m *testing.M) { 612 os.Exit(m.Run()) 613 }`, want: `testing: warning: no tests to run 614 PASS`, 615 }, 616 { 617 name: "multiple_files_no_banner", 618 prog: ` 619 package main 620 621 func main() { 622 print() 623 } 624 625 -- foo.go -- 626 package main 627 628 import "fmt" 629 630 func print() { 631 =fmt.Println("Hello, playground") 632 } 633 `, errors: `./foo.go:6:2: syntax error: unexpected =, expecting } 634 `, 635 }, 636 }