99ec7ffca9
Since https://github.com/ooni/probe-cli/pull/527, if an experiment returns an error, the corresponding measurement is not submitted since the semantics of returning an error is that something fundamental went wrong (e.g., we could not parse the input URL). This diff ensures that all experiments only return and error when something fundamental was wrong and return nil otherwise. Reference issue: https://github.com/ooni/probe/issues/1808.
164 lines
4.6 KiB
Go
164 lines
4.6 KiB
Go
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")
|
|
}
|
|
}
|