Chromium Code Reviews| Index: go/src/infra/appengine/test-results/model/aggregate_result.go |
| diff --git a/go/src/infra/appengine/test-results/model/aggregate_result.go b/go/src/infra/appengine/test-results/model/aggregate_result.go |
| index 7461629ed1a9c8c555e37540e2ebb173c9fdcd43..b75acb85d440fce6d3c0ff48101c6d65f2f01aa9 100644 |
| --- a/go/src/infra/appengine/test-results/model/aggregate_result.go |
| +++ b/go/src/infra/appengine/test-results/model/aggregate_result.go |
| @@ -42,7 +42,6 @@ func CleanJSON(r io.Reader) (io.Reader, error) { |
| } |
| // AggregateResult represents "results.json" and "results-small.json" files. |
| -// The Builder field must be set to the expected builder name before unmarshaling. |
| type AggregateResult struct { |
| Version int |
| Builder string |
| @@ -86,6 +85,36 @@ type BuilderInfo struct { |
| FixableCounts []map[string]int `json:"fixableCounts,omitempty"` |
| } |
| +// TestList is a representation an AggregateResult in which |
| +// the Results and Runtimes fields of all the AggregateTestLeafs |
| +// are set to nil. |
| +type TestList struct { |
| + Builder string |
| + Tests AggregateTest |
| +} |
| + |
| +// MarshalJSON marshals tl into JSON. |
| +func (tl *TestList) MarshalJSON() ([]byte, error) { |
| + return json.Marshal(map[string]map[string]AggregateTest{ |
| + tl.Builder: { |
| + "tests": tl.Tests, |
| + }, |
| + }) |
| +} |
| + |
| +// TestList returns a TestList representation of ag. |
| +func (ag *AggregateResult) TestList() TestList { |
| + tl := TestList{ |
| + Builder: ag.Builder, |
| + Tests: ag.Tests, |
| + } |
| + tl.Tests.WalkLeaves(func(_ string, leaf *AggregateTestLeaf) { |
|
Vadim Sh.
2016/08/16 18:36:28
is it ok that function that looks like a getter (T
|
| + leaf.Results = nil |
| + leaf.Runtimes = nil |
| + }) |
| + return tl |
| +} |
| + |
| // MarshalJSON marshal ag into JSON. |
| func (ag *AggregateResult) MarshalJSON() ([]byte, error) { |
| v, err := json.Marshal(ag.Version) |
| @@ -114,6 +143,18 @@ func (ag *AggregateResult) MarshalJSON() ([]byte, error) { |
| }) |
| } |
| +// extractBuilderName gets the builder name from the supplied map. |
| +// This depends on the fact that AggregateResults are expected to |
| +// only have two top-level keys: (1) "version" (2) the builder name. |
| +func extractBuilderName(m map[string]json.RawMessage) (string, error) { |
| + for k := range m { |
| + if k != "version" { |
| + return k, nil |
| + } |
| + } |
| + return "", errors.New("builder name not found") |
| +} |
| + |
| // UnmarshalJSON decodes JSON data into t. |
| // |
| // The expected format is a modified version of the format described in the URL |
| @@ -135,15 +176,18 @@ func (ag *AggregateResult) UnmarshalJSON(data []byte) error { |
| } |
| ag.Version = n |
| - // BuilderInfo. |
| + // Builder name. |
| - raw, ok := m[ag.Builder] |
| - if !ok { |
| - return fmt.Errorf("model: missing builder %q", ag.Builder) |
| + builder, err := extractBuilderName(m) |
| + if err != nil { |
| + return err |
| } |
| + ag.Builder = builder |
| + |
| + // BuilderInfo. |
| var info *BuilderInfo |
| - if err := json.Unmarshal(raw, &info); err != nil { |
| + if err := json.Unmarshal(m[builder], &info); err != nil { |
| return err |
| } |
| ag.BuilderInfo = info |
| @@ -177,7 +221,7 @@ type fieldError struct { |
| } |
| func (f *fieldError) Error() string { |
| - return fmt.Sprintf("model: field %q has invalid value: %v", f.Name, f.Value) |
| + return fmt.Sprintf("model: field %q has invalid value: %v (%T)", f.Name, f.Value, f.Value) |
| } |
| func (ag *AggregateResult) checkFields() error { |
| @@ -257,15 +301,6 @@ func (at AggregateTest) WalkLeaves(fn func(key string, leaf *AggregateTestLeaf)) |
| }) |
| } |
| -// ToTestList set the Results and Runtimes fields of all the |
| -// AggregateTestLeaf under the receiver AggregateTest to nil. |
| -func (at AggregateTest) ToTestList() { |
| - at.WalkLeaves(func(_ string, leaf *AggregateTestLeaf) { |
| - leaf.Results = nil |
| - leaf.Runtimes = nil |
| - }) |
| -} |
| - |
| // MarshalJSON marshals at into JSON. |
| func (at *AggregateTest) MarshalJSON() ([]byte, error) { |
| if at == nil { |
| @@ -334,7 +369,7 @@ func (at *AggregateTest) constructTree(m map[string]interface{}) error { |
| return nil |
| } |
| -// isAggregateTestLeaf returns true if the supplied map is likely represents a |
| +// isAggregateTestLeaf returns true if the supplied map is likely an |
| // AggregateTestLeaf. |
| func isAggregateTestLeaf(m map[string]interface{}) bool { |
| for key, val := range m { |
| @@ -376,7 +411,7 @@ type aggregateTestLeafAux struct { |
| Bugs []string `json:"bugs,omitempty"` |
| } |
| -// MarshalJSON marshal l into JSON. |
| +// MarshalJSON marshals leaf into JSON. |
| func (leaf *AggregateTestLeaf) MarshalJSON() ([]byte, error) { |
| aux := aggregateTestLeafAux{ |
| Results: leaf.Results, |
| @@ -389,7 +424,7 @@ func (leaf *AggregateTestLeaf) MarshalJSON() ([]byte, error) { |
| return json.Marshal(&aux) |
| } |
| -// UnmarshalJSON unmarshal the supplied data into l. |
| +// UnmarshalJSON unmarshals the supplied data into leaf. |
| func (leaf *AggregateTestLeaf) UnmarshalJSON(data []byte) error { |
| var aux aggregateTestLeafAux |
| if err := json.Unmarshal(data, &aux); err != nil { |
| @@ -654,7 +689,7 @@ func isDebugBuilder(builder string) bool { |
| return false |
| } |
| -// Trim trims the leaves of Tests in ar to the specified size. |
| +// Trim trims ag's fields to the specified size. |
| func (ag *AggregateResult) Trim(size int) error { |
| t := runtimeThresholdNormal |
| @@ -662,6 +697,11 @@ func (ag *AggregateResult) Trim(size int) error { |
| t = runtimeThresholdDebug |
| } |
| + ag.SecondsEpoch = ag.SecondsEpoch[:min(size, len(ag.SecondsEpoch))] |
| + ag.BlinkRevs = ag.BlinkRevs[:min(size, len(ag.BlinkRevs))] |
| + ag.ChromeRevs = ag.ChromeRevs[:min(size, len(ag.ChromeRevs))] |
| + ag.BuildNumbers = ag.BuildNumbers[:min(size, len(ag.BuildNumbers))] |
| + |
| return ag.Tests.trim(size, t) |
| } |