feat(ooniprobe): propagate the RunType CheckIn hint (#274)
This diff propagates the RunType CheckIn hint such that we run using less URLs when running in the background. Part of https://github.com/ooni/probe/issues/1299.
This commit is contained in:
		
							parent
							
								
									c264f61536
								
							
						
					
					
						commit
						dae02ce5b6
					
				@ -26,19 +26,23 @@ func init() {
 | 
				
			|||||||
			log.WithError(err).Error("failed to perform onboarding")
 | 
								log.WithError(err).Error("failed to perform onboarding")
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if *noCollector == true {
 | 
							if *noCollector {
 | 
				
			||||||
			probe.Config().Sharing.UploadResults = false
 | 
								probe.Config().Sharing.UploadResults = false
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	functionalRun := func(pred func(name string, gr nettests.Group) bool) error {
 | 
						functionalRun := func(runType string, pred func(name string, gr nettests.Group) bool) error {
 | 
				
			||||||
		for name, group := range nettests.All {
 | 
							for name, group := range nettests.All {
 | 
				
			||||||
			if pred(name, group) != true {
 | 
								if !pred(name, group) {
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			log.Infof("Running %s tests", color.BlueString(name))
 | 
								log.Infof("Running %s tests", color.BlueString(name))
 | 
				
			||||||
			conf := nettests.RunGroupConfig{GroupName: name, Probe: probe}
 | 
								conf := nettests.RunGroupConfig{
 | 
				
			||||||
 | 
									GroupName: name,
 | 
				
			||||||
 | 
									Probe:     probe,
 | 
				
			||||||
 | 
									RunType:   runType,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if err := nettests.RunGroup(conf); err != nil {
 | 
								if err := nettests.RunGroup(conf); err != nil {
 | 
				
			||||||
				log.WithError(err).Errorf("failed to run %s", name)
 | 
									log.WithError(err).Errorf("failed to run %s", name)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -48,7 +52,7 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	genRunWithGroupName := func(targetName string) func(*kingpin.ParseContext) error {
 | 
						genRunWithGroupName := func(targetName string) func(*kingpin.ParseContext) error {
 | 
				
			||||||
		return func(*kingpin.ParseContext) error {
 | 
							return func(*kingpin.ParseContext) error {
 | 
				
			||||||
			return functionalRun(func(groupName string, gr nettests.Group) bool {
 | 
								return functionalRun("manual", func(groupName string, gr nettests.Group) bool {
 | 
				
			||||||
				return groupName == targetName
 | 
									return groupName == targetName
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -75,14 +79,14 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	unattendedCmd := cmd.Command("unattended", "")
 | 
						unattendedCmd := cmd.Command("unattended", "")
 | 
				
			||||||
	unattendedCmd.Action(func(_ *kingpin.ParseContext) error {
 | 
						unattendedCmd.Action(func(_ *kingpin.ParseContext) error {
 | 
				
			||||||
		return functionalRun(func(name string, gr nettests.Group) bool {
 | 
							return functionalRun("timed", func(name string, gr nettests.Group) bool {
 | 
				
			||||||
			return gr.UnattendedOK == true
 | 
								return gr.UnattendedOK
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allCmd := cmd.Command("all", "").Default()
 | 
						allCmd := cmd.Command("all", "").Default()
 | 
				
			||||||
	allCmd.Action(func(_ *kingpin.ParseContext) error {
 | 
						allCmd.Action(func(_ *kingpin.ParseContext) error {
 | 
				
			||||||
		return functionalRun(func(name string, gr nettests.Group) bool {
 | 
							return functionalRun("manual", func(name string, gr nettests.Group) bool {
 | 
				
			||||||
			return true
 | 
								return true
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
				
			|||||||
@ -53,6 +53,10 @@ type Controller struct {
 | 
				
			|||||||
	// using the command line using the --input flag.
 | 
						// using the command line using the --input flag.
 | 
				
			||||||
	Inputs []string
 | 
						Inputs []string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// RunType contains the run_type hint for the CheckIn API. If
 | 
				
			||||||
 | 
						// not set, the underlying code defaults to "timed".
 | 
				
			||||||
 | 
						RunType string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// numInputs is the total number of inputs
 | 
						// numInputs is the total number of inputs
 | 
				
			||||||
	numInputs int
 | 
						numInputs int
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -115,6 +119,8 @@ func (c *Controller) Run(builder *engine.ExperimentBuilder, inputs []string) err
 | 
				
			|||||||
	start := time.Now()
 | 
						start := time.Now()
 | 
				
			||||||
	c.ntStartTime = start
 | 
						c.ntStartTime = start
 | 
				
			||||||
	for idx, input := range inputs {
 | 
						for idx, input := range inputs {
 | 
				
			||||||
 | 
							// TODO(bassosimone): should we allow for interruption when running
 | 
				
			||||||
 | 
							// in unattended mode? Likewise, should we honor MaxRuntime?
 | 
				
			||||||
		if c.Probe.IsTerminated() {
 | 
							if c.Probe.IsTerminated() {
 | 
				
			||||||
			log.Info("user requested us to terminate using Ctrl-C")
 | 
								log.Info("user requested us to terminate using Ctrl-C")
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
@ -172,7 +178,7 @@ func (c *Controller) Run(builder *engine.ExperimentBuilder, inputs []string) err
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		// We only save the measurement to disk if we failed to upload the measurement
 | 
							// We only save the measurement to disk if we failed to upload the measurement
 | 
				
			||||||
		if saveToDisk == true {
 | 
							if saveToDisk {
 | 
				
			||||||
			if err := exp.SaveMeasurement(measurement, msmt.MeasurementFilePath.String); err != nil {
 | 
								if err := exp.SaveMeasurement(measurement, msmt.MeasurementFilePath.String); err != nil {
 | 
				
			||||||
				return errors.Wrap(err, "failed to save measurement on disk")
 | 
									return errors.Wrap(err, "failed to save measurement on disk")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@ -204,6 +210,8 @@ func (c *Controller) Run(builder *engine.ExperimentBuilder, inputs []string) err
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// OnProgress should be called when a new progress event is available.
 | 
					// OnProgress should be called when a new progress event is available.
 | 
				
			||||||
func (c *Controller) OnProgress(perc float64, msg string) {
 | 
					func (c *Controller) OnProgress(perc float64, msg string) {
 | 
				
			||||||
 | 
						// TODO(bassosimone): should we adjust this algorithm when we have a
 | 
				
			||||||
 | 
						// maximum runtime that we would like to honor?
 | 
				
			||||||
	log.Debugf("OnProgress: %f - %s", perc, msg)
 | 
						log.Debugf("OnProgress: %f - %s", perc, msg)
 | 
				
			||||||
	var eta float64
 | 
						var eta float64
 | 
				
			||||||
	eta = -1.0
 | 
						eta = -1.0
 | 
				
			||||||
@ -213,7 +221,7 @@ func (c *Controller) OnProgress(perc float64, msg string) {
 | 
				
			|||||||
		step := 1.0 / float64(c.numInputs)
 | 
							step := 1.0 / float64(c.numInputs)
 | 
				
			||||||
		perc = floor + perc*step
 | 
							perc = floor + perc*step
 | 
				
			||||||
		if c.curInputIdx > 0 {
 | 
							if c.curInputIdx > 0 {
 | 
				
			||||||
			eta = (time.Now().Sub(c.ntStartTime).Seconds() / float64(c.curInputIdx)) * float64(c.numInputs-c.curInputIdx)
 | 
								eta = (time.Since(c.ntStartTime).Seconds() / float64(c.curInputIdx)) * float64(c.numInputs-c.curInputIdx)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if c.ntCount > 0 {
 | 
						if c.ntCount > 0 {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
package nettests
 | 
					package nettests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/apex/log"
 | 
						"github.com/apex/log"
 | 
				
			||||||
@ -12,9 +13,10 @@ import (
 | 
				
			|||||||
// RunGroupConfig contains the settings for running a nettest group.
 | 
					// RunGroupConfig contains the settings for running a nettest group.
 | 
				
			||||||
type RunGroupConfig struct {
 | 
					type RunGroupConfig struct {
 | 
				
			||||||
	GroupName  string
 | 
						GroupName  string
 | 
				
			||||||
	Probe      *ooni.Probe
 | 
					 | 
				
			||||||
	InputFiles []string
 | 
						InputFiles []string
 | 
				
			||||||
	Inputs     []string
 | 
						Inputs     []string
 | 
				
			||||||
 | 
						Probe      *ooni.Probe
 | 
				
			||||||
 | 
						RunType    string // hint for check-in API
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const websitesURLLimitRemoved = `WARNING: CONFIGURATION CHANGE REQUIRED:
 | 
					const websitesURLLimitRemoved = `WARNING: CONFIGURATION CHANGE REQUIRED:
 | 
				
			||||||
@ -34,16 +36,20 @@ const websitesURLLimitRemoved = `WARNING: CONFIGURATION CHANGE REQUIRED:
 | 
				
			|||||||
* Since 2022, we will start silently ignoring websites_url_limit
 | 
					* Since 2022, we will start silently ignoring websites_url_limit
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var deprecationWarningOnce sync.Once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RunGroup runs a group of nettests according to the specified config.
 | 
					// RunGroup runs a group of nettests according to the specified config.
 | 
				
			||||||
func RunGroup(config RunGroupConfig) error {
 | 
					func RunGroup(config RunGroupConfig) error {
 | 
				
			||||||
	if config.Probe.Config().Nettests.WebsitesURLLimit > 0 {
 | 
						if config.Probe.Config().Nettests.WebsitesURLLimit > 0 {
 | 
				
			||||||
		log.Warn(websitesURLLimitRemoved)
 | 
					 | 
				
			||||||
		if config.Probe.Config().Nettests.WebsitesMaxRuntime <= 0 {
 | 
							if config.Probe.Config().Nettests.WebsitesMaxRuntime <= 0 {
 | 
				
			||||||
			limit := config.Probe.Config().Nettests.WebsitesURLLimit
 | 
								limit := config.Probe.Config().Nettests.WebsitesURLLimit
 | 
				
			||||||
			maxRuntime := 5 * limit
 | 
								maxRuntime := 5 * limit
 | 
				
			||||||
			config.Probe.Config().Nettests.WebsitesMaxRuntime = maxRuntime
 | 
								config.Probe.Config().Nettests.WebsitesMaxRuntime = maxRuntime
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		time.Sleep(30 * time.Second)
 | 
							deprecationWarningOnce.Do(func() {
 | 
				
			||||||
 | 
								log.Warn(websitesURLLimitRemoved)
 | 
				
			||||||
 | 
								time.Sleep(30 * time.Second)
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if config.Probe.IsTerminated() {
 | 
						if config.Probe.IsTerminated() {
 | 
				
			||||||
@ -90,7 +96,7 @@ func RunGroup(config RunGroupConfig) error {
 | 
				
			|||||||
	config.Probe.ListenForSignals()
 | 
						config.Probe.ListenForSignals()
 | 
				
			||||||
	config.Probe.MaybeListenForStdinClosed()
 | 
						config.Probe.MaybeListenForStdinClosed()
 | 
				
			||||||
	for i, nt := range group.Nettests {
 | 
						for i, nt := range group.Nettests {
 | 
				
			||||||
		if config.Probe.IsTerminated() == true {
 | 
							if config.Probe.IsTerminated() {
 | 
				
			||||||
			log.Debugf("context is terminated, stopping group.Nettests early")
 | 
								log.Debugf("context is terminated, stopping group.Nettests early")
 | 
				
			||||||
			break
 | 
								break
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -98,6 +104,7 @@ func RunGroup(config RunGroupConfig) error {
 | 
				
			|||||||
		ctl := NewController(nt, config.Probe, result, sess)
 | 
							ctl := NewController(nt, config.Probe, result, sess)
 | 
				
			||||||
		ctl.InputFiles = config.InputFiles
 | 
							ctl.InputFiles = config.InputFiles
 | 
				
			||||||
		ctl.Inputs = config.Inputs
 | 
							ctl.Inputs = config.Inputs
 | 
				
			||||||
 | 
							ctl.RunType = config.RunType
 | 
				
			||||||
		ctl.SetNettestIndex(i, len(group.Nettests))
 | 
							ctl.SetNettestIndex(i, len(group.Nettests))
 | 
				
			||||||
		if err = nt.Run(ctl); err != nil {
 | 
							if err = nt.Run(ctl); err != nil {
 | 
				
			||||||
			log.WithError(err).Errorf("Failed to run %s", group.Label)
 | 
								log.WithError(err).Errorf("Failed to run %s", group.Label)
 | 
				
			||||||
 | 
				
			|||||||
@ -9,12 +9,15 @@ import (
 | 
				
			|||||||
	"github.com/ooni/probe-cli/v3/internal/engine/model"
 | 
						"github.com/ooni/probe-cli/v3/internal/engine/model"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO(bassosimone): we should propagate the kind of run
 | 
					 | 
				
			||||||
// to here such that we get the right runType.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func lookupURLs(ctl *Controller, categories []string) ([]string, map[int64]int64, error) {
 | 
					func lookupURLs(ctl *Controller, categories []string) ([]string, map[int64]int64, error) {
 | 
				
			||||||
	inputloader := &engine.InputLoader{
 | 
						inputloader := &engine.InputLoader{
 | 
				
			||||||
		CheckInConfig: &model.CheckInConfig{
 | 
							CheckInConfig: &model.CheckInConfig{
 | 
				
			||||||
 | 
								// Setting Charging and OnWiFi to true causes the CheckIn
 | 
				
			||||||
 | 
								// API to return to us as much URL as possible with the
 | 
				
			||||||
 | 
								// given RunType hint.
 | 
				
			||||||
 | 
								Charging: true,
 | 
				
			||||||
 | 
								OnWiFi:   true,
 | 
				
			||||||
 | 
								RunType:  ctl.RunType,
 | 
				
			||||||
			WebConnectivity: model.CheckInConfigWebConnectivity{
 | 
								WebConnectivity: model.CheckInConfigWebConnectivity{
 | 
				
			||||||
				CategoryCodes: categories,
 | 
									CategoryCodes: categories,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
@ -24,6 +27,7 @@ func lookupURLs(ctl *Controller, categories []string) ([]string, map[int64]int64
 | 
				
			|||||||
		SourceFiles:  ctl.InputFiles,
 | 
							SourceFiles:  ctl.InputFiles,
 | 
				
			||||||
		StaticInputs: ctl.Inputs,
 | 
							StaticInputs: ctl.Inputs,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						log.Infof("Calling CheckIn API with %s runType", ctl.RunType)
 | 
				
			||||||
	testlist, err := inputloader.Load(context.Background())
 | 
						testlist, err := inputloader.Load(context.Background())
 | 
				
			||||||
	var urls []string
 | 
						var urls []string
 | 
				
			||||||
	urlIDMap := make(map[int64]int64)
 | 
						urlIDMap := make(map[int64]int64)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user