ooni-probe-cli/internal/ooapi/apis_test.go
Simone Basso 306d18e466
chore: support go1.18 and update dependencies (#708)
Here's the squash of the following patches that enable support
for go1.18 and update our dependencies.

This diff WILL need to be backported to the release/3.14 branch.

* chore: use go1.17.8

See https://github.com/ooni/probe/issues/2067

* chore: upgrade to probe-assets@v0.8.0

See https://github.com/ooni/probe/issues/2067.

* chore: update dependencies and enable go1.18

As mentioned in 7a0d17ea91,
the tree won't build with `go1.18` unless we say it does.

So, not only here we need to update dependencies but also we
need to explicitly say `go1.18` in the `go.mod`.

This work is part of https://github.com/ooni/probe/issues/2067.

* chore(coverage.yml): run with go1.18

This change will give us a bare minimum confidence that we're
going to build our tree using version 1.18 of golang.

See https://github.com/ooni/probe/issues/2067.

* chore: update user agent used for measuring

See https://github.com/ooni/probe/issues/2067

* chore: run `go generate ./...`

See https://github.com/ooni/probe/issues/2067

* fix(dialer_test.go): make test work with go1.17 and go1.18

1. the original test wanted the dial to fail, so ensure we're not
passing any domain name to exercise dialing not resolving;

2. match the end of the error rather than the whole error string.

Tested locally with both go1.17 and go1.18.

See https://github.com/ooni/probe-cli/pull/708#issuecomment-1096447186
2022-04-12 11:43:12 +02:00

2777 lines
65 KiB
Go

// Code generated by go generate; DO NOT EDIT.
// 2022-04-12 11:16:00.104504 +0200 CEST m=+0.000167126
package ooapi
//go:generate go run ./internal/generator -file apis_test.go
import (
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/ooni/probe-cli/v3/internal/netxlite"
"github.com/ooni/probe-cli/v3/internal/ooapi/apimodel"
)
func TestCheckReportIDInvalidURL(t *testing.T) {
api := &simpleCheckReportIDAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleCheckReportIDAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckReportIDWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleCheckReportID struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.CheckReportIDResponse
url *url.URL
userAgent string
}
func (h *handleCheckReportID) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.CheckReportIDResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestCheckReportIDRoundTrip(t *testing.T) {
// setup
handler := &handleCheckReportID{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.CheckReportIDRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleCheckReportIDAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestCheckReportIDMandatoryFields(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 500,
}}
api := &simpleCheckReportIDAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckReportIDRequest{} // deliberately empty
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrEmptyField) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInInvalidURL(t *testing.T) {
api := &simpleCheckInAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleCheckInAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInMarshalErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleCheckInAPI{
JSONCodec: &FakeCodec{EncodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleCheckInAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleCheckInAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleCheckInAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleCheckInAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestCheckInWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleCheckInAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleCheckIn struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.CheckInResponse
url *url.URL
userAgent string
}
func (h *handleCheckIn) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.CheckInResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestCheckInRoundTrip(t *testing.T) {
// setup
handler := &handleCheckIn{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.CheckInRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleCheckInAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "POST" {
t.Fatal("invalid method")
}
// check the body
if handler.contentType != "application/json" {
t.Fatal("invalid content-type header")
}
got := &apimodel.CheckInRequest{}
if err := json.Unmarshal(handler.body, &got); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(req, got); diff != "" {
t.Fatal(diff)
}
}
func TestLoginInvalidURL(t *testing.T) {
api := &simpleLoginAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleLoginAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginMarshalErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleLoginAPI{
JSONCodec: &FakeCodec{EncodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleLoginAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleLoginAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleLoginAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleLoginAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestLoginWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleLoginAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleLogin struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.LoginResponse
url *url.URL
userAgent string
}
func (h *handleLogin) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.LoginResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestLoginRoundTrip(t *testing.T) {
// setup
handler := &handleLogin{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.LoginRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleLoginAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "POST" {
t.Fatal("invalid method")
}
// check the body
if handler.contentType != "application/json" {
t.Fatal("invalid content-type header")
}
got := &apimodel.LoginRequest{}
if err := json.Unmarshal(handler.body, &got); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(req, got); diff != "" {
t.Fatal(diff)
}
}
func TestMeasurementMetaInvalidURL(t *testing.T) {
api := &simpleMeasurementMetaAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleMeasurementMetaAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestMeasurementMetaWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleMeasurementMeta struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.MeasurementMetaResponse
url *url.URL
userAgent string
}
func (h *handleMeasurementMeta) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.MeasurementMetaResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestMeasurementMetaRoundTrip(t *testing.T) {
// setup
handler := &handleMeasurementMeta{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.MeasurementMetaRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleMeasurementMetaAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestMeasurementMetaMandatoryFields(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 500,
}}
api := &simpleMeasurementMetaAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.MeasurementMetaRequest{} // deliberately empty
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrEmptyField) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterInvalidURL(t *testing.T) {
api := &simpleRegisterAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleRegisterAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterMarshalErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleRegisterAPI{
JSONCodec: &FakeCodec{EncodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleRegisterAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleRegisterAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleRegisterAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleRegisterAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestRegisterWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleRegisterAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleRegister struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.RegisterResponse
url *url.URL
userAgent string
}
func (h *handleRegister) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.RegisterResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestRegisterRoundTrip(t *testing.T) {
// setup
handler := &handleRegister{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.RegisterRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleRegisterAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "POST" {
t.Fatal("invalid method")
}
// check the body
if handler.contentType != "application/json" {
t.Fatal("invalid content-type header")
}
got := &apimodel.RegisterRequest{}
if err := json.Unmarshal(handler.body, &got); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(req, got); diff != "" {
t.Fatal(diff)
}
}
func TestTestHelpersInvalidURL(t *testing.T) {
api := &simpleTestHelpersAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleTestHelpersAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTestHelpersWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleTestHelpers struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp apimodel.TestHelpersResponse
url *url.URL
userAgent string
}
func (h *handleTestHelpers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out apimodel.TestHelpersResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestTestHelpersRoundTrip(t *testing.T) {
// setup
handler := &handleTestHelpers{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleTestHelpersAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestTestHelpersResponseLiteralNull(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`null`)},
}}
api := &simpleTestHelpersAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.TestHelpersRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrJSONLiteralNull) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigInvalidURL(t *testing.T) {
api := &simplePsiphonConfigAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWithMissingToken(t *testing.T) {
api := &simplePsiphonConfigAPI{} // no token
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrMissingToken) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simplePsiphonConfigAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestPsiphonConfigWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handlePsiphonConfig struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp apimodel.PsiphonConfigResponse
url *url.URL
userAgent string
}
func (h *handlePsiphonConfig) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out apimodel.PsiphonConfigResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestPsiphonConfigRoundTrip(t *testing.T) {
// setup
handler := &handlePsiphonConfig{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simplePsiphonConfigAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
ff.Fill(&api.Token)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestPsiphonConfigResponseLiteralNull(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`null`)},
}}
api := &simplePsiphonConfigAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.PsiphonConfigRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrJSONLiteralNull) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsInvalidURL(t *testing.T) {
api := &simpleTorTargetsAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWithMissingToken(t *testing.T) {
api := &simpleTorTargetsAPI{} // no token
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrMissingToken) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleTorTargetsAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestTorTargetsWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleTorTargets struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp apimodel.TorTargetsResponse
url *url.URL
userAgent string
}
func (h *handleTorTargets) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out apimodel.TorTargetsResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestTorTargetsRoundTrip(t *testing.T) {
// setup
handler := &handleTorTargets{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleTorTargetsAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
ff.Fill(&api.Token)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestTorTargetsResponseLiteralNull(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`null`)},
}}
api := &simpleTorTargetsAPI{
HTTPClient: clnt,
Token: "fakeToken",
}
ctx := context.Background()
req := &apimodel.TorTargetsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrJSONLiteralNull) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsInvalidURL(t *testing.T) {
api := &simpleURLsAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleURLsAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleURLsAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleURLsAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleURLsAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleURLsAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestURLsWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleURLsAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleURLs struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.URLsResponse
url *url.URL
userAgent string
}
func (h *handleURLs) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.URLsResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestURLsRoundTrip(t *testing.T) {
// setup
handler := &handleURLs{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.URLsRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleURLsAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "GET" {
t.Fatal("invalid method")
}
// check the query
httpReq, err := api.newRequest(context.Background(), req)
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(handler.url.Path, httpReq.URL.Path); diff != "" {
t.Fatal(diff)
}
if diff := cmp.Diff(handler.url.RawQuery, httpReq.URL.RawQuery); diff != "" {
t.Fatal(diff)
}
}
func TestOpenReportInvalidURL(t *testing.T) {
api := &simpleOpenReportAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleOpenReportAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportMarshalErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleOpenReportAPI{
JSONCodec: &FakeCodec{EncodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleOpenReportAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleOpenReportAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleOpenReportAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleOpenReportAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestOpenReportWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleOpenReportAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleOpenReport struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.OpenReportResponse
url *url.URL
userAgent string
}
func (h *handleOpenReport) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.OpenReportResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestOpenReportRoundTrip(t *testing.T) {
// setup
handler := &handleOpenReport{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.OpenReportRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleOpenReportAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "POST" {
t.Fatal("invalid method")
}
// check the body
if handler.contentType != "application/json" {
t.Fatal("invalid content-type header")
}
got := &apimodel.OpenReportRequest{}
if err := json.Unmarshal(handler.body, &got); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(req, got); diff != "" {
t.Fatal(diff)
}
}
func TestSubmitMeasurementInvalidURL(t *testing.T) {
api := &simpleSubmitMeasurementAPI{
BaseURL: "\t", // invalid
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if err == nil || !strings.HasSuffix(err.Error(), "invalid control character in URL") {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWithHTTPErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Err: errMocked}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementMarshalErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleSubmitMeasurementAPI{
JSONCodec: &FakeCodec{EncodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWithNewRequestErr(t *testing.T) {
errMocked := errors.New("mocked error")
api := &simpleSubmitMeasurementAPI{
RequestMaker: &FakeRequestMaker{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWith401(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 401}}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrUnauthorized) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWith400(t *testing.T) {
clnt := &FakeHTTPClient{Resp: &http.Response{StatusCode: 400}}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, ErrHTTPFailure) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWithResponseBodyReadErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Err: errMocked},
}}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
func TestSubmitMeasurementWithUnmarshalFailure(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 200,
Body: &FakeBody{Data: []byte(`{}`)},
}}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
JSONCodec: &FakeCodec{DecodeErr: errMocked},
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}
type handleSubmitMeasurement struct {
accept string
body []byte
contentType string
count int32
method string
mu sync.Mutex
resp *apimodel.SubmitMeasurementResponse
url *url.URL
userAgent string
}
func (h *handleSubmitMeasurement) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer h.mu.Unlock()
h.mu.Lock()
if h.count > 0 {
w.WriteHeader(400)
return
}
h.count++
if r.Body != nil {
data, err := netxlite.ReadAllContext(r.Context(), r.Body)
if err != nil {
w.WriteHeader(400)
return
}
h.body = data
}
h.method = r.Method
h.url = r.URL
h.accept = r.Header.Get("Accept")
h.contentType = r.Header.Get("Content-Type")
h.userAgent = r.Header.Get("User-Agent")
var out *apimodel.SubmitMeasurementResponse
ff := fakeFill{}
ff.Fill(&out)
h.resp = out
data, err := json.Marshal(out)
if err != nil {
w.WriteHeader(400)
return
}
w.Write(data)
}
func TestSubmitMeasurementRoundTrip(t *testing.T) {
// setup
handler := &handleSubmitMeasurement{}
srvr := httptest.NewServer(handler)
defer srvr.Close()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(&req)
api := &simpleSubmitMeasurementAPI{BaseURL: srvr.URL}
ff.Fill(&api.UserAgent)
// issue request
ctx := context.Background()
resp, err := api.Call(ctx, req)
if err != nil {
t.Fatal(err)
}
if resp == nil {
t.Fatal("expected non-nil response here")
}
// compare our response and server's one
if diff := cmp.Diff(handler.resp, resp); diff != "" {
t.Fatal(diff)
}
// check whether headers are OK
if handler.accept != "application/json" {
t.Fatal("invalid accept header")
}
if handler.userAgent != api.UserAgent {
t.Fatal("invalid user-agent header")
}
// check whether the method is OK
if handler.method != "POST" {
t.Fatal("invalid method")
}
// check the body
if handler.contentType != "application/json" {
t.Fatal("invalid content-type header")
}
got := &apimodel.SubmitMeasurementRequest{}
if err := json.Unmarshal(handler.body, &got); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(req, got); diff != "" {
t.Fatal(diff)
}
}
func TestSubmitMeasurementTemplateErr(t *testing.T) {
errMocked := errors.New("mocked error")
clnt := &FakeHTTPClient{Resp: &http.Response{
StatusCode: 500,
}}
api := &simpleSubmitMeasurementAPI{
HTTPClient: clnt,
TemplateExecutor: &FakeTemplateExecutor{Err: errMocked},
}
ctx := context.Background()
req := &apimodel.SubmitMeasurementRequest{}
ff := &fakeFill{}
ff.Fill(req)
resp, err := api.Call(ctx, req)
if !errors.Is(err, errMocked) {
t.Fatal("not the error we expected", err)
}
if resp != nil {
t.Fatal("expected nil resp")
}
}