33de701263
* refactor(atomicx): move outside the engine package After merging probe-engine into probe-cli, my impression is that we have too much unnecessary nesting of packages in this repository. The idea of this commit and of a bunch of following commits will instead be to reduce the nesting and simplify the structure. While there, improve the documentation. * fix: always use the atomicx package For consistency, never use sync/atomic and always use ./internal/atomicx so we can just grep and make sure we're not risking to crash if we make a subtle mistake on a 32 bit platform. While there, mention in the contributing guidelines that we want to always prefer the ./internal/atomicx package over sync/atomic. * fix(atomicx): remove unnecessary constructor We don't need a constructor here. The default constructed `&Int64{}` instance is already usable and the constructor does not add anything to what we are doing, rather it just creates extra confusion. * cleanup(atomicx): we are not using Float64 Because atomicx.Float64 is unused, we can safely zap it. * cleanup(atomicx): simplify impl and improve tests We can simplify the implementation by using defer and by letting the Load() method call Add(0). We can improve tests by making many goroutines updated the atomic int64 value concurrently. * refactor(fsx): can live in the ./internal pkg Let us reduce the amount of nesting. While there, ensure that the package only exports the bare minimum, and improve the documentation of the tests, to ease reading the code. * refactor: move runtimex to ./internal * refactor: move shellx into the ./internal package While there, remove unnecessary dependency between packages. While there, specify in the contributing guidelines that one should use x/sys/execabs instead of os/exec. * refactor: move ooapi into the ./internal pkg * refactor(humanize): move to ./internal and better docs * refactor: move platform to ./internal * refactor(randx): move to ./internal * refactor(multierror): move into the ./internal pkg * refactor(kvstore): all kvstores in ./internal Rather than having part of the kvstore inside ./internal/engine/kvstore and part in ./internal/engine/kvstore.go, let us put every piece of code that is kvstore related into the ./internal/kvstore package. * fix(kvstore): always return ErrNoSuchKey on Get() error It should help to use the kvstore everywhere removing all the copies that are lingering around the tree. * sessionresolver: make KVStore mandatory Simplifies implementation. While there, use the ./internal/kvstore package rather than having our private implementation. * fix(ooapi): use the ./internal/kvstore package * fix(platform): better documentation
2777 lines
64 KiB
Go
2777 lines
64 KiB
Go
// Code generated by go generate; DO NOT EDIT.
|
|
// 2021-05-12 09:15:01.254917327 +0200 CEST m=+0.000217025
|
|
|
|
package ooapi
|
|
|
|
//go:generate go run ./internal/generator -file apis_test.go
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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 := ioutil.ReadAll(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")
|
|
}
|
|
}
|