github.com/bazelbuild/bazel-watcher@v0.25.2/internal/e2e/example_client/example_client.go (about) 1 package example_client 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/http" 8 "net/url" 9 "os" 10 "path/filepath" 11 "regexp" 12 "strings" 13 "testing" 14 15 "github.com/bazelbuild/rules_go/go/tools/bazel" 16 "github.com/bazelbuild/rules_go/go/tools/bazel_testing" 17 18 "github.com/bazelbuild/bazel-watcher/example_client/data" 19 "github.com/bazelbuild/bazel-watcher/internal/e2e" 20 ) 21 22 func TestMain(m *testing.M, extraTxtar ...string) { 23 // mainFiles is a string that describes all the files used in this test in 24 // txtar format as described by cmd/go/internal/txtar. 25 mainFiles := "" 26 27 wd, err := os.Getwd() 28 if err != nil { 29 fmt.Printf("os.Getwd() error: %v\n", err) 30 os.Exit(1) 31 } 32 33 exampleClientPath := filepath.Join(wd, "example_client") 34 if err := filepath.Walk(exampleClientPath, func(path string, info os.FileInfo, err error) error { 35 if err != nil { 36 return err 37 } 38 39 // Nothing to do here. Dirs are made implicitly in txtar files. 40 if info.IsDir() { 41 return nil 42 } 43 44 content, err := ioutil.ReadFile(path) 45 if err != nil { 46 return fmt.Errorf("ioutil.ReadFile(%q) err: %v", path, err) 47 } 48 49 shortPath := strings.TrimPrefix(path, wd+string(filepath.Separator)) 50 51 mainFiles += fmt.Sprintf(` 52 -- %s -- 53 %s 54 `, shortPath, content) 55 56 return nil 57 }); err != nil { 58 fmt.Printf("filepath.Walk() error: %v\n", err) 59 os.Exit(1) 60 } 61 62 for _, f := range extraTxtar { 63 mainFiles += f 64 } 65 66 bazel_testing.TestMain(m, bazel_testing.Args{ 67 Main: mainFiles, 68 }) 69 } 70 71 type ExampleClient struct { 72 ibazel *e2e.IBazelTester 73 basePath string 74 // dataPath points to the file that needs to be updated in order to have the 75 // example client render different data. This is tracked in the object 76 // because Windows paths are complex and doing that computation many times 77 // would be annoying. 78 dataPath string 79 } 80 81 func StartLiveReload(t *testing.T) (client *ExampleClient) { 82 t.Helper() 83 84 ibazel := e2e.SetUp(t) 85 ibazel.Run([]string{}, "//example_client:live_reload") 86 87 dataPath, err := bazel.Runfile("example_client/data.txt") 88 if err != nil { 89 t.Fatalf("bazel.Runfile(\"example_client/data.txt\") error: %v", err) 90 } 91 92 c := &ExampleClient{ 93 ibazel: ibazel, 94 dataPath: dataPath, 95 } 96 c.DetectServerParameters(t) 97 98 return c 99 } 100 101 func (c *ExampleClient) fatalf(t *testing.T, msg string, args ...interface{}) { 102 t.Helper() 103 104 t.Logf("Out: %v", c.ibazel.GetOutput()) 105 t.Logf("Error: %v", c.ibazel.GetError()) 106 t.Logf("iBazel Error: %v", c.ibazel.GetIBazelError()) 107 108 t.Fatalf(msg, args...) 109 } 110 111 func (c *ExampleClient) Cleanup() { 112 c.ibazel.Kill() 113 } 114 115 func (c *ExampleClient) DetectServerParameters(t *testing.T) { 116 c.ibazel.ExpectOutput("Serving: http://.+:\\d+") 117 out := c.ibazel.GetOutput() 118 119 if out == "" { 120 t.Fatal("Output was empty. Expected at least some output") 121 } 122 123 urlCaptureGroup := 1 124 r := regexp.MustCompile(`Serving: (?P<url>http://[0-9.]+:[0-9]+)`) 125 results := r.FindAllStringSubmatch(out, -1) 126 if len(results) == 0 { 127 c.fatalf(t, "Expected output to decribe where its serving from. Found nothing.") 128 } 129 130 c.basePath = results[len(results)-1][urlCaptureGroup] 131 132 // Ensure URL validity by parsing it. 133 _, err := url.ParseRequestURI(c.basePath) 134 if err != nil { 135 t.Error("url.ParseRequestURI(%q)", c.basePath, err) 136 } 137 } 138 139 func (c *ExampleClient) get(t *testing.T, path string) ([]byte, error) { 140 t.Helper() 141 142 r, err := http.Get(c.basePath + path) 143 if err != nil { 144 c.fatalf(t, "http.Get(%s/config) error: %v", c.basePath, err) 145 } 146 defer r.Body.Close() 147 148 b, err := ioutil.ReadAll(r.Body) 149 if err != nil { 150 t.Errorf("ioutil.ReadAll() error: %v", err) 151 } 152 return b, nil 153 } 154 155 func (c *ExampleClient) GetConfig(t *testing.T) *data.Config { 156 configBytes, err := c.get(t, "/config") 157 if err != nil { 158 t.Errorf("c.get(\"/config\") error: %v", err) 159 } 160 161 var config data.Config 162 if err := json.Unmarshal(configBytes, &config); err != nil { 163 t.Errorf("json.Unmarshal(configBytes, config) error: %v", err) 164 } 165 return &config 166 } 167 168 func (c *ExampleClient) Kill(t *testing.T) { 169 t.Helper() 170 171 _, err := c.get(t, "/killkillkill") 172 if err != nil { 173 t.Errorf("c.get(\"/killkillkill\") error: %v", err) 174 } 175 } 176 177 func (c *ExampleClient) GetRaw(t *testing.T) string { 178 t.Helper() 179 180 rawBytes, err := c.get(t, "/raw") 181 if err != nil { 182 t.Errorf("c.get(\"/raw\") error: %v", err) 183 } 184 185 // Files are often written with newlines at the end and therefore will be 186 // returned with extra newlines. To simplify testing against values, strip 187 // all whitespace. 188 return strings.TrimSpace(string(rawBytes)) 189 } 190 191 func (c *ExampleClient) SetData(t *testing.T, data string) { 192 t.Helper() 193 e2e.MustWriteFile(t, c.dataPath, data) 194 }