Add hooks for generating result summaries

This commit is contained in:
Arturo Filastò 2018-03-20 14:19:19 +01:00
parent a747b76ecf
commit ce0e077175
4 changed files with 88 additions and 20 deletions

View File

@ -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

View File

@ -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")

View File

@ -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
},
},
}

View File

@ -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),