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  }