package psiphon_test import ( "context" "errors" "io" "testing" "time" "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/atomicx" "github.com/ooni/probe-cli/v3/internal/engine/experiment/psiphon" "github.com/ooni/probe-cli/v3/internal/engine/experiment/urlgetter" "github.com/ooni/probe-cli/v3/internal/engine/mockable" "github.com/ooni/probe-cli/v3/internal/model" ) // Implementation note: integration test performed by // the $topdir/experiment_test.go file func TestNewExperimentMeasurer(t *testing.T) { measurer := psiphon.NewExperimentMeasurer(psiphon.Config{}) if measurer.ExperimentName() != "psiphon" { t.Fatal("unexpected name") } if measurer.ExperimentVersion() != "0.6.0" { t.Fatal("unexpected version") } } func TestRunWithCancelledContext(t *testing.T) { measurer := psiphon.NewExperimentMeasurer(psiphon.Config{}) ctx, cancel := context.WithCancel(context.Background()) cancel() // fail immediately measurement := new(model.Measurement) err := measurer.Run(ctx, newfakesession(), measurement, model.NewPrinterCallbacks(log.Log)) if !errors.Is(err, nil) { // nil because we want to submit the measurement t.Fatal("expected another error here") } tk := measurement.TestKeys.(*psiphon.TestKeys) if tk.MaxRuntime <= 0 { t.Fatal("you did not set the max runtime") } sk, err := measurer.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } if _, ok := sk.(psiphon.SummaryKeys); !ok { t.Fatal("invalid type for summary keys") } } func TestRunWithCustomInputAndCancelledContext(t *testing.T) { expected := "http://x.org" measurement := &model.Measurement{ Input: model.MeasurementTarget(expected), } measurer := psiphon.NewExperimentMeasurer(psiphon.Config{}) measurer.(*psiphon.Measurer).BeforeGetHook = func(g urlgetter.Getter) { if g.Target != expected { t.Fatal("target was not correctly set") } } ctx, cancel := context.WithCancel(context.Background()) cancel() // fail immediately err := measurer.Run(ctx, newfakesession(), measurement, model.NewPrinterCallbacks(log.Log)) if !errors.Is(err, nil) { // nil because we want to submit the measurement t.Fatal("expected another error here") } tk := measurement.TestKeys.(*psiphon.TestKeys) if tk.MaxRuntime <= 0 { t.Fatal("you did not set the max runtime") } } func TestRunWillPrintSomethingWithCancelledContext(t *testing.T) { measurement := new(model.Measurement) measurer := psiphon.NewExperimentMeasurer(psiphon.Config{}) ctx, cancel := context.WithCancel(context.Background()) measurer.(*psiphon.Measurer).BeforeGetHook = func(g urlgetter.Getter) { time.Sleep(2 * time.Second) cancel() // fail after we've given the printer a chance to run } observer := observerCallbacks{progress: &atomicx.Int64{}} err := measurer.Run(ctx, newfakesession(), measurement, observer) if !errors.Is(err, nil) { // nil because we want to submit the measurement t.Fatal("expected another error here") } tk := measurement.TestKeys.(*psiphon.TestKeys) if tk.MaxRuntime <= 0 { t.Fatal("you did not set the max runtime") } if observer.progress.Load() < 2 { t.Fatal("not enough progress emitted?!") } } type observerCallbacks struct { progress *atomicx.Int64 } func (d observerCallbacks) OnProgress(percentage float64, message string) { d.progress.Add(1) } func newfakesession() model.ExperimentSession { return &mockable.Session{MockableLogger: log.Log} } func TestSummaryKeysInvalidType(t *testing.T) { measurement := new(model.Measurement) m := &psiphon.Measurer{} _, err := m.GetSummaryKeys(measurement) if err.Error() != "invalid test keys type" { t.Fatal("not the error we expected") } } func TestSummaryKeysGood(t *testing.T) { measurement := &model.Measurement{TestKeys: &psiphon.TestKeys{TestKeys: urlgetter.TestKeys{ BootstrapTime: 123, }}} m := &psiphon.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(psiphon.SummaryKeys) if sk.BootstrapTime != 123 { t.Fatal("invalid latency") } if sk.Failure != "" { t.Fatal("invalid failure") } if sk.IsAnomaly { t.Fatal("invalid isAnomaly") } } func TestSummaryKeysFailure(t *testing.T) { expected := io.EOF.Error() measurement := &model.Measurement{TestKeys: &psiphon.TestKeys{TestKeys: urlgetter.TestKeys{ BootstrapTime: 123, Failure: &expected, }}} m := &psiphon.Measurer{} osk, err := m.GetSummaryKeys(measurement) if err != nil { t.Fatal(err) } sk := osk.(psiphon.SummaryKeys) if sk.BootstrapTime != 123 { t.Fatal("invalid latency") } if sk.Failure != expected { t.Fatal("invalid failure") } if sk.IsAnomaly == false { t.Fatal("invalid isAnomaly") } }