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
// cases, because the connection should be persistent.
for _, ev := range r.saver.Read() {
if ev.Name == netxlite.ConnectOperation {
connectTime = ev.Duration.Seconds()
if _, ok := ev.(*tracex.EventConnectOperation); ok {
connectTime = ev.Value().Duration.Seconds()
}
}
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/netx/tracex"
"github.com/ooni/probe-cli/v3/internal/model"
"github.com/ooni/probe-cli/v3/internal/netxlite"
)
func TestRunnerLoopLocateFailure(t *testing.T) {
@ -108,7 +107,7 @@ func TestRunnerLoopMeasureFailure(t *testing.T) {
func TestRunnerLoopCollectFailure(t *testing.T) {
expected := errors.New("mocked error")
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{
callbacks: model.NewPrinterCallbacks(log.Log),
httpClient: &http.Client{
@ -152,7 +151,7 @@ func TestRunnerLoopCollectFailure(t *testing.T) {
func TestRunnerLoopSuccess(t *testing.T) {
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{
callbacks: model.NewPrinterCallbacks(log.Log),
httpClient: &http.Client{

View File

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

View File

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

View File

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

View File

@ -34,22 +34,22 @@ func TestSaverDialerFailure(t *testing.T) {
if len(ev) != 1 {
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")
}
if ev[0].Duration <= 0 {
if ev[0].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if !errors.Is(ev[0].Err, expected) {
if !errors.Is(ev[0].Value().Err, expected) {
t.Fatal("unexpected Err")
}
if ev[0].Name != netxlite.ConnectOperation {
if ev[0].Name() != netxlite.ConnectOperation {
t.Fatal("unexpected Name")
}
if ev[0].Proto != "tcp" {
if ev[0].Value().Proto != "tcp" {
t.Fatal("unexpected Proto")
}
if !ev[0].Time.Before(time.Now()) {
if !ev[0].Value().Time.Before(time.Now()) {
t.Fatal("unexpected Time")
}
}
@ -111,15 +111,15 @@ func TestSaverConnDialerSuccess(t *testing.T) {
if len(events) != 3 {
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")
}
saverCheckConnectEvent(t, &events[0])
if events[1].Name != "read" {
if events[1].Name() != "read" {
t.Fatal("expected a read event")
}
saverCheckReadEvent(t, &events[1])
if events[2].Name != "write" {
if events[2].Name() != "write" {
t.Fatal("expected a write event")
}
saverCheckWriteEvent(t, &events[2])

View File

@ -4,10 +4,268 @@ import (
"crypto/x509"
"net/http"
"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
type Event struct {
type EventValue struct {
Addresses []string `json:",omitempty"`
Address string `json:",omitempty"`
DNSQuery []byte `json:",omitempty"`
@ -21,7 +279,6 @@ type Event struct {
HTTPStatusCode int `json:",omitempty"`
HTTPURL string `json:",omitempty"`
Hostname string `json:",omitempty"`
Name string `json:",omitempty"`
NoTLSVerify bool `json:",omitempty"`
NumBytes int `json:",omitempty"`
Proto string `json:",omitempty"`

View File

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

View File

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

View File

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

View File

@ -54,34 +54,34 @@ func TestHandshakeSaverSuccess(t *testing.T) {
if len(ev) != 2 {
t.Fatal("unexpected number of events")
}
if ev[0].Name != "quic_handshake_start" {
if ev[0].Name() != "quic_handshake_start" {
t.Fatal("unexpected Name")
}
if ev[0].TLSServerName != quictesting.Domain {
if ev[0].Value().TLSServerName != quictesting.Domain {
t.Fatal("unexpected TLSServerName")
}
if !reflect.DeepEqual(ev[0].TLSNextProtos, nextprotos) {
if !reflect.DeepEqual(ev[0].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos")
}
if ev[0].Time.After(time.Now()) {
if ev[0].Value().Time.After(time.Now()) {
t.Fatal("unexpected Time")
}
if ev[1].Duration <= 0 {
if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[1].Err != nil {
t.Fatal("unexpected Err", ev[1].Err)
if ev[1].Value().Err != nil {
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")
}
if !reflect.DeepEqual(ev[1].TLSNextProtos, nextprotos) {
if !reflect.DeepEqual(ev[1].Value().TLSNextProtos, nextprotos) {
t.Fatal("unexpected TLSNextProtos")
}
if ev[1].TLSServerName != quictesting.Domain {
if ev[1].Value().TLSServerName != quictesting.Domain {
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")
}
}
@ -106,14 +106,14 @@ func TestHandshakeSaverHostNameError(t *testing.T) {
t.Fatal("expected nil sess here")
}
for _, ev := range saver.Read() {
if ev.Name != "quic_handshake_done" {
if ev.Name() != "quic_handshake_done" {
continue
}
if ev.NoTLSVerify == true {
if ev.Value().NoTLSVerify == true {
t.Fatal("expected NoTLSVerify to be false")
}
if !strings.HasSuffix(ev.Err.Error(), "tls: handshake failure") {
t.Fatal("unexpected error", ev.Err)
if !strings.HasSuffix(ev.Value().Err.Error(), "tls: handshake failure") {
t.Fatal("unexpected error", ev.Value().Err)
}
}
}
@ -160,25 +160,25 @@ func TestSystemDialerSuccessWithReadWrite(t *testing.T) {
}
last := len(ev) - 1
for idx := 1; idx < last; idx++ {
if ev[idx].Data == nil {
if ev[idx].Value().Data == nil {
t.Fatal("unexpected Data")
}
if ev[idx].Duration <= 0 {
if ev[idx].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[idx].Err != nil {
if ev[idx].Value().Err != nil {
t.Fatal("unexpected Err")
}
if ev[idx].NumBytes <= 0 {
if ev[idx].Value().NumBytes <= 0 {
t.Fatal("unexpected NumBytes")
}
switch ev[idx].Name {
switch ev[idx].Name() {
case netxlite.ReadFromOperation, netxlite.WriteToOperation:
default:
t.Fatal("unexpected Name")
}
if ev[idx].Time.Before(ev[idx-1].Time) {
t.Fatal("unexpected Time", ev[idx].Time, ev[idx-1].Time)
if ev[idx].Value().Time.Before(ev[idx-1].Value().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
func (r *SaverResolver) LookupHost(ctx context.Context, hostname string) ([]string, error) {
start := time.Now()
r.Saver.Write(Event{
r.Saver.Write(&EventResolveStart{&EventValue{
Address: r.Resolver.Address(),
Hostname: hostname,
Name: "resolve_start",
Proto: r.Resolver.Network(),
Time: start,
})
}})
addrs, err := r.Resolver.LookupHost(ctx, hostname)
stop := time.Now()
r.Saver.Write(Event{
r.Saver.Write(&EventResolveDone{&EventValue{
Addresses: addrs,
Address: r.Resolver.Address(),
Duration: stop.Sub(start),
Err: err,
Hostname: hostname,
Name: "resolve_done",
Proto: r.Resolver.Network(),
Time: stop,
})
}})
return addrs, err
}
@ -111,25 +109,23 @@ func (s *Saver) WrapDNSTransport(txp model.DNSTransport) model.DNSTransport {
func (txp *SaverDNSTransport) RoundTrip(
ctx context.Context, query model.DNSQuery) (model.DNSResponse, error) {
start := time.Now()
txp.Saver.Write(Event{
txp.Saver.Write(&EventDNSRoundTripStart{&EventValue{
Address: txp.DNSTransport.Address(),
DNSQuery: dnsMaybeQueryBytes(query),
Name: "dns_round_trip_start",
Proto: txp.DNSTransport.Network(),
Time: start,
})
}})
response, err := txp.DNSTransport.RoundTrip(ctx, query)
stop := time.Now()
txp.Saver.Write(Event{
txp.Saver.Write(&EventDNSRoundTripDone{&EventValue{
Address: txp.DNSTransport.Address(),
DNSQuery: dnsMaybeQueryBytes(query),
DNSReply: dnsMaybeResponseBytes(response),
Duration: stop.Sub(start),
Err: err,
Name: "dns_round_trip_done",
Proto: txp.DNSTransport.Network(),
Time: stop,
})
}})
return response, err
}

View File

@ -29,31 +29,31 @@ func TestSaverResolverFailure(t *testing.T) {
if len(ev) != 2 {
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")
}
if ev[0].Name != "resolve_start" {
if ev[0].Name() != "resolve_start" {
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")
}
if ev[1].Addresses != nil {
if ev[1].Value().Addresses != nil {
t.Fatal("unexpected Addresses")
}
if ev[1].Duration <= 0 {
if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if !errors.Is(ev[1].Err, expected) {
if !errors.Is(ev[1].Value().Err, expected) {
t.Fatal("unexpected Err")
}
if ev[1].Hostname != "www.google.com" {
if ev[1].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname")
}
if ev[1].Name != "resolve_done" {
if ev[1].Name() != "resolve_done" {
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")
}
}
@ -73,31 +73,31 @@ func TestSaverResolverSuccess(t *testing.T) {
if len(ev) != 2 {
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")
}
if ev[0].Name != "resolve_start" {
if ev[0].Name() != "resolve_start" {
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")
}
if !reflect.DeepEqual(ev[1].Addresses, expected) {
if !reflect.DeepEqual(ev[1].Value().Addresses, expected) {
t.Fatal("unexpected Addresses")
}
if ev[1].Duration <= 0 {
if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[1].Err != nil {
if ev[1].Value().Err != nil {
t.Fatal("unexpected Err")
}
if ev[1].Hostname != "www.google.com" {
if ev[1].Value().Hostname != "www.google.com" {
t.Fatal("unexpected Hostname")
}
if ev[1].Name != "resolve_done" {
if ev[1].Name() != "resolve_done" {
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")
}
}
@ -133,31 +133,31 @@ func TestSaverDNSTransportFailure(t *testing.T) {
if len(ev) != 2 {
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")
}
if ev[0].Name != "dns_round_trip_start" {
if ev[0].Name() != "dns_round_trip_start" {
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")
}
if !bytes.Equal(ev[1].DNSQuery, rawQuery) {
if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery")
}
if ev[1].DNSReply != nil {
if ev[1].Value().DNSReply != nil {
t.Fatal("unexpected DNSReply")
}
if ev[1].Duration <= 0 {
if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if !errors.Is(ev[1].Err, expected) {
if !errors.Is(ev[1].Value().Err, expected) {
t.Fatal("unexpected Err")
}
if ev[1].Name != "dns_round_trip_done" {
if ev[1].Name() != "dns_round_trip_done" {
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")
}
}
@ -198,31 +198,31 @@ func TestSaverDNSTransportSuccess(t *testing.T) {
if len(ev) != 2 {
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")
}
if ev[0].Name != "dns_round_trip_start" {
if ev[0].Name() != "dns_round_trip_start" {
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")
}
if !bytes.Equal(ev[1].DNSQuery, rawQuery) {
if !bytes.Equal(ev[1].Value().DNSQuery, rawQuery) {
t.Fatal("unexpected DNSQuery")
}
if !bytes.Equal(ev[1].DNSReply, expected) {
if !bytes.Equal(ev[1].Value().DNSReply, expected) {
t.Fatal("unexpected DNSReply")
}
if ev[1].Duration <= 0 {
if ev[1].Value().Duration <= 0 {
t.Fatal("unexpected Duration")
}
if ev[1].Err != nil {
if ev[1].Value().Err != nil {
t.Fatal("unexpected Err")
}
if ev[1].Name != "dns_round_trip_done" {
if ev[1].Name() != "dns_round_trip_done" {
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")
}
}

View File

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

View File

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

View File

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