93f084598e
This diff extracts the fakefiller inside of internal/ooapi (a currently unused package) into its own package. The fakefiller knows how to fill many fields that are typically shared as data structures across processes. It is not perfect in that it cannot fill logger or http client fields, but still helps with better filling and testing. So, here we're using the fakefiller to improve testing of httpx and, nicely enough, we've already catched a bug in the way in which APIClientTemplate.Build misses to forward Authorization from the original template. Yay! Work part of https://github.com/ooni/probe/issues/1951
2777 lines
65 KiB
Go
2777 lines
65 KiB
Go
// Code generated by go generate; DO NOT EDIT.
|
|
// 2022-01-04 17:58:21.011087899 +0100 CET m=+0.000148552
|
|
|
|
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")
|
|
}
|
|
}
|