The objective is to make PR checks run much faster. See https://github.com/ooni/probe/issues/2113 for context. Regarding netxlite's tests: Checking for every commit on master or on a release branch is good enough and makes pull requests faster than one minute since netxlite for windows is now 1m slower than coverage. We're losing some coverage but coverage from integration tests is not so good anyway, so I'm not super sad about this loss.
351 lines
8.9 KiB
Go
351 lines
8.9 KiB
Go
package internal_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
"net/url"
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/cmd/oohelper/internal"
|
|
)
|
|
|
|
func TestMakeTCPEndpoints(t *testing.T) {
|
|
type args struct {
|
|
URL *url.URL
|
|
addrs []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []string
|
|
err error
|
|
}{{
|
|
name: "with host != hostname",
|
|
args: args{URL: &url.URL{Host: "127.0.0.1:8080"}},
|
|
err: internal.ErrUnsupportedExplicitPort,
|
|
}, {
|
|
name: "with unsupported URL scheme",
|
|
args: args{URL: &url.URL{Host: "127.0.0.1", Scheme: "imap"}},
|
|
err: internal.ErrUnsupportedURLScheme,
|
|
}, {
|
|
name: "with http scheme",
|
|
args: args{
|
|
URL: &url.URL{Host: "www.kernel.org", Scheme: "http"},
|
|
addrs: []string{"1.1.1.1", "2.2.2.2", "::1"},
|
|
},
|
|
want: []string{"1.1.1.1:80", "2.2.2.2:80", "[::1]:80"},
|
|
}, {
|
|
name: "with https scheme",
|
|
args: args{
|
|
URL: &url.URL{Host: "www.kernel.org", Scheme: "https"},
|
|
addrs: []string{"1.1.1.1", "2.2.2.2", "::1"},
|
|
},
|
|
want: []string{"1.1.1.1:443", "2.2.2.2:443", "[::1]:443"},
|
|
}}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := internal.MakeTCPEndpoints(tt.args.URL, tt.args.addrs)
|
|
if !errors.Is(err, tt.err) {
|
|
t.Errorf("MakeTCPEndpoints() error = %v, wantErr %v", err, tt.err)
|
|
return
|
|
}
|
|
if !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("MakeTCPEndpoints() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithEmptyTargetURL(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{}
|
|
clnt := internal.OOClient{}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrEmptyURL) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithEmptyServerURL(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{TargetURL: "http://www.example.com"}
|
|
clnt := internal.OOClient{}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrEmptyURL) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithInvalidTargetURL(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{TargetURL: "\t", ServerURL: "https://wcth.ooni.io"}
|
|
clnt := internal.OOClient{}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrInvalidURL) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithResolverFailure(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skip test in short mode")
|
|
}
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
HTTPClient: http.DefaultClient,
|
|
Resolver: internal.NewFakeResolverThatFails(),
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(cresp.TCPConnect) > 0 {
|
|
// The current implementation of the test helper (the legacy codebase)
|
|
// only follows the IP addresses returned by the client.
|
|
t.Fatal("expected empty TCPConnect here")
|
|
}
|
|
if cresp.HTTPRequest.StatusCode != 200 {
|
|
t.Fatal("expected 200 status code here")
|
|
}
|
|
if len(cresp.DNS.Addrs) < 1 {
|
|
t.Fatal("expected at least an IP address here")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithUnsupportedExplicitPort(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com:8080",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrUnsupportedExplicitPort) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithInvalidServerURL(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "\t",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrCannotCreateRequest) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithRoundTripError(t *testing.T) {
|
|
expected := errors.New("mocked error")
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
HTTPClient: &http.Client{
|
|
Transport: internal.FakeTransport{Err: expected},
|
|
},
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, expected) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithInvalidStatusCode(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
HTTPClient: &http.Client{Transport: internal.FakeTransport{
|
|
Resp: &http.Response{
|
|
StatusCode: 400,
|
|
Body: &internal.FakeBody{},
|
|
},
|
|
}},
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrHTTPStatusCode) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithBodyReadError(t *testing.T) {
|
|
expected := errors.New("mocked error")
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
HTTPClient: &http.Client{Transport: internal.FakeTransport{
|
|
Resp: &http.Response{
|
|
StatusCode: 200,
|
|
Body: &internal.FakeBody{
|
|
Err: expected,
|
|
},
|
|
},
|
|
}},
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, expected) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
func TestOOClientDoWithInvalidJSON(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
HTTPClient: &http.Client{Transport: internal.FakeTransport{
|
|
Resp: &http.Response{
|
|
StatusCode: 200,
|
|
Body: &internal.FakeBody{
|
|
Data: []byte("{"),
|
|
},
|
|
},
|
|
}},
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, internal.ErrCannotParseJSONReply) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp != nil {
|
|
t.Fatal("expected nil response")
|
|
}
|
|
}
|
|
|
|
const goodresponse = `{
|
|
"tcp_connect": {
|
|
"172.217.21.68:80": {
|
|
"status": true,
|
|
"failure": null
|
|
}
|
|
},
|
|
"http_request": {
|
|
"body_length": 207878,
|
|
"failure": null,
|
|
"title": "Google",
|
|
"headers": {
|
|
"Content-Type": "text/html"
|
|
},
|
|
"status_code": 200
|
|
},
|
|
"dns": {
|
|
"failure": null,
|
|
"addrs": [
|
|
"172.217.17.68"
|
|
]
|
|
}
|
|
}`
|
|
|
|
func TestOOClientDoWithParseableJSON(t *testing.T) {
|
|
ctx := context.Background()
|
|
config := internal.OOConfig{
|
|
TargetURL: "http://www.example.com",
|
|
ServerURL: "https://wcth.ooni.io",
|
|
}
|
|
clnt := internal.OOClient{
|
|
Resolver: internal.NewFakeResolverWithResult([]string{"1.1.1.1"}),
|
|
HTTPClient: &http.Client{Transport: internal.FakeTransport{
|
|
Resp: &http.Response{
|
|
StatusCode: 200,
|
|
Body: &internal.FakeBody{
|
|
Data: []byte(goodresponse),
|
|
},
|
|
},
|
|
}},
|
|
}
|
|
cresp, err := clnt.Do(ctx, config)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("not the error we expected: %+v", err)
|
|
}
|
|
if cresp.DNS.Failure != nil {
|
|
t.Fatal("unexpected Failure value")
|
|
}
|
|
if len(cresp.DNS.Addrs) != 1 {
|
|
t.Fatal("unexpected number of DNS entries")
|
|
}
|
|
if cresp.DNS.Addrs[0] != "172.217.17.68" {
|
|
t.Fatal("unexpected DNS addrs [0]")
|
|
}
|
|
if cresp.HTTPRequest.BodyLength != 207878 {
|
|
t.Fatal("invalid http body length")
|
|
}
|
|
if cresp.HTTPRequest.Failure != nil {
|
|
t.Fatal("invalid http failure")
|
|
}
|
|
if cresp.HTTPRequest.Title != "Google" {
|
|
t.Fatal("invalid http title")
|
|
}
|
|
if len(cresp.HTTPRequest.Headers) != 1 {
|
|
t.Fatal("invalid http headers length")
|
|
}
|
|
if cresp.HTTPRequest.Headers["Content-Type"] != "text/html" {
|
|
t.Fatal("invalid http content-type header")
|
|
}
|
|
if cresp.HTTPRequest.StatusCode != 200 {
|
|
t.Fatal("invalid http status code")
|
|
}
|
|
if len(cresp.TCPConnect) != 1 {
|
|
t.Fatal("invalid tcp connect length")
|
|
}
|
|
entry, ok := cresp.TCPConnect["172.217.21.68:80"]
|
|
if !ok {
|
|
t.Fatal("cannot find expected TCP connect entry")
|
|
}
|
|
if entry.Status != true {
|
|
t.Fatal("unexpected TCP connect entry status")
|
|
}
|
|
if entry.Failure != nil {
|
|
t.Fatal("unexpected TCP connect entry failure value")
|
|
}
|
|
}
|