diff --git a/internal/cli/run/run.go b/internal/cli/run/run.go index 2de0c9d..10f71e3 100644 --- a/internal/cli/run/run.go +++ b/internal/cli/run/run.go @@ -44,12 +44,12 @@ func init() { time.Now().UTC().Format(time.RFC3339Nano))) ctl := nettests.NewController(nt, ctx, result, msmtPath) - if err := nt.Run(ctl); err != nil { + if err = nt.Run(ctl); err != nil { log.WithError(err).Errorf("Failed to run %s", group.Label) return err } } - if err = result.Finished(ctx.DB); err != nil { + if err = result.Finished(ctx.DB, group.Summary); err != nil { return err } return nil diff --git a/internal/database/models.go b/internal/database/models.go index 01d44cf..258b4b1 100644 --- a/internal/database/models.go +++ b/internal/database/models.go @@ -12,6 +12,12 @@ import ( "github.com/pkg/errors" ) +// ResultSummaryFunc is the function used to generate result summaries +type ResultSummaryFunc func(SummaryMap) (string, error) + +// SummaryMap contains a mapping from test name to serialized summary for it +type SummaryMap map[string]string + // UpdateOne will run the specified update query and check that it only affected one row func UpdateOne(db *sqlx.DB, query string, arg interface{}) error { res, err := db.NamedExec(query, arg) @@ -187,17 +193,43 @@ type Result struct { MeasurementDir string `db:"measurement_dir"` } +// MakeSummaryMap return a mapping of test names to summaries for the given +// result +func MakeSummaryMap(db *sqlx.DB, r *Result) (SummaryMap, error) { + summaryMap := SummaryMap{} + + msmts := []Measurement{} + // XXX maybe we only want to select some of the columns + err := db.Select(&msmts, "SELECT name, summary FROM measurements WHERE result_id = $1", r.ID) + if err != nil { + return nil, errors.Wrap(err, "failed to get measurements") + } + for _, msmt := range msmts { + summaryMap[msmt.Name] = msmt.Summary + } + return summaryMap, nil +} + // Finished marks the result as done and sets the runtime -func (r *Result) Finished(db *sqlx.DB) error { +func (r *Result) Finished(db *sqlx.DB, makeSummary ResultSummaryFunc) error { if r.Done == true || r.Runtime != 0 { return errors.New("Result is already finished") } r.Runtime = time.Now().UTC().Sub(r.StartTime).Seconds() r.Done = true // XXX add in here functionality to compute the summary + summaryMap, err := MakeSummaryMap(db, r) + if err != nil { + return err + } - err := UpdateOne(db, `UPDATE results - SET done = :done, runtime = :runtime + r.Summary, err = makeSummary(summaryMap) + if err != nil { + return err + } + + err = UpdateOne(db, `UPDATE results + SET done = :done, runtime = :runtime, summary = :summary WHERE id = :id`, r) if err != nil { return errors.Wrap(err, "updating finished result") diff --git a/nettests/groups/groups.go b/nettests/groups/groups.go index e10b6b2..5cc5861 100644 --- a/nettests/groups/groups.go +++ b/nettests/groups/groups.go @@ -1,6 +1,10 @@ package groups import ( + "encoding/json" + + "github.com/apex/log" + "github.com/openobservatory/gooni/internal/database" "github.com/openobservatory/gooni/nettests" "github.com/openobservatory/gooni/nettests/performance" "github.com/openobservatory/gooni/nettests/websites" @@ -10,7 +14,15 @@ import ( type NettestGroup struct { Label string Nettests []nettests.Nettest - Summary func(s string) string + Summary database.ResultSummaryFunc +} + +// PerformanceSummary is the result summary for a performance test +type PerformanceSummary struct { + Upload int64 + Download int64 + Ping float64 + Bitrate int64 } // NettestGroups that can be run by the user @@ -20,8 +32,8 @@ var NettestGroups = map[string]NettestGroup{ Nettests: []nettests.Nettest{ websites.WebConnectivity{}, }, - Summary: func(s string) string { - return "{}" + Summary: func(m database.SummaryMap) (string, error) { + return "{}", nil }, }, "performance": NettestGroup{ @@ -30,22 +42,46 @@ var NettestGroups = map[string]NettestGroup{ performance.Dash{}, performance.NDT{}, }, - Summary: func(s string) string { - return "{}" + Summary: func(m database.SummaryMap) (string, error) { + var ( + err error + ndtSummary performance.NDTSummary + dashSummary performance.DashSummary + summary PerformanceSummary + ) + err = json.Unmarshal([]byte(m["Dash"]), &dashSummary) + if err != nil { + log.WithError(err).Error("failed to unmarshal Dash summary") + return "", err + } + err = json.Unmarshal([]byte(m["Ndt"]), &ndtSummary) + if err != nil { + log.WithError(err).Error("failed to unmarshal Dash summary") + return "", err + } + summary.Bitrate = dashSummary.Bitrate + summary.Download = ndtSummary.Download + summary.Upload = ndtSummary.Upload + summary.Ping = ndtSummary.AvgRTT + summaryBytes, err := json.Marshal(summary) + if err != nil { + return "", err + } + return string(summaryBytes), nil }, }, "middleboxes": NettestGroup{ Label: "Middleboxes", Nettests: []nettests.Nettest{}, - Summary: func(s string) string { - return "{}" + Summary: func(m database.SummaryMap) (string, error) { + return "{}", nil }, }, "im": NettestGroup{ Label: "Instant Messaging", Nettests: []nettests.Nettest{}, - Summary: func(s string) string { - return "{}" + Summary: func(m database.SummaryMap) (string, error) { + return "{}", nil }, }, } diff --git a/nettests/performance/ndt.go b/nettests/performance/ndt.go index 0a53f77..4c8159d 100644 --- a/nettests/performance/ndt.go +++ b/nettests/performance/ndt.go @@ -21,9 +21,9 @@ type NDTSummary struct { Upload int64 Download int64 Ping int64 - MaxRTT int64 - AvgRTT int64 - MinRTT int64 + MaxRTT float64 + AvgRTT float64 + MinRTT float64 MSS int64 OutOfOrder int64 PacketLoss float64 @@ -39,9 +39,9 @@ func (n NDT) Summary(tk map[string]interface{}) interface{} { Upload: int64(simple["upload"].(float64)), Download: int64(simple["download"].(float64)), Ping: int64(simple["ping"].(float64)), - MaxRTT: int64(advanced["max_rtt"].(float64)), - AvgRTT: int64(advanced["avg_rtt"].(float64)), - MinRTT: int64(advanced["min_rtt"].(float64)), + MaxRTT: advanced["max_rtt"].(float64), + AvgRTT: advanced["avg_rtt"].(float64), + MinRTT: advanced["min_rtt"].(float64), MSS: int64(advanced["mss"].(float64)), OutOfOrder: int64(advanced["out_of_order"].(float64)), PacketLoss: advanced["packet_loss"].(float64),