diff --git a/cmd/ooniprobe/internal/cli/geoip/geoip.go b/cmd/ooniprobe/internal/cli/geoip/geoip.go index 4a506a3..21d4ea5 100644 --- a/cmd/ooniprobe/internal/cli/geoip/geoip.go +++ b/cmd/ooniprobe/internal/cli/geoip/geoip.go @@ -8,6 +8,7 @@ import ( "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/cli/root" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/ooni" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/output" + "github.com/ooni/probe-cli/v3/internal/model" ) func init() { @@ -36,7 +37,7 @@ func dogeoip(config dogeoipconfig) error { return err } - engine, err := probeCLI.NewProbeEngine(context.Background()) + engine, err := probeCLI.NewProbeEngine(context.Background(), model.RunTypeManual) if err != nil { return err } diff --git a/cmd/ooniprobe/internal/cli/root/root.go b/cmd/ooniprobe/internal/cli/root/root.go index df4b387..0d9960a 100644 --- a/cmd/ooniprobe/internal/cli/root/root.go +++ b/cmd/ooniprobe/internal/cli/root/root.go @@ -40,7 +40,7 @@ func init() { softwareName := Cmd.Flag( "software-name", "Override application name", - ).Default("ooniprobe-cli").String() + ).Default(ooni.DefaultSoftwareName).String() softwareVersion := Cmd.Flag( "software-version", "Override the application version", ).Default(version.Version).String() diff --git a/cmd/ooniprobe/internal/cli/run/run.go b/cmd/ooniprobe/internal/cli/run/run.go index e0e827d..2418e4f 100644 --- a/cmd/ooniprobe/internal/cli/run/run.go +++ b/cmd/ooniprobe/internal/cli/run/run.go @@ -8,6 +8,7 @@ import ( "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/cli/root" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/nettests" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/ooni" + "github.com/ooni/probe-cli/v3/internal/model" ) func init() { @@ -32,7 +33,7 @@ func init() { return nil }) - functionalRun := func(runType string, pred func(name string, gr nettests.Group) bool) error { + functionalRun := func(runType model.RunType, pred func(name string, gr nettests.Group) bool) error { for name, group := range nettests.All { if !pred(name, group) { continue @@ -52,7 +53,7 @@ func init() { genRunWithGroupName := func(targetName string) func(*kingpin.ParseContext) error { return func(*kingpin.ParseContext) error { - return functionalRun("manual", func(groupName string, gr nettests.Group) bool { + return functionalRun(model.RunTypeManual, func(groupName string, gr nettests.Group) bool { return groupName == targetName }) } @@ -68,7 +69,7 @@ func init() { Probe: probe, InputFiles: *inputFile, Inputs: *input, - RunType: "manual", + RunType: model.RunTypeManual, }) }) @@ -80,14 +81,14 @@ func init() { unattendedCmd := cmd.Command("unattended", "") unattendedCmd.Action(func(_ *kingpin.ParseContext) error { - return functionalRun("timed", func(name string, gr nettests.Group) bool { + return functionalRun(model.RunTypeTimed, func(name string, gr nettests.Group) bool { return gr.UnattendedOK }) }) allCmd := cmd.Command("all", "").Default() allCmd.Action(func(_ *kingpin.ParseContext) error { - return functionalRun("manual", func(name string, gr nettests.Group) bool { + return functionalRun(model.RunTypeManual, func(name string, gr nettests.Group) bool { return true }) }) diff --git a/cmd/ooniprobe/internal/nettests/nettests.go b/cmd/ooniprobe/internal/nettests/nettests.go index 1756118..3531478 100644 --- a/cmd/ooniprobe/internal/nettests/nettests.go +++ b/cmd/ooniprobe/internal/nettests/nettests.go @@ -55,8 +55,8 @@ type Controller struct { Inputs []string // RunType contains the run_type hint for the CheckIn API. If - // not set, the underlying code defaults to "timed". - RunType string + // not set, the underlying code defaults to model.RunTypeTimed. + RunType model.RunType // numInputs is the total number of inputs numInputs int @@ -154,7 +154,7 @@ func (c *Controller) Run(builder *engine.ExperimentBuilder, inputs []string) err } maxRuntime := time.Duration(c.Probe.Config().Nettests.WebsitesMaxRuntime) * time.Second - if c.RunType == "timed" && maxRuntime > 0 { + if c.RunType == model.RunTypeTimed && maxRuntime > 0 { log.Debug("disabling maxRuntime when running in the background") maxRuntime = 0 } @@ -267,7 +267,7 @@ func (c *Controller) OnProgress(perc float64, msg string) { maxRuntime := time.Duration(c.Probe.Config().Nettests.WebsitesMaxRuntime) * time.Second _, isWebConnectivity := c.nt.(WebConnectivity) userProvidedInput := len(c.Inputs) > 0 || len(c.InputFiles) > 0 - if c.RunType == "manual" && maxRuntime > 0 && isWebConnectivity && !userProvidedInput { + if c.RunType == model.RunTypeManual && maxRuntime > 0 && isWebConnectivity && !userProvidedInput { elapsed := time.Since(c.ntStartTime) perc = float64(elapsed) / float64(maxRuntime) eta := maxRuntime.Seconds() - elapsed.Seconds() diff --git a/cmd/ooniprobe/internal/nettests/nettests_test.go b/cmd/ooniprobe/internal/nettests/nettests_test.go index 71a026b..5f6ba9c 100644 --- a/cmd/ooniprobe/internal/nettests/nettests_test.go +++ b/cmd/ooniprobe/internal/nettests/nettests_test.go @@ -9,6 +9,7 @@ import ( "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/database" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/ooni" + "github.com/ooni/probe-cli/v3/internal/model" ) func copyfile(source, dest string) error { @@ -45,7 +46,7 @@ func TestCreateContext(t *testing.T) { func TestRun(t *testing.T) { probe := newOONIProbe(t) - sess, err := probe.NewSession(context.Background()) + sess, err := probe.NewSession(context.Background(), model.RunTypeManual) if err != nil { t.Fatal(err) } diff --git a/cmd/ooniprobe/internal/nettests/run.go b/cmd/ooniprobe/internal/nettests/run.go index 137a6b6..158ef74 100644 --- a/cmd/ooniprobe/internal/nettests/run.go +++ b/cmd/ooniprobe/internal/nettests/run.go @@ -8,6 +8,7 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/database" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/ooni" + "github.com/ooni/probe-cli/v3/internal/model" "github.com/pkg/errors" ) @@ -17,7 +18,7 @@ type RunGroupConfig struct { InputFiles []string Inputs []string Probe *ooni.Probe - RunType string // hint for check-in API + RunType model.RunType // hint for check-in API } const websitesURLLimitRemoved = `WARNING: CONFIGURATION CHANGE REQUIRED: @@ -58,7 +59,7 @@ func RunGroup(config RunGroupConfig) error { return nil } - sess, err := config.Probe.NewSession(context.Background()) + sess, err := config.Probe.NewSession(context.Background(), config.RunType) if err != nil { log.WithError(err).Error("Failed to create a measurement session") return err diff --git a/cmd/ooniprobe/internal/ooni/ooni.go b/cmd/ooniprobe/internal/ooni/ooni.go index 6dd978d..c79d8aa 100644 --- a/cmd/ooniprobe/internal/ooni/ooni.go +++ b/cmd/ooniprobe/internal/ooni/ooni.go @@ -17,10 +17,14 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine" "github.com/ooni/probe-cli/v3/internal/engine/legacy/assetsdir" "github.com/ooni/probe-cli/v3/internal/kvstore" + "github.com/ooni/probe-cli/v3/internal/model" "github.com/pkg/errors" "upper.io/db.v3/lib/sqlbuilder" ) +// DefaultSoftwareName is the default software name. +const DefaultSoftwareName = "ooniprobe-cli" + // ProbeCLI is the OONI Probe CLI context. type ProbeCLI interface { Config() *config.Config @@ -28,7 +32,7 @@ type ProbeCLI interface { IsBatch() bool Home() string TempDir() string - NewProbeEngine(ctx context.Context) (ProbeEngine, error) + NewProbeEngine(ctx context.Context, runType model.RunType) (ProbeEngine, error) } // ProbeEngine is an instance of the OONI Probe engine. @@ -199,7 +203,7 @@ func (p *Probe) Init(softwareName, softwareVersion string) error { // NewSession creates a new ooni/probe-engine session using the // current configuration inside the context. The caller must close // the session when done using it, by calling sess.Close(). -func (p *Probe) NewSession(ctx context.Context) (*engine.Session, error) { +func (p *Probe) NewSession(ctx context.Context, runType model.RunType) (*engine.Session, error) { kvstore, err := kvstore.NewFS( utils.EngineDir(p.home), ) @@ -209,10 +213,18 @@ func (p *Probe) NewSession(ctx context.Context) (*engine.Session, error) { if err := os.MkdirAll(p.tunnelDir, 0700); err != nil { return nil, errors.Wrap(err, "creating tunnel dir") } + // When the software name is the default software name and we're running + // in unattended mode, adjust the software name accordingly. + // + // See https://github.com/ooni/probe/issues/2081. + softwareName := p.softwareName + if runType == model.RunTypeTimed && softwareName == DefaultSoftwareName { + softwareName = DefaultSoftwareName + "-unattended" + } return engine.NewSession(ctx, engine.SessionConfig{ KVStore: kvstore, Logger: enginex.Logger, - SoftwareName: p.softwareName, + SoftwareName: softwareName, SoftwareVersion: p.softwareVersion, TempDir: p.tempDir, TunnelDir: p.tunnelDir, @@ -220,8 +232,8 @@ func (p *Probe) NewSession(ctx context.Context) (*engine.Session, error) { } // NewProbeEngine creates a new ProbeEngine instance. -func (p *Probe) NewProbeEngine(ctx context.Context) (ProbeEngine, error) { - sess, err := p.NewSession(ctx) +func (p *Probe) NewProbeEngine(ctx context.Context, runType model.RunType) (ProbeEngine, error) { + sess, err := p.NewSession(ctx, runType) if err != nil { return nil, err } diff --git a/cmd/ooniprobe/internal/oonitest/oonitest.go b/cmd/ooniprobe/internal/oonitest/oonitest.go index 555b620..78a43e8 100644 --- a/cmd/ooniprobe/internal/oonitest/oonitest.go +++ b/cmd/ooniprobe/internal/oonitest/oonitest.go @@ -8,6 +8,7 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/config" "github.com/ooni/probe-cli/v3/cmd/ooniprobe/internal/ooni" + "github.com/ooni/probe-cli/v3/internal/model" "upper.io/db.v3/lib/sqlbuilder" ) @@ -61,7 +62,7 @@ func (cli *FakeProbeCLI) TempDir() string { } // NewProbeEngine implements ProbeCLI.NewProbeEngine -func (cli *FakeProbeCLI) NewProbeEngine(ctx context.Context) (ooni.ProbeEngine, error) { +func (cli *FakeProbeCLI) NewProbeEngine(ctx context.Context, runType model.RunType) (ooni.ProbeEngine, error) { return cli.FakeProbeEnginePtr, cli.FakeProbeEngineErr } diff --git a/internal/cmd/miniooni/libminiooni.go b/internal/cmd/miniooni/libminiooni.go index 5e39bf4..0c78bc8 100644 --- a/internal/cmd/miniooni/libminiooni.go +++ b/internal/cmd/miniooni/libminiooni.go @@ -412,7 +412,7 @@ func MainWithConfiguration(experimentName string, currentOptions Options) { inputLoader := &engine.InputLoader{ CheckInConfig: &model.OOAPICheckInConfig{ - RunType: "manual", + RunType: model.RunTypeManual, OnWiFi: true, // meaning: not on 4G Charging: true, }, diff --git a/internal/engine/probeservices/checkin_test.go b/internal/engine/probeservices/checkin_test.go index b61214f..63c9450 100644 --- a/internal/engine/probeservices/checkin_test.go +++ b/internal/engine/probeservices/checkin_test.go @@ -17,7 +17,7 @@ func TestCheckInSuccess(t *testing.T) { Platform: "android", ProbeASN: "AS12353", ProbeCC: "PT", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: model.OOAPICheckInConfigWebConnectivity{ @@ -54,7 +54,7 @@ func TestCheckInFailure(t *testing.T) { Platform: "android", ProbeASN: "AS12353", ProbeCC: "PT", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: model.OOAPICheckInConfigWebConnectivity{ diff --git a/internal/engine/session.go b/internal/engine/session.go index c5dd155..b0e3bdb 100644 --- a/internal/engine/session.go +++ b/internal/engine/session.go @@ -238,7 +238,7 @@ func (s *Session) KibiBytesSent() float64 { // // - ProbeCC: if empty, set to Session.ProbeCC(); // -// - RunType: if empty, set to "timed"; +// - RunType: if empty, set to model.RunTypeTimed; // // - SoftwareName: if empty, set to Session.SoftwareName(); // @@ -270,7 +270,7 @@ func (s *Session) CheckIn( config.ProbeCC = s.ProbeCC() } if config.RunType == "" { - config.RunType = "timed" // most conservative choice + config.RunType = model.RunTypeTimed // most conservative choice } if config.SoftwareName == "" { config.SoftwareName = s.SoftwareName() diff --git a/internal/engine/session_internal_test.go b/internal/engine/session_internal_test.go index 19e102a..04fc63d 100644 --- a/internal/engine/session_internal_test.go +++ b/internal/engine/session_internal_test.go @@ -107,7 +107,7 @@ func TestSessionCheckInSuccessful(t *testing.T) { if mockedClnt.Config.ProbeCC != "IT" { t.Fatal("invalid Config.ProbeCC") } - if mockedClnt.Config.RunType != "timed" { + if mockedClnt.Config.RunType != model.RunTypeTimed { t.Fatal("invalid Config.RunType") } if mockedClnt.Config.SoftwareName != "miniooni" { diff --git a/internal/model/ooapi.go b/internal/model/ooapi.go index 6d43433..5ee2f79 100644 --- a/internal/model/ooapi.go +++ b/internal/model/ooapi.go @@ -16,7 +16,7 @@ type OOAPICheckInConfig struct { Platform string `json:"platform"` // Platform of the probe ProbeASN string `json:"probe_asn"` // ProbeASN is the probe country code ProbeCC string `json:"probe_cc"` // ProbeCC is the probe country code - RunType string `json:"run_type"` // RunType + RunType RunType `json:"run_type"` // RunType SoftwareName string `json:"software_name"` // SoftwareName of the probe SoftwareVersion string `json:"software_version"` // SoftwareVersion of the probe WebConnectivity OOAPICheckInConfigWebConnectivity `json:"web_connectivity"` // WebConnectivity class contain an array of categories diff --git a/internal/model/runtype.go b/internal/model/runtype.go new file mode 100644 index 0000000..35af5b4 --- /dev/null +++ b/internal/model/runtype.go @@ -0,0 +1,14 @@ +package model + +// RunType describes the type of a ooniprobe run. +type RunType string + +const ( + // RunTypeManual indicates that the user manually run `ooniprobe run`. Command + // line tools such as miniooni should always use this run type. + RunTypeManual = RunType("manual") + + // RunTypeTimed indicates that the user run `ooniprobe run unattended`, which + // is the correct way to run ooniprobe from scripts and cronjobs. + RunTypeTimed = RunType("timed") +) diff --git a/internal/ooapi/apimodel/checkin.go b/internal/ooapi/apimodel/checkin.go index 8df8085..d6cd16e 100644 --- a/internal/ooapi/apimodel/checkin.go +++ b/internal/ooapi/apimodel/checkin.go @@ -1,5 +1,7 @@ package apimodel +import "github.com/ooni/probe-cli/v3/internal/model" + // CheckInRequestWebConnectivity contains WebConnectivity // specific parameters to include into CheckInRequest type CheckInRequestWebConnectivity struct { @@ -13,7 +15,7 @@ type CheckInRequest struct { Platform string `json:"platform"` ProbeASN string `json:"probe_asn"` ProbeCC string `json:"probe_cc"` - RunType string `json:"run_type"` + RunType model.RunType `json:"run_type"` SoftwareName string `json:"software_name"` SoftwareVersion string `json:"software_version"` WebConnectivity CheckInRequestWebConnectivity `json:"web_connectivity"` diff --git a/internal/ooapi/example_test.go b/internal/ooapi/example_test.go index 4cb6eb2..0b9c194 100644 --- a/internal/ooapi/example_test.go +++ b/internal/ooapi/example_test.go @@ -6,6 +6,7 @@ import ( "log" "github.com/ooni/probe-cli/v3/internal/kvstore" + "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/ooapi" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) @@ -21,7 +22,7 @@ func ExampleClient() { Platform: "linux", ProbeASN: "AS30722", ProbeCC: "IT", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "miniooni", SoftwareVersion: "0.1.0-dev", WebConnectivity: apimodel.CheckInRequestWebConnectivity{ diff --git a/internal/ooapi/integration_test.go b/internal/ooapi/integration_test.go index 3a7c1a0..0fca2f7 100644 --- a/internal/ooapi/integration_test.go +++ b/internal/ooapi/integration_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/kvstore" + "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/ooapi" "github.com/ooni/probe-cli/v3/internal/ooapi/apimodel" ) @@ -19,7 +20,7 @@ func TestWithRealServerDoCheckIn(t *testing.T) { Platform: "android", ProbeASN: "AS12353", ProbeCC: "IT", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: apimodel.CheckInRequestWebConnectivity{ diff --git a/pkg/oonimkall/session.go b/pkg/oonimkall/session.go index 955ccfb..fdbca43 100644 --- a/pkg/oonimkall/session.go +++ b/pkg/oonimkall/session.go @@ -364,9 +364,9 @@ type CheckInConfig struct { // Platform is the mobile platform (e.g. "android") Platform string - // RunType indicates whether this is an automated ("timed") run + // RunType indicates whether this is an automated (model.RunTypeTimed) run // or otherwise a manual run initiated by the user. - RunType string + RunType model.RunType // SoftwareName is the name of the application. SoftwareName string diff --git a/pkg/oonimkall/session_integration_test.go b/pkg/oonimkall/session_integration_test.go index 8faf935..70af283 100644 --- a/pkg/oonimkall/session_integration_test.go +++ b/pkg/oonimkall/session_integration_test.go @@ -259,7 +259,7 @@ func TestCheckInSuccess(t *testing.T) { Charging: true, OnWiFi: true, Platform: "android", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: &oonimkall.CheckInConfigWebConnectivity{}, @@ -307,7 +307,7 @@ func TestCheckInLookupLocationFailure(t *testing.T) { Charging: true, OnWiFi: true, Platform: "android", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: &oonimkall.CheckInConfigWebConnectivity{}, @@ -337,7 +337,7 @@ func TestCheckInNewProbeServicesFailure(t *testing.T) { Charging: true, OnWiFi: true, Platform: "android", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: &oonimkall.CheckInConfigWebConnectivity{}, @@ -366,7 +366,7 @@ func TestCheckInCheckInFailure(t *testing.T) { Charging: true, OnWiFi: true, Platform: "android", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", WebConnectivity: &oonimkall.CheckInConfigWebConnectivity{}, @@ -392,7 +392,7 @@ func TestCheckInNoParams(t *testing.T) { Charging: true, OnWiFi: true, Platform: "android", - RunType: "timed", + RunType: model.RunTypeTimed, SoftwareName: "ooniprobe-android", SoftwareVersion: "2.7.1", }