refactor(tracex): do not depend on strings for event names (#777)

Rather than matching a string, match a type.

This is more robust considering future refactorings.

We're confident the names did not change in _this_ refactoring
because we're still testing the same strings in the tests.

Part of https://github.com/ooni/probe/issues/2121
This commit is contained in:
Simone Basso 2022-06-01 14:32:16 +02:00 committed by GitHub
parent 8f7e3803eb
commit c740be987b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 533 additions and 340 deletions

View File

@ -171,8 +171,8 @@ func (r runner) measure(
// of the latest connect time. We should have one sample in most // of the latest connect time. We should have one sample in most
// cases, because the connection should be persistent. // cases, because the connection should be persistent.
for _, ev := range r.saver.Read() { for _, ev := range r.saver.Read() {
if ev.Name == netxlite.ConnectOperation { if _, ok := ev.(*tracex.EventConnectOperation); ok {
connectTime = ev.Duration.Seconds() connectTime = ev.Value().Duration.Seconds()
} }
} }
current.ConnectTime = connectTime current.ConnectTime = connectTime

View File

@ -14,7 +14,6 @@ import (
"github.com/ooni/probe-cli/v3/internal/engine/mockable" "github.com/ooni/probe-cli/v3/internal/engine/mockable"
"github.com/ooni/probe-cli/v3/internal/engine/netx/tracex" "github.com/ooni/probe-cli/v3/internal/engine/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
func TestRunnerLoopLocateFailure(t *testing.T) { func TestRunnerLoopLocateFailure(t *testing.T) {
@ -108,7 +107,7 @@ func TestRunnerLoopMeasureFailure(t *testing.T) {
func TestRunnerLoopCollectFailure(t *testing.T) { func TestRunnerLoopCollectFailure(t *testing.T) {
expected := errors.New("mocked error") expected := errors.New("mocked error")
saver := new(tracex.Saver) saver := new(tracex.Saver)
saver.Write(tracex.Event{Name: netxlite.ConnectOperation, Duration: 150 * time.Millisecond}) saver.Write(&tracex.EventConnectOperation{V: &tracex.EventValue{Duration: 150 * time.Millisecond}})
r := runner{ r := runner{
callbacks: model.NewPrinterCallbacks(log.Log), callbacks: model.NewPrinterCallbacks(log.Log),
httpClient: &http.Client{ httpClient: &http.Client{
@ -152,7 +151,7 @@ func TestRunnerLoopCollectFailure(t *testing.T) {
func TestRunnerLoopSuccess(t *testing.T) { func TestRunnerLoopSuccess(t *testing.T) {
saver := new(tracex.Saver) saver := new(tracex.Saver)
saver.Write(tracex.Event{Name: netxlite.ConnectOperation, Duration: 150 * time.Millisecond}) saver.Write(&tracex.EventConnectOperation{V: &tracex.EventValue{Duration: 150 * time.Millisecond}})
r := runner{ r := runner{
callbacks: model.NewPrinterCallbacks(log.Log), callbacks: model.NewPrinterCallbacks(log.Log),
httpClient: &http.Client{ httpClient: &http.Client{

View File

@ -45,10 +45,11 @@ var (
// NewTCPConnectList creates a new TCPConnectList // NewTCPConnectList creates a new TCPConnectList
func NewTCPConnectList(begin time.Time, events []Event) []TCPConnectEntry { func NewTCPConnectList(begin time.Time, events []Event) []TCPConnectEntry {
var out []TCPConnectEntry var out []TCPConnectEntry
for _, event := range events { for _, wrapper := range events {
if event.Name != netxlite.ConnectOperation { if _, ok := wrapper.(*EventConnectOperation); !ok {
continue continue
} }
event := wrapper.Value()
if event.Proto != "tcp" { if event.Proto != "tcp" {
continue continue
} }
@ -140,31 +141,32 @@ func newRequestList(begin time.Time, events []Event) []RequestEntry {
out []RequestEntry out []RequestEntry
entry RequestEntry entry RequestEntry
) )
for _, ev := range events { for _, wrapper := range events {
switch ev.Name { ev := wrapper.Value()
case "http_transaction_start": switch wrapper.(type) {
case *EventHTTPTransactionStart:
entry = RequestEntry{} entry = RequestEntry{}
entry.T = ev.Time.Sub(begin).Seconds() entry.T = ev.Time.Sub(begin).Seconds()
case "http_request_body_snapshot": case *EventHTTPRequestBodySnapshot:
entry.Request.Body.Value = string(ev.Data) entry.Request.Body.Value = string(ev.Data)
entry.Request.BodyIsTruncated = ev.DataIsTruncated entry.Request.BodyIsTruncated = ev.DataIsTruncated
case "http_request_metadata": case *EventHTTPRequestMetadata:
entry.Request.Headers = make(map[string]MaybeBinaryValue) entry.Request.Headers = make(map[string]MaybeBinaryValue)
httpAddHeaders( httpAddHeaders(
ev.HTTPHeaders, &entry.Request.HeadersList, &entry.Request.Headers) ev.HTTPHeaders, &entry.Request.HeadersList, &entry.Request.Headers)
entry.Request.Method = ev.HTTPMethod entry.Request.Method = ev.HTTPMethod
entry.Request.URL = ev.HTTPURL entry.Request.URL = ev.HTTPURL
entry.Request.Transport = ev.Transport entry.Request.Transport = ev.Transport
case "http_response_metadata": case *EventHTTPResponseMetadata:
entry.Response.Headers = make(map[string]MaybeBinaryValue) entry.Response.Headers = make(map[string]MaybeBinaryValue)
httpAddHeaders( httpAddHeaders(
ev.HTTPHeaders, &entry.Response.HeadersList, &entry.Response.Headers) ev.HTTPHeaders, &entry.Response.HeadersList, &entry.Response.Headers)
entry.Response.Code = int64(ev.HTTPStatusCode) entry.Response.Code = int64(ev.HTTPStatusCode)
entry.Response.Locations = ev.HTTPHeaders.Values("Location") entry.Response.Locations = ev.HTTPHeaders.Values("Location")
case "http_response_body_snapshot": case *EventHTTPResponseBodySnapshot:
entry.Response.Body.Value = string(ev.Data) entry.Response.Body.Value = string(ev.Data)
entry.Response.BodyIsTruncated = ev.DataIsTruncated entry.Response.BodyIsTruncated = ev.DataIsTruncated
case "http_transaction_done": case *EventHTTPTransactionDone:
entry.Failure = NewFailure(ev.Err) entry.Failure = NewFailure(ev.Err)
out = append(out, entry) out = append(out, entry)
} }
@ -178,10 +180,11 @@ type dnsQueryType string
func NewDNSQueriesList(begin time.Time, events []Event) []DNSQueryEntry { func NewDNSQueriesList(begin time.Time, events []Event) []DNSQueryEntry {
// TODO(bassosimone): add support for CNAME lookups. // TODO(bassosimone): add support for CNAME lookups.
var out []DNSQueryEntry var out []DNSQueryEntry
for _, ev := range events { for _, wrapper := range events {
if ev.Name != "resolve_done" { if _, ok := wrapper.(*EventResolveDone); !ok {
continue continue
} }
ev := wrapper.Value()
for _, qtype := range []dnsQueryType{"A", "AAAA"} { for _, qtype := range []dnsQueryType{"A", "AAAA"} {
entry := qtype.makeQueryEntry(begin, ev) entry := qtype.makeQueryEntry(begin, ev)
for _, addr := range ev.Addresses { for _, addr := range ev.Addresses {
@ -230,7 +233,7 @@ func (qtype dnsQueryType) makeAnswerEntry(addr string) DNSAnswerEntry {
return answer return answer
} }
func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev Event) DNSQueryEntry { func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev *EventValue) DNSQueryEntry {
return DNSQueryEntry{ return DNSQueryEntry{
Engine: ev.Proto, Engine: ev.Proto,
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
@ -244,60 +247,54 @@ func (qtype dnsQueryType) makeQueryEntry(begin time.Time, ev Event) DNSQueryEntr
// NewNetworkEventsList returns a list of DNS queries. // NewNetworkEventsList returns a list of DNS queries.
func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent { func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent {
var out []NetworkEvent var out []NetworkEvent
for _, ev := range events { for _, wrapper := range events {
if ev.Name == netxlite.ConnectOperation { ev := wrapper.Value()
switch wrapper.(type) {
case *EventConnectOperation:
out = append(out, NetworkEvent{ out = append(out, NetworkEvent{
Address: ev.Address, Address: ev.Address,
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
Operation: ev.Name, Operation: wrapper.Name(),
Proto: ev.Proto, Proto: ev.Proto,
T: ev.Time.Sub(begin).Seconds(), T: ev.Time.Sub(begin).Seconds(),
}) })
continue case *EventReadOperation:
}
if ev.Name == netxlite.ReadOperation {
out = append(out, NetworkEvent{ out = append(out, NetworkEvent{
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
Operation: ev.Name, Operation: wrapper.Name(),
NumBytes: int64(ev.NumBytes), NumBytes: int64(ev.NumBytes),
T: ev.Time.Sub(begin).Seconds(), T: ev.Time.Sub(begin).Seconds(),
}) })
continue case *EventWriteOperation:
}
if ev.Name == netxlite.WriteOperation {
out = append(out, NetworkEvent{ out = append(out, NetworkEvent{
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
Operation: ev.Name, Operation: wrapper.Name(),
NumBytes: int64(ev.NumBytes), NumBytes: int64(ev.NumBytes),
T: ev.Time.Sub(begin).Seconds(), T: ev.Time.Sub(begin).Seconds(),
}) })
continue case *EventReadFromOperation:
}
if ev.Name == netxlite.ReadFromOperation {
out = append(out, NetworkEvent{ out = append(out, NetworkEvent{
Address: ev.Address, Address: ev.Address,
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
Operation: ev.Name, Operation: wrapper.Name(),
NumBytes: int64(ev.NumBytes), NumBytes: int64(ev.NumBytes),
T: ev.Time.Sub(begin).Seconds(), T: ev.Time.Sub(begin).Seconds(),
}) })
continue case *EventWriteToOperation:
}
if ev.Name == netxlite.WriteToOperation {
out = append(out, NetworkEvent{ out = append(out, NetworkEvent{
Address: ev.Address, Address: ev.Address,
Failure: NewFailure(ev.Err), Failure: NewFailure(ev.Err),
Operation: ev.Name, Operation: wrapper.Name(),
NumBytes: int64(ev.NumBytes), NumBytes: int64(ev.NumBytes),
T: ev.Time.Sub(begin).Seconds(), T: ev.Time.Sub(begin).Seconds(),
}) })
continue default:
out = append(out, NetworkEvent{
Failure: NewFailure(ev.Err),
Operation: wrapper.Name(),
T: ev.Time.Sub(begin).Seconds(),
})
} }
out = append(out, NetworkEvent{
Failure: NewFailure(ev.Err),
Operation: ev.Name,
T: ev.Time.Sub(begin).Seconds(),
})
} }
return out return out
} }
@ -305,10 +302,13 @@ func NewNetworkEventsList(begin time.Time, events []Event) []NetworkEvent {
// NewTLSHandshakesList creates a new TLSHandshakesList // NewTLSHandshakesList creates a new TLSHandshakesList
func NewTLSHandshakesList(begin time.Time, events []Event) []TLSHandshake { func NewTLSHandshakesList(begin time.Time, events []Event) []TLSHandshake {
var out []TLSHandshake var out []TLSHandshake
for _, ev := range events { for _, wrapper := range events {
if !strings.Contains(ev.Name, "_handshake_done") { switch wrapper.(type) {
continue case *EventQUICHandshakeDone, *EventTLSHandshakeDone: // ok
default:
continue // not interested
} }
ev := wrapper.Value()
out = append(out, TLSHandshake{ out = append(out, TLSHandshake{
Address: ev.Address, Address: ev.Address,
CipherSuite: ev.TLSCipherSuite, CipherSuite: ev.TLSCipherSuite,

View File

@ -74,31 +74,27 @@ func TestNewTCPConnectList(t *testing.T) {
name: "realistic run", name: "realistic run",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventResolveDone{&EventValue{
Addresses: []string{"8.8.8.8", "8.8.4.4"}, Addresses: []string{"8.8.8.8", "8.8.4.4"},
Hostname: "dns.google.com", Hostname: "dns.google.com",
Name: "resolve_done",
Time: begin.Add(100 * time.Millisecond), Time: begin.Add(100 * time.Millisecond),
}, { }}, &EventConnectOperation{&EventValue{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Duration: 30 * time.Millisecond, Duration: 30 * time.Millisecond,
Name: netxlite.ConnectOperation,
Proto: "tcp", Proto: "tcp",
Time: begin.Add(130 * time.Millisecond), Time: begin.Add(130 * time.Millisecond),
}, { }}, &EventConnectOperation{&EventValue{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Duration: 55 * time.Millisecond, Duration: 55 * time.Millisecond,
Name: netxlite.ConnectOperation,
Proto: "udp", Proto: "udp",
Time: begin.Add(130 * time.Millisecond), Time: begin.Add(130 * time.Millisecond),
}, { }}, &EventConnectOperation{&EventValue{
Address: "8.8.4.4:53", Address: "8.8.4.4:53",
Duration: 50 * time.Millisecond, Duration: 50 * time.Millisecond,
Err: io.EOF, Err: io.EOF,
Name: netxlite.ConnectOperation,
Proto: "tcp", Proto: "tcp",
Time: begin.Add(180 * time.Millisecond), Time: begin.Add(180 * time.Millisecond),
}}, }}},
}, },
want: []TCPConnectEntry{{ want: []TCPConnectEntry{{
IP: "8.8.8.8", IP: "8.8.8.8",
@ -147,46 +143,36 @@ func TestNewRequestList(t *testing.T) {
name: "realistic run", name: "realistic run",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventHTTPTransactionStart{&EventValue{
Name: "http_transaction_start",
Time: begin.Add(10 * time.Millisecond), Time: begin.Add(10 * time.Millisecond),
}, { }}, &EventHTTPRequestBodySnapshot{&EventValue{
Name: "http_request_body_snapshot",
Data: []byte("deadbeef"), Data: []byte("deadbeef"),
DataIsTruncated: false, DataIsTruncated: false,
}, { }}, &EventHTTPRequestMetadata{&EventValue{
Name: "http_request_metadata",
HTTPHeaders: http.Header{ HTTPHeaders: http.Header{
"User-Agent": []string{"miniooni/0.1.0-dev"}, "User-Agent": []string{"miniooni/0.1.0-dev"},
}, },
HTTPMethod: "POST", HTTPMethod: "POST",
HTTPURL: "https://www.example.com/submit", HTTPURL: "https://www.example.com/submit",
}, { }}, &EventHTTPResponseMetadata{&EventValue{
Name: "http_response_metadata",
HTTPHeaders: http.Header{ HTTPHeaders: http.Header{
"Server": []string{"miniooni/0.1.0-dev"}, "Server": []string{"miniooni/0.1.0-dev"},
}, },
HTTPStatusCode: 200, HTTPStatusCode: 200,
}, { }}, &EventHTTPResponseBodySnapshot{&EventValue{
Name: "http_response_body_snapshot",
Data: []byte("{}"), Data: []byte("{}"),
DataIsTruncated: false, DataIsTruncated: false,
}, { }}, &EventHTTPTransactionDone{&EventValue{}}, &EventHTTPTransactionStart{&EventValue{
Name: "http_transaction_done",
}, {
Name: "http_transaction_start",
Time: begin.Add(20 * time.Millisecond), Time: begin.Add(20 * time.Millisecond),
}, { }}, &EventHTTPRequestMetadata{&EventValue{
Name: "http_request_metadata",
HTTPHeaders: http.Header{ HTTPHeaders: http.Header{
"User-Agent": []string{"miniooni/0.1.0-dev"}, "User-Agent": []string{"miniooni/0.1.0-dev"},
}, },
HTTPMethod: "GET", HTTPMethod: "GET",
HTTPURL: "https://www.example.com/result", HTTPURL: "https://www.example.com/result",
}, { }}, &EventHTTPTransactionDone{&EventValue{
Name: "http_transaction_done", Err: io.EOF,
Err: io.EOF, }}},
}},
}, },
want: []RequestEntry{{ want: []RequestEntry{{
Failure: NewFailure(io.EOF), Failure: NewFailure(io.EOF),
@ -245,26 +231,21 @@ func TestNewRequestList(t *testing.T) {
name: "run with redirect and headers to sort", name: "run with redirect and headers to sort",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventHTTPTransactionStart{&EventValue{
Name: "http_transaction_start",
Time: begin.Add(10 * time.Millisecond), Time: begin.Add(10 * time.Millisecond),
}, { }}, &EventHTTPRequestMetadata{&EventValue{
Name: "http_request_metadata",
HTTPHeaders: http.Header{ HTTPHeaders: http.Header{
"User-Agent": []string{"miniooni/0.1.0-dev"}, "User-Agent": []string{"miniooni/0.1.0-dev"},
}, },
HTTPMethod: "GET", HTTPMethod: "GET",
HTTPURL: "https://www.example.com/", HTTPURL: "https://www.example.com/",
}, { }}, &EventHTTPResponseMetadata{&EventValue{
Name: "http_response_metadata",
HTTPHeaders: http.Header{ HTTPHeaders: http.Header{
"Server": []string{"miniooni/0.1.0-dev"}, "Server": []string{"miniooni/0.1.0-dev"},
"Location": []string{"https://x.example.com", "https://y.example.com"}, "Location": []string{"https://x.example.com", "https://y.example.com"},
}, },
HTTPStatusCode: 302, HTTPStatusCode: 302,
}, { }}, &EventHTTPTransactionDone{&EventValue{}}},
Name: "http_transaction_done",
}},
}, },
want: []RequestEntry{{ want: []RequestEntry{{
Request: HTTPRequest{ Request: HTTPRequest{
@ -339,27 +320,24 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "realistic run", name: "realistic run",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventResolveDone{&EventValue{
Address: "1.1.1.1:853", Address: "1.1.1.1:853",
Addresses: []string{"8.8.8.8", "8.8.4.4"}, Addresses: []string{"8.8.8.8", "8.8.4.4"},
Hostname: "dns.google.com", Hostname: "dns.google.com",
Name: "resolve_done",
Proto: "dot", Proto: "dot",
Time: begin.Add(100 * time.Millisecond), Time: begin.Add(100 * time.Millisecond),
}, { }}, &EventConnectOperation{&EventValue{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Duration: 30 * time.Millisecond, Duration: 30 * time.Millisecond,
Name: netxlite.ConnectOperation,
Proto: "tcp", Proto: "tcp",
Time: begin.Add(130 * time.Millisecond), Time: begin.Add(130 * time.Millisecond),
}, { }}, &EventConnectOperation{&EventValue{
Address: "8.8.4.4:53", Address: "8.8.4.4:53",
Duration: 50 * time.Millisecond, Duration: 50 * time.Millisecond,
Err: io.EOF, Err: io.EOF,
Name: netxlite.ConnectOperation,
Proto: "tcp", Proto: "tcp",
Time: begin.Add(180 * time.Millisecond), Time: begin.Add(180 * time.Millisecond),
}}, }}},
}, },
want: []DNSQueryEntry{{ want: []DNSQueryEntry{{
Answers: []DNSAnswerEntry{{ Answers: []DNSAnswerEntry{{
@ -383,12 +361,11 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "run with IPv6 results", name: "run with IPv6 results",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventResolveDone{&EventValue{
Addresses: []string{"2001:4860:4860::8888"}, Addresses: []string{"2001:4860:4860::8888"},
Hostname: "dns.google.com", Hostname: "dns.google.com",
Name: "resolve_done",
Time: begin.Add(200 * time.Millisecond), Time: begin.Add(200 * time.Millisecond),
}}, }}},
}, },
want: []DNSQueryEntry{{ want: []DNSQueryEntry{{
Answers: []DNSAnswerEntry{{ Answers: []DNSAnswerEntry{{
@ -405,12 +382,11 @@ func TestNewDNSQueriesList(t *testing.T) {
name: "run with errors", name: "run with errors",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventResolveDone{&EventValue{
Err: &netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError}, Err: &netxlite.ErrWrapper{Failure: netxlite.FailureDNSNXDOMAINError},
Hostname: "dns.google.com", Hostname: "dns.google.com",
Name: "resolve_done",
Time: begin.Add(200 * time.Millisecond), Time: begin.Add(200 * time.Millisecond),
}}, }}},
}, },
want: []DNSQueryEntry{{ want: []DNSQueryEntry{{
Answers: nil, Answers: nil,
@ -459,39 +435,30 @@ func TestNewNetworkEventsList(t *testing.T) {
name: "realistic run", name: "realistic run",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventConnectOperation{&EventValue{
Name: netxlite.ConnectOperation,
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Err: io.EOF, Err: io.EOF,
Proto: "tcp", Proto: "tcp",
Time: begin.Add(7 * time.Millisecond), Time: begin.Add(7 * time.Millisecond),
}, { }}, &EventReadOperation{&EventValue{
Name: netxlite.ReadOperation,
Err: context.Canceled, Err: context.Canceled,
NumBytes: 7117, NumBytes: 7117,
Time: begin.Add(11 * time.Millisecond), Time: begin.Add(11 * time.Millisecond),
}, { }}, &EventReadFromOperation{&EventValue{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Name: netxlite.ReadFromOperation,
Err: context.Canceled, Err: context.Canceled,
NumBytes: 7117, NumBytes: 7117,
Time: begin.Add(11 * time.Millisecond), Time: begin.Add(11 * time.Millisecond),
}, { }}, &EventWriteOperation{&EventValue{
Name: netxlite.WriteOperation,
Err: websocket.ErrBadHandshake, Err: websocket.ErrBadHandshake,
NumBytes: 4114, NumBytes: 4114,
Time: begin.Add(14 * time.Millisecond), Time: begin.Add(14 * time.Millisecond),
}, { }}, &EventWriteToOperation{&EventValue{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
Name: netxlite.WriteToOperation,
Err: websocket.ErrBadHandshake, Err: websocket.ErrBadHandshake,
NumBytes: 4114, NumBytes: 4114,
Time: begin.Add(14 * time.Millisecond), Time: begin.Add(14 * time.Millisecond),
}, { }}},
Name: netxlite.CloseOperation,
Err: websocket.ErrReadLimit,
Time: begin.Add(17 * time.Millisecond),
}},
}, },
want: []NetworkEvent{{ want: []NetworkEvent{{
Address: "8.8.8.8:853", Address: "8.8.8.8:853",
@ -521,10 +488,6 @@ func TestNewNetworkEventsList(t *testing.T) {
NumBytes: 4114, NumBytes: 4114,
Operation: netxlite.WriteToOperation, Operation: netxlite.WriteToOperation,
T: 0.014, T: 0.014,
}, {
Failure: NewFailure(websocket.ErrReadLimit),
Operation: netxlite.CloseOperation,
T: 0.017,
}}, }},
}} }}
for _, tt := range tests { for _, tt := range tests {
@ -557,13 +520,8 @@ func TestNewTLSHandshakesList(t *testing.T) {
name: "realistic run", name: "realistic run",
args: args{ args: args{
begin: begin, begin: begin,
events: []Event{{ events: []Event{&EventTLSHandshakeDone{&EventValue{
Name: netxlite.CloseOperation,
Err: websocket.ErrReadLimit,
Time: begin.Add(17 * time.Millisecond),
}, {
Address: "131.252.210.176:443", Address: "131.252.210.176:443",
Name: "tls_handshake_done",
Err: io.EOF, Err: io.EOF,
NoTLSVerify: false, NoTLSVerify: false,
TLSCipherSuite: "SUITE", TLSCipherSuite: "SUITE",
@ -576,7 +534,7 @@ func TestNewTLSHandshakesList(t *testing.T) {
TLSServerName: "x.org", TLSServerName: "x.org",
TLSVersion: "TLSv1.3", TLSVersion: "TLSv1.3",
Time: begin.Add(55 * time.Millisecond), Time: begin.Add(55 * time.Millisecond),
}}, }}},
}, },
want: []TLSHandshake{{ want: []TLSHandshake{{
Address: "131.252.210.176:443", Address: "131.252.210.176:443",

View File

@ -10,7 +10,6 @@ import (
"time" "time"
"github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
// SaverDialer saves events occurring during the dial // SaverDialer saves events occurring during the dial
@ -52,14 +51,13 @@ func (d *SaverDialer) DialContext(ctx context.Context, network, address string)
start := time.Now() start := time.Now()
conn, err := d.Dialer.DialContext(ctx, network, address) conn, err := d.Dialer.DialContext(ctx, network, address)
stop := time.Now() stop := time.Now()
d.Saver.Write(Event{ d.Saver.Write(&EventConnectOperation{&EventValue{
Address: address, Address: address,
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
Name: netxlite.ConnectOperation,
Proto: network, Proto: network,
Time: stop, Time: stop,
}) }})
return conn, err return conn, err
} }
@ -124,14 +122,13 @@ func (c *saverConn) Read(p []byte) (int, error) {
start := time.Now() start := time.Now()
count, err := c.Conn.Read(p) count, err := c.Conn.Read(p)
stop := time.Now() stop := time.Now()
c.saver.Write(Event{ c.saver.Write(&EventReadOperation{&EventValue{
Data: p[:count], Data: p[:count],
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
NumBytes: count, NumBytes: count,
Name: netxlite.ReadOperation,
Time: stop, Time: stop,
}) }})
return count, err return count, err
} }
@ -139,14 +136,13 @@ func (c *saverConn) Write(p []byte) (int, error) {
start := time.Now() start := time.Now()
count, err := c.Conn.Write(p) count, err := c.Conn.Write(p)
stop := time.Now() stop := time.Now()
c.saver.Write(Event{ c.saver.Write(&EventWriteOperation{&EventValue{
Data: p[:count], Data: p[:count],
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
NumBytes: count, NumBytes: count,
Name: netxlite.WriteOperation,
Time: stop, Time: stop,
}) }})
return count, err return count, err
} }

View File

@ -34,22 +34,22 @@ func TestSaverDialerFailure(t *testing.T) {
if len(ev) != 1 { if len(ev) != 1 {
t.Fatal("expected a single event here") t.Fatal("expected a single event here")
} }
if ev[0].Address != "www.google.com:443" { if ev[0].Value().Address != "www.google.com:443" {
t.Fatal("unexpected Address") t.Fatal("unexpected Address")
} }
if ev[0].Duration <= 0 { if ev[0].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if !errors.Is(ev[0].Err, expected) { if !errors.Is(ev[0].Value().Err, expected) {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[0].Name != netxlite.ConnectOperation { if ev[0].Name() != netxlite.ConnectOperation {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[0].Proto != "tcp" { if ev[0].Value().Proto != "tcp" {
t.Fatal("unexpected Proto") t.Fatal("unexpected Proto")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -111,15 +111,15 @@ func TestSaverConnDialerSuccess(t *testing.T) {
if len(events) != 3 { if len(events) != 3 {
t.Fatal("unexpected number of events saved", len(events)) t.Fatal("unexpected number of events saved", len(events))
} }
if events[0].Name != "connect" { if events[0].Name() != "connect" {
t.Fatal("expected a connect event") t.Fatal("expected a connect event")
} }
saverCheckConnectEvent(t, &events[0]) saverCheckConnectEvent(t, &events[0])
if events[1].Name != "read" { if events[1].Name() != "read" {
t.Fatal("expected a read event") t.Fatal("expected a read event")
} }
saverCheckReadEvent(t, &events[1]) saverCheckReadEvent(t, &events[1])
if events[2].Name != "write" { if events[2].Name() != "write" {
t.Fatal("expected a write event") t.Fatal("expected a write event")
} }
saverCheckWriteEvent(t, &events[2]) saverCheckWriteEvent(t, &events[2])

View File

@ -4,10 +4,268 @@ import (
"crypto/x509" "crypto/x509"
"net/http" "net/http"
"time" "time"
"github.com/ooni/probe-cli/v3/internal/netxlite"
) )
// Event is one of the events within a trace.
type Event interface {
// Value returns the event value
Value() *EventValue
// Name returns the event name
Name() string
}
// EventTLSHandshakeStart is the beginning of the TLS handshake.
type EventTLSHandshakeStart struct {
V *EventValue
}
func (ev *EventTLSHandshakeStart) Value() *EventValue {
return ev.V
}
func (ev *EventTLSHandshakeStart) Name() string {
return "tls_handshake_start"
}
// EventTLSHandshakeDone is the end of the TLS handshake.
type EventTLSHandshakeDone struct {
V *EventValue
}
func (ev *EventTLSHandshakeDone) Value() *EventValue {
return ev.V
}
func (ev *EventTLSHandshakeDone) Name() string {
return "tls_handshake_done"
}
// EventResolveStart is the beginning of a DNS lookup operation.
type EventResolveStart struct {
V *EventValue
}
func (ev *EventResolveStart) Value() *EventValue {
return ev.V
}
func (ev *EventResolveStart) Name() string {
return "resolve_start"
}
// EventResolveDone is the end of a DNS lookup operation.
type EventResolveDone struct {
V *EventValue
}
func (ev *EventResolveDone) Value() *EventValue {
return ev.V
}
func (ev *EventResolveDone) Name() string {
return "resolve_done"
}
// EventDNSRoundTripStart is the start of a DNS round trip.
type EventDNSRoundTripStart struct {
V *EventValue
}
func (ev *EventDNSRoundTripStart) Value() *EventValue {
return ev.V
}
func (ev *EventDNSRoundTripStart) Name() string {
return "dns_round_trip_start"
}
// EventDNSRoundTripDone is the end of a DNS round trip.
type EventDNSRoundTripDone struct {
V *EventValue
}
func (ev *EventDNSRoundTripDone) Value() *EventValue {
return ev.V
}
func (ev *EventDNSRoundTripDone) Name() string {
return "dns_round_trip_done"
}
// EventQUICHandshakeStart is the start of a QUIC handshake.
type EventQUICHandshakeStart struct {
V *EventValue
}
func (ev *EventQUICHandshakeStart) Value() *EventValue {
return ev.V
}
func (ev *EventQUICHandshakeStart) Name() string {
return "quic_handshake_start"
}
// EventQUICHandshakeDone is the end of a QUIC handshake.
type EventQUICHandshakeDone struct {
V *EventValue
}
func (ev *EventQUICHandshakeDone) Value() *EventValue {
return ev.V
}
func (ev *EventQUICHandshakeDone) Name() string {
return "quic_handshake_done"
}
// EventWriteToOperation summarizes the WriteTo operation.
type EventWriteToOperation struct {
V *EventValue
}
func (ev *EventWriteToOperation) Value() *EventValue {
return ev.V
}
func (ev *EventWriteToOperation) Name() string {
return netxlite.WriteToOperation
}
// EventReadFromOperation summarizes the ReadFrom operation.
type EventReadFromOperation struct {
V *EventValue
}
func (ev *EventReadFromOperation) Value() *EventValue {
return ev.V
}
func (ev *EventReadFromOperation) Name() string {
return netxlite.ReadFromOperation
}
// EventHTTPRequestMetadata contains HTTP request metadata.
type EventHTTPRequestMetadata struct {
V *EventValue
}
func (ev *EventHTTPRequestMetadata) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPRequestMetadata) Name() string {
return "http_request_metadata"
}
// EventHTTPResponseMetadata contains HTTP response metadata.
type EventHTTPResponseMetadata struct {
V *EventValue
}
func (ev *EventHTTPResponseMetadata) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPResponseMetadata) Name() string {
return "http_response_metadata"
}
// EventHTTPTransactionStart is the beginning of an HTTP transaction.
type EventHTTPTransactionStart struct {
V *EventValue
}
func (ev *EventHTTPTransactionStart) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPTransactionStart) Name() string {
return "http_transaction_start"
}
// EventHTTPTransactionDone is the end of an HTTP transaction.
type EventHTTPTransactionDone struct {
V *EventValue
}
func (ev *EventHTTPTransactionDone) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPTransactionDone) Name() string {
return "http_transaction_done"
}
// EventHTTPRequestBodySnapshot contains a snapshot of the request body.
type EventHTTPRequestBodySnapshot struct {
V *EventValue
}
func (ev *EventHTTPRequestBodySnapshot) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPRequestBodySnapshot) Name() string {
return "http_request_body_snapshot"
}
// EventHTTPResponseBodySnapshot contains a snapshot of the response body.
type EventHTTPResponseBodySnapshot struct {
V *EventValue
}
func (ev *EventHTTPResponseBodySnapshot) Value() *EventValue {
return ev.V
}
func (ev *EventHTTPResponseBodySnapshot) Name() string {
return "http_response_body_snapshot"
}
// EventConnectOperation contains information about the connect operation.
type EventConnectOperation struct {
V *EventValue
}
func (ev *EventConnectOperation) Value() *EventValue {
return ev.V
}
func (ev *EventConnectOperation) Name() string {
return netxlite.ConnectOperation
}
// EventReadOperation contains information about a read operation.
type EventReadOperation struct {
V *EventValue
}
func (ev *EventReadOperation) Value() *EventValue {
return ev.V
}
func (ev *EventReadOperation) Name() string {
return netxlite.ReadOperation
}
// EventWriteOperation contains information about a write operation.
type EventWriteOperation struct {
V *EventValue
}
func (ev *EventWriteOperation) Value() *EventValue {
return ev.V
}
func (ev *EventWriteOperation) Name() string {
return netxlite.WriteOperation
}
// Event is one of the events within a trace // Event is one of the events within a trace
type Event struct { type EventValue struct {
Addresses []string `json:",omitempty"` Addresses []string `json:",omitempty"`
Address string `json:",omitempty"` Address string `json:",omitempty"`
DNSQuery []byte `json:",omitempty"` DNSQuery []byte `json:",omitempty"`
@ -21,7 +279,6 @@ type Event struct {
HTTPStatusCode int `json:",omitempty"` HTTPStatusCode int `json:",omitempty"`
HTTPURL string `json:",omitempty"` HTTPURL string `json:",omitempty"`
Hostname string `json:",omitempty"` Hostname string `json:",omitempty"`
Name string `json:",omitempty"`
NoTLSVerify bool `json:",omitempty"` NoTLSVerify bool `json:",omitempty"`
NumBytes int `json:",omitempty"` NumBytes int `json:",omitempty"`
Proto string `json:",omitempty"` Proto string `json:",omitempty"`

View File

@ -24,24 +24,22 @@ type SaverMetadataHTTPTransport struct {
// RoundTrip implements RoundTripper.RoundTrip // RoundTrip implements RoundTripper.RoundTrip
func (txp SaverMetadataHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { func (txp SaverMetadataHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPRequestMetadata{&EventValue{
HTTPHeaders: httpCloneHeaders(req), HTTPHeaders: httpCloneHeaders(req),
HTTPMethod: req.Method, HTTPMethod: req.Method,
HTTPURL: req.URL.String(), HTTPURL: req.URL.String(),
Transport: txp.HTTPTransport.Network(), Transport: txp.HTTPTransport.Network(),
Name: "http_request_metadata",
Time: time.Now(), Time: time.Now(),
}) }})
resp, err := txp.HTTPTransport.RoundTrip(req) resp, err := txp.HTTPTransport.RoundTrip(req)
if err != nil { if err != nil {
return nil, err return nil, err
} }
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPResponseMetadata{&EventValue{
HTTPHeaders: resp.Header, HTTPHeaders: resp.Header,
HTTPStatusCode: resp.StatusCode, HTTPStatusCode: resp.StatusCode,
Name: "http_response_metadata",
Time: time.Now(), Time: time.Now(),
}) }})
return resp, err return resp, err
} }
@ -67,16 +65,14 @@ type SaverTransactionHTTPTransport struct {
// RoundTrip implements RoundTripper.RoundTrip // RoundTrip implements RoundTripper.RoundTrip
func (txp SaverTransactionHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) { func (txp SaverTransactionHTTPTransport) RoundTrip(req *http.Request) (*http.Response, error) {
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPTransactionStart{&EventValue{
Name: "http_transaction_start",
Time: time.Now(), Time: time.Now(),
}) }})
resp, err := txp.HTTPTransport.RoundTrip(req) resp, err := txp.HTTPTransport.RoundTrip(req)
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPTransactionDone{&EventValue{
Err: err, Err: err,
Name: "http_transaction_done",
Time: time.Now(), Time: time.Now(),
}) }})
return resp, err return resp, err
} }
@ -101,12 +97,11 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response,
return nil, err return nil, err
} }
req.Body = httpSaverCompose(data, req.Body) req.Body = httpSaverCompose(data, req.Body)
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPRequestBodySnapshot{&EventValue{
DataIsTruncated: len(data) >= snapsize, DataIsTruncated: len(data) >= snapsize,
Data: data, Data: data,
Name: "http_request_body_snapshot",
Time: time.Now(), Time: time.Now(),
}) }})
} }
resp, err := txp.HTTPTransport.RoundTrip(req) resp, err := txp.HTTPTransport.RoundTrip(req)
if err != nil { if err != nil {
@ -118,12 +113,11 @@ func (txp SaverBodyHTTPTransport) RoundTrip(req *http.Request) (*http.Response,
return nil, err return nil, err
} }
resp.Body = httpSaverCompose(data, resp.Body) resp.Body = httpSaverCompose(data, resp.Body)
txp.Saver.Write(Event{ txp.Saver.Write(&EventHTTPResponseBodySnapshot{&EventValue{
DataIsTruncated: len(data) >= snapsize, DataIsTruncated: len(data) >= snapsize,
Data: data, Data: data,
Name: "http_response_body_snapshot",
Time: time.Now(), Time: time.Now(),
}) }})
return resp, nil return resp, nil
} }

View File

@ -41,32 +41,32 @@ func TestSaverMetadataSuccess(t *testing.T) {
t.Fatal("expected two events") t.Fatal("expected two events")
} }
// //
if ev[0].HTTPMethod != "GET" { if ev[0].Value().HTTPMethod != "GET" {
t.Fatal("unexpected Method") t.Fatal("unexpected Method")
} }
if len(ev[0].HTTPHeaders) <= 0 { if len(ev[0].Value().HTTPHeaders) <= 0 {
t.Fatal("unexpected Headers") t.Fatal("unexpected Headers")
} }
if ev[0].HTTPURL != "https://www.google.com" { if ev[0].Value().HTTPURL != "https://www.google.com" {
t.Fatal("unexpected URL") t.Fatal("unexpected URL")
} }
if ev[0].Name != "http_request_metadata" { if ev[0].Name() != "http_request_metadata" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
// //
if ev[1].HTTPStatusCode != 200 { if ev[1].Value().HTTPStatusCode != 200 {
t.Fatal("unexpected StatusCode") t.Fatal("unexpected StatusCode")
} }
if len(ev[1].HTTPHeaders) <= 0 { if len(ev[1].Value().HTTPHeaders) <= 0 {
t.Fatal("unexpected Headers") t.Fatal("unexpected Headers")
} }
if ev[1].Name != "http_response_metadata" { if ev[1].Name() != "http_response_metadata" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -96,19 +96,19 @@ func TestSaverMetadataFailure(t *testing.T) {
if len(ev) != 1 { if len(ev) != 1 {
t.Fatal("expected one event") t.Fatal("expected one event")
} }
if ev[0].HTTPMethod != "GET" { if ev[0].Value().HTTPMethod != "GET" {
t.Fatal("unexpected Method") t.Fatal("unexpected Method")
} }
if len(ev[0].HTTPHeaders) <= 0 { if len(ev[0].Value().HTTPHeaders) <= 0 {
t.Fatal("unexpected Headers") t.Fatal("unexpected Headers")
} }
if ev[0].HTTPURL != "http://www.google.com" { if ev[0].Value().HTTPURL != "http://www.google.com" {
t.Fatal("unexpected URL") t.Fatal("unexpected URL")
} }
if ev[0].Name != "http_request_metadata" { if ev[0].Name() != "http_request_metadata" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -138,20 +138,20 @@ func TestSaverTransactionSuccess(t *testing.T) {
t.Fatal("expected two events") t.Fatal("expected two events")
} }
// //
if ev[0].Name != "http_transaction_start" { if ev[0].Name() != "http_transaction_start" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
// //
if ev[1].Err != nil { if ev[1].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Name != "http_transaction_done" { if ev[1].Name() != "http_transaction_done" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -180,19 +180,19 @@ func TestSaverTransactionFailure(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("expected two events") t.Fatal("expected two events")
} }
if ev[0].Name != "http_transaction_start" { if ev[0].Name() != "http_transaction_start" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
if ev[1].Name != "http_transaction_done" { if ev[1].Name() != "http_transaction_done" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !errors.Is(ev[1].Err, expected) { if !errors.Is(ev[1].Value().Err, expected) {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -242,28 +242,28 @@ func TestSaverBodySuccess(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if string(ev[0].Data) != "dead" { if string(ev[0].Value().Data) != "dead" {
t.Fatal("invalid Data") t.Fatal("invalid Data")
} }
if ev[0].DataIsTruncated != true { if ev[0].Value().DataIsTruncated != true {
t.Fatal("invalid DataIsTruncated") t.Fatal("invalid DataIsTruncated")
} }
if ev[0].Name != "http_request_body_snapshot" { if ev[0].Name() != "http_request_body_snapshot" {
t.Fatal("invalid Name") t.Fatal("invalid Name")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("invalid Time") t.Fatal("invalid Time")
} }
if string(ev[1].Data) != "abad" { if string(ev[1].Value().Data) != "abad" {
t.Fatal("invalid Data") t.Fatal("invalid Data")
} }
if ev[1].DataIsTruncated != true { if ev[1].Value().DataIsTruncated != true {
t.Fatal("invalid DataIsTruncated") t.Fatal("invalid DataIsTruncated")
} }
if ev[1].Name != "http_response_body_snapshot" { if ev[1].Name() != "http_response_body_snapshot" {
t.Fatal("invalid Name") t.Fatal("invalid Name")
} }
if ev[1].Time.Before(ev[0].Time) { if ev[1].Value().Time.Before(ev[0].Value().Time) {
t.Fatal("invalid Time") t.Fatal("invalid Time")
} }
} }
@ -324,16 +324,16 @@ func TestSaverBodyRoundTripError(t *testing.T) {
if len(ev) != 1 { if len(ev) != 1 {
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if string(ev[0].Data) != "dead" { if string(ev[0].Value().Data) != "dead" {
t.Fatal("invalid Data") t.Fatal("invalid Data")
} }
if ev[0].DataIsTruncated != true { if ev[0].Value().DataIsTruncated != true {
t.Fatal("invalid DataIsTruncated") t.Fatal("invalid DataIsTruncated")
} }
if ev[0].Name != "http_request_body_snapshot" { if ev[0].Name() != "http_request_body_snapshot" {
t.Fatal("invalid Name") t.Fatal("invalid Name")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("invalid Time") t.Fatal("invalid Time")
} }
} }
@ -371,16 +371,16 @@ func TestSaverBodyResponseReadError(t *testing.T) {
if len(ev) != 1 { if len(ev) != 1 {
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if string(ev[0].Data) != "dead" { if string(ev[0].Value().Data) != "dead" {
t.Fatal("invalid Data") t.Fatal("invalid Data")
} }
if ev[0].DataIsTruncated != true { if ev[0].Value().DataIsTruncated != true {
t.Fatal("invalid DataIsTruncated") t.Fatal("invalid DataIsTruncated")
} }
if ev[0].Name != "http_request_body_snapshot" { if ev[0].Name() != "http_request_body_snapshot" {
t.Fatal("invalid Name") t.Fatal("invalid Name")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("invalid Time") t.Fatal("invalid Time")
} }
} }

View File

@ -45,34 +45,31 @@ func (h *QUICHandshakeSaver) DialContext(ctx context.Context, network string,
start := time.Now() start := time.Now()
// TODO(bassosimone): in the future we probably want to also save // TODO(bassosimone): in the future we probably want to also save
// information about what versions we're willing to accept. // information about what versions we're willing to accept.
h.Saver.Write(Event{ h.Saver.Write(&EventQUICHandshakeStart{&EventValue{
Address: host, Address: host,
Name: "quic_handshake_start",
NoTLSVerify: tlsCfg.InsecureSkipVerify, NoTLSVerify: tlsCfg.InsecureSkipVerify,
Proto: network, Proto: network,
TLSNextProtos: tlsCfg.NextProtos, TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName, TLSServerName: tlsCfg.ServerName,
Time: start, Time: start,
}) }})
sess, err := h.QUICDialer.DialContext(ctx, network, host, tlsCfg, cfg) sess, err := h.QUICDialer.DialContext(ctx, network, host, tlsCfg, cfg)
stop := time.Now() stop := time.Now()
if err != nil { if err != nil {
// TODO(bassosimone): here we should save the peer certs // TODO(bassosimone): here we should save the peer certs
h.Saver.Write(Event{ h.Saver.Write(&EventQUICHandshakeDone{&EventValue{
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify, NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSNextProtos: tlsCfg.NextProtos, TLSNextProtos: tlsCfg.NextProtos,
TLSServerName: tlsCfg.ServerName, TLSServerName: tlsCfg.ServerName,
Time: stop, Time: stop,
}) }})
return nil, err return nil, err
} }
state := quicConnectionState(sess) state := quicConnectionState(sess)
h.Saver.Write(Event{ h.Saver.Write(&EventQUICHandshakeDone{&EventValue{
Duration: stop.Sub(start), Duration: stop.Sub(start),
Name: "quic_handshake_done",
NoTLSVerify: tlsCfg.InsecureSkipVerify, NoTLSVerify: tlsCfg.InsecureSkipVerify,
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite), TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
TLSNegotiatedProto: state.NegotiatedProtocol, TLSNegotiatedProto: state.NegotiatedProtocol,
@ -81,7 +78,7 @@ func (h *QUICHandshakeSaver) DialContext(ctx context.Context, network string,
TLSServerName: tlsCfg.ServerName, TLSServerName: tlsCfg.ServerName,
TLSVersion: netxlite.TLSVersionString(state.Version), TLSVersion: netxlite.TLSVersionString(state.Version),
Time: stop, Time: stop,
}) }})
return sess, nil return sess, nil
} }
@ -144,15 +141,14 @@ func (c *udpLikeConnSaver) WriteTo(p []byte, addr net.Addr) (int, error) {
start := time.Now() start := time.Now()
count, err := c.UDPLikeConn.WriteTo(p, addr) count, err := c.UDPLikeConn.WriteTo(p, addr)
stop := time.Now() stop := time.Now()
c.saver.Write(Event{ c.saver.Write(&EventWriteToOperation{&EventValue{
Address: addr.String(), Address: addr.String(),
Data: p[:count], Data: p[:count],
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
NumBytes: count, NumBytes: count,
Name: netxlite.WriteToOperation,
Time: stop, Time: stop,
}) }})
return count, err return count, err
} }
@ -164,15 +160,14 @@ func (c *udpLikeConnSaver) ReadFrom(b []byte) (int, net.Addr, error) {
if n > 0 { if n > 0 {
data = b[:n] data = b[:n]
} }
c.saver.Write(Event{ c.saver.Write(&EventReadFromOperation{&EventValue{
Address: c.safeAddrString(addr), Address: c.safeAddrString(addr),
Data: data, Data: data,
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
NumBytes: n, NumBytes: n,
Name: netxlite.ReadFromOperation,
Time: stop, Time: stop,
}) }})
return n, addr, err return n, addr, err
} }

View File

@ -54,34 +54,34 @@ func TestHandshakeSaverSuccess(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if ev[0].Name != "quic_handshake_start" { if ev[0].Name() != "quic_handshake_start" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[0].TLSServerName != quictesting.Domain { if ev[0].Value().TLSServerName != quictesting.Domain {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[1].Err != nil { if ev[1].Value().Err != nil {
t.Fatal("unexpected Err", ev[1].Err) t.Fatal("unexpected Err", ev[1].Value().Err)
} }
if ev[1].Name != "quic_handshake_done" { if ev[1].Name() != "quic_handshake_done" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if !reflect.DeepEqual(ev[1].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[1].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[1].TLSServerName != quictesting.Domain { if ev[1].Value().TLSServerName != quictesting.Domain {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if ev[1].Time.Before(ev[0].Time) { if ev[1].Value().Time.Before(ev[0].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -106,14 +106,14 @@ func TestHandshakeSaverHostNameError(t *testing.T) {
t.Fatal("expected nil sess here") t.Fatal("expected nil sess here")
} }
for _, ev := range saver.Read() { for _, ev := range saver.Read() {
if ev.Name != "quic_handshake_done" { if ev.Name() != "quic_handshake_done" {
continue continue
} }
if ev.NoTLSVerify == true { if ev.Value().NoTLSVerify == true {
t.Fatal("expected NoTLSVerify to be false") t.Fatal("expected NoTLSVerify to be false")
} }
if !strings.HasSuffix(ev.Err.Error(), "tls: handshake failure") { if !strings.HasSuffix(ev.Value().Err.Error(), "tls: handshake failure") {
t.Fatal("unexpected error", ev.Err) t.Fatal("unexpected error", ev.Value().Err)
} }
} }
} }
@ -160,25 +160,25 @@ func TestSystemDialerSuccessWithReadWrite(t *testing.T) {
} }
last := len(ev) - 1 last := len(ev) - 1
for idx := 1; idx < last; idx++ { for idx := 1; idx < last; idx++ {
if ev[idx].Data == nil { if ev[idx].Value().Data == nil {
t.Fatal("unexpected Data") t.Fatal("unexpected Data")
} }
if ev[idx].Duration <= 0 { if ev[idx].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[idx].Err != nil { if ev[idx].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[idx].NumBytes <= 0 { if ev[idx].Value().NumBytes <= 0 {
t.Fatal("unexpected NumBytes") t.Fatal("unexpected NumBytes")
} }
switch ev[idx].Name { switch ev[idx].Name() {
case netxlite.ReadFromOperation, netxlite.WriteToOperation: case netxlite.ReadFromOperation, netxlite.WriteToOperation:
default: default:
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[idx].Time.Before(ev[idx-1].Time) { if ev[idx].Value().Time.Before(ev[idx-1].Value().Time) {
t.Fatal("unexpected Time", ev[idx].Time, ev[idx-1].Time) t.Fatal("unexpected Time", ev[idx].Value().Time, ev[idx-1].Value().Time)
} }
} }
} }

View File

@ -39,25 +39,23 @@ func (s *Saver) WrapResolver(r model.Resolver) model.Resolver {
// LookupHost implements Resolver.LookupHost // LookupHost implements Resolver.LookupHost
func (r *SaverResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) { func (r *SaverResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
start := time.Now() start := time.Now()
r.Saver.Write(Event{ r.Saver.Write(&EventResolveStart{&EventValue{
Address: r.Resolver.Address(), Address: r.Resolver.Address(),
Hostname: hostname, Hostname: hostname,
Name: "resolve_start",
Proto: r.Resolver.Network(), Proto: r.Resolver.Network(),
Time: start, Time: start,
}) }})
addrs, err := r.Resolver.LookupHost(ctx, hostname) addrs, err := r.Resolver.LookupHost(ctx, hostname)
stop := time.Now() stop := time.Now()
r.Saver.Write(Event{ r.Saver.Write(&EventResolveDone{&EventValue{
Addresses: addrs, Addresses: addrs,
Address: r.Resolver.Address(), Address: r.Resolver.Address(),
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
Hostname: hostname, Hostname: hostname,
Name: "resolve_done",
Proto: r.Resolver.Network(), Proto: r.Resolver.Network(),
Time: stop, Time: stop,
}) }})
return addrs, err return addrs, err
} }
@ -111,25 +109,23 @@ func (s *Saver) WrapDNSTransport(txp model.DNSTransport) model.DNSTransport {
func (txp *SaverDNSTransport) RoundTrip( func (txp *SaverDNSTransport) RoundTrip(
ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) { ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
start := time.Now() start := time.Now()
txp.Saver.Write(Event{ txp.Saver.Write(&EventDNSRoundTripStart{&EventValue{
Address: txp.DNSTransport.Address(), Address: txp.DNSTransport.Address(),
DNSQuery: dnsMaybeQueryBytes(query), DNSQuery: dnsMaybeQueryBytes(query),
Name: "dns_round_trip_start",
Proto: txp.DNSTransport.Network(), Proto: txp.DNSTransport.Network(),
Time: start, Time: start,
}) }})
response, err := txp.DNSTransport.RoundTrip(ctx, query) response, err := txp.DNSTransport.RoundTrip(ctx, query)
stop := time.Now() stop := time.Now()
txp.Saver.Write(Event{ txp.Saver.Write(&EventDNSRoundTripDone{&EventValue{
Address: txp.DNSTransport.Address(), Address: txp.DNSTransport.Address(),
DNSQuery: dnsMaybeQueryBytes(query), DNSQuery: dnsMaybeQueryBytes(query),
DNSReply: dnsMaybeResponseBytes(response), DNSReply: dnsMaybeResponseBytes(response),
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
Name: "dns_round_trip_done",
Proto: txp.DNSTransport.Network(), Proto: txp.DNSTransport.Network(),
Time: stop, Time: stop,
}) }})
return response, err return response, err
} }

View File

@ -29,31 +29,31 @@ func TestSaverResolverFailure(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("expected number of events") t.Fatal("expected number of events")
} }
if ev[0].Hostname != "www.google.com" { if ev[0].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname") t.Fatal("unexpected Hostname")
} }
if ev[0].Name != "resolve_start" { if ev[0].Name() != "resolve_start" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
if ev[1].Addresses != nil { if ev[1].Value().Addresses != nil {
t.Fatal("unexpected Addresses") t.Fatal("unexpected Addresses")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if !errors.Is(ev[1].Err, expected) { if !errors.Is(ev[1].Value().Err, expected) {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Hostname != "www.google.com" { if ev[1].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname") t.Fatal("unexpected Hostname")
} }
if ev[1].Name != "resolve_done" { if ev[1].Name() != "resolve_done" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
} }
@ -73,31 +73,31 @@ func TestSaverResolverSuccess(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("expected number of events") t.Fatal("expected number of events")
} }
if ev[0].Hostname != "www.google.com" { if ev[0].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname") t.Fatal("unexpected Hostname")
} }
if ev[0].Name != "resolve_start" { if ev[0].Name() != "resolve_start" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
if !reflect.DeepEqual(ev[1].Addresses, expected) { if !reflect.DeepEqual(ev[1].Value().Addresses, expected) {
t.Fatal("unexpected Addresses") t.Fatal("unexpected Addresses")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[1].Err != nil { if ev[1].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Hostname != "www.google.com" { if ev[1].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname") t.Fatal("unexpected Hostname")
} }
if ev[1].Name != "resolve_done" { if ev[1].Name() != "resolve_done" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
} }
@ -133,31 +133,31 @@ func TestSaverDNSTransportFailure(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("expected number of events") t.Fatal("expected number of events")
} }
if !bytes.Equal(ev[0].DNSQuery, rawQuery) { if !bytes.Equal(ev[0].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery") t.Fatal("unexpected DNSQuery")
} }
if ev[0].Name != "dns_round_trip_start" { if ev[0].Name() != "dns_round_trip_start" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
if !bytes.Equal(ev[1].DNSQuery, rawQuery) { if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery") t.Fatal("unexpected DNSQuery")
} }
if ev[1].DNSReply != nil { if ev[1].Value().DNSReply != nil {
t.Fatal("unexpected DNSReply") t.Fatal("unexpected DNSReply")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if !errors.Is(ev[1].Err, expected) { if !errors.Is(ev[1].Value().Err, expected) {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Name != "dns_round_trip_done" { if ev[1].Name() != "dns_round_trip_done" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
} }
@ -198,31 +198,31 @@ func TestSaverDNSTransportSuccess(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("expected number of events") t.Fatal("expected number of events")
} }
if !bytes.Equal(ev[0].DNSQuery, rawQuery) { if !bytes.Equal(ev[0].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery") t.Fatal("unexpected DNSQuery")
} }
if ev[0].Name != "dns_round_trip_start" { if ev[0].Name() != "dns_round_trip_start" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[0].Time.Before(time.Now()) { if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
if !bytes.Equal(ev[1].DNSQuery, rawQuery) { if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery") t.Fatal("unexpected DNSQuery")
} }
if !bytes.Equal(ev[1].DNSReply, expected) { if !bytes.Equal(ev[1].Value().DNSReply, expected) {
t.Fatal("unexpected DNSReply") t.Fatal("unexpected DNSReply")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[1].Err != nil { if ev[1].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Name != "dns_round_trip_done" { if ev[1].Name() != "dns_round_trip_done" {
t.Fatal("unexpected name") t.Fatal("unexpected name")
} }
if !ev[1].Time.After(ev[0].Time) { if !ev[1].Value().Time.After(ev[0].Value().Time) {
t.Fatal("the saved time is wrong") t.Fatal("the saved time is wrong")
} }
} }

View File

@ -12,7 +12,7 @@ func TestSaver(t *testing.T) {
wg.Add(parallel) wg.Add(parallel)
for idx := 0; idx < parallel; idx++ { for idx := 0; idx < parallel; idx++ {
go func() { go func() {
saver.Write(Event{}) saver.Write(&EventReadFromOperation{&EventValue{}})
wg.Done() wg.Done()
}() }()
} }

View File

@ -44,21 +44,19 @@ func (s *Saver) WrapTLSHandshaker(thx model.TLSHandshaker) model.TLSHandshaker {
func (h *SaverTLSHandshaker) Handshake( func (h *SaverTLSHandshaker) Handshake(
ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) { ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, tls.ConnectionState, error) {
start := time.Now() start := time.Now()
h.Saver.Write(Event{ h.Saver.Write(&EventTLSHandshakeStart{&EventValue{
Name: "tls_handshake_start",
NoTLSVerify: config.InsecureSkipVerify, NoTLSVerify: config.InsecureSkipVerify,
TLSNextProtos: config.NextProtos, TLSNextProtos: config.NextProtos,
TLSServerName: config.ServerName, TLSServerName: config.ServerName,
Time: start, Time: start,
}) }})
remoteAddr := conn.RemoteAddr().String() remoteAddr := conn.RemoteAddr().String()
tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config) tlsconn, state, err := h.TLSHandshaker.Handshake(ctx, conn, config)
stop := time.Now() stop := time.Now()
h.Saver.Write(Event{ h.Saver.Write(&EventTLSHandshakeDone{&EventValue{
Address: remoteAddr, Address: remoteAddr,
Duration: stop.Sub(start), Duration: stop.Sub(start),
Err: err, Err: err,
Name: "tls_handshake_done",
NoTLSVerify: config.InsecureSkipVerify, NoTLSVerify: config.InsecureSkipVerify,
TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite), TLSCipherSuite: netxlite.TLSCipherSuiteString(state.CipherSuite),
TLSNegotiatedProto: state.NegotiatedProtocol, TLSNegotiatedProto: state.NegotiatedProtocol,
@ -67,7 +65,7 @@ func (h *SaverTLSHandshaker) Handshake(
TLSServerName: config.ServerName, TLSServerName: config.ServerName,
TLSVersion: netxlite.TLSVersionString(state.Version), TLSVersion: netxlite.TLSVersionString(state.Version),
Time: stop, Time: stop,
}) }})
return tlsconn, state, err return tlsconn, state, err
} }

View File

@ -39,69 +39,69 @@ func TestSaverTLSHandshakerSuccessWithReadWrite(t *testing.T) {
// events because network conditions may influence that // events because network conditions may influence that
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if ev[0].Name != "tls_handshake_start" { if ev[0].Name() != "tls_handshake_start" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[0].TLSServerName != "www.google.com" { if ev[0].Value().TLSServerName != "www.google.com" {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
last := len(ev) - 1 last := len(ev) - 1
for idx := 1; idx < last; idx++ { for idx := 1; idx < last; idx++ {
if ev[idx].Data == nil { if ev[idx].Value().Data == nil {
t.Fatal("unexpected Data") t.Fatal("unexpected Data")
} }
if ev[idx].Duration <= 0 { if ev[idx].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[idx].Err != nil { if ev[idx].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[idx].NumBytes <= 0 { if ev[idx].Value().NumBytes <= 0 {
t.Fatal("unexpected NumBytes") t.Fatal("unexpected NumBytes")
} }
switch ev[idx].Name { switch ev[idx].Name() {
case netxlite.ReadOperation, netxlite.WriteOperation: case netxlite.ReadOperation, netxlite.WriteOperation:
default: default:
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[idx].Time.Before(ev[idx-1].Time) { if ev[idx].Value().Time.Before(ev[idx-1].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
if ev[last].Duration <= 0 { if ev[last].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[last].Err != nil { if ev[last].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[last].Name != "tls_handshake_done" { if ev[last].Name() != "tls_handshake_done" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[last].TLSCipherSuite == "" { if ev[last].Value().TLSCipherSuite == "" {
t.Fatal("unexpected TLSCipherSuite") t.Fatal("unexpected TLSCipherSuite")
} }
if ev[last].TLSNegotiatedProto != "h2" { if ev[last].Value().TLSNegotiatedProto != "h2" {
t.Fatal("unexpected TLSNegotiatedProto") t.Fatal("unexpected TLSNegotiatedProto")
} }
if !reflect.DeepEqual(ev[last].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[last].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[last].TLSPeerCerts == nil { if ev[last].Value().TLSPeerCerts == nil {
t.Fatal("unexpected TLSPeerCerts") t.Fatal("unexpected TLSPeerCerts")
} }
if ev[last].TLSServerName != "www.google.com" { if ev[last].Value().TLSServerName != "www.google.com" {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if ev[last].TLSVersion == "" { if ev[last].Value().TLSVersion == "" {
t.Fatal("unexpected TLSVersion") t.Fatal("unexpected TLSVersion")
} }
if ev[last].Time.Before(ev[last-1].Time) { if ev[last].Value().Time.Before(ev[last-1].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -126,46 +126,46 @@ func TestSaverTLSHandshakerSuccess(t *testing.T) {
if len(ev) != 2 { if len(ev) != 2 {
t.Fatal("unexpected number of events") t.Fatal("unexpected number of events")
} }
if ev[0].Name != "tls_handshake_start" { if ev[0].Name() != "tls_handshake_start" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[0].TLSServerName != "www.google.com" { if ev[0].Value().TLSServerName != "www.google.com" {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[0].Time.After(time.Now()) { if ev[0].Value().Time.After(time.Now()) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
if ev[1].Duration <= 0 { if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration") t.Fatal("unexpected Duration")
} }
if ev[1].Err != nil { if ev[1].Value().Err != nil {
t.Fatal("unexpected Err") t.Fatal("unexpected Err")
} }
if ev[1].Name != "tls_handshake_done" { if ev[1].Name() != "tls_handshake_done" {
t.Fatal("unexpected Name") t.Fatal("unexpected Name")
} }
if ev[1].TLSCipherSuite == "" { if ev[1].Value().TLSCipherSuite == "" {
t.Fatal("unexpected TLSCipherSuite") t.Fatal("unexpected TLSCipherSuite")
} }
if ev[1].TLSNegotiatedProto != "h2" { if ev[1].Value().TLSNegotiatedProto != "h2" {
t.Fatal("unexpected TLSNegotiatedProto") t.Fatal("unexpected TLSNegotiatedProto")
} }
if !reflect.DeepEqual(ev[1].TLSNextProtos, nextprotos) { if !reflect.DeepEqual(ev[1].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos") t.Fatal("unexpected TLSNextProtos")
} }
if ev[1].TLSPeerCerts == nil { if ev[1].Value().TLSPeerCerts == nil {
t.Fatal("unexpected TLSPeerCerts") t.Fatal("unexpected TLSPeerCerts")
} }
if ev[1].TLSServerName != "www.google.com" { if ev[1].Value().TLSServerName != "www.google.com" {
t.Fatal("unexpected TLSServerName") t.Fatal("unexpected TLSServerName")
} }
if ev[1].TLSVersion == "" { if ev[1].Value().TLSVersion == "" {
t.Fatal("unexpected TLSVersion") t.Fatal("unexpected TLSVersion")
} }
if ev[1].Time.Before(ev[0].Time) { if ev[1].Value().Time.Before(ev[0].Value().Time) {
t.Fatal("unexpected Time") t.Fatal("unexpected Time")
} }
} }
@ -188,13 +188,13 @@ func TestSaverTLSHandshakerHostnameError(t *testing.T) {
t.Fatal("expected nil conn here") t.Fatal("expected nil conn here")
} }
for _, ev := range saver.Read() { for _, ev := range saver.Read() {
if ev.Name != "tls_handshake_done" { if ev.Name() != "tls_handshake_done" {
continue continue
} }
if ev.NoTLSVerify == true { if ev.Value().NoTLSVerify == true {
t.Fatal("expected NoTLSVerify to be false") t.Fatal("expected NoTLSVerify to be false")
} }
if len(ev.TLSPeerCerts) < 1 { if len(ev.Value().TLSPeerCerts) < 1 {
t.Fatal("expected at least a certificate here") t.Fatal("expected at least a certificate here")
} }
} }
@ -218,13 +218,13 @@ func TestSaverTLSHandshakerInvalidCertError(t *testing.T) {
t.Fatal("expected nil conn here") t.Fatal("expected nil conn here")
} }
for _, ev := range saver.Read() { for _, ev := range saver.Read() {
if ev.Name != "tls_handshake_done" { if ev.Name() != "tls_handshake_done" {
continue continue
} }
if ev.NoTLSVerify == true { if ev.Value().NoTLSVerify == true {
t.Fatal("expected NoTLSVerify to be false") t.Fatal("expected NoTLSVerify to be false")
} }
if len(ev.TLSPeerCerts) < 1 { if len(ev.Value().TLSPeerCerts) < 1 {
t.Fatal("expected at least a certificate here") t.Fatal("expected at least a certificate here")
} }
} }
@ -248,13 +248,13 @@ func TestSaverTLSHandshakerAuthorityError(t *testing.T) {
t.Fatal("expected nil conn here") t.Fatal("expected nil conn here")
} }
for _, ev := range saver.Read() { for _, ev := range saver.Read() {
if ev.Name != "tls_handshake_done" { if ev.Name() != "tls_handshake_done" {
continue continue
} }
if ev.NoTLSVerify == true { if ev.Value().NoTLSVerify == true {
t.Fatal("expected NoTLSVerify to be false") t.Fatal("expected NoTLSVerify to be false")
} }
if len(ev.TLSPeerCerts) < 1 { if len(ev.Value().TLSPeerCerts) < 1 {
t.Fatal("expected at least a certificate here") t.Fatal("expected at least a certificate here")
} }
} }
@ -280,13 +280,13 @@ func TestSaverTLSHandshakerNoTLSVerify(t *testing.T) {
} }
conn.Close() conn.Close()
for _, ev := range saver.Read() { for _, ev := range saver.Read() {
if ev.Name != "tls_handshake_done" { if ev.Name() != "tls_handshake_done" {
continue continue
} }
if ev.NoTLSVerify != true { if ev.Value().NoTLSVerify != true {
t.Fatal("expected NoTLSVerify to be true") t.Fatal("expected NoTLSVerify to be true")
} }
if len(ev.TLSPeerCerts) < 1 { if len(ev.Value().TLSPeerCerts) < 1 {
t.Fatal("expected at least a certificate here") t.Fatal("expected at least a certificate here")
} }
} }