diff options
Diffstat (limited to 'doc/articles/wiki/wiki_test.go')
-rw-r--r-- | doc/articles/wiki/wiki_test.go | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/doc/articles/wiki/wiki_test.go b/doc/articles/wiki/wiki_test.go new file mode 100644 index 0000000000..1d976fd77e --- /dev/null +++ b/doc/articles/wiki/wiki_test.go @@ -0,0 +1,165 @@ +// Copyright 2019 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 main_test + +import ( + "bytes" + "fmt" + "io/ioutil" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" +) + +func TestSnippetsCompile(t *testing.T) { + if testing.Short() { + t.Skip("skipping slow builds in short mode") + } + + goFiles, err := filepath.Glob("*.go") + if err != nil { + t.Fatal(err) + } + + for _, f := range goFiles { + if strings.HasSuffix(f, "_test.go") { + continue + } + f := f + t.Run(f, func(t *testing.T) { + t.Parallel() + + cmd := exec.Command("go", "build", "-o", os.DevNull, f) + out, err := cmd.CombinedOutput() + if err != nil { + t.Errorf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) + } + }) + } +} + +func TestWikiServer(t *testing.T) { + must := func(err error) { + if err != nil { + t.Helper() + t.Fatal(err) + } + } + + dir, err := ioutil.TempDir("", t.Name()) + must(err) + defer os.RemoveAll(dir) + + // We're testing a walkthrough example of how to write a server. + // + // That server hard-codes a port number to make the walkthrough simpler, but + // we can't assume that the hard-coded port is available on an arbitrary + // builder. So we'll patch out the hard-coded port, and replace it with a + // function that writes the server's address to stdout + // so that we can read it and know where to send the test requests. + + finalGo, err := ioutil.ReadFile("final.go") + must(err) + const patchOld = `log.Fatal(http.ListenAndServe(":8080", nil))` + patched := bytes.ReplaceAll(finalGo, []byte(patchOld), []byte(`log.Fatal(serve())`)) + if bytes.Equal(patched, finalGo) { + t.Fatalf("Can't patch final.go: %q not found.", patchOld) + } + must(ioutil.WriteFile(filepath.Join(dir, "final_patched.go"), patched, 0644)) + + // Build the server binary from the patched sources. + // The 'go' command requires that they all be in the same directory. + // final_test.go provides the implemtation for our serve function. + must(copyFile(filepath.Join(dir, "final_srv.go"), "final_test.go")) + cmd := exec.Command("go", "build", + "-o", filepath.Join(dir, "final.exe"), + filepath.Join(dir, "final_patched.go"), + filepath.Join(dir, "final_srv.go")) + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, out) + } + + // Run the server in our temporary directory so that it can + // write its content there. It also needs a couple of template files, + // and looks for them in the same directory. + must(copyFile(filepath.Join(dir, "edit.html"), "edit.html")) + must(copyFile(filepath.Join(dir, "view.html"), "view.html")) + cmd = exec.Command(filepath.Join(dir, "final.exe")) + cmd.Dir = dir + stderr := bytes.NewBuffer(nil) + cmd.Stderr = stderr + stdout, err := cmd.StdoutPipe() + must(err) + must(cmd.Start()) + + defer func() { + cmd.Process.Kill() + err := cmd.Wait() + if stderr.Len() > 0 { + t.Logf("%s: %v\n%s", strings.Join(cmd.Args, " "), err, stderr) + } + }() + + var addr string + if _, err := fmt.Fscanln(stdout, &addr); err != nil || addr == "" { + t.Fatalf("Failed to read server address: %v", err) + } + + // The server is up and has told us its address. + // Make sure that its HTTP API works as described in the article. + + r, err := http.Get(fmt.Sprintf("http://%s/edit/Test", addr)) + must(err) + responseMustMatchFile(t, r, "test_edit.good") + + r, err = http.Post(fmt.Sprintf("http://%s/save/Test", addr), + "application/x-www-form-urlencoded", + strings.NewReader("body=some%20content")) + must(err) + responseMustMatchFile(t, r, "test_view.good") + + gotTxt, err := ioutil.ReadFile(filepath.Join(dir, "Test.txt")) + must(err) + wantTxt, err := ioutil.ReadFile("test_Test.txt.good") + must(err) + if !bytes.Equal(wantTxt, gotTxt) { + t.Fatalf("Test.txt differs from expected after posting to /save.\ngot:\n%s\nwant:\n%s", gotTxt, wantTxt) + } + + r, err = http.Get(fmt.Sprintf("http://%s/view/Test", addr)) + must(err) + responseMustMatchFile(t, r, "test_view.good") +} + +func responseMustMatchFile(t *testing.T, r *http.Response, filename string) { + t.Helper() + + defer r.Body.Close() + body, err := ioutil.ReadAll(r.Body) + if err != nil { + t.Fatal(err) + } + + wantBody, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(body, wantBody) { + t.Fatalf("%v: body does not match %s.\ngot:\n%s\nwant:\n%s", r.Request.URL, filename, body, wantBody) + } +} + +func copyFile(dst, src string) error { + buf, err := ioutil.ReadFile(src) + if err != nil { + return err + } + return ioutil.WriteFile(dst, buf, 0644) +} |