a50efdbcf1
The current implementation assumes the user has already installed tor on the current system. If tor is not present, the experiment fails. This is meant to be the first version of this experiment. We are going to add more functionality in subsequent revisions of this experiment, once we've collected more feedback. Reference issue: https://github.com/ooni/probe/issues/1565. Here's the spec PR: https://github.com/ooni/spec/pull/218. Here's the issue tracking future work: https://github.com/ooni/probe/issues/1686
168 lines
4.1 KiB
Go
168 lines
4.1 KiB
Go
package torsf
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/apex/log"
|
|
"github.com/ooni/probe-cli/v3/internal/engine/internal/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")
|
|
}
|
|
}
|