ooni-probe-cli/internal/ooapi/apis_test.go
Simone Basso 6d3a4f1db8
refactor: merge dnsx and errorsx into netxlite (#517)
When preparing a tutorial for netxlite, I figured it is easier
to tell people "hey, this is the package you should use for all
low-level networking stuff" rather than introducing people to
a set of packages working together where some piece of functionality
is here and some other piece is there.

Part of https://github.com/ooni/probe/issues/1591
2021-09-28 12:42:01 +02:00

2777 lines
65 KiB
Go

// Code generated by go generate; DO NOT EDIT.
// 2021-09-28 12:05:20.537692 +0200 CEST m=+0.000164918
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")
}
}