Skip to content

Commit

Permalink
fix: handle nil opts and add webtests flag
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Stewart <[email protected]>
  • Loading branch information
paralin committed Jul 10, 2024
1 parent 7cd316b commit c51e097
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 2 deletions.
59 changes: 59 additions & 0 deletions doc/WEB_TESTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Web Tests

Some tests in this project require internet access to perform HTTP requests to external services. These tests are controlled by the `webtests` build tag.

## Running Web Tests

To run tests that include web requests, use the following command:

```
go test -tags webtests ./...
```

This will enable the `webtests` build tag and run all tests, including those that make HTTP requests to external services.

### WebAssembly

This package can be tested in a browser environment using [`wasmbrowsertest`](https://github.com/agnivade/wasmbrowsertest).

1. Install `wasmbrowsertest`:
```bash
go install github.com/agnivade/wasmbrowsertest@latest
```

2. Rename the `wasmbrowsertest` binary to `go_js_wasm_exec`:
```bash
mv $(go env GOPATH)/bin/wasmbrowsertest $(go env GOPATH)/bin/go_js_wasm_exec
```

3. Run the tests with the `js` GOOS and `wasm` GOARCH:
```bash
GOOS=js GOARCH=wasm go test -tags "webtests" -v ./...
```

This will compile the tests to WebAssembly and run them in a headless browser environment.


## Skipping Web Tests

By default, tests that require internet access are not run. To run all other tests without the web tests, simply run:

```
go test ./...
```

This will skip any tests that have the `webtests` build tag.

## Writing Web Tests

When writing tests that require internet access or make HTTP requests to external services, make sure to add the `webtests` build tag to the test file. For example:

```go
//go:build js && webtests

package mypackage

// Test code here
```

This ensures that these tests are only run when explicitly requested with the `webtests` build tag.
7 changes: 6 additions & 1 deletion http/log/fetch/fetch_js.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/sirupsen/logrus"
)

// logHeaders is the set of headers to attach to the logger as fields.
var logHeaders = []string{"range", "content-range", "content-type", "content-length", "accept"}

// Fetch uses the JS Fetch API to make requests with logging.
Expand Down Expand Up @@ -50,7 +51,11 @@ func Fetch(le *logrus.Entry, url string, opts *fetch.Opts, verbose bool) (*fetch
duration := time.Since(startTime)

if le != nil {
fields := make(logrus.Fields, 2+len(resp.Headers))
mapSize := 1
if resp != nil {
mapSize += 1 + min(len(resp.Headers), len(logHeaders))
}
fields := make(logrus.Fields, mapSize)
fields["dur"] = duration.String()
if resp != nil {
fields["status"] = resp.Status
Expand Down
90 changes: 90 additions & 0 deletions http/log/fetch/fetch_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//go:build js && webtests

package httplog_fetch

import (
"bytes"
"net/http"
"testing"

fetch "github.com/aperturerobotics/bifrost/util/js-fetch"
"github.com/sirupsen/logrus"
)

func TestFetch(t *testing.T) {
// Create a logger
logger := logrus.New()
logger.SetLevel(logrus.DebugLevel)

// Test cases
testCases := []struct {
name string
url string
opts *fetch.Opts
verbose bool
expectError bool
}{
{
name: "Successful GET request",
url: "https://httpbin.org/get",
verbose: true,
},
{
name: "POST request with headers",
url: "https://httpbin.org/post",
opts: &fetch.Opts{
Method: "POST",
Headers: map[string]string{
"Content-Type": "application/json",
},
Body: bytes.NewReader([]byte(`{"test": "data"}`)),
},
verbose: true,
},
{
name: "Non-existent URL",
url: "https://thisurldoesnotexist.example.com",
expectError: true,
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
le := logger.WithField("test", tc.name)

resp, err := Fetch(le, tc.url, tc.opts, tc.verbose)

if tc.expectError {
if err == nil {
t.Errorf("Expected an error, but got nil")
}
if resp != nil {
t.Errorf("Expected nil response, but got %v", resp)
}
} else {
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if resp == nil {
t.Fatalf("Expected non-nil response, but got nil")
}
if resp.Status != http.StatusOK {
t.Errorf("Expected status %d, but got %d", http.StatusOK, resp.Status)
}
}
})
}
}

func TestFetchWithNilLogger(t *testing.T) {
resp, err := Fetch(nil, "https://httpbin.org/get", nil, false)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
if resp == nil {
t.Fatal("Expected non-nil response, but got nil")
}
if resp.Status != http.StatusOK {
t.Errorf("Expected status %d, but got %d", http.StatusOK, resp.Status)
}
}
5 changes: 4 additions & 1 deletion util/js-fetch/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func Fetch(url string, opts *Opts) (*Response, error) {
e error
}
ch := make(chan *fetchResponse)
if opts.Signal != nil {
if opts != nil && opts.Signal != nil {
controller := js.Global().Get("AbortController").New()
signal := controller.Get("signal")
optsMap["signal"] = signal
Expand Down Expand Up @@ -181,6 +181,9 @@ func Fetch(url string, opts *Opts) (*Response, error) {
// oof.
func mapOpts(opts *Opts) (map[string]interface{}, error) {
mp := map[string]interface{}{}
if opts == nil {
return mp, nil
}

if opts.Method != "" {
mp["method"] = opts.Method
Expand Down

0 comments on commit c51e097

Please sign in to comment.