Skip to content

Commit

Permalink
refactor(dslx): use Runtime for logger, ID generator, and zero time
Browse files Browse the repository at this point in the history
This diff builds upon the previous diff to use the Runtime to get
the logger, ID generator, and zero time.

By doing this, we make most structures that DSL functions takes
as input or emit in output serializable and deserializable.
  • Loading branch information
bassosimone committed Oct 18, 2023
1 parent b775572 commit 7a555f4
Show file tree
Hide file tree
Showing 18 changed files with 184 additions and 451 deletions.
93 changes: 15 additions & 78 deletions internal/dslx/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package dslx

import (
"context"
"sync/atomic"
"time"

"github.com/ooni/probe-cli/v3/internal/logx"
Expand All @@ -20,47 +19,20 @@ type DomainName string
// DNSLookupOption is an option you can pass to NewDomainToResolve.
type DNSLookupOption func(*DomainToResolve)

// DNSLookupOptionIDGenerator configures a specific ID generator.
// See DomainToResolve docs for more information.
func DNSLookupOptionIDGenerator(value *atomic.Int64) DNSLookupOption {
return func(dis *DomainToResolve) {
dis.IDGenerator = value
}
}

// DNSLookupOptionLogger configures a specific logger.
// See DomainToResolve docs for more information.
func DNSLookupOptionLogger(value model.Logger) DNSLookupOption {
return func(dis *DomainToResolve) {
dis.Logger = value
}
}

// DNSLookupOptionTags allows to set tags to tag observations.
func DNSLookupOptionTags(value ...string) DNSLookupOption {
return func(dis *DomainToResolve) {
dis.Tags = append(dis.Tags, value...)
}
}

// DNSLookupOptionZeroTime configures the measurement's zero time.
// See DomainToResolve docs for more information.
func DNSLookupOptionZeroTime(value time.Time) DNSLookupOption {
return func(dis *DomainToResolve) {
dis.ZeroTime = value
}
}

// NewDomainToResolve creates input for performing DNS lookups. The only mandatory
// argument is the domain name to resolve. You can also supply optional
// values by passing options to this function.
func NewDomainToResolve(domain DomainName, options ...DNSLookupOption) *DomainToResolve {
state := &DomainToResolve{
Domain: string(domain),
IDGenerator: &atomic.Int64{},
Logger: model.DiscardLogger,
Tags: []string{},
ZeroTime: time.Now(),
Domain: string(domain),
Tags: []string{},
}
for _, option := range options {
option(state)
Expand All @@ -78,25 +50,8 @@ type DomainToResolve struct {
// Domain is the MANDATORY domain name to lookup.
Domain string

// IDGenerator is the MANDATORY ID generator. We will use this field
// to assign unique IDs to distinct sub-measurements. The default
// construction implemented by NewDomainToResolve creates a new generator
// that starts counting from zero, leading to the first trace having
// one as its index.
IDGenerator *atomic.Int64

// Logger is the MANDATORY logger to use. The default construction
// implemented by NewDomainToResolve uses model.DiscardLogger.
Logger model.Logger

// Tags contains OPTIONAL tags to tag observations.
Tags []string

// ZeroTime is the MANDATORY zero time of the measurement. We will
// use this field as the zero value to compute relative elapsed times
// when generating measurements. The default construction by
// NewDomainToResolve initializes this field with the current time.
ZeroTime time.Time
}

// ResolvedAddresses contains the results of DNS lookups. To initialize
Expand All @@ -109,22 +64,10 @@ type ResolvedAddresses struct {
// from the value inside the DomainToResolve.
Domain string

// IDGenerator is the ID generator. We inherit this field
// from the value inside the DomainToResolve.
IDGenerator *atomic.Int64

// Logger is the logger to use. We inherit this field
// from the value inside the DomainToResolve.
Logger model.Logger

// Trace is the trace we're currently using. This struct is
// created by the various Apply functions using values inside
// the DomainToResolve to initialize the Trace.
Trace Trace

// ZeroTime is the zero time of the measurement. We inherit this field
// from the value inside the DomainToResolve.
ZeroTime time.Time
}

// DNSLookupGetaddrinfo returns a function that resolves a domain name to
Expand All @@ -144,11 +87,11 @@ func (f *dnsLookupGetaddrinfoFunc) Apply(
ctx context.Context, input *DomainToResolve) *Maybe[*ResolvedAddresses] {

// create trace
trace := f.rt.NewTrace(input.IDGenerator.Add(1), input.ZeroTime, input.Tags...)
trace := f.rt.NewTrace(f.rt.IDGenerator().Add(1), f.rt.ZeroTime(), input.Tags...)

// start the operation logger
ol := logx.NewOperationLogger(
input.Logger,
f.rt.Logger(),
"[#%d] DNSLookup[getaddrinfo] %s",
trace.Index(),
input.Domain,
Expand All @@ -161,7 +104,7 @@ func (f *dnsLookupGetaddrinfoFunc) Apply(

resolver := f.resolver
if resolver == nil {
resolver = trace.NewStdlibResolver(input.Logger)
resolver = trace.NewStdlibResolver(f.rt.Logger())
}

// lookup
Expand All @@ -171,12 +114,9 @@ func (f *dnsLookupGetaddrinfoFunc) Apply(
ol.Stop(err)

state := &ResolvedAddresses{
Addresses: addrs, // maybe empty
Domain: input.Domain,
IDGenerator: input.IDGenerator,
Logger: input.Logger,
Trace: trace,
ZeroTime: input.ZeroTime,
Addresses: addrs, // maybe empty
Domain: input.Domain,
Trace: trace,
}

return &Maybe[*ResolvedAddresses]{
Expand Down Expand Up @@ -210,11 +150,11 @@ func (f *dnsLookupUDPFunc) Apply(
ctx context.Context, input *DomainToResolve) *Maybe[*ResolvedAddresses] {

// create trace
trace := f.rt.NewTrace(input.IDGenerator.Add(1), input.ZeroTime, input.Tags...)
trace := f.rt.NewTrace(f.rt.IDGenerator().Add(1), f.rt.ZeroTime(), input.Tags...)

// start the operation logger
ol := logx.NewOperationLogger(
input.Logger,
f.rt.Logger(),
"[#%d] DNSLookup[%s/udp] %s",
trace.Index(),
f.Resolver,
Expand All @@ -229,8 +169,8 @@ func (f *dnsLookupUDPFunc) Apply(
resolver := f.mockResolver
if resolver == nil {
resolver = trace.NewParallelUDPResolver(
input.Logger,
trace.NewDialerWithoutResolver(input.Logger),
f.rt.Logger(),
trace.NewDialerWithoutResolver(f.rt.Logger()),
f.Resolver,
)
}
Expand All @@ -242,12 +182,9 @@ func (f *dnsLookupUDPFunc) Apply(
ol.Stop(err)

state := &ResolvedAddresses{
Addresses: addrs, // maybe empty
Domain: input.Domain,
IDGenerator: input.IDGenerator,
Logger: input.Logger,
Trace: trace,
ZeroTime: input.ZeroTime,
Addresses: addrs, // maybe empty
Domain: input.Domain,
Trace: trace,
}

return &Maybe[*ResolvedAddresses]{
Expand Down
27 changes: 4 additions & 23 deletions internal/dslx/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,13 @@ func TestNewDomainToResolve(t *testing.T) {
t.Run("with options", func(t *testing.T) {
idGen := &atomic.Int64{}
idGen.Add(42)
zt := time.Now()
domainToResolve := NewDomainToResolve(
DomainName("www.example.com"),
DNSLookupOptionIDGenerator(idGen),
DNSLookupOptionLogger(model.DiscardLogger),
DNSLookupOptionZeroTime(zt),
DNSLookupOptionTags("antani"),
)
if domainToResolve.Domain != "www.example.com" {
t.Fatalf("unexpected domain")
}
if domainToResolve.IDGenerator != idGen {
t.Fatalf("unexpected id generator")
}
if domainToResolve.Logger != model.DiscardLogger {
t.Fatalf("unexpected logger")
}
if domainToResolve.ZeroTime != zt {
t.Fatalf("unexpected zerotime")
}
if diff := cmp.Diff([]string{"antani"}, domainToResolve.Tags); diff != "" {
t.Fatal(diff)
}
Expand All @@ -75,11 +62,8 @@ func TestGetaddrinfo(t *testing.T) {

t.Run("Apply dnsLookupGetaddrinfoFunc", func(t *testing.T) {
domain := &DomainToResolve{
Domain: "example.com",
Logger: model.DiscardLogger,
IDGenerator: &atomic.Int64{},
Tags: []string{"antani"},
ZeroTime: time.Time{},
Domain: "example.com",
Tags: []string{"antani"},
}

t.Run("with nil resolver", func(t *testing.T) {
Expand Down Expand Up @@ -166,11 +150,8 @@ func TestLookupUDP(t *testing.T) {

t.Run("Apply dnsLookupGetaddrinfoFunc", func(t *testing.T) {
domain := &DomainToResolve{
Domain: "example.com",
Logger: model.DiscardLogger,
IDGenerator: &atomic.Int64{},
Tags: []string{"antani"},
ZeroTime: time.Time{},
Domain: "example.com",
Tags: []string{"antani"},
}

t.Run("with nil resolver", func(t *testing.T) {
Expand Down
48 changes: 4 additions & 44 deletions internal/dslx/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ package dslx
// Manipulate endpoints
//

import (
"sync/atomic"
"time"

"github.com/ooni/probe-cli/v3/internal/model"
)

type (
// EndpointNetwork is the network of the endpoint
EndpointNetwork string
Expand All @@ -29,20 +22,11 @@ type Endpoint struct {
// Domain is the OPTIONAL domain used to resolve the endpoints' IP address.
Domain string

// IDGenerator is MANDATORY the ID generator to use.
IDGenerator *atomic.Int64

// Logger is the MANDATORY logger to use.
Logger model.Logger

// Network is the MANDATORY endpoint network.
Network string

// Tags contains OPTIONAL tags for tagging observations.
Tags []string

// ZeroTime is the MANDATORY zero time of the measurement.
ZeroTime time.Time
}

// EndpointOption is an option you can use to construct EndpointState.
Expand All @@ -55,34 +39,13 @@ func EndpointOptionDomain(value string) EndpointOption {
}
}

// EndpointOptionIDGenerator allows to set the ID generator.
func EndpointOptionIDGenerator(value *atomic.Int64) EndpointOption {
return func(es *Endpoint) {
es.IDGenerator = value
}
}

// EndpointOptionLogger allows to set the logger.
func EndpointOptionLogger(value model.Logger) EndpointOption {
return func(es *Endpoint) {
es.Logger = value
}
}

// EndpointOptionTags allows to set tags to tag observations.
func EndpointOptionTags(value ...string) EndpointOption {
return func(es *Endpoint) {
es.Tags = append(es.Tags, value...)
}
}

// EndpointOptionZeroTime allows to set the zero time.
func EndpointOptionZeroTime(value time.Time) EndpointOption {
return func(es *Endpoint) {
es.ZeroTime = value
}
}

// NewEndpoint creates a new network endpoint (i.e., a three tuple composed
// of a network protocol, an IP address, and a port).
//
Expand All @@ -97,13 +60,10 @@ func EndpointOptionZeroTime(value time.Time) EndpointOption {
func NewEndpoint(
network EndpointNetwork, address EndpointAddress, options ...EndpointOption) *Endpoint {
epnt := &Endpoint{
Address: string(address),
Domain: "",
IDGenerator: &atomic.Int64{},
Logger: model.DiscardLogger,
Network: string(network),
Tags: []string{},
ZeroTime: time.Now(),
Address: string(address),
Domain: "",
Network: string(network),
Tags: []string{},
}
for _, option := range options {
option(epnt)
Expand Down
15 changes: 0 additions & 15 deletions internal/dslx/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,19 @@ package dslx
import (
"sync/atomic"
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/ooni/probe-cli/v3/internal/model"
)

func TestEndpoint(t *testing.T) {
idGen := &atomic.Int64{}
idGen.Add(42)
zt := time.Now()

t.Run("Create new endpoint", func(t *testing.T) {
testEndpoint := NewEndpoint(
"network",
"10.9.8.76",
EndpointOptionDomain("www.example.com"),
EndpointOptionIDGenerator(idGen),
EndpointOptionLogger(model.DiscardLogger),
EndpointOptionZeroTime(zt),
EndpointOptionTags("antani"),
)
if testEndpoint.Network != "network" {
Expand All @@ -33,15 +27,6 @@ func TestEndpoint(t *testing.T) {
if testEndpoint.Domain != "www.example.com" {
t.Fatalf("unexpected domain")
}
if testEndpoint.IDGenerator != idGen {
t.Fatalf("unexpected IDGenerator")
}
if testEndpoint.Logger != model.DiscardLogger {
t.Fatalf("unexpected logger")
}
if testEndpoint.ZeroTime != zt {
t.Fatalf("unexpected zero time")
}
if diff := cmp.Diff([]string{"antani"}, testEndpoint.Tags); diff != "" {
t.Fatal(diff)
}
Expand Down
Loading

0 comments on commit 7a555f4

Please sign in to comment.