package torsf import ( "context" "errors" "net/url" "testing" "time" "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/engine/mockable" "github.com/ooni/probe-cli/v3/internal/engine/model" "github.com/ooni/probe-cli/v3/internal/tunnel" ) func TestExperimentNameAndVersion(t *testing.T) { m := NewExperimentMeasurer(Config{}) if m.ExperimentName() != "torsf" { t.Fatal("invalid experiment name") } if m.ExperimentVersion() != "0.1.0" { t.Fatal("invalid experiment version") } } // mockedTunnel is a mocked tunnel. type mockedTunnel struct { bootstrapTime time.Duration proxyURL *url.URL } // BootstrapTime implements Tunnel.BootstrapTime. func (mt *mockedTunnel) BootstrapTime() time.Duration { return mt.bootstrapTime } // SOCKS5ProxyURL implements Tunnel.SOCKS5ProxyURL. func (mt *mockedTunnel) SOCKS5ProxyURL() *url.URL { return mt.proxyURL } // Stop implements Tunnel.Stop. func (mt *mockedTunnel) Stop() { // nothing } func TestSuccessWithMockedTunnelStart(t *testing.T) { bootstrapTime := 400 * time.Millisecond m := &Measurer{ config: Config{}, mockStartTunnel: func(ctx context.Context, config *tunnel.Config) (tunnel.Tunnel, error) { // run for some time so we also exercise printing progress. time.Sleep(bootstrapTime) return &mockedTunnel{ bootstrapTime: time.Duration(bootstrapTime), }, nil }, } ctx := context.Background() measurement := &model.Measurement{} sess := &mockable.Session{} callbacks := &model.PrinterCallbacks{ Logger: log.Log, } if err := m.Run(ctx, sess, measurement, callbacks); err != nil { t.Fatal(err) } tk := measurement.TestKeys.(*TestKeys) if tk.BootstrapTime != bootstrapTime.Seconds() { t.Fatal("unexpected bootstrap time") } } func TestFailureToStartTunnel(t *testing.T) { expected := errors.New("mocked error") m := &Measurer{ config: Config{}, mockStartTunnel: func(ctx context.Context, config *tunnel.Config) (tunnel.Tunnel, error) { return nil, expected }, } ctx := context.Background() measurement := &model.Measurement{} sess := &mockable.Session{} callbacks := &model.PrinterCallbacks{ Logger: log.Log, } if err := m.Run(ctx, sess, measurement, callbacks); err != nil { t.Fatal(err) } tk := measurement.TestKeys.(*TestKeys) if tk.BootstrapTime != 0 { t.Fatal("unexpected bootstrap time") } if tk.Failure == nil { t.Fatal("unexpectedly nil failure string") } if *tk.Failure != "unknown_failure: mocked error" { t.Fatal("unexpected failure string", *tk.Failure) } } func TestFailureToStartPTXListener(t *testing.T) { expected := errors.New("mocked error") m := &Measurer{ config: Config{}, mockStartListener: func() error { return expected }, } ctx := context.Background() measurement := &model.Measurement{} sess := &mockable.Session{} callbacks := &model.PrinterCallbacks{ Logger: log.Log, } if err := m.Run(ctx, sess, measurement, callbacks); !errors.Is(err, expected) { t.Fatal("not the error we expected", err) } tk := measurement.TestKeys.(*TestKeys) if tk.BootstrapTime != 0 { t.Fatal("unexpected bootstrap time") } if tk.Failure == nil { t.Fatal("unexpectedly nil failure string") } if *tk.Failure != "unknown_failure: mocked error" { t.Fatal("unexpected failure string", *tk.Failure) } } func TestStartWithCancelledContext(t *testing.T) { m := &Measurer{config: Config{}} ctx, cancel := context.WithCancel(context.Background()) cancel() // fail immediately measurement := &model.Measurement{} sess := &mockable.Session{} callbacks := &model.PrinterCallbacks{ Logger: log.Log, } if err := m.Run(ctx, sess, measurement, callbacks); err != nil { t.Fatal(err) } tk := measurement.TestKeys.(*TestKeys) if tk.BootstrapTime != 0 { t.Fatal("unexpected bootstrap time") } if tk.Failure == nil { t.Fatal("unexpected nil failure") } if *tk.Failure != "interrupted" { t.Fatal("unexpected failure string", *tk.Failure) } } func TestGetSummaryKeys(t *testing.T) { measurement := &model.Measurement{} m := &Measurer{} sk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } rsk := sk.(*SummaryKeys) if rsk.IsAnomaly { t.Fatal("expected no anomaly here") } }