diff --git a/GHGEN/utils.go b/GHGEN/utils.go index f04c1b0890..9a6a19be03 100644 --- a/GHGEN/utils.go +++ b/GHGEN/utils.go @@ -7,77 +7,77 @@ package main import ( "fmt" "io" - "os" "path/filepath" "strings" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) func newJob(w io.Writer, name, runsOn, needs string, permissions map[string]string) { - mustFprintf(w, " %s:\n", name) - mustFprintf(w, " runs-on: %s\n", runsOn) + must.Fprintf(w, " %s:\n", name) + must.Fprintf(w, " runs-on: %s\n", runsOn) if needs != "" { - mustFprintf(w, " needs: %s\n", needs) + must.Fprintf(w, " needs: %s\n", needs) } if len(permissions) > 0 { - mustFprintf(w, " permissions:\n") + must.Fprintf(w, " permissions:\n") for key, value := range permissions { - mustFprintf(w, " %s: %s\n", key, value) + must.Fprintf(w, " %s: %s\n", key, value) } } - mustFprintf(w, " steps:\n") + must.Fprintf(w, " steps:\n") } func newStepCheckout(w io.Writer) { - mustFprintf(w, " - uses: actions/checkout@v2\n") - mustFprintf(w, " with:\n") - mustFprintf(w, " fetch-depth: 0\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - uses: actions/checkout@v2\n") + must.Fprintf(w, " with:\n") + must.Fprintf(w, " fetch-depth: 0\n") + must.Fprintf(w, "\n") } func newStepSetupGo(w io.Writer, cacheName string) { - mustFprintf(w, " - name: Get GOVERSION content\n") - mustFprintf(w, " id: goversion\n") - mustFprintf(w, " run: echo ::set-output name=version::$(cat GOVERSION)\n") - mustFprintf(w, " - uses: magnetikonline/action-golang-cache@v2\n") - mustFprintf(w, " with:\n") - mustFprintf(w, " go-version: \"${{ steps.goversion.outputs.version }}\"\n") - mustFprintf(w, " cache-key-suffix: \"-%s-${{ steps.goversion.outputs.version }}\"\n", cacheName) - mustFprintf(w, "\n") + must.Fprintf(w, " - name: Get GOVERSION content\n") + must.Fprintf(w, " id: goversion\n") + must.Fprintf(w, " run: echo ::set-output name=version::$(cat GOVERSION)\n") + must.Fprintf(w, " - uses: magnetikonline/action-golang-cache@v2\n") + must.Fprintf(w, " with:\n") + must.Fprintf(w, " go-version: \"${{ steps.goversion.outputs.version }}\"\n") + must.Fprintf(w, " cache-key-suffix: \"-%s-${{ steps.goversion.outputs.version }}\"\n", cacheName) + must.Fprintf(w, "\n") } func newStepSetupPsiphon(w io.Writer) { - mustFprintf(w, " - run: |\n") - mustFprintf(w, " echo -n $PSIPHON_CONFIG_KEY > ./internal/engine/psiphon-config.key\n") - mustFprintf(w, " echo $PSIPHON_CONFIG_JSON_AGE_BASE64 | base64 -d > ./internal/engine/psiphon-config.json.age\n") - mustFprintf(w, " env:\n") - mustFprintf(w, " PSIPHON_CONFIG_KEY: ${{ secrets.PSIPHON_CONFIG_KEY }}\n") - mustFprintf(w, " PSIPHON_CONFIG_JSON_AGE_BASE64: ${{ secrets.PSIPHON_CONFIG_JSON_AGE_BASE64 }}\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: |\n") + must.Fprintf(w, " echo -n $PSIPHON_CONFIG_KEY > ./internal/engine/psiphon-config.key\n") + must.Fprintf(w, " echo $PSIPHON_CONFIG_JSON_AGE_BASE64 | base64 -d > ./internal/engine/psiphon-config.json.age\n") + must.Fprintf(w, " env:\n") + must.Fprintf(w, " PSIPHON_CONFIG_KEY: ${{ secrets.PSIPHON_CONFIG_KEY }}\n") + must.Fprintf(w, " PSIPHON_CONFIG_JSON_AGE_BASE64: ${{ secrets.PSIPHON_CONFIG_JSON_AGE_BASE64 }}\n") + must.Fprintf(w, "\n") } func newStepMake(w io.Writer, target string) { - mustFprintf(w, " - run: make %s\n", target) - mustFprintf(w, "\n") + must.Fprintf(w, " - run: make %s\n", target) + must.Fprintf(w, "\n") } func newStepUploadArtifacts(w io.Writer, artifacts []string) { for _, arti := range artifacts { - mustFprintf(w, " - uses: actions/upload-artifact@v2\n") - mustFprintf(w, " with:\n") - mustFprintf(w, " name: %s\n", filepath.Base(arti)) - mustFprintf(w, " path: %s\n", arti) - mustFprintf(w, "\n") + must.Fprintf(w, " - uses: actions/upload-artifact@v2\n") + must.Fprintf(w, " with:\n") + must.Fprintf(w, " name: %s\n", filepath.Base(arti)) + must.Fprintf(w, " path: %s\n", arti) + must.Fprintf(w, "\n") } } func newStepDownloadArtifacts(w io.Writer, artifacts []string) { for _, arti := range artifacts { - mustFprintf(w, " - uses: actions/download-artifact@v2\n") - mustFprintf(w, " with:\n") - mustFprintf(w, " name: %s\n", filepath.Base(arti)) - mustFprintf(w, "\n") + must.Fprintf(w, " - uses: actions/download-artifact@v2\n") + must.Fprintf(w, " with:\n") + must.Fprintf(w, " name: %s\n", filepath.Base(arti)) + must.Fprintf(w, "\n") } } @@ -87,91 +87,80 @@ func newStepGHPublish(w io.Writer, artifacts []string) { for _, arti := range artifacts { artifactsNames = append(artifactsNames, filepath.Base(arti)) } - mustFprintf(w, " - run: ./script/ghpublish.bash %s\n", strings.Join(artifactsNames, " ")) - mustFprintf(w, " env:\n") - mustFprintf(w, " GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: ./script/ghpublish.bash %s\n", strings.Join(artifactsNames, " ")) + must.Fprintf(w, " env:\n") + must.Fprintf(w, " GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n") + must.Fprintf(w, "\n") } func newStepSetupLinuxDockerGoCache(w io.Writer, name string) { - mustFprintf(w, " - uses: actions/cache@v3\n") - mustFprintf(w, " with:\n") - mustFprintf(w, " path: GOCACHE\n") - mustFprintf(w, " key: linux-build-cache-%s\n", name) - mustFprintf(w, "\n") + must.Fprintf(w, " - uses: actions/cache@v3\n") + must.Fprintf(w, " with:\n") + must.Fprintf(w, " path: GOCACHE\n") + must.Fprintf(w, " key: linux-build-cache-%s\n", name) + must.Fprintf(w, "\n") } func newSetupInstallQemuUserStatic(w io.Writer) { - mustFprintf(w, " - run: sudo apt-get update -q\n") - mustFprintf(w, " - run: sudo apt-get install -y qemu-user-static\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: sudo apt-get update -q\n") + must.Fprintf(w, " - run: sudo apt-get install -y qemu-user-static\n") + must.Fprintf(w, "\n") } func newStepInstallTor(w io.Writer) { - mustFprintf(w, " - run: sudo apt-get update -q\n") - mustFprintf(w, " - run: sudo apt-get install -y tor\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: sudo apt-get update -q\n") + must.Fprintf(w, " - run: sudo apt-get install -y tor\n") + must.Fprintf(w, "\n") } func newStepRunOONIProbeIntegrationTests(w io.Writer, os, arch, ext string) { executable := fmt.Sprintf("ooniprobe-%s-%s%s", os, arch, ext) if os != "windows" { - mustFprintf(w, " - run: chmod +x %s\n", executable) + must.Fprintf(w, " - run: chmod +x %s\n", executable) } - mustFprintf(w, " - run: ./E2E/ooniprobe.bash ./%s\n", executable) - mustFprintf(w, " shell: bash\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: ./E2E/ooniprobe.bash ./%s\n", executable) + must.Fprintf(w, " shell: bash\n") + must.Fprintf(w, "\n") } func newStepRunMiniooniIntegrationTests(w io.Writer, os, arch, ext string) { executable := fmt.Sprintf("miniooni-%s-%s%s", os, arch, ext) if os != "windows" { - mustFprintf(w, " - run: chmod +x %s\n", executable) + must.Fprintf(w, " - run: chmod +x %s\n", executable) } - mustFprintf(w, " - run: ./E2E/miniooni.bash ./%s\n", executable) - mustFprintf(w, " shell: bash\n") - mustFprintf(w, "\n") + must.Fprintf(w, " - run: ./E2E/miniooni.bash ./%s\n", executable) + must.Fprintf(w, " shell: bash\n") + must.Fprintf(w, "\n") } func newStepInstallMingwW64(w io.Writer) { - mustFprintf(w, " - run: sudo apt-get update -q\n") - mustFprintf(w, " - run: sudo apt-get install -y mingw-w64\n") - mustFprintf(w, "\n") -} - -func mustFprintf(w io.Writer, format string, v ...any) { - _, err := fmt.Fprintf(w, format, v...) - runtimex.PanicOnError(err, "fmt.Fprintf failed") -} - -func mustClose(c io.Closer) { - err := c.Close() - runtimex.PanicOnError(err, "c.Close failed") + must.Fprintf(w, " - run: sudo apt-get update -q\n") + must.Fprintf(w, " - run: sudo apt-get install -y mingw-w64\n") + must.Fprintf(w, "\n") } func generateWorkflowFile(name string, jobs []Job) { filename := filepath.Join(".github", "workflows", name+".yml") - fp, err := os.Create(filename) - runtimex.PanicOnError(err, "os.Create failed") - defer mustClose(fp) - mustFprintf(fp, "# File generated by `go run ./GHGEN`; DO NOT EDIT.\n") - mustFprintf(fp, "\n") - mustFprintf(fp, "name: %s\n", name) - mustFprintf(fp, "on:\n") - mustFprintf(fp, " push:\n") - mustFprintf(fp, " branches:\n") - mustFprintf(fp, " - \"release/**\"\n") - mustFprintf(fp, " - \"fullbuild\"\n") - mustFprintf(fp, " - \"%sbuild\"\n", name) - mustFprintf(fp, " tags:\n") - mustFprintf(fp, " - \"v*\"\n") - mustFprintf(fp, " schedule:\n") - mustFprintf(fp, " - cron: \"17 1 * * *\"\n") - mustFprintf(fp, "\n") - mustFprintf(fp, "jobs:\n") + fp := must.CreateFile(filename) + defer fp.MustClose() + must.Fprintf(fp, "# File generated by `go run ./GHGEN`; DO NOT EDIT.\n") + must.Fprintf(fp, "\n") + must.Fprintf(fp, "name: %s\n", name) + must.Fprintf(fp, "on:\n") + must.Fprintf(fp, " push:\n") + must.Fprintf(fp, " branches:\n") + must.Fprintf(fp, " - \"release/**\"\n") + must.Fprintf(fp, " - \"fullbuild\"\n") + must.Fprintf(fp, " - \"%sbuild\"\n", name) + must.Fprintf(fp, " tags:\n") + must.Fprintf(fp, " - \"v*\"\n") + must.Fprintf(fp, " schedule:\n") + must.Fprintf(fp, " - cron: \"17 1 * * *\"\n") + must.Fprintf(fp, "\n") + must.Fprintf(fp, "jobs:\n") for _, job := range jobs { job.Action(fp, &job) } - mustFprintf(fp, "# End of autogenerated file\n") + must.Fprintf(fp, "# End of autogenerated file\n") } diff --git a/internal/cmd/miniooni/session.go b/internal/cmd/miniooni/session.go index a56262c02b..1bef28ce70 100644 --- a/internal/cmd/miniooni/session.go +++ b/internal/cmd/miniooni/session.go @@ -10,6 +10,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine" "github.com/ooni/probe-cli/v3/internal/kvstore" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) @@ -24,7 +25,7 @@ func newSessionOrPanic(ctx context.Context, currentOptions *Options, miniooniDir string, logger model.Logger) *engine.Session { var proxyURL *url.URL if currentOptions.Proxy != "" { - proxyURL = mustParseURL(currentOptions.Proxy) + proxyURL = must.ParseURL(currentOptions.Proxy) } kvstore2dir := filepath.Join(miniooniDir, "kvstore2") diff --git a/internal/cmd/miniooni/utils.go b/internal/cmd/miniooni/utils.go index cb51e13398..ac0c4f5294 100644 --- a/internal/cmd/miniooni/utils.go +++ b/internal/cmd/miniooni/utils.go @@ -6,7 +6,6 @@ package main import ( "errors" - "net/url" "os" "runtime" "strings" @@ -54,13 +53,6 @@ func mustMakeMapStringAny(input []string) (output map[string]any) { return } -// mustParseURL parses the given URL or panics -func mustParseURL(URL string) *url.URL { - rv, err := url.Parse(URL) - runtimex.PanicOnError(err, "cannot parse URL") - return rv -} - // gethomedir returns the home directory. If optionsHome is set, then we // return that string as the home directory. Otherwise, we use typical // platform-specific environment variables to determine the home. In case diff --git a/internal/cmd/oohelper/internal/client.go b/internal/cmd/oohelper/internal/client.go index f175d5cb4e..bdf47beaec 100644 --- a/internal/cmd/oohelper/internal/client.go +++ b/internal/cmd/oohelper/internal/client.go @@ -12,8 +12,8 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) @@ -110,8 +110,7 @@ func (oo OOClient) Do(ctx context.Context, config OOConfig) (*CtrlResponse, erro }, TCPConnect: endpoints, } - data, err := json.Marshal(creq) - runtimex.PanicOnError(err, "oohelper: cannot marshal control request") + data := must.MarshalJSON(creq) log.Debugf("out: %s", string(data)) req, err := http.NewRequestWithContext(ctx, "POST", config.ServerURL, bytes.NewReader(data)) if err != nil { diff --git a/internal/cmd/oohelper/oohelper.go b/internal/cmd/oohelper/oohelper.go index 132194c6de..e946d0e0d6 100644 --- a/internal/cmd/oohelper/oohelper.go +++ b/internal/cmd/oohelper/oohelper.go @@ -4,13 +4,13 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/cmd/oohelper/internal" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -41,8 +41,7 @@ func main() { flag.Parse() log.SetLevel(logmap[*debug]) cresp := wcth() - data, err := json.MarshalIndent(cresp, "", " ") - runtimex.PanicOnError(err, "json.MarshalIndent failed") + data := must.MarshalAndIndentJSON(cresp, "", " ") fmt.Printf("%s\n", string(data)) } diff --git a/internal/cmd/oohelperd/handler.go b/internal/cmd/oohelperd/handler.go index 2e186ac708..f8e2a46acb 100644 --- a/internal/cmd/oohelperd/handler.go +++ b/internal/cmd/oohelperd/handler.go @@ -13,8 +13,8 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" ) @@ -87,8 +87,7 @@ func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { metricRequestsCount.WithLabelValues("200", "ok").Inc() // We assume that the following call cannot fail because it's a // clearly-serializable data structure. - data, err = json.Marshal(cresp) - runtimex.PanicOnError(err, "json.Marshal failed") + data = must.MarshalJSON(cresp) w.Header().Add("Content-Type", "application/json") w.Write(data) } diff --git a/internal/cmd/oohelperd/main.go b/internal/cmd/oohelperd/main.go index 3e97b9d3a9..84f0cebb86 100644 --- a/internal/cmd/oohelperd/main.go +++ b/internal/cmd/oohelperd/main.go @@ -4,7 +4,6 @@ package main import ( "context" "flag" - "net" "net/http" "sync" "sync/atomic" @@ -12,8 +11,8 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/prometheus/client_golang/prometheus/promhttp" ) @@ -103,8 +102,7 @@ func main() { }, }) srv := &http.Server{Addr: *endpoint, Handler: mux} - listener, err := net.Listen("tcp", *endpoint) - runtimex.PanicOnError(err, "net.Listen failed") + listener := must.Listen("tcp", *endpoint) srvAddr <- listener.Addr().String() srvWg.Add(1) go srv.Serve(listener) diff --git a/internal/cmd/oohelperd/main_test.go b/internal/cmd/oohelperd/main_test.go index 001a68460e..9d392bd2b7 100644 --- a/internal/cmd/oohelperd/main_test.go +++ b/internal/cmd/oohelperd/main_test.go @@ -10,8 +10,8 @@ import ( "testing" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func TestMainWorkingAsIntended(t *testing.T) { @@ -34,8 +34,7 @@ func TestMainWorkingAsIntended(t *testing.T) { "8.8.4.4:443", }, } - data, err := json.Marshal(jsonReq) - runtimex.PanicOnError(err, "cannot marshal request") + data := must.MarshalJSON(jsonReq) // construct the test helper's URL endpoint := <-srvAddr @@ -44,8 +43,7 @@ func TestMainWorkingAsIntended(t *testing.T) { Host: endpoint, Path: "/", } - req, err := http.NewRequest("POST", URL.String(), bytes.NewReader(data)) - runtimex.PanicOnError(err, "cannot create new HTTP request") + req := must.NewHTTPRequest("POST", URL.String(), bytes.NewReader(data)) // issue the request and get the response resp, err := http.DefaultClient.Do(req) diff --git a/internal/cmd/oonireport/oonireport.go b/internal/cmd/oonireport/oonireport.go index 80dddb45ad..b0f20f604e 100644 --- a/internal/cmd/oonireport/oonireport.go +++ b/internal/cmd/oonireport/oonireport.go @@ -4,7 +4,6 @@ package main import ( "bufio" "context" - "encoding/json" "fmt" "io" "os" @@ -14,6 +13,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/engine" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/probeservices" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/version" @@ -59,9 +59,8 @@ func canOpen(filepath string) bool { func readLines(path string) []string { // open measurement file - file, err := os.Open(path) - runtimex.PanicOnError(err, "Open file error.") - defer file.Close() + file := must.OpenFile(path) + defer file.MustClose() scanner := bufio.NewScanner(file) // the maximum line length should be selected really big @@ -103,8 +102,7 @@ func newSubmitter(sess *engine.Session, ctx context.Context) *probeservices.Subm // toMeasurement loads an input string as model.Measurement func toMeasurement(s string) *model.Measurement { var mm model.Measurement - err := json.Unmarshal([]byte(s), &mm) - runtimex.PanicOnError(err, "json.Unmarshal error") + must.UnmarshalJSON([]byte(s), &mm) return &mm } diff --git a/internal/cmd/ooporthelper/main.go b/internal/cmd/ooporthelper/main.go index 55b77f0e64..9d0d345e14 100644 --- a/internal/cmd/ooporthelper/main.go +++ b/internal/cmd/ooporthelper/main.go @@ -10,7 +10,7 @@ import ( "github.com/apex/log" "github.com/ooni/probe-cli/v3/internal/experiment/portfiltering" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) var ( @@ -41,8 +41,7 @@ func handleConnection(ctx context.Context, conn net.Conn) { func listenTCP(ctx context.Context, port string) { defer srvWg.Done() address := net.JoinHostPort("127.0.0.1", port) - listener, err := net.Listen("tcp", address) - runtimex.PanicOnError(err, "net.Listen failed") + listener := must.Listen("tcp", address) go shutdown(ctx, listener) srvTestChan <- port // send to channel to imply server will start listening on port for { diff --git a/internal/database/database_test.go b/internal/database/database_test.go index 355471c078..146cfbc980 100644 --- a/internal/database/database_test.go +++ b/internal/database/database_test.go @@ -4,8 +4,6 @@ import ( "io/ioutil" "os" "testing" - - "github.com/apex/log" ) func TestConnect(t *testing.T) { @@ -26,7 +24,6 @@ func TestConnect(t *testing.T) { } if len(colls) < 1 { - log.Fatal("missing tables") + t.Fatal("missing tables") } - } diff --git a/internal/engine/checkincache.go b/internal/engine/checkincache.go index 0e7e09e854..4960ac4228 100644 --- a/internal/engine/checkincache.go +++ b/internal/engine/checkincache.go @@ -9,7 +9,7 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // checkInFlagsState is the state created by check-in flags. @@ -33,8 +33,7 @@ func (s *Session) updateCheckInFlagsState(resp *model.OOAPICheckInResult) error Expire: time.Now().Add(24 * time.Hour), Flags: resp.Conf.Features, } - data, err := json.Marshal(wrapper) - runtimex.PanicOnError(err, "json.Marshal unexpectedly failed") + data := must.MarshalJSON(wrapper) return s.kvStore.Set(checkInFlagsState, data) } diff --git a/internal/experiment/dnscheck/dnscheck.go b/internal/experiment/dnscheck/dnscheck.go index 5979861bd3..39d784a147 100644 --- a/internal/experiment/dnscheck/dnscheck.go +++ b/internal/experiment/dnscheck/dnscheck.go @@ -17,7 +17,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/experiment/urlgetter" "github.com/ooni/probe-cli/v3/internal/legacy/netx" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/tracex" ) @@ -291,10 +291,9 @@ func makeResolverURL(URL *url.URL, addr string) string { } // 2. adjust hostname if we also have a port if hasPort := URL.Port() != ""; hasPort { - _, port, err := net.SplitHostPort(URL.Host) // We say this cannot fail because we already parsed the URL to validate // its scheme and hence the URL hostname should be well formed. - runtimex.PanicOnError(err, "net.SplitHostPort should not fail here") + _, port := must.SplitHostPort(URL.Host) hostname = net.JoinHostPort(hostname, port) } else if idx := strings.Index(addr, ":"); idx >= 0 { // Make sure an IPv6 address hostname without a port is properly diff --git a/internal/experiment/dnsping/dnsping_test.go b/internal/experiment/dnsping/dnsping_test.go index bc03bea34d..9b6b80a6e9 100644 --- a/internal/experiment/dnsping/dnsping_test.go +++ b/internal/experiment/dnsping/dnsping_test.go @@ -3,7 +3,6 @@ package dnsping import ( "context" "errors" - "log" "net" "net/url" "testing" @@ -101,7 +100,7 @@ func TestMeasurer_run(t *testing.T) { t.Run("with local listener", func(t *testing.T) { srvrURL, dnsListener, err := startDNSServer() if err != nil { - log.Fatal(err) + t.Fatal(err) } defer dnsListener.Close() meas, m, err := runHelper(srvrURL) diff --git a/internal/experiment/simplequicping/simplequicping_test.go b/internal/experiment/simplequicping/simplequicping_test.go index 808d21ca9c..f4c3b118e7 100644 --- a/internal/experiment/simplequicping/simplequicping_test.go +++ b/internal/experiment/simplequicping/simplequicping_test.go @@ -8,7 +8,6 @@ import ( "crypto/x509" "encoding/pem" "errors" - "log" "math/big" "net/url" "testing" @@ -105,7 +104,7 @@ func TestMeasurer_run(t *testing.T) { t.Run("with local listener", func(t *testing.T) { srvrURL, listener, err := startEchoServer() if err != nil { - log.Fatal(err) + t.Fatal(err) } defer listener.Close() meas, m, err := runHelper(srvrURL) diff --git a/internal/experiment/tlsmiddlebox/conn_test.go b/internal/experiment/tlsmiddlebox/conn_test.go index 364688fc12..9b043ea681 100644 --- a/internal/experiment/tlsmiddlebox/conn_test.go +++ b/internal/experiment/tlsmiddlebox/conn_test.go @@ -6,13 +6,12 @@ import ( "io" "net/http" "net/http/httptest" - "net/url" "syscall" "testing" "github.com/ooni/probe-cli/v3/internal/model/mocks" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func TestDialerTTLWrapperConn(t *testing.T) { @@ -143,8 +142,7 @@ func TestGetSoErr(t *testing.T) { w.WriteHeader(200) })) defer srvr.Close() - URL, err := url.Parse(srvr.URL) - runtimex.PanicOnError(err, "url.Parse failed") + URL := must.ParseURL(srvr.URL) d := NewDialerTTLWrapper() ctx := context.Background() conn, err := d.DialContext(ctx, "tcp", URL.Host) diff --git a/internal/experiment/tor/tor.go b/internal/experiment/tor/tor.go index 11fe42cbae..ee2e2f7ae4 100644 --- a/internal/experiment/tor/tor.go +++ b/internal/experiment/tor/tor.go @@ -5,7 +5,6 @@ package tor import ( "context" - "encoding/json" "errors" "fmt" "net/url" @@ -15,6 +14,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/measurex" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" "github.com/ooni/probe-cli/v3/internal/scrubber" @@ -270,15 +270,13 @@ func maybeSanitize(input TargetResults, kt keytarget) TargetResults { if !kt.private() { return input } - data, err := json.Marshal(input) - runtimex.PanicOnError(err, "json.Marshal should not fail here") + data := must.MarshalJSON(input) // Implementation note: here we are using a strict scrubbing policy where // we remove all IP _endpoints_, mainly for convenience, because we already // have a well tested implementation that does that. data = []byte(scrubber.Scrub(string(data))) var out TargetResults - err = json.Unmarshal(data, &out) - runtimex.PanicOnError(err, "json.Unmarshal should not fail here") + must.UnmarshalJSON(data, &out) return out } diff --git a/internal/experiment/urlgetter/runner.go b/internal/experiment/urlgetter/runner.go index 825160754d..8ea656123e 100644 --- a/internal/experiment/urlgetter/runner.go +++ b/internal/experiment/urlgetter/runner.go @@ -11,6 +11,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/legacy/netx" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -62,8 +63,7 @@ func MaybeUserAgent(ua string) string { func (r Runner) httpGet(ctx context.Context, url string) error { // Implementation note: empty Method implies using the GET method - req, err := http.NewRequest(r.Config.Method, url, nil) - runtimex.PanicOnError(err, "http.NewRequest failed") + req := must.NewHTTPRequest(r.Config.Method, url, nil) req = req.WithContext(ctx) req.Header.Set("Accept", model.HTTPHeaderAccept) req.Header.Set("Accept-Language", model.HTTPHeaderAcceptLanguage) diff --git a/internal/experiment/webconnectivity/endpoints.go b/internal/experiment/webconnectivity/endpoints.go index ac7d072745..6ca9021a1b 100644 --- a/internal/experiment/webconnectivity/endpoints.go +++ b/internal/experiment/webconnectivity/endpoints.go @@ -4,7 +4,7 @@ import ( "net" "net/url" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // EndpointInfo describes a TCP/TLS endpoint. @@ -69,8 +69,7 @@ func NewEndpointPort(URL *url.URL) (out EndpointPort) { out.URLGetterScheme, out.Port = "tlshandshake", "443" } if URL.Host != URL.Hostname() { - _, port, err := net.SplitHostPort(URL.Host) - runtimex.PanicOnError(err, "SplitHostPort should not fail here") + _, port := must.SplitHostPort(URL.Host) out.Port = port } return diff --git a/internal/experiment/webconnectivitylte/priority.go b/internal/experiment/webconnectivitylte/priority.go index c86a4cce90..50814eccc1 100644 --- a/internal/experiment/webconnectivitylte/priority.go +++ b/internal/experiment/webconnectivitylte/priority.go @@ -30,10 +30,10 @@ import ( "context" "errors" "fmt" - "net" "time" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -126,8 +126,7 @@ func (ps *prioritySelector) log(format string, v ...any) { // permissionToFetch returns whether this ready-to-use connection // is permitted to perform a round trip and fetch the webpage. func (ps *prioritySelector) permissionToFetch(address string) bool { - ipAddr, _, err := net.SplitHostPort(address) - runtimex.PanicOnError(err, "net.SplitHostPort failed") + ipAddr, _ := must.SplitHostPort(address) r := &priorityRequest{ addr: ipAddr, resp: make(chan bool, 1), // buffer to simplify selector() implementation diff --git a/internal/experiment/whatsapp/whatsapp.go b/internal/experiment/whatsapp/whatsapp.go index 94055b07dd..8a3cab1777 100644 --- a/internal/experiment/whatsapp/whatsapp.go +++ b/internal/experiment/whatsapp/whatsapp.go @@ -8,13 +8,12 @@ import ( "errors" "fmt" "math/rand" - "net/url" "regexp" "time" "github.com/ooni/probe-cli/v3/internal/experiment/urlgetter" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) const ( @@ -74,8 +73,7 @@ func (tk *TestKeys) Update(v urlgetter.MultiOutput) { // Set the status of WhatsApp endpoints if endpointPattern.MatchString(v.Input.Target) { if v.TestKeys.Failure != nil { - parsed, err := url.Parse(v.Input.Target) - runtimex.PanicOnError(err, "url.Parse should not fail here") + parsed := must.ParseURL(v.Input.Target) hostname := parsed.Hostname() tk.WhatsappEndpointsCount[hostname]++ // Implementation note: here we're counting twice because we test each diff --git a/internal/geoipx/geoipx.go b/internal/geoipx/geoipx.go index 5640e8b3fd..2c54b34f2a 100644 --- a/internal/geoipx/geoipx.go +++ b/internal/geoipx/geoipx.go @@ -34,7 +34,7 @@ func LookupASN(ip string) (asn uint, org string, err error) { func LookupCC(ip string) (cc string, err error) { cc = model.DefaultProbeCC db, err := maxminddb.FromBytes(assets.OOMMDBDatabaseBytes) - runtimex.PanicOnError(err, "cannot load embedded geoip2 country database") + runtimex.PanicOnError(err, "cannot load embedded geoip2 database") defer db.Close() record, err := assets.OOMMDBLooup(db, net.ParseIP(ip)) if err != nil { diff --git a/internal/model/measurement.go b/internal/model/measurement.go index 7cd2a8e13e..03b36b3328 100644 --- a/internal/model/measurement.go +++ b/internal/model/measurement.go @@ -12,7 +12,7 @@ import ( "net" "time" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) const ( @@ -198,8 +198,7 @@ var scrubJSONUnmarshalTopLevelKeys = json.Unmarshal // scrubTopLevelKeys removes [currentIP] from the top-level keys // of [m] by rewriting these keys in place. func scrubTopLevelKeys(m *Measurement, currentIP string) error { - data, err := json.Marshal(m) - runtimex.PanicOnError(err, "json.Marshal(m) failed") // m must serialize + data := must.MarshalJSON(m) data = bytes.ReplaceAll(data, []byte(currentIP), []byte(Scrubbed)) return scrubJSONUnmarshalTopLevelKeys(data, &m) } @@ -210,8 +209,7 @@ var scrubJSONUnmarshalTestKeys = json.Unmarshal // scrubTestKeys removes [currentIP] from the TestKeys by rewriting // them in place while preserving their original type func scrubTestKeys(m *Measurement, currentIP string) error { - data, err := json.Marshal(m.TestKeys) - runtimex.PanicOnError(err, "json.Marshal(m.TestKeys) failed") // m.TestKeys must serialize + data := must.MarshalJSON(m.TestKeys) data = bytes.ReplaceAll(data, []byte(currentIP), []byte(Scrubbed)) return scrubJSONUnmarshalTestKeys(data, &m.TestKeys) } diff --git a/internal/must/must.go b/internal/must/must.go new file mode 100644 index 0000000000..fcd8fd2655 --- /dev/null +++ b/internal/must/must.go @@ -0,0 +1,104 @@ +// Package must contains functions that panic on error. +package must + +import ( + "encoding/json" + "fmt" + "io" + "net" + "net/http" + "net/url" + "os" + + "github.com/ooni/probe-cli/v3/internal/runtimex" +) + +// CreateFile is like [os.Create] but calls +// [runtimex.PanicOnError] on failure. +func CreateFile(name string) *File { + fp, err := os.Create(name) + runtimex.PanicOnError(err, "os.Create failed") + return &File{fp} +} + +// OpenFile is like [os.Open] but calls +// [runtimex.PanicOnError] on failure. +func OpenFile(name string) *File { + fp, err := os.Open(name) + runtimex.PanicOnError(err, "os.Open failed") + return &File{fp} +} + +// File wraps [os.File]. +type File struct { + *os.File +} + +// MustClose is like [os.File.Close] but calls +// [runtimex.PanicOnError] on failure. +func (fp *File) MustClose() { + err := fp.File.Close() + runtimex.PanicOnError(err, "fp.File.Close failed") +} + +// Fprintf is like [fmt.Fprintf] but calls +// [runtimex.PanicOnError] on failure. +func Fprintf(w io.Writer, format string, v ...any) { + _, err := fmt.Fprintf(w, format, v...) + runtimex.PanicOnError(err, "fmt.Fprintf failed") +} + +// ParseURL is like [url.Parse] but calls +// [runtimex.PanicOnError] on failure. +func ParseURL(URL string) *url.URL { + parsed, err := url.Parse(URL) + runtimex.PanicOnError(err, "url.Parse failed") + return parsed +} + +// MarshalJSON is like [json.Marshal] but calls +// [runtimex.PanicOnError] on failure. +func MarshalJSON(v any) []byte { + data, err := json.Marshal(v) + runtimex.PanicOnError(err, "json.Marshal failed") + return data +} + +// MarshalAndIndentJSON is like [json.MarshalIndent] but calls +// [runtimex.PanicOnError] on failure. +func MarshalAndIndentJSON(v any, prefix string, indent string) []byte { + data, err := json.MarshalIndent(v, prefix, indent) + runtimex.PanicOnError(err, "json.MarshalIndent failed") + return data +} + +// UnmarshalJSON is like [json.Marshal] but calls +// [runtimex.PanicOnError] on failure. +func UnmarshalJSON(data []byte, v any) { + err := json.Unmarshal(data, v) + runtimex.PanicOnError(err, "json.Unmarshal failed") +} + +// Listen is like [net.Listen] but calls +// [runtimex.PanicOnError] on failure. +func Listen(network string, address string) net.Listener { + listener, err := net.Listen(network, address) + runtimex.PanicOnError(err, "net.Listen failed") + return listener +} + +// NewHTTPRequest is like [http.NewRequest] but calls +// [runtimex.PanicOnError] on failure. +func NewHTTPRequest(method string, url string, body io.Reader) *http.Request { + req, err := http.NewRequest(method, url, body) + runtimex.PanicOnError(err, "http.NewRequest failed") + return req +} + +// SplitHostPort is like [net.SplitHostPort] but calls +// [runtimex.PanicOnError] on failure. +func SplitHostPort(hostport string) (host string, port string) { + host, port, err := net.SplitHostPort(hostport) + runtimex.PanicOnError(err, "net.SplitHostPort failed") + return host, port +} diff --git a/internal/must/must_test.go b/internal/must/must_test.go new file mode 100644 index 0000000000..ff20a7eb6e --- /dev/null +++ b/internal/must/must_test.go @@ -0,0 +1,110 @@ +package must + +import ( + "bytes" + "io" + "os" + "path/filepath" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestCreateFile(t *testing.T) { + filename := filepath.Join("testdata", "test.txt") + filep := CreateFile(filename) + if _, err := filep.WriteString("antani"); err != nil { + t.Fatal(err) + } + defer os.Remove(filename) + filep.MustClose() + data, err := os.ReadFile(filename) + if err != nil { + t.Fatal(err) + } + if string(data) != "antani" { + t.Fatal("did not write the expected content") + } +} + +func TestOpenFile(t *testing.T) { + filename := filepath.Join("testdata", ".gitignore") + filep := OpenFile(filename) + data, err := io.ReadAll(filep) + if err != nil { + t.Fatal(err) + } + filep.MustClose() + if string(data) != "*\n" && string(data) != "*\r\n" { + t.Fatal("unexpected content") + } +} + +func TestFprintf(t *testing.T) { + w := &bytes.Buffer{} + Fprintf(w, "hello %s", "world") + if w.String() != "hello world" { + t.Fatal("unexpected buffer content") + } +} + +func TestParseURL(t *testing.T) { + URL := ParseURL("https://www.google.com/") + if URL.Scheme != "https" || URL.Host != "www.google.com" || URL.Path != "/" { + t.Fatal("unexpected parsed URL") + } +} + +func TestMarshalJSON(t *testing.T) { + data := MarshalJSON("foobar") + if string(data) != "\"foobar\"" { + t.Fatal("incorrect marshalling") + } +} + +type example struct { + Name string + Age int +} + +func TestMarshalAndIndentJSON(t *testing.T) { + input := &example{Name: "sbs", Age: 40} + data := MarshalAndIndentJSON(input, "", " ") + expected := []byte("{\n \"Name\": \"sbs\",\n \"Age\": 40\n}") + if diff := cmp.Diff(expected, data); diff != "" { + t.Fatal(diff) + } +} + +func TestUnmarshalJSON(t *testing.T) { + input := []byte("{\n \"Name\": \"sbs\",\n \"Age\": 40\n}") + var entry example + UnmarshalJSON(input, &entry) + if entry.Name != "sbs" || entry.Age != 40 { + t.Fatal("did not unmarshal correctly") + } +} + +func TestListen(t *testing.T) { + conn := Listen("tcp", "127.0.0.1:0") + // TODO(bassosimone): unclear to me what to test here? + conn.Close() +} + +func TestNewHTTPRequest(t *testing.T) { + req := NewHTTPRequest("GET", "https://www.google.com/", nil) + if req.Method != "GET" { + t.Fatal("invalid method") + } + URL := req.URL + if URL.Scheme != "https" || URL.Host != "www.google.com" || URL.Path != "/" { + t.Fatal("unexpected parsed URL") + } +} + +func TestSplitHostPort(t *testing.T) { + addr, port := SplitHostPort("127.0.0.1:8080") + if addr != "127.0.0.1" || port != "8080" { + t.Fatal("unexpected result") + } +} diff --git a/internal/must/testdata/.gitignore b/internal/must/testdata/.gitignore new file mode 100644 index 0000000000..72e8ffc0db --- /dev/null +++ b/internal/must/testdata/.gitignore @@ -0,0 +1 @@ +* diff --git a/internal/netxlite/filtering/http.go b/internal/netxlite/filtering/http.go index 031a0ea5bc..403bd8e59f 100644 --- a/internal/netxlite/filtering/http.go +++ b/internal/netxlite/filtering/http.go @@ -11,6 +11,7 @@ import ( "github.com/google/martian/v3/mitm" "github.com/miekg/dns" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -89,8 +90,7 @@ func (p *HTTPServer) TLSConfig() *tls.Config { // newHTTPOrHTTPSServer is an internal factory for creating a new instance. func newHTTPOrHTTPSServer(action HTTPAction, enableTLS bool) *HTTPServer { - listener, err := net.Listen("tcp", "127.0.0.1:0") - runtimex.PanicOnError(err, "net.Listen failed") + listener := must.Listen("tcp", "127.0.0.1:0") srv := &HTTPServer{ action: action, cert: nil, diff --git a/internal/netxlite/filtering/http_test.go b/internal/netxlite/filtering/http_test.go index a2e297524f..9ee9261cce 100644 --- a/internal/netxlite/filtering/http_test.go +++ b/internal/netxlite/filtering/http_test.go @@ -30,7 +30,7 @@ func TestHTTPServer(t *testing.T) { clnt := &http.Client{Transport: txp} req, err := http.NewRequestWithContext( ctx, method, URL.String(), bytes.NewReader(requestBody)) - runtimex.PanicOnError(err, "http.NewRequest failed") + runtimex.PanicOnError(err, "http.NewRequestWithContext failed") req.Host = host return clnt.Do(req) } diff --git a/internal/netxlite/filtering/tls.go b/internal/netxlite/filtering/tls.go index af6210a897..dc64d62e52 100644 --- a/internal/netxlite/filtering/tls.go +++ b/internal/netxlite/filtering/tls.go @@ -10,6 +10,7 @@ import ( "time" "github.com/google/martian/v3/mitm" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -79,8 +80,7 @@ func tlsConfigMITM() (*x509.Certificate, *rsa.PrivateKey, *mitm.Config) { func NewTLSServer(action TLSAction) *TLSServer { done := make(chan bool) cert, privkey, config := tlsConfigMITM() - listener, err := net.Listen("tcp", "127.0.0.1:0") - runtimex.PanicOnError(err, "net.Listen failed") + listener := must.Listen("tcp", "127.0.0.1:0") ctx, cancel := context.WithCancel(context.Background()) endpoint := listener.Addr().String() server := &TLSServer{ diff --git a/internal/netxlite/quic_test.go b/internal/netxlite/quic_test.go index 5ccb888660..6fd74d045c 100644 --- a/internal/netxlite/quic_test.go +++ b/internal/netxlite/quic_test.go @@ -217,7 +217,7 @@ func TestQUICDialerQUICGo(t *testing.T) { t.Fatal("not the error we expected", err) } if qconn != nil { - log.Fatal("expected nil connection here") + t.Fatal("expected nil connection here") } }) diff --git a/internal/ooapi/checkin.go b/internal/ooapi/checkin.go index 89753280fe..b897660ff7 100644 --- a/internal/ooapi/checkin.go +++ b/internal/ooapi/checkin.go @@ -5,12 +5,11 @@ package ooapi // import ( - "encoding/json" "net/http" "github.com/ooni/probe-cli/v3/internal/httpapi" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // NewDescriptorCheckIn creates a new [httpapi.Descriptor] describing how @@ -18,8 +17,7 @@ import ( func NewDescriptorCheckIn( config *model.OOAPICheckInConfig, ) *httpapi.Descriptor[*model.OOAPICheckInConfig, *model.OOAPICheckInResult] { - rawRequest, err := json.Marshal(config) - runtimex.PanicOnError(err, "json.Marshal failed unexpectedly") + rawRequest := must.MarshalJSON(config) return &httpapi.Descriptor[*model.OOAPICheckInConfig, *model.OOAPICheckInResult]{ Accept: httpapi.ApplicationJSON, AcceptEncodingGzip: true, // we want a small response diff --git a/internal/ooapi/th.go b/internal/ooapi/th.go index fd057b18fb..58fefe8e28 100644 --- a/internal/ooapi/th.go +++ b/internal/ooapi/th.go @@ -5,12 +5,11 @@ package ooapi // import ( - "encoding/json" "net/http" "github.com/ooni/probe-cli/v3/internal/httpapi" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // NewDescriptorTH creates a new [httpapi.Descriptor] describing how @@ -18,8 +17,7 @@ import ( func NewDescriptorTH( creq *model.THRequest, ) *httpapi.Descriptor[*model.THRequest, *model.THResponse] { - rawRequest, err := json.Marshal(creq) - runtimex.PanicOnError(err, "json.Marshal failed unexpectedly") + rawRequest := must.MarshalJSON(creq) return &httpapi.Descriptor[*model.THRequest, *model.THResponse]{ Accept: httpapi.ApplicationJSON, AcceptEncodingGzip: false, diff --git a/internal/oonirun/v2.go b/internal/oonirun/v2.go index a6d82a5c7d..cac4e6a6ca 100644 --- a/internal/oonirun/v2.go +++ b/internal/oonirun/v2.go @@ -17,7 +17,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/httpx" "github.com/ooni/probe-cli/v3/internal/kvstore" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) var ( @@ -151,8 +151,7 @@ func (cache *v2DescriptorCache) PullChangesWithoutSideEffects( func (cache *v2DescriptorCache) Update( fsstore model.KeyValueStore, URL string, entry *V2Descriptor) error { cache.Entries[URL] = entry - data, err := json.Marshal(cache) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(cache) return fsstore.Set(v2DescriptorCacheKey, data) } @@ -209,10 +208,8 @@ var ErrNeedToAcceptChanges = errors.New("oonirun: need to accept changes") // v2DescriptorDiff shows what changed between the old and the new descriptors. func v2DescriptorDiff(oldValue, newValue *V2Descriptor, URL string) string { - oldData, err := json.MarshalIndent(oldValue, "", " ") - runtimex.PanicOnError(err, "json.MarshalIndent failed unexpectedly") - newData, err := json.MarshalIndent(newValue, "", " ") - runtimex.PanicOnError(err, "json.MarshalIndent failed unexpectedly") + oldData := must.MarshalAndIndentJSON(oldValue, "", " ") + newData := must.MarshalAndIndentJSON(newValue, "", " ") oldString, newString := string(oldData)+"\n", string(newData)+"\n" oldFile := "OLD " + URL newFile := "NEW " + URL diff --git a/internal/oonirun/v2_test.go b/internal/oonirun/v2_test.go index fffbb9e7ff..d044a7a485 100644 --- a/internal/oonirun/v2_test.go +++ b/internal/oonirun/v2_test.go @@ -2,7 +2,6 @@ package oonirun import ( "context" - "encoding/json" "errors" "net/http" "net/http/httptest" @@ -12,7 +11,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/kvstore" "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/model/mocks" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func TestOONIRunV2LinkCommonCase(t *testing.T) { @@ -29,8 +28,7 @@ func TestOONIRunV2LinkCommonCase(t *testing.T) { TestName: "example", }}, } - data, err := json.Marshal(descriptor) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(descriptor) w.Write(data) })) defer server.Close() @@ -68,8 +66,7 @@ func TestOONIRunV2LinkCannotUpdateCache(t *testing.T) { TestName: "example", }}, } - data, err := json.Marshal(descriptor) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(descriptor) w.Write(data) })) defer server.Close() @@ -116,8 +113,7 @@ func TestOONIRunV2LinkWithoutAcceptChanges(t *testing.T) { TestName: "example", }}, } - data, err := json.Marshal(descriptor) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(descriptor) w.Write(data) })) defer server.Close() @@ -182,8 +178,7 @@ func TestOONIRunV2LinkEmptyTestName(t *testing.T) { TestName: "", // empty! }}, } - data, err := json.Marshal(descriptor) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(descriptor) w.Write(data) })) defer server.Close() diff --git a/internal/sessionresolver/resolver.go b/internal/sessionresolver/resolver.go index a8b96bc996..fef523f7d9 100644 --- a/internal/sessionresolver/resolver.go +++ b/internal/sessionresolver/resolver.go @@ -6,7 +6,6 @@ package sessionresolver import ( "context" - "encoding/json" "errors" "fmt" "math/rand" @@ -18,7 +17,7 @@ import ( "github.com/ooni/probe-cli/v3/internal/bytecounter" "github.com/ooni/probe-cli/v3/internal/model" "github.com/ooni/probe-cli/v3/internal/multierror" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // Resolver is the session resolver. Resolver will try to use @@ -84,8 +83,7 @@ func (r *Resolver) CloseIdleConnections() { // Stats returns stats about the session resolver. func (r *Resolver) Stats() string { - data, err := json.Marshal(r.readstatedefault()) - runtimex.PanicOnError(err, "json.Marshal should not fail here") + data := must.MarshalJSON(r.readstatedefault()) return fmt.Sprintf("sessionresolver: %s", string(data)) } diff --git a/internal/tutorial/measurex/chapter01/README.md b/internal/tutorial/measurex/chapter01/README.md index 4c04d4ab5f..a8994b3a3b 100644 --- a/internal/tutorial/measurex/chapter01/README.md +++ b/internal/tutorial/measurex/chapter01/README.md @@ -45,13 +45,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -172,8 +171,7 @@ we first convert it to the "archival" format. This is the data format specified at [ooni/spec](https://github.com/ooni/spec/tree/master/data-formats). ```Go - data, err := json.Marshal(measurex.NewArchivalDNSMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalDNSMeasurement(m)) fmt.Printf("%s\n", string(data)) ``` diff --git a/internal/tutorial/measurex/chapter01/main.go b/internal/tutorial/measurex/chapter01/main.go index fc14d9bb6d..3c0ef16605 100644 --- a/internal/tutorial/measurex/chapter01/main.go +++ b/internal/tutorial/measurex/chapter01/main.go @@ -46,13 +46,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -173,8 +172,7 @@ func main() { // data format specified at [ooni/spec](https://github.com/ooni/spec/tree/master/data-formats). // // ```Go - data, err := json.Marshal(measurex.NewArchivalDNSMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalDNSMeasurement(m)) fmt.Printf("%s\n", string(data)) // ``` // diff --git a/internal/tutorial/measurex/chapter02/README.md b/internal/tutorial/measurex/chapter02/README.md index 7edc3b2cdd..68abb09df3 100644 --- a/internal/tutorial/measurex/chapter02/README.md +++ b/internal/tutorial/measurex/chapter02/README.md @@ -20,13 +20,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -74,8 +73,7 @@ chapter. Like we did before, we convert the obtained measurement to the "archival" data format before printing. ```Go - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter02/main.go b/internal/tutorial/measurex/chapter02/main.go index d39336a692..dde78df92c 100644 --- a/internal/tutorial/measurex/chapter02/main.go +++ b/internal/tutorial/measurex/chapter02/main.go @@ -21,13 +21,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -75,8 +74,7 @@ func main() { // to the "archival" data format before printing. // // ```Go - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter03/README.md b/internal/tutorial/measurex/chapter03/README.md index 0f0b4f3023..a27fb1f6f3 100644 --- a/internal/tutorial/measurex/chapter03/README.md +++ b/internal/tutorial/measurex/chapter03/README.md @@ -20,13 +20,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -57,8 +56,7 @@ Also this operation returns a measurement, which we print using the usual three-liner. ```Go - data, err := json.Marshal(measurex.NewArchivalDNSMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalDNSMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter03/main.go b/internal/tutorial/measurex/chapter03/main.go index b309980100..a922cd9963 100644 --- a/internal/tutorial/measurex/chapter03/main.go +++ b/internal/tutorial/measurex/chapter03/main.go @@ -21,13 +21,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) func main() { @@ -58,8 +57,7 @@ func main() { // we print using the usual three-liner. // // ```Go - data, err := json.Marshal(measurex.NewArchivalDNSMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalDNSMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter04/README.md b/internal/tutorial/measurex/chapter04/README.md index f4f1118421..a0e90a3f74 100644 --- a/internal/tutorial/measurex/chapter04/README.md +++ b/internal/tutorial/measurex/chapter04/README.md @@ -20,14 +20,13 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func main() { @@ -69,8 +68,7 @@ As usual, the method to perform a measurement returns the measurement itself, which we print below. ``` - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter04/main.go b/internal/tutorial/measurex/chapter04/main.go index 28b2553672..3714d00e5f 100644 --- a/internal/tutorial/measurex/chapter04/main.go +++ b/internal/tutorial/measurex/chapter04/main.go @@ -21,14 +21,13 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func main() { @@ -70,8 +69,7 @@ func main() { // the measurement itself, which we print below. // // ``` - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter05/README.md b/internal/tutorial/measurex/chapter05/README.md index 6d4e515c53..973c50e43d 100644 --- a/internal/tutorial/measurex/chapter05/README.md +++ b/internal/tutorial/measurex/chapter05/README.md @@ -26,14 +26,13 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func main() { @@ -69,8 +68,7 @@ As we did in the previous chapters, here's the usual three lines of code for printing the resulting measurement. ``` - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter05/main.go b/internal/tutorial/measurex/chapter05/main.go index 4d1bef6ac6..ef55d70df3 100644 --- a/internal/tutorial/measurex/chapter05/main.go +++ b/internal/tutorial/measurex/chapter05/main.go @@ -27,14 +27,13 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) func main() { @@ -70,8 +69,7 @@ func main() { // lines of code for printing the resulting measurement. // // ``` - data, err := json.Marshal(measurex.NewArchivalEndpointMeasurement(m)) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(measurex.NewArchivalEndpointMeasurement(m)) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter06/README.md b/internal/tutorial/measurex/chapter06/README.md index 3184b88646..65c48b285a 100644 --- a/internal/tutorial/measurex/chapter06/README.md +++ b/internal/tutorial/measurex/chapter06/README.md @@ -29,14 +29,13 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) ``` @@ -46,8 +45,7 @@ into the following utility function called `print`. ```Go func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter06/main.go b/internal/tutorial/measurex/chapter06/main.go index c242d1003e..d3f0bd47f1 100644 --- a/internal/tutorial/measurex/chapter06/main.go +++ b/internal/tutorial/measurex/chapter06/main.go @@ -30,14 +30,13 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // ``` @@ -47,8 +46,7 @@ import ( // // ```Go func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter07/README.md b/internal/tutorial/measurex/chapter07/README.md index 2adefae5dc..0606d5a0be 100644 --- a/internal/tutorial/measurex/chapter07/README.md +++ b/internal/tutorial/measurex/chapter07/README.md @@ -18,13 +18,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -45,8 +44,7 @@ The rest of the program is quite similar to what we had before. ```Go func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -57,8 +55,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() ``` diff --git a/internal/tutorial/measurex/chapter07/main.go b/internal/tutorial/measurex/chapter07/main.go index 19172481d5..11eb399cb1 100644 --- a/internal/tutorial/measurex/chapter07/main.go +++ b/internal/tutorial/measurex/chapter07/main.go @@ -19,13 +19,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -46,8 +45,7 @@ type measurement struct { // // ```Go func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -58,8 +56,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() // ``` // diff --git a/internal/tutorial/measurex/chapter08/README.md b/internal/tutorial/measurex/chapter08/README.md index 4a7e2364f4..bec28398ae 100644 --- a/internal/tutorial/measurex/chapter08/README.md +++ b/internal/tutorial/measurex/chapter08/README.md @@ -23,13 +23,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -39,8 +38,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -51,8 +49,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} ``` diff --git a/internal/tutorial/measurex/chapter08/main.go b/internal/tutorial/measurex/chapter08/main.go index 6b586ddd9e..52d9cbf1fb 100644 --- a/internal/tutorial/measurex/chapter08/main.go +++ b/internal/tutorial/measurex/chapter08/main.go @@ -24,13 +24,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -40,8 +39,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -52,8 +50,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} // ``` diff --git a/internal/tutorial/measurex/chapter09/README.md b/internal/tutorial/measurex/chapter09/README.md index 1f4a26f1bf..f05ea075ea 100644 --- a/internal/tutorial/measurex/chapter09/README.md +++ b/internal/tutorial/measurex/chapter09/README.md @@ -33,13 +33,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -49,8 +48,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -61,8 +59,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} m.DNS = append(m.DNS, mx.LookupHostUDP(ctx, parsed.Hostname(), *address)) diff --git a/internal/tutorial/measurex/chapter09/main.go b/internal/tutorial/measurex/chapter09/main.go index 94162f19c1..258e8d1ef8 100644 --- a/internal/tutorial/measurex/chapter09/main.go +++ b/internal/tutorial/measurex/chapter09/main.go @@ -34,13 +34,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -50,8 +49,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -62,8 +60,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} m.DNS = append(m.DNS, mx.LookupHostUDP(ctx, parsed.Hostname(), *address)) diff --git a/internal/tutorial/measurex/chapter10/README.md b/internal/tutorial/measurex/chapter10/README.md index a7c4f42f74..8dada58d8a 100644 --- a/internal/tutorial/measurex/chapter10/README.md +++ b/internal/tutorial/measurex/chapter10/README.md @@ -22,13 +22,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -38,8 +37,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -49,8 +47,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} ``` diff --git a/internal/tutorial/measurex/chapter10/main.go b/internal/tutorial/measurex/chapter10/main.go index 7a72589ef5..77420e9680 100644 --- a/internal/tutorial/measurex/chapter10/main.go +++ b/internal/tutorial/measurex/chapter10/main.go @@ -23,13 +23,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "net/url" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) @@ -39,8 +38,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } @@ -50,8 +48,7 @@ func main() { flag.Parse() ctx, cancel := context.WithTimeout(context.Background(), *timeout) defer cancel() - parsed, err := url.Parse(*URL) - runtimex.PanicOnError(err, "url.Parse failed") + parsed := must.ParseURL(*URL) mx := measurex.NewMeasurerWithDefaultSettings() m := &measurement{} // ``` diff --git a/internal/tutorial/measurex/chapter11/README.md b/internal/tutorial/measurex/chapter11/README.md index 0c0fec526c..61202afe8f 100644 --- a/internal/tutorial/measurex/chapter11/README.md +++ b/internal/tutorial/measurex/chapter11/README.md @@ -25,18 +25,17 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter11/main.go b/internal/tutorial/measurex/chapter11/main.go index 9df5a8edc1..2c96e925bc 100644 --- a/internal/tutorial/measurex/chapter11/main.go +++ b/internal/tutorial/measurex/chapter11/main.go @@ -26,18 +26,17 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/runtimex" ) func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter12/README.md b/internal/tutorial/measurex/chapter12/README.md index 07d4debec8..f90d87e79c 100644 --- a/internal/tutorial/measurex/chapter12/README.md +++ b/internal/tutorial/measurex/chapter12/README.md @@ -22,13 +22,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) type measurement struct { @@ -36,8 +35,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter12/main.go b/internal/tutorial/measurex/chapter12/main.go index 8c4a06407b..b8bffe65db 100644 --- a/internal/tutorial/measurex/chapter12/main.go +++ b/internal/tutorial/measurex/chapter12/main.go @@ -23,13 +23,12 @@ package main import ( "context" - "encoding/json" "flag" "fmt" "time" "github.com/ooni/probe-cli/v3/internal/measurex" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) type measurement struct { @@ -37,8 +36,7 @@ type measurement struct { } func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter14/README.md b/internal/tutorial/measurex/chapter14/README.md index 620e59c737..9c5f2000c4 100644 --- a/internal/tutorial/measurex/chapter14/README.md +++ b/internal/tutorial/measurex/chapter14/README.md @@ -17,7 +17,6 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "net/http" @@ -25,13 +24,13 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" ) func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/internal/tutorial/measurex/chapter14/main.go b/internal/tutorial/measurex/chapter14/main.go index 1447bae4c1..89d9f5765d 100644 --- a/internal/tutorial/measurex/chapter14/main.go +++ b/internal/tutorial/measurex/chapter14/main.go @@ -18,7 +18,6 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" "net/http" @@ -26,13 +25,13 @@ import ( "time" "github.com/ooni/probe-cli/v3/internal/measurex" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/netxlite" "github.com/ooni/probe-cli/v3/internal/runtimex" ) func print(v interface{}) { - data, err := json.Marshal(v) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(v) fmt.Printf("%s\n", string(data)) } diff --git a/pkg/oonimkall/session.go b/pkg/oonimkall/session.go index 5ec01dc34d..5946510a12 100644 --- a/pkg/oonimkall/session.go +++ b/pkg/oonimkall/session.go @@ -13,8 +13,8 @@ import ( "github.com/ooni/probe-cli/v3/internal/kvstore" "github.com/ooni/probe-cli/v3/internal/legacy/assetsdir" "github.com/ooni/probe-cli/v3/internal/model" + "github.com/ooni/probe-cli/v3/internal/must" "github.com/ooni/probe-cli/v3/internal/probeservices" - "github.com/ooni/probe-cli/v3/internal/runtimex" ) // AtomicInt64 allows us to export atomic.Int64 variables to @@ -326,8 +326,7 @@ func (sess *Session) Submit(ctx *Context, measurement string) (*SubmitMeasuremen if err := sess.submitter.Submit(ctx.ctx, &mm); err != nil { return nil, err } - data, err := json.Marshal(mm) - runtimex.PanicOnError(err, "json.Marshal should not fail here") + data := must.MarshalJSON(mm) return &SubmitMeasurementResults{ UpdatedMeasurement: string(data), UpdatedReportID: mm.ReportID, diff --git a/pkg/oonimkall/task.go b/pkg/oonimkall/task.go index 541b6dda96..0021c41187 100644 --- a/pkg/oonimkall/task.go +++ b/pkg/oonimkall/task.go @@ -5,7 +5,7 @@ import ( "encoding/json" "sync/atomic" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // Task is an asynchronous task running an experiment. It mimics the @@ -67,8 +67,7 @@ func (t *Task) WaitForNextEvent() string { t.isdone.Add(1) return terminated } - data, err := json.Marshal(evp) - runtimex.PanicOnError(err, "json.Marshal failed") + data := must.MarshalJSON(evp) return string(data) } diff --git a/pkg/oonimkall/taskrunner.go b/pkg/oonimkall/taskrunner.go index 7ec5eb12d9..608d8b7806 100644 --- a/pkg/oonimkall/taskrunner.go +++ b/pkg/oonimkall/taskrunner.go @@ -2,14 +2,13 @@ package oonimkall import ( "context" - "encoding/json" "fmt" "net/url" "time" "github.com/ooni/probe-cli/v3/internal/engine" "github.com/ooni/probe-cli/v3/internal/model" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // runnerForTask runs a specific task @@ -304,8 +303,7 @@ func (r *runnerForTask) Run(rootCtx context.Context) { continue } m.AddAnnotations(r.settings.Annotations) - data, err := json.Marshal(m) - runtimex.PanicOnError(err, "measurement.MarshalJSON failed") + data := must.MarshalJSON(m) r.emitter.Emit(eventTypeMeasurement, eventMeasurementGeneric{ Idx: int64(idx), Input: input, diff --git a/pkg/oonimkall/webconnectivity.go b/pkg/oonimkall/webconnectivity.go index e96df38d4c..c4235ebd04 100644 --- a/pkg/oonimkall/webconnectivity.go +++ b/pkg/oonimkall/webconnectivity.go @@ -2,9 +2,8 @@ package oonimkall import ( "context" - "encoding/json" - "github.com/ooni/probe-cli/v3/internal/runtimex" + "github.com/ooni/probe-cli/v3/internal/must" ) // WebConnectivityConfig contains settings for WebConnectivity. @@ -69,8 +68,7 @@ func (r *webConnectivityRunner) run(ctx context.Context, config *WebConnectivity if err != nil { return nil, err } - data, err := json.Marshal(measurement) - runtimex.PanicOnError(err, "json.Marshal should not fail here") + data := must.MarshalJSON(measurement) return &WebConnectivityResults{ KibiBytesReceived: exp.KibiBytesReceived(), KibiBytesSent: exp.KibiBytesSent(), diff --git a/script/nocopyreadall.bash b/script/nocopyreadall.bash index ae8fedcc0f..8dd811cde9 100755 --- a/script/nocopyreadall.bash +++ b/script/nocopyreadall.bash @@ -13,6 +13,12 @@ for file in $(find . -type f -name \*.go); do # inside of netxlite's own test suite. continue fi + if [ "$file" = "./internal/must/must_test.go" ]; then + # We're allowed to use ReadAll and Copy in this file to + # avoid depending on netxlite, given that netxlite's test + # suite already depends on must. + continue + fi if grep -q 'io\.ReadAll' $file; then echo "in $file: do not use io.ReadAll, use netxlite.ReadAllContext" 1>&2 exitcode=1