2022-07-08 16:53:59 +02:00
|
|
|
package oonirun
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/kvstore"
|
2022-08-31 18:40:27 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model"
|
2022-07-08 16:53:59 +02:00
|
|
|
"github.com/ooni/probe-cli/v3/internal/model/mocks"
|
|
|
|
"github.com/ooni/probe-cli/v3/internal/runtimex"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestOONIRunV2LinkCommonCase(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2022-09-29 11:43:23 +02:00
|
|
|
descriptor := &V2Descriptor{
|
2022-07-08 16:53:59 +02:00
|
|
|
Name: "",
|
|
|
|
Description: "",
|
|
|
|
Author: "",
|
2022-09-29 11:43:23 +02:00
|
|
|
Nettests: []V2Nettest{{
|
2022-07-08 16:53:59 +02:00
|
|
|
Inputs: []string{},
|
|
|
|
Options: map[string]any{
|
|
|
|
"SleepTime": int64(10 * time.Millisecond),
|
|
|
|
},
|
|
|
|
TestName: "example",
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(descriptor)
|
|
|
|
runtimex.PanicOnError(err, "json.Marshal failed")
|
|
|
|
w.Write(data)
|
|
|
|
}))
|
|
|
|
defer server.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: true, // avoid "oonirun: need to accept changes" error
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"platform": "linux",
|
|
|
|
},
|
|
|
|
KVStore: &kvstore.Memory{},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: true,
|
|
|
|
NoJSON: true,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
r := NewLinkRunner(config, server.URL)
|
|
|
|
if err := r.Run(ctx); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOONIRunV2LinkCannotUpdateCache(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2022-09-29 11:43:23 +02:00
|
|
|
descriptor := &V2Descriptor{
|
2022-07-08 16:53:59 +02:00
|
|
|
Name: "",
|
|
|
|
Description: "",
|
|
|
|
Author: "",
|
2022-09-29 11:43:23 +02:00
|
|
|
Nettests: []V2Nettest{{
|
2022-07-08 16:53:59 +02:00
|
|
|
Inputs: []string{},
|
|
|
|
Options: map[string]any{
|
|
|
|
"SleepTime": int64(10 * time.Millisecond),
|
|
|
|
},
|
|
|
|
TestName: "example",
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(descriptor)
|
|
|
|
runtimex.PanicOnError(err, "json.Marshal failed")
|
|
|
|
w.Write(data)
|
|
|
|
}))
|
|
|
|
defer server.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
expected := errors.New("mocked")
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: true, // avoid "oonirun: need to accept changes" error
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"platform": "linux",
|
|
|
|
},
|
|
|
|
KVStore: &mocks.KeyValueStore{
|
|
|
|
MockGet: func(key string) ([]byte, error) {
|
|
|
|
return []byte("{}"), nil
|
|
|
|
},
|
|
|
|
MockSet: func(key string, value []byte) error {
|
|
|
|
return expected
|
|
|
|
},
|
|
|
|
},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: true,
|
|
|
|
NoJSON: true,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
r := NewLinkRunner(config, server.URL)
|
|
|
|
err := r.Run(ctx)
|
|
|
|
if !errors.Is(err, expected) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOONIRunV2LinkWithoutAcceptChanges(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2022-09-29 11:43:23 +02:00
|
|
|
descriptor := &V2Descriptor{
|
2022-07-08 16:53:59 +02:00
|
|
|
Name: "",
|
|
|
|
Description: "",
|
|
|
|
Author: "",
|
2022-09-29 11:43:23 +02:00
|
|
|
Nettests: []V2Nettest{{
|
2022-07-08 16:53:59 +02:00
|
|
|
Inputs: []string{},
|
|
|
|
Options: map[string]any{
|
|
|
|
"SleepTime": int64(10 * time.Millisecond),
|
|
|
|
},
|
|
|
|
TestName: "example",
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(descriptor)
|
|
|
|
runtimex.PanicOnError(err, "json.Marshal failed")
|
|
|
|
w.Write(data)
|
|
|
|
}))
|
|
|
|
defer server.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: false, // should see "oonirun: need to accept changes" error
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"platform": "linux",
|
|
|
|
},
|
|
|
|
KVStore: &kvstore.Memory{},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: true,
|
|
|
|
NoJSON: true,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
r := NewLinkRunner(config, server.URL)
|
|
|
|
err := r.Run(ctx)
|
|
|
|
if !errors.Is(err, ErrNeedToAcceptChanges) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOONIRunV2LinkNilDescriptor(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
w.Write([]byte("null"))
|
|
|
|
}))
|
|
|
|
defer server.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: true, // avoid "oonirun: need to accept changes" error
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"platform": "linux",
|
|
|
|
},
|
|
|
|
KVStore: &kvstore.Memory{},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: true,
|
|
|
|
NoJSON: true,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
r := NewLinkRunner(config, server.URL)
|
|
|
|
if err := r.Run(ctx); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestOONIRunV2LinkEmptyTestName(t *testing.T) {
|
2022-08-31 18:40:27 +02:00
|
|
|
emptyTestNamesPrev := v2CountEmptyNettestNames.Load()
|
2022-07-08 16:53:59 +02:00
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2022-09-29 11:43:23 +02:00
|
|
|
descriptor := &V2Descriptor{
|
2022-07-08 16:53:59 +02:00
|
|
|
Name: "",
|
|
|
|
Description: "",
|
|
|
|
Author: "",
|
2022-09-29 11:43:23 +02:00
|
|
|
Nettests: []V2Nettest{{
|
2022-07-08 16:53:59 +02:00
|
|
|
Inputs: []string{},
|
|
|
|
Options: map[string]any{
|
|
|
|
"SleepTime": int64(10 * time.Millisecond),
|
|
|
|
},
|
|
|
|
TestName: "", // empty!
|
|
|
|
}},
|
|
|
|
}
|
|
|
|
data, err := json.Marshal(descriptor)
|
|
|
|
runtimex.PanicOnError(err, "json.Marshal failed")
|
|
|
|
w.Write(data)
|
|
|
|
}))
|
|
|
|
defer server.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: true, // avoid "oonirun: need to accept changes" error
|
|
|
|
Annotations: map[string]string{
|
|
|
|
"platform": "linux",
|
|
|
|
},
|
|
|
|
KVStore: &kvstore.Memory{},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: true,
|
|
|
|
NoJSON: true,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
r := NewLinkRunner(config, server.URL)
|
|
|
|
if err := r.Run(ctx); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2022-08-31 18:40:27 +02:00
|
|
|
if v2CountEmptyNettestNames.Load() != emptyTestNamesPrev+1 {
|
|
|
|
t.Fatal("expected to see 1 more instance of empty nettest names")
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestV2MeasureDescriptor(t *testing.T) {
|
|
|
|
t.Run("with nil descriptor", func(t *testing.T) {
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{}
|
2022-09-29 11:43:23 +02:00
|
|
|
err := V2MeasureDescriptor(ctx, config, nil)
|
2022-07-08 16:53:59 +02:00
|
|
|
if !errors.Is(err, ErrNilDescriptor) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
})
|
2022-08-31 18:40:27 +02:00
|
|
|
|
|
|
|
t.Run("with failing experiment", func(t *testing.T) {
|
|
|
|
previousFailedExperiments := v2CountFailedExperiments.Load()
|
|
|
|
expected := errors.New("mocked error")
|
|
|
|
ctx := context.Background()
|
|
|
|
sess := newMinimalFakeSession()
|
|
|
|
sess.MockNewSubmitter = func(ctx context.Context) (model.Submitter, error) {
|
|
|
|
subm := &mocks.Submitter{
|
|
|
|
MockSubmit: func(ctx context.Context, m *model.Measurement) error {
|
|
|
|
panic("should not be called")
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return subm, nil
|
|
|
|
}
|
|
|
|
sess.MockNewExperimentBuilder = func(name string) (model.ExperimentBuilder, error) {
|
|
|
|
eb := &mocks.ExperimentBuilder{
|
|
|
|
MockInputPolicy: func() model.InputPolicy {
|
|
|
|
return model.InputNone
|
|
|
|
},
|
|
|
|
MockSetOptionsAny: func(options map[string]any) error {
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
MockNewExperiment: func() model.Experiment {
|
|
|
|
exp := &mocks.Experiment{
|
|
|
|
MockMeasureAsync: func(ctx context.Context, input string) (<-chan *model.Measurement, error) {
|
|
|
|
return nil, expected
|
|
|
|
},
|
|
|
|
MockKibiBytesReceived: func() float64 {
|
|
|
|
return 1.1
|
|
|
|
},
|
|
|
|
MockKibiBytesSent: func() float64 {
|
|
|
|
return 0.1
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return exp
|
|
|
|
},
|
|
|
|
}
|
|
|
|
return eb, nil
|
|
|
|
}
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: false,
|
|
|
|
Annotations: map[string]string{},
|
|
|
|
KVStore: nil,
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: false,
|
|
|
|
NoJSON: false,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
|
|
|
Session: sess,
|
|
|
|
}
|
2022-09-29 11:43:23 +02:00
|
|
|
descr := &V2Descriptor{
|
2022-08-31 18:40:27 +02:00
|
|
|
Name: "",
|
|
|
|
Description: "",
|
|
|
|
Author: "",
|
2022-09-29 11:43:23 +02:00
|
|
|
Nettests: []V2Nettest{{
|
2022-08-31 18:40:27 +02:00
|
|
|
Inputs: []string{},
|
|
|
|
Options: map[string]any{},
|
|
|
|
TestName: "example",
|
|
|
|
}},
|
|
|
|
}
|
2022-09-29 11:43:23 +02:00
|
|
|
err := V2MeasureDescriptor(ctx, config, descr)
|
2022-08-31 18:40:27 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if v2CountFailedExperiments.Load() != previousFailedExperiments+1 {
|
|
|
|
t.Fatal("expected to see a failed experiment")
|
|
|
|
}
|
|
|
|
})
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestV2MeasureHTTPS(t *testing.T) {
|
|
|
|
t.Run("when we cannot load from cache", func(t *testing.T) {
|
|
|
|
expected := errors.New("mocked error")
|
|
|
|
ctx := context.Background()
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: false,
|
|
|
|
Annotations: map[string]string{},
|
|
|
|
KVStore: &mocks.KeyValueStore{
|
|
|
|
MockGet: func(key string) (value []byte, err error) {
|
|
|
|
return nil, expected
|
|
|
|
},
|
|
|
|
},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: false,
|
|
|
|
NoJSON: false,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
err := v2MeasureHTTPS(ctx, config, "")
|
|
|
|
if !errors.Is(err, expected) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("when we cannot pull changes", func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
cancel() // fail immediately
|
|
|
|
config := &LinkConfig{
|
|
|
|
AcceptChanges: false,
|
|
|
|
Annotations: map[string]string{},
|
|
|
|
KVStore: &kvstore.Memory{},
|
|
|
|
MaxRuntime: 0,
|
|
|
|
NoCollector: false,
|
|
|
|
NoJSON: false,
|
|
|
|
Random: false,
|
|
|
|
ReportFile: "",
|
2022-08-31 18:40:27 +02:00
|
|
|
Session: newMinimalFakeSession(),
|
2022-07-08 16:53:59 +02:00
|
|
|
}
|
|
|
|
err := v2MeasureHTTPS(ctx, config, "https://example.com") // should not use URL
|
|
|
|
if !errors.Is(err, context.Canceled) {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestV2DescriptorCacheLoad(t *testing.T) {
|
|
|
|
t.Run("cannot unmarshal cache content", func(t *testing.T) {
|
|
|
|
fsstore := &kvstore.Memory{}
|
|
|
|
if err := fsstore.Set(v2DescriptorCacheKey, []byte("{")); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
cache, err := v2DescriptorCacheLoad(fsstore)
|
|
|
|
if err == nil || err.Error() != "unexpected end of JSON input" {
|
|
|
|
t.Fatal("unexpected err", err)
|
|
|
|
}
|
|
|
|
if cache != nil {
|
|
|
|
t.Fatal("expected nil cache")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|