// Code generated by go generate; DO NOT EDIT. // 2021-10-20 14:12:56.092704 +0200 CEST m=+0.000214376 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") } }