From ca1213a1bcbda234fe18522ab8792019fbb16960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Barcarol=20Guimar=C3=A3es?= Date: Tue, 20 Aug 2019 11:50:20 +0000 Subject: [PATCH 1/2] ci-operator: remove unused test function --- pkg/api/config_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/pkg/api/config_test.go b/pkg/api/config_test.go index bfae3ae89e0..d3fd5d32d4a 100644 --- a/pkg/api/config_test.go +++ b/pkg/api/config_test.go @@ -385,10 +385,6 @@ func TestValidateBaseRpmImages(t *testing.T) { } } -func parseError(id string, err error) error { - return fmt.Errorf("%q expected to be valid, got 'Error(%v)' instead", id, err) -} - func parseValidError(id string) error { return fmt.Errorf("%q expected to be invalid, but returned valid", id) } From 440a9bea7bb33b09ab19a0bbd390b485cc339ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Barcarol=20Guimar=C3=A3es?= Date: Mon, 22 Jul 2019 18:45:10 +0000 Subject: [PATCH 2/2] ci-operator: add TestStep type --- pkg/api/config.go | 23 +++++++++ pkg/api/config_test.go | 105 +++++++++++++++++++++++++++++++++++++++++ pkg/api/types.go | 8 ++++ 3 files changed, 136 insertions(+) diff --git a/pkg/api/config.go b/pkg/api/config.go index 7ba88d90a4c..07ab71708bc 100644 --- a/pkg/api/config.go +++ b/pkg/api/config.go @@ -9,6 +9,7 @@ import ( "strings" "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/util/sets" ) // ValidateAtRuntime validates all the configuration's values without knowledge of config @@ -286,6 +287,28 @@ func validateTestConfigurationType(fieldRoot string, test TestStepConfiguration, return validationErrors } +func validateTestSteps(fieldRoot string, steps []TestStep) (ret []error) { + seen := sets.NewString() + for i, s := range steps { + fieldRootI := fmt.Sprintf("%s[%d]", fieldRoot, i) + if len(s.Name) == 0 { + ret = append(ret, fmt.Errorf("%s: `name` is required", fieldRootI)) + } else if seen.Has(s.Name) { + ret = append(ret, fmt.Errorf("%s: duplicated name %q", fieldRootI, s.Name)) + } else { + seen.Insert(s.Name) + } + if len(s.Image) == 0 { + ret = append(ret, fmt.Errorf("%s: `image` is required", fieldRootI)) + } + if len(s.Commands) == 0 { + ret = append(ret, fmt.Errorf("%s: `commands` is required", fieldRootI)) + } + ret = append(ret, validateResourceRequirements(fieldRootI+".resources", s.Resources)...) + } + return +} + func validateReleaseBuildConfiguration(input *ReleaseBuildConfiguration, org, repo string) []error { var validationErrors []error diff --git a/pkg/api/config_test.go b/pkg/api/config_test.go index d3fd5d32d4a..09ce7962f5c 100644 --- a/pkg/api/config_test.go +++ b/pkg/api/config_test.go @@ -1,9 +1,12 @@ package api import ( + "errors" "fmt" + "reflect" "testing" + "k8s.io/apimachinery/pkg/util/diff" kerrors "k8s.io/apimachinery/pkg/util/errors" ) @@ -385,6 +388,108 @@ func TestValidateBaseRpmImages(t *testing.T) { } } +func TestValidateTestSteps(t *testing.T) { + for _, tc := range []struct { + name string + steps []TestStep + errs []error + }{{ + name: "valid step", + steps: []TestStep{{ + Name: "name", + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }}, + }, { + name: "no name", + steps: []TestStep{{ + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }}, + errs: []error{errors.New("test[0]: `name` is required")}, + }, { + name: "duplicated names", + steps: []TestStep{{ + Name: "s0", + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }, { + Name: "s1", + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }, { + Name: "s0", + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }}, + errs: []error{errors.New(`test[2]: duplicated name "s0"`)}, + }, { + name: "no image", + steps: []TestStep{{ + Name: "no_image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }}, + errs: []error{errors.New("test[0]: `image` is required")}, + }, { + name: "no commands", + steps: []TestStep{{ + Name: "no_commands", + Image: "image", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "1"}, + Limits: ResourceList{"memory": "1m"}, + }, + }}, + errs: []error{errors.New("test[0]: `commands` is required")}, + }, { + name: "invalid resources", + steps: []TestStep{{ + Name: "bad_resources", + Image: "image", + Commands: "commands", + Resources: ResourceRequirements{ + Requests: ResourceList{"cpu": "yes"}, + Limits: ResourceList{"piña_colada": "10dL"}, + }, + }}, + errs: []error{ + errors.New("'test[0].resources.limits' specifies an invalid key piña_colada"), + errors.New("test[0].resources.requests.cpu: invalid quantity: quantities must match the regular expression '^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$'"), + }, + }} { + t.Run(tc.name, func(t *testing.T) { + ret := validateTestSteps("test", tc.steps) + if !reflect.DeepEqual(ret, tc.errs) { + t.Fatal(diff.ObjectReflectDiff(ret, tc.errs)) + } + }) + } +} + func parseValidError(id string) error { return fmt.Errorf("%q expected to be invalid, but returned valid", id) } diff --git a/pkg/api/types.go b/pkg/api/types.go index 97bddd41f55..fe19b9ff471 100644 --- a/pkg/api/types.go +++ b/pkg/api/types.go @@ -307,6 +307,14 @@ type TestStepConfiguration struct { OpenshiftInstallerCustomTestImageClusterTestConfiguration *OpenshiftInstallerCustomTestImageClusterTestConfiguration `json:"openshift_installer_custom_test_image,omitempty"` } +type TestStep struct { + Name string `json:"name,omitempty"` + Image string `json:"image,omitempty"` + Commands string `json:"commands,omitempty"` + ArtifactDir string `json:"artifact_dir,omitempty"` + Resources ResourceRequirements `json:"resources,omitempty"` +} + // Secret describes a secret to be mounted inside a test // container. type Secret struct {