Chromium Code Reviews| Index: go/src/infra/appengine/test-results/model/trim.go |
| diff --git a/go/src/infra/appengine/test-results/model/trim.go b/go/src/infra/appengine/test-results/model/trim.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..03bd251e60f99af9b706021bce7917f37868cd1c |
| --- /dev/null |
| +++ b/go/src/infra/appengine/test-results/model/trim.go |
| @@ -0,0 +1,117 @@ |
| +package model |
| + |
| +import ( |
| + "errors" |
| + "strings" |
| +) |
| + |
| +const ( |
| + // ResultsSize is the size that "results.json" should be trimmed to. |
| + ResultsSize = 500 |
| + |
| + // ResultsSmallSize is the size that "results_small.json" should |
| + // be trimmed to. |
| + ResultsSmallSize = 100 |
| + |
| + runtimeThresholdNormal float64 = 3 |
| + runtimeThresholdDebug float64 = 9 |
| +) |
| + |
| +func isDebugBuilder(builder string) bool { |
| + for _, s := range []string{"debug", "dbg"} { |
| + if strings.Contains(strings.ToLower(builder), s) { |
| + return true |
| + } |
| + } |
| + return false |
| +} |
| + |
| +// Trim trims the leaves of Tests in ar to the specified size. |
| +func (ar *AggregateResult) Trim(size int) error { |
| + t := runtimeThresholdNormal |
| + |
| + if isDebugBuilder(ar.Builder) { |
| + t = runtimeThresholdDebug |
| + } |
| + |
| + return ar.Tests.trim(size, t) |
| +} |
| + |
| +func (at AggregateTest) trim(size int, threshold float64) error { |
| + for k, v := range at { |
| + if leaf, ok := v.(*AggregateTestLeaf); ok { |
| + leaf.trim(size) |
| + if leaf.shouldDelete(threshold) { |
| + delete(at, k) |
| + } |
| + continue |
| + } |
| + |
| + child, ok := v.(AggregateTest) |
| + if !ok { |
| + return errors.New("model: trim: expected AggregateTest") |
| + } |
| + if err := child.trim(size, threshold); err != nil { |
| + return err |
| + } |
| + if len(child) == 0 { |
| + delete(at, k) |
| + } |
| + } |
| + return nil |
| +} |
| + |
| +func (leaf *AggregateTestLeaf) trim(size int) { |
|
martiniss
2016/08/12 00:14:24
why is size an int here, but threshold is declared
nishanths
2016/08/12 02:37:40
threshold is a float because it is used to compare
|
| + n := 0 |
| + |
| + for i, r := range leaf.Results { |
| + leaf.Results[i].Count = min(r.Count, size) |
| + n += r.Count |
| + if n >= size { |
| + leaf.Results = leaf.Results[:i+1] |
| + break |
| + } |
| + } |
| + |
| + n = 0 |
| + |
| + for i, r := range leaf.Runtimes { |
| + leaf.Runtimes[i].Count = min(r.Count, size) |
| + n += r.Count |
| + if n >= size { |
| + leaf.Runtimes = leaf.Runtimes[:i+1] |
| + break |
| + } |
| + } |
| +} |
| + |
| +func min(a, b int) int { |
| + if a < b { |
| + return a |
| + } |
| + return b |
| +} |
| + |
| +var deletableTypes = map[string]bool{"P": true, "N": true, "Y": true} |
| + |
| +func (leaf *AggregateTestLeaf) shouldDelete(threshold float64) bool { |
| + if len(leaf.Expected) == 1 && leaf.Expected[0] != "PASS" { |
| + return false |
| + } |
| + if leaf.Bugs != nil { |
| + return false |
| + } |
| + |
| + for _, r := range leaf.Results { |
| + if !deletableTypes[r.Type] { |
| + return false |
| + } |
| + } |
| + for _, r := range leaf.Runtimes { |
| + if r.Runtime >= threshold { |
| + return false |
| + } |
| + } |
| + |
| + return true |
| +} |