2022-05-31 21:53:01 +02:00
|
|
|
package tracex
|
2021-02-02 12:05:47 +01:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
|
|
"github.com/gorilla/websocket"
|
2021-09-28 12:42:01 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/netxlite"
|
2021-02-02 12:05:47 +01:00
|
|
|
)
|
|
|
|
|
2022-06-01 23:15:47 +02:00
|
|
|
func TestDNSQueryType(t *testing.T) {
|
|
|
|
t.Run("ipOfType", func(t *testing.T) {
|
|
|
|
type expectation struct {
|
|
|
|
qtype dnsQueryType
|
|
|
|
ip string
|
|
|
|
output bool
|
2022-05-31 21:53:01 +02:00
|
|
|
}
|
2022-06-01 23:15:47 +02:00
|
|
|
var expectations = []expectation{{
|
|
|
|
qtype: "A",
|
|
|
|
ip: "8.8.8.8",
|
|
|
|
output: true,
|
|
|
|
}, {
|
|
|
|
qtype: "A",
|
|
|
|
ip: "2a00:1450:4002:801::2004",
|
|
|
|
output: false,
|
|
|
|
}, {
|
|
|
|
qtype: "AAAA",
|
|
|
|
ip: "8.8.8.8",
|
|
|
|
output: false,
|
|
|
|
}, {
|
|
|
|
qtype: "AAAA",
|
|
|
|
ip: "2a00:1450:4002:801::2004",
|
|
|
|
output: true,
|
|
|
|
}, {
|
|
|
|
qtype: "ANTANI",
|
|
|
|
ip: "2a00:1450:4002:801::2004",
|
|
|
|
output: false,
|
|
|
|
}, {
|
|
|
|
qtype: "ANTANI",
|
|
|
|
ip: "8.8.8.8",
|
|
|
|
output: false,
|
|
|
|
}}
|
|
|
|
for _, exp := range expectations {
|
|
|
|
if exp.qtype.ipOfType(exp.ip) != exp.output {
|
|
|
|
t.Fatalf("failure for %+v", exp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
2022-05-31 21:53:01 +02:00
|
|
|
}
|
|
|
|
|
2021-02-02 12:05:47 +01:00
|
|
|
func TestNewTCPConnectList(t *testing.T) {
|
|
|
|
begin := time.Now()
|
|
|
|
type args struct {
|
|
|
|
begin time.Time
|
2022-05-31 21:53:01 +02:00
|
|
|
events []Event
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
2022-05-31 21:53:01 +02:00
|
|
|
want []TCPConnectEntry
|
2021-02-02 12:05:47 +01:00
|
|
|
}{{
|
|
|
|
name: "empty run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
|
|
|
name: "realistic run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 23:15:47 +02:00
|
|
|
events: []Event{&EventResolveDone{&EventValue{ // skipped because not relevant
|
2021-02-02 12:05:47 +01:00
|
|
|
Addresses: []string{"8.8.8.8", "8.8.4.4"},
|
|
|
|
Hostname: "dns.google.com",
|
|
|
|
Time: begin.Add(100 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventConnectOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
|
|
|
Duration: 30 * time.Millisecond,
|
|
|
|
Proto: "tcp",
|
|
|
|
Time: begin.Add(130 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventConnectOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
|
|
|
Duration: 55 * time.Millisecond,
|
2022-06-01 23:15:47 +02:00
|
|
|
Proto: "udp", // this one should be skipped because it's UDP
|
2021-02-02 12:05:47 +01:00
|
|
|
Time: begin.Add(130 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventConnectOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.4.4:53",
|
|
|
|
Duration: 50 * time.Millisecond,
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2021-02-02 12:05:47 +01:00
|
|
|
Proto: "tcp",
|
|
|
|
Time: begin.Add(180 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []TCPConnectEntry{{
|
2021-02-02 12:05:47 +01:00
|
|
|
IP: "8.8.8.8",
|
|
|
|
Port: 853,
|
2022-05-31 21:53:01 +02:00
|
|
|
Status: TCPConnectStatus{
|
2021-02-02 12:05:47 +01:00
|
|
|
Success: true,
|
|
|
|
},
|
|
|
|
T: 0.13,
|
|
|
|
}, {
|
|
|
|
IP: "8.8.4.4",
|
|
|
|
Port: 53,
|
2022-05-31 21:53:01 +02:00
|
|
|
Status: TCPConnectStatus{
|
|
|
|
Failure: NewFailure(io.EOF),
|
2021-02-02 12:05:47 +01:00
|
|
|
Success: false,
|
|
|
|
},
|
|
|
|
T: 0.18,
|
|
|
|
}},
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-06-01 23:15:47 +02:00
|
|
|
got := NewTCPConnectList(tt.args.begin, tt.args.events)
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewRequestList(t *testing.T) {
|
|
|
|
begin := time.Now()
|
|
|
|
type args struct {
|
|
|
|
begin time.Time
|
2022-05-31 21:53:01 +02:00
|
|
|
events []Event
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
2022-05-31 21:53:01 +02:00
|
|
|
want []RequestEntry
|
2021-02-02 12:05:47 +01:00
|
|
|
}{{
|
|
|
|
name: "empty run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
|
|
|
name: "realistic run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 23:15:47 +02:00
|
|
|
// Two round trips so we can test the sorting expected by OONI
|
2022-06-01 19:27:47 +02:00
|
|
|
events: []Event{&EventHTTPTransactionDone{&EventValue{
|
2022-06-01 15:20:28 +02:00
|
|
|
HTTPRequestHeaders: http.Header{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": []string{"miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
HTTPMethod: "POST",
|
|
|
|
HTTPURL: "https://www.example.com/submit",
|
2022-06-01 15:20:28 +02:00
|
|
|
HTTPResponseHeaders: http.Header{
|
2021-04-02 12:03:18 +02:00
|
|
|
"Server": []string{"miniooni/0.1.0-dev"},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-06-01 19:27:47 +02:00
|
|
|
HTTPStatusCode: 200,
|
|
|
|
HTTPResponseBody: []byte("{}"),
|
|
|
|
HTTPResponseBodyIsTruncated: false,
|
|
|
|
Time: begin.Add(10 * time.Millisecond),
|
|
|
|
}}, &EventHTTPTransactionDone{&EventValue{
|
2022-06-01 15:20:28 +02:00
|
|
|
HTTPRequestHeaders: http.Header{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": []string{"miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
HTTPMethod: "GET",
|
|
|
|
HTTPURL: "https://www.example.com/result",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2022-06-01 19:27:47 +02:00
|
|
|
Time: begin.Add(20 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []RequestEntry{{
|
|
|
|
Failure: NewFailure(io.EOF),
|
|
|
|
Request: HTTPRequest{
|
|
|
|
HeadersList: []HTTPHeader{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Key: "User-Agent",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "miniooni/0.1.0-dev",
|
|
|
|
},
|
|
|
|
}},
|
2022-05-31 21:53:01 +02:00
|
|
|
Headers: map[string]MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": {Value: "miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
Method: "GET",
|
|
|
|
URL: "https://www.example.com/result",
|
|
|
|
},
|
2022-06-01 19:27:47 +02:00
|
|
|
Response: HTTPResponse{
|
|
|
|
HeadersList: []HTTPHeader{},
|
|
|
|
Headers: make(map[string]MaybeBinaryValue),
|
|
|
|
},
|
2021-02-02 12:05:47 +01:00
|
|
|
T: 0.02,
|
|
|
|
}, {
|
2022-05-31 21:53:01 +02:00
|
|
|
Request: HTTPRequest{
|
|
|
|
Body: MaybeBinaryValue{
|
2022-06-01 19:27:47 +02:00
|
|
|
Value: "",
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
HeadersList: []HTTPHeader{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Key: "User-Agent",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "miniooni/0.1.0-dev",
|
|
|
|
},
|
|
|
|
}},
|
2022-05-31 21:53:01 +02:00
|
|
|
Headers: map[string]MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": {Value: "miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
Method: "POST",
|
|
|
|
URL: "https://www.example.com/submit",
|
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
Response: HTTPResponse{
|
|
|
|
Body: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "{}",
|
|
|
|
},
|
|
|
|
Code: 200,
|
2022-05-31 21:53:01 +02:00
|
|
|
HeadersList: []HTTPHeader{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Key: "Server",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-04-02 12:03:18 +02:00
|
|
|
Value: "miniooni/0.1.0-dev",
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
}},
|
2022-05-31 21:53:01 +02:00
|
|
|
Headers: map[string]MaybeBinaryValue{
|
2021-04-02 12:03:18 +02:00
|
|
|
"Server": {Value: "miniooni/0.1.0-dev"},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
Locations: nil,
|
|
|
|
},
|
|
|
|
T: 0.01,
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
// for an example of why we need to sort headers, see
|
forwardport: pull the patches mentioned in ooni/probe#1908 (#629)
* [forwardport] fix(oonimkall): make logger used by tasks unit testable (#623)
This diff forward ports e4b04642c51e7461728b25941624e1b97ef0ec83.
Reference issue: https://github.com/ooni/probe/issues/1903
* [forwardport] feat(oonimkall): improve taskEmitter testability (#624)
This diff forward ports 3e0f01a389c1f4cdd7878ec151aff91870a0bdff.
1. rename eventemitter{,_test}.go => taskemitter{,_test}.go because
the new name is more proper after we merged the internal/task package
inside of the oonimkall package;
2. rename runner.go's `run` function to `runTask`;
3. modify `runTask` to use the new `taskEmitterUsingChan` abstraction
on which we will spend more works in a later point of this list;
4. introduce `runTaskWithEmitter` factory that is called by `runTask`
and allows us to more easily write unit tests;
5. acknowledge that `runner` was not using its `out` field;
6. use the new `taskEmitterWrapper` in `newRunner`;
7. acknowledge that `runnerCallbacks` could use a generic
`taskEmitter` as field type rather than a specific type;
8. rewrite tests to use `runTaskWithEmitter` which leads to
simpler code that does not require a goroutine;
9. acknowledge that the code has been ignoring the `DisabledEvents`
settings for quite some time, so stop supporting it;
10. refactor the `taskEmitter` implementation to be like:
1. we still have the `taskEmitter` interface;
2. `taskEmitterUsingChan` wraps the channel and allows for
emitting events using the channel;
3. `taskEmitterUsingChan` owns an `eof` channel that is
closed by `Close` (which is idempotent) and signals we
should be stop emitting;
4. make sure `runTask` creates a `taskEmitterUsingChan`
and calls its `Close` method when done;
5. completely remove the code for disabling events
since the code was actually ignoring the stting;
6. add a `taskEmitterWrapper` that adds common functions
for emitting events to _any_ `taskWrapper`;
7. write unit tests for `taskEmitterUsingChan` and
for `taskEmitterWrapper`;
11. acknowledge that the abstraction we need for testing is
actually a thread-safe thing that collects events into a
vector containing events and refactor all tests accordingly.
See https://github.com/ooni/probe/issues/1903
* [forwardport] refactor(oonimkall): make the runner unit-testable (#625)
This diff forward ports 9423947faf6980d92d2fe67efe3829e8fef76586.
See https://github.com/ooni/probe/issues/1903
* [forwardport] feat(oonimkall): write unit tests for the runner component (#626)
This diff forward ports 35dd0e3788b8fa99c541452bbb5e0ae4871239e1.
Forward porting note: compared to 35dd0e3788b8fa99c541452bbb5e0ae4871239e1,
the diff I'm committing here is slightly different. In `master` we do not
have the case where a measurement fails and a measurement is returned, thus
I needed to adapt the test to become like this:
```diff
diff --git a/pkg/oonimkall/runner_internal_test.go b/pkg/oonimkall/runner_internal_test.go
index 334b574..84c7436 100644
--- a/pkg/oonimkall/runner_internal_test.go
+++ b/pkg/oonimkall/runner_internal_test.go
@@ -568,15 +568,6 @@ func TestTaskRunnerRun(t *testing.T) {
}, {
Key: failureMeasurement,
Count: 1,
- }, {
- Key: measurement,
- Count: 1,
- }, {
- Key: statusMeasurementSubmission,
- Count: 1,
- }, {
- Key: statusMeasurementDone,
- Count: 1,
}, {
Key: statusEnd,
Count: 1,
```
I still need to write more assertions for each emitted event
but the code we've here is already a great starting point.
See https://github.com/ooni/probe/issues/1903
* [forwardport] refactor(oonimkall): merge files, use proper names, zap unneeded integration tests (#627)
This diff forward ports f894427d24edc9a03fc78306d0093e7b51c46c25.
Forward porting note: this diff is slightly different from the original
mentioned above because it carries forward changes mentioned in the
previous diff caused by a different way of handling a failed measurement
in the master branch compared to the release/3.11 branch.
Move everything that looked like "task's model" inside of the
taskmodel.go file, for consistency.
Make sure it's clear some variables are event types.
Rename the concrete `runner` as `runnerForTask`.
Also, remove now-unnecessary (and flaky!) integration tests
for the `runnerForTask` type.
While there, notice there were wrong URLs that were generated
during the probe-engine => probe-cli move and fix them.
See https://github.com/ooni/probe/issues/1903
* [forwardport] refactor(oonimkall): we can simplify StartTask tests (#628)
This diff forward ports dcf2986c2032d8185d58d24130a7f2c2d61ef2fb.
* refactor(oonimkall): we can simplify StartTask tests
We have enough checks for runnerForTask. So we do not need to
duplicate them when checking for StartTask.
While there, refactor how we start tasks to remove the need for
extra runner functions.
This is the objective I wanted to achieve for oonimkall:
1. less duplicate tests, and
2. more unit tests (which are less flaky)
At this point, we're basically done (pending forwardporting to
master) with https://github.com/ooni/probe/issues/1903.
* fix(oonimkall): TestStartTaskGood shouldn't cancel the test
This creates a race condition where the test may fail if we cannot
complete the whole "Example" test in less than one second.
This should explain the build failures I've seen so far and why
I didn't see those failures when running locally.
2021-12-02 12:47:07 +01:00
|
|
|
// https://github.com/ooni/probe-engine/pull/751/checks?check_run_id=853562310
|
2021-02-02 12:05:47 +01:00
|
|
|
name: "run with redirect and headers to sort",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 19:27:47 +02:00
|
|
|
events: []Event{&EventHTTPTransactionDone{&EventValue{
|
2022-06-01 15:20:28 +02:00
|
|
|
HTTPRequestHeaders: http.Header{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": []string{"miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
HTTPMethod: "GET",
|
|
|
|
HTTPURL: "https://www.example.com/",
|
2022-06-01 15:20:28 +02:00
|
|
|
HTTPResponseHeaders: http.Header{
|
2021-04-02 12:03:18 +02:00
|
|
|
"Server": []string{"miniooni/0.1.0-dev"},
|
2021-02-02 12:05:47 +01:00
|
|
|
"Location": []string{"https://x.example.com", "https://y.example.com"},
|
|
|
|
},
|
|
|
|
HTTPStatusCode: 302,
|
2022-06-01 19:27:47 +02:00
|
|
|
Time: begin.Add(10 * time.Millisecond),
|
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []RequestEntry{{
|
|
|
|
Request: HTTPRequest{
|
|
|
|
HeadersList: []HTTPHeader{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Key: "User-Agent",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "miniooni/0.1.0-dev",
|
|
|
|
},
|
|
|
|
}},
|
2022-05-31 21:53:01 +02:00
|
|
|
Headers: map[string]MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
"User-Agent": {Value: "miniooni/0.1.0-dev"},
|
|
|
|
},
|
|
|
|
Method: "GET",
|
|
|
|
URL: "https://www.example.com/",
|
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
Response: HTTPResponse{
|
2021-02-02 12:05:47 +01:00
|
|
|
Code: 302,
|
2022-05-31 21:53:01 +02:00
|
|
|
HeadersList: []HTTPHeader{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Key: "Location",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "https://x.example.com",
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
Key: "Location",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "https://y.example.com",
|
|
|
|
},
|
|
|
|
}, {
|
|
|
|
Key: "Server",
|
2022-05-31 21:53:01 +02:00
|
|
|
Value: MaybeBinaryValue{
|
2021-04-02 12:03:18 +02:00
|
|
|
Value: "miniooni/0.1.0-dev",
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
}},
|
2022-05-31 21:53:01 +02:00
|
|
|
Headers: map[string]MaybeBinaryValue{
|
2021-04-02 12:03:18 +02:00
|
|
|
"Server": {Value: "miniooni/0.1.0-dev"},
|
2021-02-02 12:05:47 +01:00
|
|
|
"Location": {Value: "https://x.example.com"},
|
|
|
|
},
|
|
|
|
Locations: []string{
|
|
|
|
"https://x.example.com", "https://y.example.com",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
T: 0.01,
|
|
|
|
}},
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-06-01 23:15:47 +02:00
|
|
|
got := NewRequestList(tt.args.begin, tt.args.events)
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewDNSQueriesList(t *testing.T) {
|
|
|
|
begin := time.Now()
|
|
|
|
type args struct {
|
|
|
|
begin time.Time
|
2022-05-31 21:53:01 +02:00
|
|
|
events []Event
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
2022-05-31 21:53:01 +02:00
|
|
|
want []DNSQueryEntry
|
2021-02-02 12:05:47 +01:00
|
|
|
}{{
|
|
|
|
name: "empty run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
|
|
|
name: "realistic run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 14:32:16 +02:00
|
|
|
events: []Event{&EventResolveDone{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "1.1.1.1:853",
|
|
|
|
Addresses: []string{"8.8.8.8", "8.8.4.4"},
|
|
|
|
Hostname: "dns.google.com",
|
|
|
|
Proto: "dot",
|
|
|
|
Time: begin.Add(100 * time.Millisecond),
|
2022-06-01 23:15:47 +02:00
|
|
|
}}, &EventConnectOperation{&EventValue{ // skipped because not relevant
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
|
|
|
Duration: 30 * time.Millisecond,
|
|
|
|
Proto: "tcp",
|
|
|
|
Time: begin.Add(130 * time.Millisecond),
|
2022-06-01 23:15:47 +02:00
|
|
|
}}, &EventConnectOperation{&EventValue{ // skipped because not relevant
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.4.4:53",
|
|
|
|
Duration: 50 * time.Millisecond,
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2021-02-02 12:05:47 +01:00
|
|
|
Proto: "tcp",
|
|
|
|
Time: begin.Add(180 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []DNSQueryEntry{{
|
|
|
|
Answers: []DNSAnswerEntry{{
|
2021-04-01 16:57:31 +02:00
|
|
|
ASN: 15169,
|
|
|
|
ASOrgName: "Google LLC",
|
2021-02-02 12:05:47 +01:00
|
|
|
AnswerType: "A",
|
|
|
|
IPv4: "8.8.8.8",
|
|
|
|
}, {
|
2021-04-01 16:57:31 +02:00
|
|
|
ASN: 15169,
|
|
|
|
ASOrgName: "Google LLC",
|
2021-02-02 12:05:47 +01:00
|
|
|
AnswerType: "A",
|
|
|
|
IPv4: "8.8.4.4",
|
|
|
|
}},
|
|
|
|
Engine: "dot",
|
|
|
|
Hostname: "dns.google.com",
|
|
|
|
QueryType: "A",
|
|
|
|
ResolverAddress: "1.1.1.1:853",
|
|
|
|
T: 0.1,
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "run with IPv6 results",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 14:32:16 +02:00
|
|
|
events: []Event{&EventResolveDone{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Addresses: []string{"2001:4860:4860::8888"},
|
|
|
|
Hostname: "dns.google.com",
|
|
|
|
Time: begin.Add(200 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []DNSQueryEntry{{
|
|
|
|
Answers: []DNSAnswerEntry{{
|
2021-02-02 12:05:47 +01:00
|
|
|
ASN: 15169,
|
|
|
|
ASOrgName: "Google LLC",
|
|
|
|
AnswerType: "AAAA",
|
|
|
|
IPv6: "2001:4860:4860::8888",
|
|
|
|
}},
|
|
|
|
Hostname: "dns.google.com",
|
|
|
|
QueryType: "AAAA",
|
|
|
|
T: 0.2,
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "run with errors",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 14:32:16 +02:00
|
|
|
events: []Event{&EventResolveDone{&EventValue{
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureDNSNXDOMAINError,
|
2021-02-02 12:05:47 +01:00
|
|
|
Hostname: "dns.google.com",
|
|
|
|
Time: begin.Add(200 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []DNSQueryEntry{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Answers: nil,
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(
|
2021-09-28 12:42:01 +02:00
|
|
|
&netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}),
|
2021-02-02 12:05:47 +01:00
|
|
|
Hostname: "dns.google.com",
|
|
|
|
QueryType: "A",
|
|
|
|
T: 0.2,
|
|
|
|
}, {
|
|
|
|
Answers: nil,
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(
|
2021-09-28 12:42:01 +02:00
|
|
|
&netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}),
|
2021-02-02 12:05:47 +01:00
|
|
|
Hostname: "dns.google.com",
|
|
|
|
QueryType: "AAAA",
|
|
|
|
T: 0.2,
|
|
|
|
}},
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-05-31 21:53:01 +02:00
|
|
|
got := NewDNSQueriesList(tt.args.begin, tt.args.events)
|
2021-04-01 16:57:31 +02:00
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewNetworkEventsList(t *testing.T) {
|
|
|
|
begin := time.Now()
|
|
|
|
type args struct {
|
|
|
|
begin time.Time
|
2022-05-31 21:53:01 +02:00
|
|
|
events []Event
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
2022-05-31 21:53:01 +02:00
|
|
|
want []NetworkEvent
|
2021-02-02 12:05:47 +01:00
|
|
|
}{{
|
|
|
|
name: "empty run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
|
|
|
name: "realistic run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 14:32:16 +02:00
|
|
|
events: []Event{&EventConnectOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2021-02-02 12:05:47 +01:00
|
|
|
Proto: "tcp",
|
|
|
|
Time: begin.Add(7 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventReadOperation{&EventValue{
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureInterrupted,
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 7117,
|
|
|
|
Time: begin.Add(11 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventReadFromOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureInterrupted,
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 7117,
|
|
|
|
Time: begin.Add(11 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventWriteOperation{&EventValue{
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: NewFailureStr(websocket.ErrBadHandshake),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 4114,
|
|
|
|
Time: begin.Add(14 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}, &EventWriteToOperation{&EventValue{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: NewFailureStr(websocket.ErrBadHandshake),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 4114,
|
|
|
|
Time: begin.Add(14 * time.Millisecond),
|
2022-06-01 23:15:47 +02:00
|
|
|
}}, &EventResolveStart{&EventValue{
|
|
|
|
// We expect this event to be logged event though it's not a typical I/O
|
|
|
|
// event (it seems these extra events are useful for debugging)
|
|
|
|
Time: begin.Add(15 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []NetworkEvent{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Address: "8.8.8.8:853",
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(io.EOF),
|
2021-09-28 12:42:01 +02:00
|
|
|
Operation: netxlite.ConnectOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
Proto: "tcp",
|
|
|
|
T: 0.007,
|
|
|
|
}, {
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(context.Canceled),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 7117,
|
2021-09-28 12:42:01 +02:00
|
|
|
Operation: netxlite.ReadOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
T: 0.011,
|
|
|
|
}, {
|
|
|
|
Address: "8.8.8.8:853",
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(context.Canceled),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 7117,
|
2021-09-28 12:42:01 +02:00
|
|
|
Operation: netxlite.ReadFromOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
T: 0.011,
|
|
|
|
}, {
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(websocket.ErrBadHandshake),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 4114,
|
2021-09-28 12:42:01 +02:00
|
|
|
Operation: netxlite.WriteOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
T: 0.014,
|
|
|
|
}, {
|
|
|
|
Address: "8.8.8.8:853",
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(websocket.ErrBadHandshake),
|
2021-02-02 12:05:47 +01:00
|
|
|
NumBytes: 4114,
|
2021-09-28 12:42:01 +02:00
|
|
|
Operation: netxlite.WriteToOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
T: 0.014,
|
2022-06-01 23:15:47 +02:00
|
|
|
}, {
|
|
|
|
Operation: "resolve_start",
|
|
|
|
T: 0.015,
|
2021-02-02 12:05:47 +01:00
|
|
|
}},
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-06-01 23:15:47 +02:00
|
|
|
got := NewNetworkEventsList(tt.args.begin, tt.args.events)
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewTLSHandshakesList(t *testing.T) {
|
|
|
|
begin := time.Now()
|
|
|
|
type args struct {
|
|
|
|
begin time.Time
|
2022-05-31 21:53:01 +02:00
|
|
|
events []Event
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
2022-05-31 21:53:01 +02:00
|
|
|
want []TLSHandshake
|
2021-02-02 12:05:47 +01:00
|
|
|
}{{
|
|
|
|
name: "empty run",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
2022-06-01 23:15:47 +02:00
|
|
|
name: "realistic run with TLS",
|
2021-02-02 12:05:47 +01:00
|
|
|
args: args{
|
|
|
|
begin: begin,
|
2022-06-01 14:32:16 +02:00
|
|
|
events: []Event{&EventTLSHandshakeDone{&EventValue{
|
2022-05-06 11:09:54 +02:00
|
|
|
Address: "131.252.210.176:443",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2021-02-02 12:05:47 +01:00
|
|
|
NoTLSVerify: false,
|
2022-06-01 23:15:47 +02:00
|
|
|
Proto: "tcp",
|
2021-02-02 12:05:47 +01:00
|
|
|
TLSCipherSuite: "SUITE",
|
|
|
|
TLSNegotiatedProto: "h2",
|
2022-06-02 11:07:02 +02:00
|
|
|
TLSPeerCerts: [][]byte{
|
|
|
|
[]byte("deadbeef"),
|
|
|
|
[]byte("abad1dea"),
|
|
|
|
},
|
2021-02-02 12:05:47 +01:00
|
|
|
TLSServerName: "x.org",
|
|
|
|
TLSVersion: "TLSv1.3",
|
|
|
|
Time: begin.Add(55 * time.Millisecond),
|
2022-06-01 14:32:16 +02:00
|
|
|
}}},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
2022-05-31 21:53:01 +02:00
|
|
|
want: []TLSHandshake{{
|
2022-05-06 11:09:54 +02:00
|
|
|
Address: "131.252.210.176:443",
|
2021-02-02 12:05:47 +01:00
|
|
|
CipherSuite: "SUITE",
|
2022-05-31 21:53:01 +02:00
|
|
|
Failure: NewFailure(io.EOF),
|
2021-02-02 12:05:47 +01:00
|
|
|
NegotiatedProtocol: "h2",
|
|
|
|
NoTLSVerify: false,
|
2022-05-31 21:53:01 +02:00
|
|
|
PeerCertificates: []MaybeBinaryValue{{
|
2021-02-02 12:05:47 +01:00
|
|
|
Value: "deadbeef",
|
|
|
|
}, {
|
|
|
|
Value: "abad1dea",
|
|
|
|
}},
|
|
|
|
ServerName: "x.org",
|
|
|
|
T: 0.055,
|
|
|
|
TLSVersion: "TLSv1.3",
|
|
|
|
}},
|
2022-06-01 23:15:47 +02:00
|
|
|
}, {
|
|
|
|
name: "realistic run with QUIC",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: []Event{&EventQUICHandshakeDone{&EventValue{
|
|
|
|
Address: "131.252.210.176:443",
|
refactor(tracex): internally represent errors as strings (#786)
There are two reasons why this is beneficial:
1. github.com/google/go-cmp is more annoying to use for comparing
data structures when there are interfaces to compare. Sure, there's
a recipe for teaching it to compare errors, but how about making
the errors trivially comparable instead?
2. if we want to send errors over the network, JSON serialization
works but we cannot unmarshal the resulting string back to an error,
so how about making this representation trivial to serialize (we
are not going this now, but we need this property for websteps and
it may be sensible to try to avoid to have duplicate code because
of that -- measurex currently duplicates many tracex functionality
and this is quite unfortunate because it slows development down)
Additionally, if an error is a string:
3. we can very easily use a switch for comparing its possible
values with "" representing the absence of errors, while it is
more complex to do the same when using a nullable string or even
an error (i.e., an interface)
4. if a type is not nullable, it's easier to write safe code for
it and we may want to refactor experiments to use the internal
representation of measurements for more robust processing code
For all these reasons, let's internally use strings in tracex.
The overall aim here is to reduce the duplicated code between pre
and post-measurex measurements (see https://github.com/ooni/probe/issues/2035).
2022-06-02 10:37:07 +02:00
|
|
|
Err: netxlite.FailureEOFError,
|
2022-06-01 23:15:47 +02:00
|
|
|
NoTLSVerify: false,
|
2022-09-08 17:19:59 +02:00
|
|
|
Proto: "udp",
|
2022-06-01 23:15:47 +02:00
|
|
|
TLSCipherSuite: "SUITE",
|
|
|
|
TLSNegotiatedProto: "h3",
|
2022-06-02 11:07:02 +02:00
|
|
|
TLSPeerCerts: [][]byte{
|
|
|
|
[]byte("deadbeef"),
|
|
|
|
[]byte("abad1dea"),
|
|
|
|
},
|
2022-06-01 23:15:47 +02:00
|
|
|
TLSServerName: "x.org",
|
|
|
|
TLSVersion: "TLSv1.3",
|
|
|
|
Time: begin.Add(55 * time.Millisecond),
|
|
|
|
}}},
|
|
|
|
},
|
|
|
|
want: []TLSHandshake{{
|
|
|
|
Address: "131.252.210.176:443",
|
|
|
|
CipherSuite: "SUITE",
|
|
|
|
Failure: NewFailure(io.EOF),
|
|
|
|
NegotiatedProtocol: "h3",
|
|
|
|
NoTLSVerify: false,
|
|
|
|
PeerCertificates: []MaybeBinaryValue{{
|
|
|
|
Value: "deadbeef",
|
|
|
|
}, {
|
|
|
|
Value: "abad1dea",
|
|
|
|
}},
|
|
|
|
ServerName: "x.org",
|
|
|
|
T: 0.055,
|
|
|
|
TLSVersion: "TLSv1.3",
|
|
|
|
}},
|
|
|
|
}, {
|
|
|
|
name: "realistic run with no suitable events",
|
|
|
|
args: args{
|
|
|
|
begin: begin,
|
|
|
|
events: []Event{&EventResolveStart{&EventValue{
|
|
|
|
Time: begin.Add(55 * time.Millisecond),
|
|
|
|
}}},
|
|
|
|
},
|
|
|
|
want: nil,
|
2021-02-02 12:05:47 +01:00
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-06-01 23:15:47 +02:00
|
|
|
got := NewTLSHandshakesList(tt.args.begin, tt.args.events)
|
|
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
|
|
t.Fatal(diff)
|
2021-02-02 12:05:47 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewFailure(t *testing.T) {
|
|
|
|
type args struct {
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
|
|
|
want *string
|
|
|
|
}{{
|
|
|
|
name: "when error is nil",
|
|
|
|
args: args{
|
|
|
|
err: nil,
|
|
|
|
},
|
|
|
|
want: nil,
|
|
|
|
}, {
|
|
|
|
name: "when error is wrapped and failure meaningful",
|
|
|
|
args: args{
|
2021-09-28 12:42:01 +02:00
|
|
|
err: &netxlite.ErrWrapper{
|
|
|
|
Failure: netxlite.FailureConnectionRefused,
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
want: func() *string {
|
2021-09-28 12:42:01 +02:00
|
|
|
s := netxlite.FailureConnectionRefused
|
2021-02-02 12:05:47 +01:00
|
|
|
return &s
|
|
|
|
}(),
|
|
|
|
}, {
|
|
|
|
name: "when error is wrapped and failure is not meaningful",
|
|
|
|
args: args{
|
2021-09-28 12:42:01 +02:00
|
|
|
err: &netxlite.ErrWrapper{},
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
want: func() *string {
|
|
|
|
s := "unknown_failure: errWrapper.Failure is empty"
|
|
|
|
return &s
|
|
|
|
}(),
|
|
|
|
}, {
|
|
|
|
name: "when error is not wrapped but wrappable",
|
|
|
|
args: args{err: io.EOF},
|
|
|
|
want: func() *string {
|
|
|
|
s := "eof_error"
|
|
|
|
return &s
|
|
|
|
}(),
|
|
|
|
}, {
|
|
|
|
name: "when the error is not wrapped and not wrappable",
|
|
|
|
args: args{
|
|
|
|
err: errors.New("use of closed socket 127.0.0.1:8080->10.0.0.1:22"),
|
|
|
|
},
|
|
|
|
want: func() *string {
|
|
|
|
s := "unknown_failure: use of closed socket [scrubbed]->[scrubbed]"
|
|
|
|
return &s
|
|
|
|
}(),
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-05-31 21:53:01 +02:00
|
|
|
got := NewFailure(tt.args.err)
|
2021-02-02 12:05:47 +01:00
|
|
|
if tt.want == nil && got == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if tt.want == nil && got != nil {
|
|
|
|
t.Errorf("NewFailure: want %+v, got %s", tt.want, *got)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if tt.want != nil && got == nil {
|
|
|
|
t.Errorf("NewFailure: want %s, got %+v", *tt.want, got)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if *tt.want != *got {
|
|
|
|
t.Errorf("NewFailure: want %s, got %s", *tt.want, *got)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewFailedOperation(t *testing.T) {
|
|
|
|
type args struct {
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
|
|
|
args args
|
|
|
|
want *string
|
|
|
|
}{{
|
|
|
|
name: "With no error",
|
|
|
|
args: args{
|
|
|
|
err: nil, // explicit
|
|
|
|
},
|
|
|
|
want: nil, // explicit
|
|
|
|
}, {
|
|
|
|
name: "With wrapped error and non-empty operation",
|
|
|
|
args: args{
|
2021-09-28 12:42:01 +02:00
|
|
|
err: &netxlite.ErrWrapper{
|
|
|
|
Failure: netxlite.FailureConnectionRefused,
|
|
|
|
Operation: netxlite.ConnectOperation,
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
want: (func() *string {
|
2021-09-28 12:42:01 +02:00
|
|
|
s := netxlite.ConnectOperation
|
2021-02-02 12:05:47 +01:00
|
|
|
return &s
|
|
|
|
})(),
|
|
|
|
}, {
|
|
|
|
name: "With wrapped error and empty operation",
|
|
|
|
args: args{
|
2021-09-28 12:42:01 +02:00
|
|
|
err: &netxlite.ErrWrapper{
|
|
|
|
Failure: netxlite.FailureConnectionRefused,
|
2021-02-02 12:05:47 +01:00
|
|
|
},
|
|
|
|
},
|
|
|
|
want: (func() *string {
|
2021-09-28 12:42:01 +02:00
|
|
|
s := netxlite.UnknownOperation
|
2021-02-02 12:05:47 +01:00
|
|
|
return &s
|
|
|
|
})(),
|
|
|
|
}, {
|
|
|
|
name: "With non wrapped error",
|
|
|
|
args: args{
|
|
|
|
err: io.EOF,
|
|
|
|
},
|
|
|
|
want: (func() *string {
|
2021-09-28 12:42:01 +02:00
|
|
|
s := netxlite.UnknownOperation
|
2021-02-02 12:05:47 +01:00
|
|
|
return &s
|
|
|
|
})(),
|
|
|
|
}}
|
|
|
|
for _, tt := range tests {
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
2022-05-31 21:53:01 +02:00
|
|
|
got := NewFailedOperation(tt.args.err)
|
2021-02-02 12:05:47 +01:00
|
|
|
if got == nil && tt.want == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if got == nil && tt.want != nil {
|
|
|
|
t.Errorf("NewFailedOperation() = %v, want %v", got, tt.want)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if got != nil && tt.want == nil {
|
|
|
|
t.Errorf("NewFailedOperation() = %v, want %v", got, tt.want)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if got != nil && tt.want != nil && *got != *tt.want {
|
|
|
|
t.Errorf("NewFailedOperation() = %v, want %v", got, tt.want)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|