1// Package example contains a simple example experiment. 2// 3// You could use this code to boostrap the implementation of 4// a new experiment that you are working on. 5package example 6 7import ( 8 "context" 9 "errors" 10 "time" 11 12 "github.com/ooni/probe-engine/model" 13) 14 15const testVersion = "0.1.0" 16 17// Config contains the experiment config. 18// 19// This contains all the settings that user can set to modify the behaviour 20// of this experiment. By tagging these variables with `ooni:"..."`, we allow 21// miniooni's -O flag to find them and set them. 22type Config struct { 23 Message string `ooni:"Message to emit at test completion"` 24 ReturnError bool `ooni:"Toogle to return a mocked error"` 25 SleepTime int64 `ooni:"Amount of time to sleep for"` 26} 27 28// TestKeys contains the experiment's result. 29// 30// This is what will end up into the Measurement.TestKeys field 31// when you run this experiment. 32// 33// In other words, the variables in this struct will be 34// the specific results of this experiment. 35type TestKeys struct { 36 Success bool `json:"success"` 37} 38 39// Measurer performs the measurement. 40type Measurer struct { 41 config Config 42 testName string 43} 44 45// ExperimentName implements model.ExperimentMeasurer.ExperimentName. 46func (m Measurer) ExperimentName() string { 47 return m.testName 48} 49 50// ExperimentVersion implements model.ExperimentMeasurer.ExperimentVersion. 51func (m Measurer) ExperimentVersion() string { 52 return testVersion 53} 54 55// ErrFailure is the error returned when you set the 56// config.ReturnError field to true. 57var ErrFailure = errors.New("mocked error") 58 59// Run implements model.ExperimentMeasurer.Run. 60func (m Measurer) Run( 61 ctx context.Context, sess model.ExperimentSession, 62 measurement *model.Measurement, callbacks model.ExperimentCallbacks, 63) error { 64 var err error 65 if m.config.ReturnError { 66 err = ErrFailure 67 } 68 testkeys := &TestKeys{Success: err == nil} 69 measurement.TestKeys = testkeys 70 sess.Logger().Warnf("%s", "Follow the white rabbit.") 71 ctx, cancel := context.WithTimeout(ctx, time.Duration(m.config.SleepTime)) 72 defer cancel() 73 <-ctx.Done() 74 sess.Logger().Infof("%s", "Knock, knock, Neo.") 75 callbacks.OnProgress(1.0, m.config.Message) 76 return err 77} 78 79// NewExperimentMeasurer creates a new ExperimentMeasurer. 80func NewExperimentMeasurer(config Config, testName string) model.ExperimentMeasurer { 81 return Measurer{config: config, testName: testName} 82} 83 84// SummaryKeys contains summary keys for this experiment. 85// 86// Note that this structure is part of the ABI contract with probe-cli 87// therefore we should be careful when changing it. 88type SummaryKeys struct { 89 IsAnomaly bool `json:"-"` 90} 91 92// GetSummaryKeys implements model.ExperimentMeasurer.GetSummaryKeys. 93func (m Measurer) GetSummaryKeys(measurement *model.Measurement) (interface{}, error) { 94 return SummaryKeys{IsAnomaly: false}, nil 95} 96