Skip to content

Commit

Permalink
Merge pull request #1267 from bryan-lou/bryan-cell-metrics
Browse files Browse the repository at this point in the history
Add cell metrics to resultstore
  • Loading branch information
google-oss-prow[bot] authored Nov 27, 2023
2 parents 2c7f95e + f7d0e90 commit c4fba0a
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 1 deletion.
5 changes: 4 additions & 1 deletion pkg/updater/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -526,9 +526,12 @@ func overallCell(result gcsResult) Cell {
return c
}

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

// TestMethodsElapsedKey is the key for the test results duration metric.
const TestMethodsElapsedKey = "test-methods-duration-minutes"

// setElapsed inserts the seconds-elapsed metric.
func setElapsed(metrics map[string]float64, seconds float64) map[string]float64 {
if metrics == nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/updater/resultstore/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ go_test(
"@com_github_google_go_cmp//cmp/cmpopts:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@go_googleapis//google/devtools/resultstore/v2:resultstore_go_proto",
"@io_bazel_rules_go//proto/wkt:duration_go_proto",
"@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_google_protobuf//testing/protocmp:go_default_library",
Expand Down
65 changes: 65 additions & 0 deletions pkg/updater/resultstore/resultstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ func processGroup(tg *configpb.TestGroup, group *invocationGroup) *updater.Infla
}
}

cell.Metrics = calculateMetrics(sar)

// TODO (@bryanlou) check if we need to include properties from the target in addition to test cases
properties := map[string][]string{}
testSuite := sar.ActionProto.GetTestAction().GetTestSuite()
Expand Down Expand Up @@ -536,6 +538,69 @@ func processGroup(tg *configpb.TestGroup, group *invocationGroup) *updater.Infla
return col
}

// calculateMetrics calculates the numeric metrics (properties), test results
// and a target for singleActionResult and stores the duration in a map
func calculateMetrics(sar *singleActionResult) map[string]float64 {
properties := map[string][]string{}
testResultProperties(properties, sar.ActionProto.GetTestAction().GetTestSuite())
numerics := updater.Means(properties)
targetElapsed := sar.TargetProto.GetTiming().GetDuration().AsDuration()
if targetElapsed > 0 {
numerics[updater.ElapsedKey] = targetElapsed.Minutes()
}

if dur := testResultDuration(sar.ActionProto.GetTestAction().GetTestSuite()); dur > 0 {
numerics[updater.TestMethodsElapsedKey] = dur.Minutes()
}

return numerics
}

// testResultProperties recursively inserts all result and its children's properties into the map.
func testResultProperties(properties map[string][]string, suite *resultstorepb.TestSuite) {

if suite == nil {
return
}

// add parent suite properties
for _, p := range suite.GetProperties() {
properties[p.GetKey()] = append(properties[p.GetKey()], p.GetValue())
}

// add test case properties
for _, test := range suite.GetTests() {
if tc := test.GetTestCase(); tc != nil {
for _, p := range tc.GetProperties() {
properties[p.GetKey()] = append(properties[p.GetKey()], p.GetValue())
}
} else {
testResultProperties(properties, test.GetTestSuite())
}
}
}

// testResultDuration calculates the overall duration of test results.
func testResultDuration(suite *resultstorepb.TestSuite) time.Duration {
var totalDur time.Duration
if suite == nil {
return totalDur
}

if dur := suite.GetTiming().GetDuration().AsDuration(); dur > 0 {
return dur
}

for _, test := range suite.GetTests() {
if tc := test.GetTestCase(); tc != nil {
totalDur += tc.GetTiming().GetDuration().AsDuration()
} else {
totalDur += testResultDuration(test.GetTestSuite())
}
}
return totalDur
}

// filterProperties returns the subset of results containing all the specified properties.
func filterProperties(results []*resultstorepb.Test, properties []*configpb.TestGroup_KeyValue) []*resultstorepb.Test {
if len(properties) == 0 {
Expand Down
168 changes: 168 additions & 0 deletions pkg/updater/resultstore/resultstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
statepb "github.com/GoogleCloudPlatform/testgrid/pb/state"
teststatuspb "github.com/GoogleCloudPlatform/testgrid/pb/test_status"
"github.com/GoogleCloudPlatform/testgrid/pkg/updater"
durationpb "github.com/golang/protobuf/ptypes/duration"
timestamppb "github.com/golang/protobuf/ptypes/timestamp"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
Expand Down Expand Up @@ -3372,3 +3373,170 @@ func TestCompileHeaders(t *testing.T) {
})
}
}

func TestCalculateMetrics(t *testing.T) {
cases := []struct {
name string
sar *singleActionResult
want map[string]float64
}{
{
name: "no numeric properties, no duration",
sar: &singleActionResult{
ActionProto: &resultstore.Action{
ActionType: &resultstore.Action_TestAction{
TestAction: &resultstore.TestAction{
TestSuite: &resultstore.TestSuite{
Properties: []*resultstore.Property{
{Key: "marco", Value: "polo"},
},
},
},
},
},
},
want: map[string]float64{},
},
{
name: "no numeric properties, suite duration",
sar: &singleActionResult{
ActionProto: &resultstore.Action{
ActionType: &resultstore.Action_TestAction{
TestAction: &resultstore.TestAction{
TestSuite: &resultstore.TestSuite{
Properties: []*resultstore.Property{
{Key: "marco", Value: "polo"},
},
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 120,
},
},
},
},
},
},
},
want: map[string]float64{
updater.TestMethodsElapsedKey: 2,
},
},
{
name: "no numeric properties, cases duration only",
sar: &singleActionResult{
ActionProto: &resultstore.Action{
ActionType: &resultstore.Action_TestAction{
TestAction: &resultstore.TestAction{
TestSuite: &resultstore.TestSuite{
Properties: []*resultstore.Property{
{Key: "marco", Value: "polo"},
},
Tests: []*resultstore.Test{
{
TestType: &resultstore.Test_TestCase{
TestCase: &resultstore.TestCase{
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 60,
},
},
},
},
},
{
TestType: &resultstore.Test_TestCase{
TestCase: &resultstore.TestCase{
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 60,
},
},
},
},
},
},
},
},
},
},
},
want: map[string]float64{
updater.TestMethodsElapsedKey: 2,
},
},
{
name: "numeric properties and durations",
sar: &singleActionResult{
ActionProto: &resultstore.Action{
ActionType: &resultstore.Action_TestAction{
TestAction: &resultstore.TestAction{
TestSuite: &resultstore.TestSuite{
Properties: []*resultstore.Property{
{Key: "pizza", Value: "12"},
},
Tests: []*resultstore.Test{
{
TestType: &resultstore.Test_TestCase{
TestCase: &resultstore.TestCase{
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 60,
},
},
Properties: []*resultstore.Property{
{Key: "pizza", Value: "6"},
},
},
},
},
{
TestType: &resultstore.Test_TestCase{
TestCase: &resultstore.TestCase{
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 60,
},
},
Properties: []*resultstore.Property{
{Key: "pizza", Value: "6"},
},
},
},
},
},
},
},
},
},
},
want: map[string]float64{
"pizza": 8,
updater.TestMethodsElapsedKey: 2,
},
},
{
name: "numeric properties and durations",
sar: &singleActionResult{
TargetProto: &resultstore.Target{
Timing: &resultstore.Timing{
Duration: &durationpb.Duration{
Seconds: 600,
},
},
},
},
want: map[string]float64{
updater.ElapsedKey: 10,
},
},
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
got := calculateMetrics(tc.sar)
if diff := cmp.Diff(tc.want, got); diff != "" {
t.Fatalf("calculateMetrics(...) differed (-want,+got): %s", diff)
}
})
}
}

0 comments on commit c4fba0a

Please sign in to comment.