This repository has been archived by the owner on May 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fetchback: code to fetch measurement from API
We're aiming for writing a full end to end experiment where the code performs measurements and then fetches them back from API. However, the API code currently does not store measurements submitted by us using ams-pg.ooni.org, so we cannot go that far. Yet, let us have support for this functionality, which has been tested by adapting ooni/explorer#486. Also, for now just write basic smoke testing. The diff itself details a plan for integrating this code into probe-engine. When we'll do that we'll most likely want to write more testing code. This work is part of ooni/backend#446.
- Loading branch information
1 parent
cb1935e
commit 98b587a
Showing
3 changed files
with
175 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
name: fetchback | ||
on: | ||
pull_request: | ||
push: | ||
jobs: | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/setup-go@v1 | ||
with: | ||
go-version: "1.14" | ||
- uses: actions/checkout@v2 | ||
- run: sudo apt install jq | ||
- run: ./script/fetchbacktest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// +build ignore | ||
// +build forcetesting | ||
|
||
package main | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"io/ioutil" | ||
"log" | ||
"net/http" | ||
"net/url" | ||
"time" | ||
) | ||
|
||
// TODO(bassosimone): most of the code in this file should be moved to | ||
// github.com/ooni/probe-engine once we're always using the new API. When | ||
// this happens, this code will be part of the probeservices package. | ||
|
||
// The following errors are returned by this API. | ||
var ( | ||
ErrEmptyReportID = errors.New("empty report ID") | ||
) | ||
|
||
// Config contains the configuration for fetching a measurement. | ||
type Config struct { | ||
// ReportID is the mandatory report ID. | ||
ReportID string | ||
|
||
// Full indicates whether we also want the full measurement body. | ||
Full bool | ||
|
||
// Input is the optional input. | ||
Input string | ||
|
||
// Debugf is a function called to emit debug messages. | ||
Debugf func(format string, v ...interface{}) | ||
|
||
// Client is the optional HTTP client. | ||
Client *http.Client | ||
|
||
// BaseURL is the optiona base URL. | ||
BaseURL string | ||
} | ||
|
||
// MeasurementMeta contains measurement metadata. | ||
type MeasurementMeta struct { | ||
// Fields returned by the API server whenever we are | ||
// calling /api/v1/measurement_meta. | ||
Anomaly bool `json:"anomaly"` | ||
CategoryCode string `json:"category_code"` | ||
Confirmed bool `json:"confirmed"` | ||
Failure bool `json:"failure"` | ||
Input *string `json:"input"` | ||
MeasurementStartTime time.Time `json:"measurement_start_time"` | ||
ProbeASN int64 `json:"probe_asn"` | ||
ProbeCC string `json:"probe_cc"` | ||
ReportID string `json:"report_id"` | ||
Scores string `json:"scores"` | ||
TestName string `json:"test_name"` | ||
TestStartTime time.Time `json:"test_start_time"` | ||
|
||
// This field is only included if the user has specified | ||
// the full option, otherwise it's an empty string. | ||
RawMeasurement string `json:"raw_measurement"` | ||
|
||
// This field contains the body that we received from the | ||
// API server and it's here to help debugging. | ||
RawBody []byte `json:"-"` | ||
} | ||
|
||
// GetMeasurementMeta gets measurement metadata. | ||
func GetMeasurementMeta(ctx context.Context, config Config) (MeasurementMeta, error) { | ||
if config.ReportID == "" { | ||
return MeasurementMeta{}, ErrEmptyReportID | ||
} | ||
if config.Debugf == nil { | ||
config.Debugf = log.Printf | ||
} | ||
if config.Client == nil { | ||
config.Client = http.DefaultClient | ||
} | ||
if config.BaseURL == "" { | ||
config.BaseURL = "https://ams-pg.ooni.org" | ||
} | ||
URL, err := url.Parse(config.BaseURL) | ||
if err != nil { | ||
return MeasurementMeta{}, err | ||
} | ||
URL.Path = "/api/v1/measurement_meta" | ||
query := url.Values{} | ||
query.Add("report_id", config.ReportID) | ||
if config.Input != "" { | ||
query.Add("input", config.Input) | ||
} | ||
if config.Full { | ||
query.Add("full", "true") | ||
} | ||
URL.RawQuery = query.Encode() | ||
config.Debugf("> GET %s", URL.String()) | ||
resp, err := config.Client.Get(URL.String()) | ||
if err != nil { | ||
return MeasurementMeta{}, err | ||
} | ||
config.Debugf("< %d", resp.StatusCode) | ||
defer resp.Body.Close() | ||
reader := io.LimitReader(resp.Body, 1<<25) | ||
body, err := ioutil.ReadAll(reader) | ||
if err != nil { | ||
return MeasurementMeta{}, err | ||
} | ||
var mmeta MeasurementMeta | ||
err = json.Unmarshal(body, &mmeta) | ||
mmeta.RawBody = body // helps debugging | ||
if err != nil { | ||
return mmeta, err | ||
} | ||
return mmeta, nil | ||
} | ||
|
||
func fatalOnError(err error) { | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
} | ||
|
||
func main() { | ||
reportid := flag.String("report-id", "", "Report ID of the measurement") | ||
input := flag.String("input", "", "Input of the measurement") | ||
full := flag.Bool("full", false, "Also include the measurement body") | ||
flag.Parse() | ||
mmeta, err := GetMeasurementMeta(context.Background(), Config{ | ||
ReportID: *reportid, | ||
Input: *input, | ||
Full: *full, | ||
}) | ||
fatalOnError(err) | ||
data, err := json.Marshal(mmeta) | ||
fatalOnError(err) | ||
fmt.Printf("%s\n", data) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#!/bin/bash | ||
set -ex | ||
|
||
# TODO(bassosimone): consider writing more comprehensive tests. At the same | ||
# time consider that the backend has good coverage. We should still probably | ||
# ensure we're getting the expected result to validate _our_ code. | ||
|
||
# measurement from the past where the input doesn't matter | ||
go run ./script/fetchback.go -report-id \ | ||
20200316T235941Z_AS14522_uY1btNTrufkzxq1sIQ5s4TgcEjPiTmnXTN0jdj1N64GJUVIV5e \ | ||
| jq | ||
|
||
# measurement from the past where the input matters | ||
go run ./script/fetchback.go -report-id \ | ||
20200316T221937Z_AS4181_rdC4mBUM3RA2Qks35LXLEhZ6ZG8Sm8TDkuXEE2tRNUkOMc0QEe \ | ||
-input http://emule.com/ | jq |