testplan: Replace proto.MessageReflect with standard Go reflect.
- The dev-go/protobuf ebuild installs v1.3.2 of the
github.com/golang/protobuf package, which does not contain the
MessageReflect function. Bumping the version of this package broke
dependent packages. Use the standard reflect package instead.
- In the future, a better fix might be fixing the dependent
packages or installing multiple versions of the protobuf package.
BUG=b:189223005
TEST=`emerge test-plan`
TEST=`go test ./...`
Change-Id: Iabec1dc81f1d80cf88867563325bab18d733217b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/dev-util/+/2949113
Reviewed-by: Jaques Clapauch <jaquesc@google.com>
Reviewed-by: C Shapiro <shapiroc@chromium.org>
Commit-Queue: Andrew Lamb <andrewlamb@chromium.org>
Tested-by: Andrew Lamb <andrewlamb@chromium.org>
diff --git a/src/chromiumos/test/plan/internal/coveragerules/coveragerules.go b/src/chromiumos/test/plan/internal/coveragerules/coveragerules.go
index 7002fd9..37010e7 100644
--- a/src/chromiumos/test/plan/internal/coveragerules/coveragerules.go
+++ b/src/chromiumos/test/plan/internal/coveragerules/coveragerules.go
@@ -7,15 +7,15 @@
import (
"fmt"
+ "reflect"
+ "strings"
"github.com/golang/glog"
- "github.com/golang/protobuf/proto"
configpb "go.chromium.org/chromiumos/config/go/api"
buildpb "go.chromium.org/chromiumos/config/go/build/api"
testpb "go.chromium.org/chromiumos/config/go/test/api"
"go.chromium.org/chromiumos/config/go/test/plan"
"go.chromium.org/luci/common/data/stringset"
- "google.golang.org/protobuf/reflect/protoreflect"
)
var (
@@ -310,11 +310,6 @@
return nil
}
-// typeName is a convenience function for the FullName of m.
-func typeName(m proto.Message) protoreflect.FullName {
- return proto.MessageReflect(m).Descriptor().FullName()
-}
-
// Generate computes a list of CoverageRules, based on sourceTestPlan and
// buildSummaryList.
func Generate(
@@ -329,50 +324,65 @@
//
// Return an error if no requirements are set, or a requirement is
// unimplemented.
- var unimplementedReq protoreflect.FieldDescriptor
hasRequirement := false
- proto.MessageReflect(sourceTestPlan.Requirements).Range(
- func(fd protoreflect.FieldDescriptor, _ protoreflect.Value) bool {
+ reqs := sourceTestPlan.Requirements
+ if reqs != nil {
+ // As of 6/9/2021, the dev-go/protobuf ebuild installs v1.3.2 of the
+ // github.com/golang/protobuf package, which does not contain the
+ // MessageReflect function.
+ //
+ // Bumping the version of this package broke dependent packages. Use the
+ // standard reflect package instead.
+ //
+ // TODO(b/189223005): Fix dependent package or install multiple versions
+ // of the protobuf package.
+ reqsValue := reflect.ValueOf(*reqs)
+
+ for i := 0; i < reqsValue.NumField(); i++ {
+ fieldValue := reqsValue.Field(i)
+
+ // All Requirements should be messages, so pointers to structs in
+ // the generated Go. Use IsZero to check if they are set (even if
+ // no fields within them are set).
+ if fieldValue.Kind() != reflect.Ptr || fieldValue.IsZero() {
+ continue
+ }
+
hasRequirement = true
- // It is not possible to do a type switch on the FieldDescriptor or
- // Value, so switch on the full type name.
- switch fd.Message().FullName() {
- case typeName(&plan.SourceTestPlan_Requirements_ArcVersions{}):
+ // Get the type name of the field, removing "*plan.", for use in log
+ // and error messages.
+ typeName := strings.ReplaceAll(fieldValue.Type().String(), "*plan.", "")
+
+ switch fieldValue.Interface().(type) {
+ case *plan.SourceTestPlan_Requirements_ArcVersions:
coverageRules = expandCoverageRules(coverageRules, arcCoverageRules(sourceTestPlan, buildSummaryList))
- case typeName(&plan.SourceTestPlan_Requirements_KernelVersions{}):
+ case *plan.SourceTestPlan_Requirements_KernelVersions:
coverageRules = expandCoverageRules(coverageRules, kernelCoverageRules(sourceTestPlan, buildSummaryList))
- case typeName(&plan.SourceTestPlan_Requirements_SocFamilies{}):
+ case *plan.SourceTestPlan_Requirements_SocFamilies:
coverageRules = expandCoverageRules(coverageRules, socCoverageRules(sourceTestPlan, buildSummaryList))
- case typeName(&plan.SourceTestPlan_Requirements_Fingerprint{}):
+ case *plan.SourceTestPlan_Requirements_Fingerprint:
coverageRules = expandCoverageRules(
coverageRules, []*testpb.CoverageRule{fingerprintCoverageRule(sourceTestPlan)},
)
default:
- unimplementedReq = fd
- return false
+ return nil, fmt.Errorf("unimplemented requirement %q", typeName)
}
- glog.V(1).Infof("Added CoverageRules for %s, now have %d CoverageRules", fd.Message().FullName(), len(coverageRules))
-
- return true
- },
- )
+ glog.V(1).Infof("Added CoverageRules for %q, now have %d CoverageRules", typeName, len(coverageRules))
+ }
+ }
if !hasRequirement {
return nil, fmt.Errorf("at least one requirement must be set in SourceTestPlan: %v", sourceTestPlan)
}
- if unimplementedReq != nil {
- return nil, fmt.Errorf("unimplemented requirement %q", unimplementedReq.Name())
- }
-
if err := checkDutAttributesValid(coverageRules, dutAttributeList); err != nil {
return nil, err
}
diff --git a/src/chromiumos/test/plan/internal/coveragerules/coveragerules_test.go b/src/chromiumos/test/plan/internal/coveragerules/coveragerules_test.go
index b41af85..9816942 100644
--- a/src/chromiumos/test/plan/internal/coveragerules/coveragerules_test.go
+++ b/src/chromiumos/test/plan/internal/coveragerules/coveragerules_test.go
@@ -5,6 +5,7 @@
import (
"chromiumos/test/plan/internal/coveragerules"
+ "strings"
"testing"
"github.com/google/go-cmp/cmp"
@@ -402,6 +403,7 @@
name string
input *plan.SourceTestPlan
dutAttributeList *testpb.DutAttributeList
+ expectedError string
}{
{
name: "no requirements",
@@ -411,6 +413,28 @@
},
},
dutAttributeList: dutAttributeList,
+ expectedError: "at least one requirement must be set in SourceTestPlan",
+ },
+ {
+ name: "empty requirements",
+ input: &plan.SourceTestPlan{
+ EnabledTestEnvironments: []plan.SourceTestPlan_TestEnvironment{
+ plan.SourceTestPlan_HARDWARE,
+ },
+ Requirements: &plan.SourceTestPlan_Requirements{},
+ },
+ dutAttributeList: dutAttributeList,
+ expectedError: "at least one requirement must be set in SourceTestPlan",
+ },
+ {
+ name: "unimplemented requirement",
+ input: &plan.SourceTestPlan{
+ Requirements: &plan.SourceTestPlan_Requirements{
+ ChromeosConfig: &plan.SourceTestPlan_Requirements_ChromeOSConfig{},
+ },
+ },
+ dutAttributeList: dutAttributeList,
+ expectedError: `unimplemented requirement "SourceTestPlan_Requirements_ChromeOSConfig"`,
},
{
name: "invalid dut attributes",
@@ -432,6 +456,7 @@
},
},
},
+ expectedError: "CoverageRule contains invalid DutAttributes",
},
}
for _, test := range tests {
@@ -440,6 +465,8 @@
test.input, buildSummaryList, test.dutAttributeList,
); err == nil {
t.Errorf("Expected error from coveragerules.Generate")
+ } else if !strings.Contains(err.Error(), test.expectedError) {
+ t.Errorf("Got error %q, wanted error to contain %q", err.Error(), test.expectedError)
}
})
}