Skip to content

Commit

Permalink
feat(testworkflows): allow to pass matrix/shards for the TestWorkflow…
Browse files Browse the repository at this point in the history
…'s `execute` step (#241)

* feat(testworkflows): allow to pass matrix/shards for the TestWorkflow's `execute` step
* feat(testworkflows): reorder props for execute strategy
* feat(testworkflows): add executionRequest for Tests in TestWorkflow's `execute` step
* feat(testworkflows): add executionName for executing sub-workflows
* feat(testworkflows): expose `description` for `execute.*`
* feat(testworkflows): support values different than string in DynamicList
  • Loading branch information
rangoo94 authored Apr 17, 2024
1 parent 42e9be4 commit 3be9f81
Show file tree
Hide file tree
Showing 5 changed files with 2,530 additions and 2 deletions.
100 changes: 99 additions & 1 deletion api/testworkflows/v1/step_types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package v1

import "k8s.io/apimachinery/pkg/util/intstr"
import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"

testsv3 "github.com/kubeshop/testkube-operator/api/tests/v3"
)

type RetryPolicy struct {
// how many times at most it should retry
Expand Down Expand Up @@ -114,14 +119,51 @@ type StepExecute struct {
Workflows []StepExecuteWorkflow `json:"workflows,omitempty" expr:"include"`
}

type StepExecuteStrategy struct {
// matrix of parameters to spawn instances (static)
// +kubebuilder:validation:Schemaless
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Type="object"
Matrix map[string]DynamicList `json:"matrix,omitempty" expr:"force"`

// static number of sharded instances to spawn
Count *intstr.IntOrString `json:"count,omitempty" expr:"expression"`

// dynamic number of sharded instances to spawn - it will be lowered if there is not enough sharded values
MaxCount *intstr.IntOrString `json:"maxCount,omitempty" expr:"expression"`

// parameters that should be distributed across sharded instances
// +kubebuilder:validation:Schemaless
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Type="object"
Shards map[string]DynamicList `json:"shards,omitempty" expr:"force"`
}

type StepExecuteTest struct {
// test name to run
Name string `json:"name,omitempty" expr:"template"`

// test execution description to display
Description string `json:"description,omitempty" expr:"template"`

StepExecuteStrategy `json:",inline" expr:"include"`

// pass the execution request overrides
ExecutionRequest *TestExecutionRequest `json:"executionRequest,omitempty" expr:"include"`
}

type StepExecuteWorkflow struct {
// workflow name to run
Name string `json:"name,omitempty" expr:"template"`

// test workflow execution description to display
Description string `json:"description,omitempty" expr:"template"`

StepExecuteStrategy `json:",inline" expr:"include"`

// unique execution name to use
ExecutionName string `json:"executionName,omitempty" expr:"template"`

// configuration to pass for the workflow
Config map[string]intstr.IntOrString `json:"config,omitempty" expr:"template"`
}
Expand All @@ -141,3 +183,59 @@ type ArtifactCompression struct {
// +kubebuilder:validation:MinLength=1
Name string `json:"name" expr:"template"`
}

type TestExecutionRequest struct {
// test execution custom name
Name string `json:"name,omitempty" expr:"template"`
// test execution labels
ExecutionLabels map[string]string `json:"executionLabels,omitempty" expr:"template,template"`
// variables file content - need to be in format for particular executor (e.g. postman envs file)
VariablesFile string `json:"variablesFile,omitempty" expr:"template"`
IsVariablesFileUploaded bool `json:"isVariablesFileUploaded,omitempty" expr:"ignore"`
Variables map[string]testsv3.Variable `json:"variables,omitempty" expr:"template,force"`
// test secret uuid
TestSecretUUID string `json:"testSecretUUID,omitempty" expr:"template"`
// additional executor binary arguments
Args []string `json:"args,omitempty" expr:"template"`
// usage mode for arguments
ArgsMode testsv3.ArgsModeType `json:"argsMode,omitempty" expr:"template"`
// executor binary command
Command []string `json:"command,omitempty" expr:"template"`
// container executor image
Image string `json:"image,omitempty" expr:"template"`
// container executor image pull secrets
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty" expr:"template"`
// whether to start execution sync or async
Sync bool `json:"sync,omitempty" expr:"ignore"`
// http proxy for executor containers
HttpProxy string `json:"httpProxy,omitempty" expr:"template"`
// https proxy for executor containers
HttpsProxy string `json:"httpsProxy,omitempty" expr:"template"`
// negative test will fail the execution if it is a success and it will succeed if it is a failure
NegativeTest bool `json:"negativeTest,omitempty" expr:"ignore"`
// Optional duration in seconds the pod may be active on the node relative to
// StartTime before the system will actively try to mark it failed and kill associated containers.
// Value must be a positive integer.
ActiveDeadlineSeconds int64 `json:"activeDeadlineSeconds,omitempty" expr:"ignore"`
ArtifactRequest *testsv3.ArtifactRequest `json:"artifactRequest,omitempty" expr:"force"`
// job template extensions
JobTemplate string `json:"jobTemplate,omitempty" expr:"ignore"`
// cron job template extensions
CronJobTemplate string `json:"cronJobTemplate,omitempty" expr:"ignore"`
// script to run before test execution
PreRunScript string `json:"preRunScript,omitempty" expr:"template"`
// script to run after test execution
PostRunScript string `json:"postRunScript,omitempty" expr:"template"`
// execute post run script before scraping (prebuilt executor only)
ExecutePostRunScriptBeforeScraping bool `json:"executePostRunScriptBeforeScraping,omitempty" expr:"ignore"`
// run scripts using source command (container executor only)
SourceScripts bool `json:"sourceScripts,omitempty" expr:"ignore"`
// scraper template extensions
ScraperTemplate string `json:"scraperTemplate,omitempty" expr:"ignore"`
// config map references
EnvConfigMaps []testsv3.EnvReference `json:"envConfigMaps,omitempty" expr:"force"`
// secret references
EnvSecrets []testsv3.EnvReference `json:"envSecrets,omitempty" expr:"force"`
// namespace for test execution (Pro edition only)
ExecutionNamespace string `json:"executionNamespace,omitempty" expr:"template"`
}
58 changes: 58 additions & 0 deletions api/testworkflows/v1/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package v1

import (
"encoding/json"

corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
Expand Down Expand Up @@ -72,3 +74,59 @@ type PodConfig struct {
// volumes to include in the pod
Volumes []corev1.Volume `json:"volumes,omitempty" expr:"force"`
}

type DynamicList struct {
Dynamic bool `expr:"ignore"`
Static []string `expr:"template"`
Expression string `expr:"expression"`
}

// UnmarshalJSON implements the json.Unmarshaller interface.
func (s *DynamicList) UnmarshalJSON(value []byte) error {
if value[0] == '[' {
result := make([]interface{}, 0)
err := json.Unmarshal(value, &result)
if err != nil {
return err
}
isStringOnly := true
for i := range result {
if _, ok := result[i].(string); !ok {
isStringOnly = false
break
}
}
if isStringOnly {
s.Dynamic = false
s.Static = make([]string, len(result))
for i := range result {
s.Static[i] = result[i].(string)
}
} else {
s.Dynamic = true
s.Expression = string(value)
}
return nil
}
if value[0] == '"' {
s.Dynamic = true
return json.Unmarshal(value, &s.Expression)
}
s.Dynamic = true
s.Expression = string(value)
return nil
}

// MarshalJSON implements the json.Marshaller interface.
func (s DynamicList) MarshalJSON() ([]byte, error) {
if s.Dynamic {
var v []interface{}
err := json.Unmarshal([]byte(s.Expression), &v)
if err != nil {
return json.Marshal(s.Expression)
} else {
return []byte(s.Expression), nil
}
}
return json.Marshal(s.Static)
}
130 changes: 129 additions & 1 deletion api/testworkflows/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3be9f81

Please sign in to comment.