-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathexperimentbuilder_test.go
169 lines (150 loc) · 5.17 KB
/
experimentbuilder_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package engine
import (
"context"
"encoding/json"
"errors"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/ooni/probe-cli/v3/internal/model"
)
func TestExperimentBuilderEngineWebConnectivity(t *testing.T) {
// create a session for testing that does not use the network at all
sess := newSessionForTestingNoLookups(t)
// create an experiment builder for Web Connectivity
builder, err := sess.NewExperimentBuilder("WebConnectivity")
if err != nil {
t.Fatal(err)
}
// create suitable loader config
config := &model.ExperimentTargetLoaderConfig{
CheckInConfig: &model.OOAPICheckInConfig{
// nothing
},
Session: sess,
StaticInputs: nil,
SourceFiles: nil,
}
// create the loader
loader := builder.NewTargetLoader(config)
// create cancelled context to interrupt immediately so that we
// don't use the network when running this test
ctx, cancel := context.WithCancel(context.Background())
cancel()
// attempt to load targets
targets, err := loader.Load(ctx)
// make sure we've got the expected error
if !errors.Is(err, context.Canceled) {
t.Fatal("unexpected err", err)
}
// make sure there are no targets
if len(targets) != 0 {
t.Fatal("expected zero length targets")
}
}
func TestExperimentBuilderBasicOperations(t *testing.T) {
// create a session for testing that does not use the network at all
sess := newSessionForTestingNoLookups(t)
// create an experiment builder for example
builder, err := sess.NewExperimentBuilder("example")
if err != nil {
t.Fatal(err)
}
// example should be interruptible
t.Run("Interruptible", func(t *testing.T) {
if !builder.Interruptible() {
t.Fatal("example should be interruptible")
}
})
// we expect to see the InputNone input policy
t.Run("InputPolicy", func(t *testing.T) {
if builder.InputPolicy() != model.InputNone {
t.Fatal("unexpectyed input policy")
}
})
// get the options and check whether they are what we expect
t.Run("Options", func(t *testing.T) {
options, err := builder.Options()
if err != nil {
t.Fatal(err)
}
expectOptions := map[string]model.ExperimentOptionInfo{
"Message": {Doc: "Message to emit at test completion", Type: "string", Value: "Good day from the example experiment!"},
"ReturnError": {Doc: "Toogle to return a mocked error", Type: "bool", Value: false},
"SleepTime": {Doc: "Amount of time to sleep for in nanosecond", Type: "int64", Value: int64(1000000000)},
}
if diff := cmp.Diff(expectOptions, options); diff != "" {
t.Fatal(diff)
}
})
// we can set a specific existing option
t.Run("SetOptionAny", func(t *testing.T) {
if err := builder.SetOptionAny("Message", "foobar"); err != nil {
t.Fatal(err)
}
options, err := builder.Options()
if err != nil {
t.Fatal(err)
}
expectOptions := map[string]model.ExperimentOptionInfo{
"Message": {Doc: "Message to emit at test completion", Type: "string", Value: "foobar"},
"ReturnError": {Doc: "Toogle to return a mocked error", Type: "bool", Value: false},
"SleepTime": {Doc: "Amount of time to sleep for in nanosecond", Type: "int64", Value: int64(1000000000)},
}
if diff := cmp.Diff(expectOptions, options); diff != "" {
t.Fatal(diff)
}
})
// we can set all options at the same time
t.Run("SetOptions", func(t *testing.T) {
inputs := map[string]any{
"Message": "foobar",
"ReturnError": true,
}
if err := builder.SetOptionsAny(inputs); err != nil {
t.Fatal(err)
}
options, err := builder.Options()
if err != nil {
t.Fatal(err)
}
expectOptions := map[string]model.ExperimentOptionInfo{
"Message": {Doc: "Message to emit at test completion", Type: "string", Value: "foobar"},
"ReturnError": {Doc: "Toogle to return a mocked error", Type: "bool", Value: true},
"SleepTime": {Doc: "Amount of time to sleep for in nanosecond", Type: "int64", Value: int64(1000000000)},
}
if diff := cmp.Diff(expectOptions, options); diff != "" {
t.Fatal(diff)
}
})
// we can set all options using JSON
t.Run("SetOptionsJSON", func(t *testing.T) {
inputs := json.RawMessage(`{
"Message": "foobar",
"ReturnError": true
}`)
if err := builder.SetOptionsJSON(inputs); err != nil {
t.Fatal(err)
}
options, err := builder.Options()
if err != nil {
t.Fatal(err)
}
expectOptions := map[string]model.ExperimentOptionInfo{
"Message": {Doc: "Message to emit at test completion", Type: "string", Value: "foobar"},
"ReturnError": {Doc: "Toogle to return a mocked error", Type: "bool", Value: true},
"SleepTime": {Doc: "Amount of time to sleep for in nanosecond", Type: "int64", Value: int64(1000000000)},
}
if diff := cmp.Diff(expectOptions, options); diff != "" {
t.Fatal(diff)
}
})
// TODO(bassosimone): we could possibly add more checks here. I am not doing this
// right now, because https://github.com/ooni/probe-cli/pull/1629 mostly cares about
// providing input and the rest of the codebase did not change.
//
// Also, it would make sense to eventually merge experimentbuilder.go with the
// ./internal/registry package, which also has coverage.
//
// In conclusion, our main objective for now is to make sure we don't screw the
// pooch when setting options using the experiment builder.
}