From 3fe5e32afda744bcc8df37c67af1b2c457e5aa74 Mon Sep 17 00:00:00 2001 From: Simone Basso Date: Thu, 14 Sep 2023 10:07:46 +0200 Subject: [PATCH] feat(measurexlite): Trace now implements MeasuringNetwork (#1262) This diff is still yak shaving for https://github.com/ooni/probe/issues/2531 but produces some nice side effects. Now, we can either use netxlite.Netx or measurexlite.Trace as a dependency for measuring code. The cost of this change is (1) switching some functions to use a `model.DebugLogger`, which is not an issue, and (2) adding some optional wrappers to other functions. I made these functions to ignore the wrappers and documented this limitation, because measurexlite code does not need this functionality. It is a bit debateable whether this is the best way to implement this change, but I am doing this because I would like to see these wrappers gone when we stop using legacy/netx in the codebase, so I think it's fine to ignore them, to better signal they're deprecated stuff. This change is absolutely in line with the original spirit of measurexlite because it's now much simpler to write code for netxlite and then upgrade to measurexlite. I noticed this possibility yesterday while working on a much larger diff, and now I am committing this smaller diff to start the working day. --- internal/measurexlite/dialer.go | 5 ++++- internal/measurexlite/dns.go | 6 +++--- internal/measurexlite/quic.go | 6 +++++- internal/measurexlite/trace.go | 2 ++ internal/measurexlite/udp.go | 7 +++++++ internal/measurexlite/udp_test.go | 24 ++++++++++++++++++++++++ 6 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 internal/measurexlite/udp.go create mode 100644 internal/measurexlite/udp_test.go diff --git a/internal/measurexlite/dialer.go b/internal/measurexlite/dialer.go index 663b88915f..e0837a6b66 100644 --- a/internal/measurexlite/dialer.go +++ b/internal/measurexlite/dialer.go @@ -18,7 +18,10 @@ import ( // NewDialerWithoutResolver is equivalent to netxlite.NewDialerWithoutResolver // except that it returns a model.Dialer that uses this trace. -func (tx *Trace) NewDialerWithoutResolver(dl model.DebugLogger) model.Dialer { +// +// Caveat: the dialer wrappers are there to implement the [model.MeasuringNetwork] +// interface, but they're not used by this function. +func (tx *Trace) NewDialerWithoutResolver(dl model.DebugLogger, wrappers ...model.DialerWrapper) model.Dialer { return &dialerTrace{ d: tx.Netx.NewDialerWithoutResolver(dl), tx: tx, diff --git a/internal/measurexlite/dns.go b/internal/measurexlite/dns.go index 4d214a3d52..8c72544426 100644 --- a/internal/measurexlite/dns.go +++ b/internal/measurexlite/dns.go @@ -92,17 +92,17 @@ func (r *resolverTrace) LookupNS(ctx context.Context, domain string) ([]*net.NS, } // NewStdlibResolver returns a trace-ware system resolver -func (tx *Trace) NewStdlibResolver(logger model.Logger) model.Resolver { +func (tx *Trace) NewStdlibResolver(logger model.DebugLogger) model.Resolver { return tx.wrapResolver(tx.Netx.NewStdlibResolver(logger)) } // NewParallelUDPResolver returns a trace-ware parallel UDP resolver -func (tx *Trace) NewParallelUDPResolver(logger model.Logger, dialer model.Dialer, address string) model.Resolver { +func (tx *Trace) NewParallelUDPResolver(logger model.DebugLogger, dialer model.Dialer, address string) model.Resolver { return tx.wrapResolver(tx.Netx.NewParallelUDPResolver(logger, dialer, address)) } // NewParallelDNSOverHTTPSResolver returns a trace-aware parallel DoH resolver -func (tx *Trace) NewParallelDNSOverHTTPSResolver(logger model.Logger, URL string) model.Resolver { +func (tx *Trace) NewParallelDNSOverHTTPSResolver(logger model.DebugLogger, URL string) model.Resolver { return tx.wrapResolver(tx.Netx.NewParallelDNSOverHTTPSResolver(logger, URL)) } diff --git a/internal/measurexlite/quic.go b/internal/measurexlite/quic.go index fa21d05b27..949068f505 100644 --- a/internal/measurexlite/quic.go +++ b/internal/measurexlite/quic.go @@ -16,7 +16,11 @@ import ( // NewQUICDialerWithoutResolver is equivalent to netxlite.NewQUICDialerWithoutResolver // except that it returns a model.QUICDialer that uses this trace. -func (tx *Trace) NewQUICDialerWithoutResolver(listener model.UDPListener, dl model.DebugLogger) model.QUICDialer { +// +// Caveat: the dialer wrappers are there to implement the [model.MeasuringNetwork] +// interface, but they're not used by this function. +func (tx *Trace) NewQUICDialerWithoutResolver( + listener model.UDPListener, dl model.DebugLogger, wrappers ...model.QUICDialerWrapper) model.QUICDialer { return &quicDialerTrace{ qd: tx.Netx.NewQUICDialerWithoutResolver(listener, dl), tx: tx, diff --git a/internal/measurexlite/trace.go b/internal/measurexlite/trace.go index 84bf672632..7a7e79a6f8 100644 --- a/internal/measurexlite/trace.go +++ b/internal/measurexlite/trace.go @@ -75,6 +75,8 @@ type Trace struct { ZeroTime time.Time } +var _ model.MeasuringNetwork = &Trace{} + // NetworkEventBufferSize is the [*Trace] buffer size for network I/O events. const NetworkEventBufferSize = 64 diff --git a/internal/measurexlite/udp.go b/internal/measurexlite/udp.go new file mode 100644 index 0000000000..ee9d1aaf05 --- /dev/null +++ b/internal/measurexlite/udp.go @@ -0,0 +1,7 @@ +package measurexlite + +import "github.com/ooni/probe-cli/v3/internal/model" + +func (tx *Trace) NewUDPListener() model.UDPListener { + return tx.Netx.NewUDPListener() +} diff --git a/internal/measurexlite/udp_test.go b/internal/measurexlite/udp_test.go new file mode 100644 index 0000000000..a5ee8d617a --- /dev/null +++ b/internal/measurexlite/udp_test.go @@ -0,0 +1,24 @@ +package measurexlite + +import ( + "testing" + "time" + + "github.com/ooni/probe-cli/v3/internal/mocks" + "github.com/ooni/probe-cli/v3/internal/model" +) + +func TestNewUDPListener(t *testing.T) { + // Make sure that we're forwarding the call to the measuring network. + expectListener := &mocks.UDPListener{} + trace := NewTrace(0, time.Now()) + trace.Netx = &mocks.MeasuringNetwork{ + MockNewUDPListener: func() model.UDPListener { + return expectListener + }, + } + listener := trace.NewUDPListener() + if listener != expectListener { + t.Fatal("unexpected listener") + } +}