Sitelet https://github.com/GoogleCloudPlatform/testgrid/commit/c4fba0a8cb22f048b5336fa9b2934df80ea938b1
Skip to content

Commit c4fba0a

Browse files
Merge pull request #1267 from bryan-lou/bryan-cell-metrics
Add cell metrics to resultstore
2 parents 2c7f95e + f7d0e90 commit c4fba0a

4 files changed

Lines changed: 238 additions & 1 deletion

File tree

‎pkg/updater/gcs.go‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,12 @@ func overallCell(result gcsResult) Cell {
526526
return c
527527
}
528528

529-
// ElapsedKey is the key for the test duration metric.
529+
// ElapsedKey is the key for the target duration metric.
530530
const ElapsedKey = "test-duration-minutes"
531531

532+
// TestMethodsElapsedKey is the key for the test results duration metric.
533+
const TestMethodsElapsedKey = "test-methods-duration-minutes"
534+
532535
// setElapsed inserts the seconds-elapsed metric.
533536
func setElapsed(metrics map[string]float64, seconds float64) map[string]float64 {
534537
if metrics == nil {

‎pkg/updater/resultstore/BUILD.bazel‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ go_test(
3939
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
4040
"@com_github_sirupsen_logrus//:go_default_library",
4141
"@go_googleapis//google/devtools/resultstore/v2:resultstore_go_proto",
42+
"@io_bazel_rules_go//proto/wkt:duration_go_proto",
4243
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
4344
"@org_golang_google_grpc//:go_default_library",
4445
"@org_golang_google_protobuf//testing/protocmp:go_default_library",

‎pkg/updater/resultstore/resultstore.go‎

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,8 @@ func processGroup(tg *configpb.TestGroup, group *invocationGroup) *updater.Infla
508508
}
509509
}
510510

511+
cell.Metrics = calculateMetrics(sar)
512+
511513
// TODO (@bryanlou) check if we need to include properties from the target in addition to test cases
512514
properties := map[string][]string{}
513515
testSuite := sar.ActionProto.GetTestAction().GetTestSuite()
@@ -536,6 +538,69 @@ func processGroup(tg *configpb.TestGroup, group *invocationGroup) *updater.Infla
536538
return col
537539
}
538540

541+
// calculateMetrics calculates the numeric metrics (properties), test results
542+
// and a target for singleActionResult and stores the duration in a map
543+
func calculateMetrics(sar *singleActionResult) map[string]float64 {
544+
properties := map[string][]string{}
545+
testResultProperties(properties, sar.ActionProto.GetTestAction().GetTestSuite())
546+
numerics := updater.Means(properties)
547+
targetElapsed := sar.TargetProto.GetTiming().GetDuration().AsDuration()
548+
if targetElapsed > 0 {
549+
numerics[updater.ElapsedKey] = targetElapsed.Minutes()
550+
}
551+
552+
if dur := testResultDuration(sar.ActionProto.GetTestAction().GetTestSuite()); dur > 0 {
553+
numerics[updater.TestMethodsElapsedKey] = dur.Minutes()
554+
}
555+
556+
return numerics
557+
}
558+
559+
// testResultProperties recursively inserts all result and its children's properties into the map.
560+
func testResultProperties(properties map[string][]string, suite *resultstorepb.TestSuite) {
561+
562+
if suite == nil {
563+
return
564+
}
565+
566+
// add parent suite properties
567+
for _, p := range suite.GetProperties() {
568+
properties[p.GetKey()] = append(properties[p.GetKey()], p.GetValue())
569+
}
570+
571+
// add test case properties
572+
for _, test := range suite.GetTests() {
573+
if tc := test.GetTestCase(); tc != nil {
574+
for _, p := range tc.GetProperties() {
575+
properties[p.GetKey()] = append(properties[p.GetKey()], p.GetValue())
576+
}
577+
} else {
578+
testResultProperties(properties, test.GetTestSuite())
579+
}
580+
}
581+
}
582+
583+
// testResultDuration calculates the overall duration of test results.
584+
func testResultDuration(suite *resultstorepb.TestSuite) time.Duration {
585+
var totalDur time.Duration
586+
if suite == nil {
587+
return totalDur
588+
}
589+
590+
if dur := suite.GetTiming().GetDuration().AsDuration(); dur > 0 {
591+
return dur
592+
}
593+
594+
for _, test := range suite.GetTests() {
595+
if tc := test.GetTestCase(); tc != nil {
596+
totalDur += tc.GetTiming().GetDuration().AsDuration()
597+
} else {
598+
totalDur += testResultDuration(test.GetTestSuite())
599+
}
600+
}
601+
return totalDur
602+
}
603+
539604
// filterProperties returns the subset of results containing all the specified properties.
540605
func filterProperties(results []*resultstorepb.Test, properties []*configpb.TestGroup_KeyValue) []*resultstorepb.Test {
541606
if len(properties) == 0 {

‎pkg/updater/resultstore/resultstore_test.go‎

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
statepb "github.com/GoogleCloudPlatform/testgrid/pb/state"
3131
teststatuspb "github.com/GoogleCloudPlatform/testgrid/pb/test_status"
3232
"github.com/GoogleCloudPlatform/testgrid/pkg/updater"
33+
durationpb "github.com/golang/protobuf/ptypes/duration"
3334
timestamppb "github.com/golang/protobuf/ptypes/timestamp"
3435
"github.com/google/go-cmp/cmp"
3536
"github.com/google/go-cmp/cmp/cmpopts"
@@ -3372,3 +3373,170 @@ func TestCompileHeaders(t *testing.T) {
33723373
})
33733374
}
33743375
}
3376+
3377+
func TestCalculateMetrics(t *testing.T) {
3378+
cases := []struct {
3379+
name string
3380+
sar *singleActionResult
3381+
want map[string]float64
3382+
}{
3383+
{
3384+
name: "no numeric properties, no duration",
3385+
sar: &singleActionResult{
3386+
ActionProto: &resultstore.Action{
3387+
ActionType: &resultstore.Action_TestAction{
3388+
TestAction: &resultstore.TestAction{
3389+
TestSuite: &resultstore.TestSuite{
3390+
Properties: []*resultstore.Property{
3391+
{Key: "marco", Value: "polo"},
3392+
},
3393+
},
3394+
},
3395+
},
3396+
},
3397+
},
3398+
want: map[string]float64{},
3399+
},
3400+
{
3401+
name: "no numeric properties, suite duration",
3402+
sar: &singleActionResult{
3403+
ActionProto: &resultstore.Action{
3404+
ActionType: &resultstore.Action_TestAction{
3405+
TestAction: &resultstore.TestAction{
3406+
TestSuite: &resultstore.TestSuite{
3407+
Properties: []*resultstore.Property{
3408+
{Key: "marco", Value: "polo"},
3409+
},
3410+
Timing: &resultstore.Timing{
3411+
Duration: &durationpb.Duration{
3412+
Seconds: 120,
3413+
},
3414+
},
3415+
},
3416+
},
3417+
},
3418+
},
3419+
},
3420+
want: map[string]float64{
3421+
updater.TestMethodsElapsedKey: 2,
3422+
},
3423+
},
3424+
{
3425+
name: "no numeric properties, cases duration only",
3426+
sar: &singleActionResult{
3427+
ActionProto: &resultstore.Action{
3428+
ActionType: &resultstore.Action_TestAction{
3429+
TestAction: &resultstore.TestAction{
3430+
TestSuite: &resultstore.TestSuite{
3431+
Properties: []*resultstore.Property{
3432+
{Key: "marco", Value: "polo"},
3433+
},
3434+
Tests: []*resultstore.Test{
3435+
{
3436+
TestType: &resultstore.Test_TestCase{
3437+
TestCase: &resultstore.TestCase{
3438+
Timing: &resultstore.Timing{
3439+
Duration: &durationpb.Duration{
3440+
Seconds: 60,
3441+
},
3442+
},
3443+
},
3444+
},
3445+
},
3446+
{
3447+
TestType: &resultstore.Test_TestCase{
3448+
TestCase: &resultstore.TestCase{
3449+
Timing: &resultstore.Timing{
3450+
Duration: &durationpb.Duration{
3451+
Seconds: 60,
3452+
},
3453+
},
3454+
},
3455+
},
3456+
},
3457+
},
3458+
},
3459+
},
3460+
},
3461+
},
3462+
},
3463+
want: map[string]float64{
3464+
updater.TestMethodsElapsedKey: 2,
3465+
},
3466+
},
3467+
{
3468+
name: "numeric properties and durations",
3469+
sar: &singleActionResult{
3470+
ActionProto: &resultstore.Action{
3471+
ActionType: &resultstore.Action_TestAction{
3472+
TestAction: &resultstore.TestAction{
3473+
TestSuite: &resultstore.TestSuite{
3474+
Properties: []*resultstore.Property{
3475+
{Key: "pizza", Value: "12"},
3476+
},
3477+
Tests: []*resultstore.Test{
3478+
{
3479+
TestType: &resultstore.Test_TestCase{
3480+
TestCase: &resultstore.TestCase{
3481+
Timing: &resultstore.Timing{
3482+
Duration: &durationpb.Duration{
3483+
Seconds: 60,
3484+
},
3485+
},
3486+
Properties: []*resultstore.Property{
3487+
{Key: "pizza", Value: "6"},
3488+
},
3489+
},
3490+
},
3491+
},
3492+
{
3493+
TestType: &resultstore.Test_TestCase{
3494+
TestCase: &resultstore.TestCase{
3495+
Timing: &resultstore.Timing{
3496+
Duration: &durationpb.Duration{
3497+
Seconds: 60,
3498+
},
3499+
},
3500+
Properties: []*resultstore.Property{
3501+
{Key: "pizza", Value: "6"},
3502+
},
3503+
},
3504+
},
3505+
},
3506+
},
3507+
},
3508+
},
3509+
},
3510+
},
3511+
},
3512+
want: map[string]float64{
3513+
"pizza": 8,
3514+
updater.TestMethodsElapsedKey: 2,
3515+
},
3516+
},
3517+
{
3518+
name: "numeric properties and durations",
3519+
sar: &singleActionResult{
3520+
TargetProto: &resultstore.Target{
3521+
Timing: &resultstore.Timing{
3522+
Duration: &durationpb.Duration{
3523+
Seconds: 600,
3524+
},
3525+
},
3526+
},
3527+
},
3528+
want: map[string]float64{
3529+
updater.ElapsedKey: 10,
3530+
},
3531+
},
3532+
}
3533+
3534+
for _, tc := range cases {
3535+
t.Run(tc.name, func(t *testing.T) {
3536+
got := calculateMetrics(tc.sar)
3537+
if diff := cmp.Diff(tc.want, got); diff != "" {
3538+
t.Fatalf("calculateMetrics(...) differed (-want,+got): %s", diff)
3539+
}
3540+
})
3541+
}
3542+
}

0 commit comments

Comments
 (0)