Skip to content

Commit

Permalink
Tests for slice/array returned from jrpc calls as well as a cleaner s…
Browse files Browse the repository at this point in the history
…hortcut: `jrpc.GetArray()` (#634)

* add test for slice/array returned from jrpc calls as well as a cleaner shortcut jrpc.GetArray(). Also fix #633

* update test accordingly to error message change

* test the nil slice case

* prep for 1.38.2, would in theory be 1.39.0 as there is a new api but this is a super minor addition
  • Loading branch information
ldemailly committed Oct 24, 2022
1 parent fbcebcb commit d2a2d42
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 8 deletions.
12 changes: 6 additions & 6 deletions README.md
Expand Up @@ -52,13 +52,13 @@ You can install from source:
The [releases](https://github.com/fortio/fortio/releases) page has binaries for many OS/architecture combinations (see assets).

```shell
curl -L https://github.com/fortio/fortio/releases/download/v1.38.1/fortio-linux_amd64-1.38.1.tgz \
curl -L https://github.com/fortio/fortio/releases/download/v1.38.2/fortio-linux_amd64-1.38.2.tgz \
| sudo tar -C / -xvzpf -
# or the debian package
wget https://github.com/fortio/fortio/releases/download/v1.38.1/fortio_1.38.1_amd64.deb
dpkg -i fortio_1.38.1_amd64.deb
wget https://github.com/fortio/fortio/releases/download/v1.38.2/fortio_1.38.2_amd64.deb
dpkg -i fortio_1.38.2_amd64.deb
# or the rpm
rpm -i https://github.com/fortio/fortio/releases/download/v1.38.1/fortio-1.38.1-1.x86_64.rpm
rpm -i https://github.com/fortio/fortio/releases/download/v1.38.2/fortio-1.38.2-1.x86_64.rpm
# and more, see assets in release page
```

Expand All @@ -68,7 +68,7 @@ On a MacOS you can also install Fortio using [Homebrew](https://brew.sh/):
brew install fortio
```

On Windows, download https://github.com/fortio/fortio/releases/download/v1.38.1/fortio_win_1.38.1.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt:
On Windows, download https://github.com/fortio/fortio/releases/download/v1.38.2/fortio_win_1.38.2.zip and extract `fortio.exe` to any location, then using the Windows Command Prompt:
```
fortio.exe server
```
Expand Down Expand Up @@ -116,7 +116,7 @@ Full list of command line flags (`fortio help`):
<details>
<!-- use release/updateFlags.sh to update this section -->
<pre>
Φορτίο 1.38.1 usage:
Φορτίο 1.38.2 usage:
fortio command [flags] target
where command is one of: load (load testing), server (starts ui, rest api,
http-echo, redirect, proxies, tcp-echo and grpc ping servers), tcp-echo (only
Expand Down
12 changes: 11 additions & 1 deletion jrpc/jrpcClient.go
Expand Up @@ -120,6 +120,16 @@ func Get[Q any](url *Destination) (*Q, error) {
return Fetch[Q](url, []byte{})
}

// GetArray fetches and deseializes the JSON returned by the Destination into a slice of
// Q struct (ie the response is a json array).
func GetArray[Q any](url *Destination) ([]Q, error) {
slicePtr, err := Fetch[[]Q](url, []byte{})
if slicePtr == nil {
return nil, err
}
return *slicePtr, err
}

// GetURL is Get without additional options (default timeout and headers).
func GetURL[Q any](url string) (*Q, error) {
return Get[Q](NewDestination(url))
Expand Down Expand Up @@ -162,7 +172,7 @@ func Fetch[Q any](url *Destination, bytes []byte) (*Q, error) {
if ok {
return nil, err
}
return nil, &FetchError{"deserialization error", code, err, bytes}
return nil, &FetchError{"non ok http result and deserialization error", code, err, bytes}
}
if !ok {
// can still be "ok" for some callers, they can use the result object as it deserialized as expected.
Expand Down
95 changes: 94 additions & 1 deletion jrpc/jrpc_test.go
Expand Up @@ -270,7 +270,7 @@ func TestJPRC(t *testing.T) {
if unwrap.Error() != expected {
t.Errorf("unwrapped error expected to be %q, got %v", expected, unwrap.Error())
}
expected = "deserialization error, code 747: " + expected + " (raw reply: {bad})"
expected = "non ok http result and deserialization error, code 747: " + expected + " (raw reply: {bad})"
if err.Error() != expected {
t.Errorf("error string expected %q, got %q", expected, err.Error())
}
Expand Down Expand Up @@ -396,3 +396,96 @@ func TestSerializeServerReply(t *testing.T) {
t.Errorf("expected %s, got %s", expected, str)
}
}

// Testing slices

type SliceRequest struct {
HowMany int
}

type SliceOneResponse struct {
Index int
Data string
}

func TestJPRCSlices(t *testing.T) {
mux, addr := fhttp.HTTPServer("test3", "0")
port := addr.(*net.TCPAddr).Port
mux.HandleFunc("/test-api-array", func(w http.ResponseWriter, r *http.Request) {
req, err := jrpc.HandleCall[SliceRequest](w, r)
if err != nil {
err = jrpc.ReplyError(w, "request error", err)
if err != nil {
t.Errorf("Error in replying error: %v", err)
}
return
}
n := req.HowMany
if n < 0 {
jrpc.ReplyError(w, "invalid negative count", nil)
return
}
if r.FormValue("errror") != "" {
jrpc.ReplyError(w, "error requested", nil)
return
}
if n == 0 {
n = 42 // for testing of GetArray
}
resp := make([]SliceOneResponse, n)
for i := 0; i < n; i++ {
resp[i] = SliceOneResponse{
Index: i,
Data: fmt.Sprintf("data %d", i),
}
}
jrpc.ReplyOk(w, &resp)
})
url := fmt.Sprintf("http://localhost:%d/test-api-array", port)
req := SliceRequest{10}
res, err := jrpc.CallURL[[]SliceOneResponse](url, &req)
if err != nil {
t.Errorf("failed Call: %v", err)
}
if res == nil {
t.Errorf("nil response")
return
}
slice := *res
if len(slice) != 10 {
t.Errorf("expected 10 results, got %d", len(slice))
}
for i := 0; i < len(slice); i++ {
el := slice[i]
if el.Index != i {
t.Errorf("expected index %d, got %d", i, el.Index)
}
if el.Data != fmt.Sprintf("data %d", i) {
t.Errorf("expected data %d, got %s", i, el.Data)
}
}
slice, err = jrpc.GetArray[SliceOneResponse](jrpc.NewDestination(url))
if err != nil {
t.Errorf("failed GetArray: %v", err)
}
if len(slice) != 42 {
t.Errorf("expected 42 results, got %d", len(slice))
}
for i := 0; i < len(slice); i++ {
el := slice[i]
if el.Index != i {
t.Errorf("expected index %d, got %d", i, el.Index)
}
if el.Data != fmt.Sprintf("data %d", i) {
t.Errorf("expected data %d, got %s", i, el.Data)
}
}
// Empty slice/error
slice, err = jrpc.GetArray[SliceOneResponse](jrpc.NewDestination(url + "?errror=true"))
if err == nil {
t.Errorf("expected error, got nil")
}
if slice != nil {
t.Errorf("expected nil slice, got %v", slice)
}
}

0 comments on commit d2a2d42

Please sign in to comment.