Skip to content

Commit

Permalink
Add more tests for DDR experiment
Browse files Browse the repository at this point in the history
  • Loading branch information
frcroth committed Feb 4, 2025
1 parent 8739b76 commit 27a2ebc
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 15 deletions.
25 changes: 11 additions & 14 deletions internal/experiment/ddr/ddr.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ type TestKeys struct {
Failure *string `json:"failure"`
}

func (m *Measurer) Run(
ctx context.Context,
args *model.ExperimentArgs) error {

func (m *Measurer) Run(ctx context.Context, args *model.ExperimentArgs) error {
log.SetLevel(log.DebugLevel)
measurement := args.Measurement

Expand All @@ -77,20 +74,22 @@ func (m *Measurer) Run(
resolver = *m.config.CustomResolver
}

// DDR queries are queries of the SVCB type for the _dns.resolver.arpa. domain.

netx := &netxlite.Netx{}
dialer := netx.NewDialerWithoutResolver(log.Log)
transport := netxlite.NewUnwrappedDNSOverUDPTransport(
dialer, resolver)
transport := netxlite.NewUnwrappedDNSOverUDPTransport(dialer, resolver)
encoder := &netxlite.DNSEncoderMiekg{}
query := encoder.Encode(
"_dns.resolver.arpa.", // As specified in RFC 9462
dns.TypeSVCB,
true)
// As specified in RFC 9462 a DDR Query is a SVCB query for the _dns.resolver.arpa. domain
query := encoder.Encode("_dns.resolver.arpa.", dns.TypeSVCB, true)
t0 := time.Since(measurement.MeasurementStartTimeSaved).Seconds()

resp, err := transport.RoundTrip(ctx, query)
if err != nil {
// Since we are using a custom transport, we need to check for context errors manually
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
failure := "interrupted"
tk.Failure = &failure
return nil
}
failure := err.Error()
tk.Failure = &failure
return nil
Expand All @@ -105,14 +104,12 @@ func (m *Measurer) Run(
}

ddrResponse, err := decodeResponse(reply.Answer)

if err != nil {
decodingError := err.Error()
tk.Failure = &decodingError
}
t := time.Since(measurement.MeasurementStartTimeSaved).Seconds()
tk.Queries = createResult(t, t0, tk.Failure, resp, resolver, ddrResponse)

tk.SupportsDDR = len(ddrResponse) > 0

return nil
Expand Down
84 changes: 83 additions & 1 deletion internal/experiment/ddr/ddr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ddr
import (
"context"
"testing"
"time"

"github.com/apex/log"
"github.com/ooni/probe-cli/v3/internal/mocks"
Expand Down Expand Up @@ -52,7 +53,7 @@ func TestMeasurerRun(t *testing.T) {
t.Fatal("unexpected AnswerType")
}

if tk.Queries.ResolverAddress != oneOneOneOneResolver {
if tk.Queries.ResolverAddress != "1.1.1.1" {
t.Fatal("Resolver should be written to TestKeys")
}

Expand Down Expand Up @@ -81,6 +82,87 @@ func TestMeasurerFailsWithNoPort(t *testing.T) {
}
}

func TestMeasurerFailsWithInvalidResolver(t *testing.T) {
invalidResolver := "256.256.256.256:53"

tk, _ := runExperiment(invalidResolver)
if tk.Failure == nil {
t.Fatal("expected Failure")
}
}

func TestMeasurerRunWithSystemResolver(t *testing.T) {
if testing.Short() {
t.Skip("skip test in short mode")
}

measurer := NewExperimentMeasurer(Config{})
args := &model.ExperimentArgs{
Callbacks: model.NewPrinterCallbacks(log.Log),
Measurement: new(model.Measurement),
Session: &mocks.Session{
MockLogger: func() model.Logger {
return log.Log
},
},
}
if err := measurer.Run(context.Background(), args); err != nil {
t.Fatal(err)
}
tk := args.Measurement.TestKeys.(*TestKeys)
if tk.Failure != nil {
t.Fatal("unexpected Failure")
}
}

func TestMeasurerRunWithCancelledContext(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel() // immediately cancel the context

measurer := NewExperimentMeasurer(Config{})
args := &model.ExperimentArgs{
Callbacks: model.NewPrinterCallbacks(log.Log),
Measurement: new(model.Measurement),
Session: &mocks.Session{
MockLogger: func() model.Logger {
return log.Log
},
},
}
err := measurer.Run(ctx, args)
if err != nil {
t.Fatal("expected no error due to cancelled context")
}
tk := args.Measurement.TestKeys.(*TestKeys)
if tk.Failure == nil || *tk.Failure != "interrupted" {
t.Fatal("expected interrupted failure")
}
}

func TestMeasurerRunWithTimeout(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond)
defer cancel()

measurer := NewExperimentMeasurer(Config{})
args := &model.ExperimentArgs{
Callbacks: model.NewPrinterCallbacks(log.Log),
Measurement: new(model.Measurement),
Session: &mocks.Session{
MockLogger: func() model.Logger {
return log.Log
},
},
}
err := measurer.Run(ctx, args)
if err != nil {
t.Fatal("expected no error due to context timeout")
}
tk := args.Measurement.TestKeys.(*TestKeys)
if tk.Failure == nil || *tk.Failure != "interrupted" {
t.Fatal("expected interrupted failure")
}
}

func runExperiment(resolver string) (*TestKeys, error) {
measurer := NewExperimentMeasurer(Config{
CustomResolver: &resolver,
Expand Down

0 comments on commit 27a2ebc

Please sign in to comment.