[testsharder] Introduce top-level Dimensions
Have an Environment only specify Swarming dimensions in a single
Dimensions struct.
Bug: IN-497
Change-Id: I8a6c91a1d457d7c676e3c46c65026b9ae4ea5d8e
diff --git a/fuchsia/testexec/environment.go b/fuchsia/testexec/environment.go
index acb3af9..0ae28a3 100644
--- a/fuchsia/testexec/environment.go
+++ b/fuchsia/testexec/environment.go
@@ -2,96 +2,55 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// We say that an Environment (or FooSpec) "resolves to" another if the
-// properties or constraints given by the former are also given by the latter.
-// This gives a partial ordering on environments expressing a subobject
-// relationship.
-//
-// The utility of being able to express that one environment is a
-// subenvironment of another lies in validation: an environment is valid if
-// it resolves to any member of a golden set of environments we refer to as
-// "platforms", as they correspond to the currently available test platforms
-// supported by the infrastructure.
-//
// The GN environments specified by test authors in the Fuchsia source
// correspond directly to the Environment struct defined here.
+//
+// Note that by "platforms" we mean a specific group of dimension sets which
+// correspond to the currently available test platforms supported by the
+// infrastructure.
package testexec
import (
"encoding/json"
"io/ioutil"
- "strings"
)
-// NameBuilder is a helper struct used to give names to environments. It
-// effectively concatenates all given tags with a dash, having replaced each
-// space with an underscore.
-type nameBuilder []string
-
-func (b *nameBuilder) addTags(tags ...string) {
- *b = append(*b, tags...)
-}
-
-func (b nameBuilder) getName() string {
- return strings.Replace(strings.Join(b, "-"), " ", "_", -1)
-}
-
// Environment describes the full environment a test requires.
type Environment struct {
- // Device represents properties of the device that are part of the test
- // environment.
- Device DeviceSpec `json:"device"`
+ // Dimensions gives the Swarming dimensions a test wishes to target.
+ Dimensions DimensionSet `json:"dimensions"`
}
-// Name returns a name calculated from its specfied properties. It is used to
-// give a human-readable identifier to a shard.
-// Names of different shards might coincide.
+// Name returns a name calculated from its specfied properties.
+// In the first iteration, this just returns the device type.
func (env Environment) Name() string {
- var b nameBuilder
- b.addTags(env.Device.name())
- return b.getName()
+ return env.Dimensions.DeviceType
}
-// ResolvesTo gives a partial ordering on environments in which one environment
-// resolves to another if the properties given by the former are also given by
-// the latter.
-func (env Environment) resolvesTo(other Environment) bool {
- if !env.Device.resolvesTo(other.Device) {
- return false
- }
- return true
-}
-
-// DeviceSpec describes the device environment a test requires.
-type DeviceSpec struct {
- // Type represents the class of device the test should run on.
+// DimensionSet encapsulate the Swarming dimensions a test wishes to target.
+type DimensionSet struct {
+ // DeviceType represents the class of device the test should run on.
// This is a required field.
- Type string `json:"type"`
+ DeviceType string `json:"device_type"`
}
-func (ds DeviceSpec) name() string {
- var b nameBuilder
- if ds.Type != "" {
- b.addTags(ds.Type)
- }
- return b.getName()
-}
-
-func (ds DeviceSpec) resolvesTo(other DeviceSpec) bool {
- if ds.Type != "" && ds.Type != other.Type {
+// ResolvesTo gives a partial ordering on DimensionSets in which one resolves to
+// another if the former's dimensions are given the latter.
+func (dims DimensionSet) resolvesTo(other DimensionSet) bool {
+ if dims.DeviceType != "" && dims.DeviceType != other.DeviceType {
return false
}
return true
}
-// LoadPlatforms loads the list of test platform environments specified as a
+// LoadPlatforms loads the list of test platform dimension sets specified as a
// JSON list at a given filepath.
-func LoadPlatforms(platformManifestPath string) ([]Environment, error) {
+func LoadPlatforms(platformManifestPath string) ([]DimensionSet, error) {
bytes, err := ioutil.ReadFile(platformManifestPath)
if err != nil {
return nil, err
}
- var platforms []Environment
+ var platforms []DimensionSet
if err = json.Unmarshal(bytes, &platforms); err != nil {
return nil, err
}
diff --git a/fuchsia/testexec/shard_test.go b/fuchsia/testexec/shard_test.go
index 8575cb2..46d319f 100644
--- a/fuchsia/testexec/shard_test.go
+++ b/fuchsia/testexec/shard_test.go
@@ -14,10 +14,10 @@
test1 := testexec.Test{Location: "/path/to/binary"}
test2 := testexec.Test{Location: "/path/to/binary2"}
env1 := testexec.Environment{
- Device: testexec.DeviceSpec{Type: "QEMU"},
+ Dimensions: testexec.DimensionSet{DeviceType: "QEMU"},
}
env2 := testexec.Environment{
- Device: testexec.DeviceSpec{Type: "NUC"},
+ Dimensions: testexec.DimensionSet{DeviceType: "NUC"},
}
spec1 := testexec.TestSpec{
Test: test1,
diff --git a/fuchsia/testexec/test_spec.go b/fuchsia/testexec/test_spec.go
index 94e6b48..159683d 100644
--- a/fuchsia/testexec/test_spec.go
+++ b/fuchsia/testexec/test_spec.go
@@ -13,28 +13,10 @@
"fuchsia.googlesource.com/infra/infra/fuchsia"
)
-// These are the default environments to be used if an author specifies none.
-//
-// TODO(IN-497) We include the NUC here as a tranistional policy. We will give
-// people a week from flag day to begin explicitly specifying their
-// environments, after which we will set the default as only QEMU.
-var defaultEnvs = []Environment{
- Environment{
- Device: DeviceSpec{
- Type: "QEMU",
- },
- },
- Environment{
- Device: DeviceSpec{
- Type: "Intel NUC Kit NUC7i5DNHE",
- },
- },
-}
-
// TestSpec is the specification for a single test and the environments it
// should be executed in.
type TestSpec struct {
- // Test is the test that this specuration is for.
+ // Test is the test that this specification is for.
Test `json:"test"`
// Envs is a set of environments that the test should be executed in.
@@ -52,7 +34,7 @@
Location string `json:"location"`
}
-func (spec TestSpec) validateAgainst(platforms []Environment) error {
+func (spec TestSpec) validateAgainst(platforms []DimensionSet) error {
if spec.Test.Name == "" {
return fmt.Errorf("A test spec's test must have a non-empty name")
}
@@ -60,9 +42,9 @@
return fmt.Errorf("A test spec's test must have a non-empty location")
}
- resolvesToOneOf := func(env Environment, platforms []Environment) bool {
+ resolvesToOneOf := func(env Environment, platforms []DimensionSet) bool {
for _, platform := range platforms {
- if env.resolvesTo(platform) {
+ if env.Dimensions.resolvesTo(platform) {
return true
}
}
@@ -85,8 +67,8 @@
}
// ValidateTestSpecs validates a list of test specs against a list of test
-// platform environments.
-func ValidateTestSpecs(specs []TestSpec, platforms []Environment) error {
+// platform dimension sets.
+func ValidateTestSpecs(specs []TestSpec, platforms []DimensionSet) error {
errMsg := ""
for _, spec := range specs {
if err := spec.validateAgainst(platforms); err != nil {
@@ -159,9 +141,6 @@
if err := json.NewDecoder(f).Decode(&spec); err != nil {
return nil, fmt.Errorf("failed to decode %s: %s", path, err.Error())
}
- if len(spec.Envs) == 0 {
- spec.Envs = defaultEnvs
- }
specs = append(specs, spec)
}
}
diff --git a/fuchsia/testexec/test_spec_test.go b/fuchsia/testexec/test_spec_test.go
index 6a4288a..46862ad 100644
--- a/fuchsia/testexec/test_spec_test.go
+++ b/fuchsia/testexec/test_spec_test.go
@@ -17,16 +17,20 @@
"fuchsia.googlesource.com/infra/infra/fuchsia/testexec"
)
+var qemuPlatform = testexec.DimensionSet{
+ DeviceType: "QEMU",
+}
+
+var nucPlatform = testexec.DimensionSet{
+ DeviceType: "NUC",
+}
+
var qemuEnv = testexec.Environment{
- Device: testexec.DeviceSpec{
- Type: "QEMU",
- },
+ Dimensions: qemuPlatform,
}
var nucEnv = testexec.Environment{
- Device: testexec.DeviceSpec{
- Type: "NUC",
- },
+ Dimensions: nucPlatform,
}
var specFoo1 = testexec.TestSpec{
@@ -229,13 +233,13 @@
},
Envs: []testexec.Environment{
testexec.Environment{
- Device: testexec.DeviceSpec{
- Type: "NON-EXISTENT-DEVICE",
+ Dimensions: testexec.DimensionSet{
+ DeviceType: "NON-EXISTENT-DEVICE",
},
},
},
}
- platforms := []testexec.Environment{qemuEnv, nucEnv}
+ platforms := []testexec.DimensionSet{qemuPlatform, nucPlatform}
t.Run("valid specs are validated", func(t *testing.T) {
validSpecLists := [][]testexec.TestSpec{
diff --git a/testsharder b/testsharder
new file mode 100755
index 0000000..0addd55
--- /dev/null
+++ b/testsharder
Binary files differ