blob: d2f2506ed492a29f33985e8000ef73448ea1842f [file] [log] [blame] [edit]
package perfresults
import (
"context"
"net/http"
apipb "go.chromium.org/luci/swarming/proto/api_v2"
"go.skia.org/infra/go/skerr"
)
type rbeProvider func(ctx context.Context, casInstance string) (*RBEPerfLoader, error)
type loader struct {
client *http.Client
rbeProvider rbeProvider
}
// NewLoader returns a new loader to load perf_results from the buildbucket.
//
// This is a simple lightweight struct used to inject dependencies and for testing purposes.
// One can simply call: NewLoader().LoadPerfResults(...).
func NewLoader() loader {
return loader{
rbeProvider: NewRBEPerfLoader,
}
}
func getNonNilCAS(cases ...*apipb.CASReference) []*apipb.CASReference {
nonnil := make([]*apipb.CASReference, len(cases))
ct := 0
for _, c := range cases {
if c == nil {
continue
}
nonnil[ct] = c
ct++
}
return nonnil[:ct]
}
// checkCasInstances returns true if all the cas instances are from the same rbe instance.
func checkCasInstances(cases ...*apipb.CASReference) bool {
// empty slice is considered to be true.
if len(cases) == 0 {
return true
}
first := cases[0]
for _, c := range cases[1:] {
if first.GetCasInstance() != c.GetCasInstance() {
return false
}
}
return true
}
// LoadPerfResults loads and merges all the perf_results.json from the given buildID.
func (loader loader) LoadPerfResults(ctx context.Context, buildID int64) (BuildInfo, map[string]*PerfResults, error) {
bc, _ := newBuildsClient(ctx, loader.client)
bi, err := bc.findBuildInfo(ctx, buildID)
if err != nil {
return BuildInfo{}, nil, skerr.Wrap(err)
}
sc, err := newSwarmingClient(ctx, bi.SwarmingInstance, loader.client)
if err != nil {
return BuildInfo{}, nil, skerr.Wrap(err)
}
childIDs, err := sc.findChildTaskIds(ctx, bi.TaskID)
if err != nil {
return BuildInfo{}, nil, skerr.Wrap(err)
}
cases, err := sc.findTaskCASOutputs(ctx, childIDs...)
if err != nil {
return BuildInfo{}, nil, skerr.Wrap(err)
}
cases = getNonNilCAS(cases...)
// If there is no test runs, we return the build info only.
if len(cases) == 0 {
return bi, nil, nil
}
if !checkCasInstances(cases...) {
return BuildInfo{}, nil, skerr.Fmt("CAS outputs are not from the same instance (%v)", buildID)
}
rbe, err := loader.rbeProvider(ctx, cases[0].GetCasInstance())
if err != nil {
return BuildInfo{}, nil, skerr.Wrap(err)
}
pr, err := rbe.LoadPerfResults(ctx, cases...)
return bi, pr, err
}