diff --git a/.github/workflows/docker-build-api-executors-tag.yaml b/.github/workflows/docker-build-api-executors-tag.yaml index 0d8edc1a389..07bc3616a21 100644 --- a/.github/workflows/docker-build-api-executors-tag.yaml +++ b/.github/workflows/docker-build-api-executors-tag.yaml @@ -5,7 +5,7 @@ on: - "v[0-9]+.[0-9]+.[0-9]+" env: - ALPINE_IMAGE: alpine:3.18.0 + ALPINE_IMAGE: alpine:3.19.0 GO_VERSION: 1.21.5 permissions: @@ -31,7 +31,7 @@ jobs: - name: Set-up Go uses: actions/setup-go@v4 with: - go-version: ${{ env.GO_VERSION }} + go-version: ${{ env.GO_VERSION }} cache: false - name: Go Cache @@ -584,11 +584,11 @@ jobs: - name: Create manifests run: | - docker manifest create kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }} --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress12-amd64 --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress12-arm64v8 + docker manifest create kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }} --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress13-amd64 --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress13-arm64v8 docker manifest push -p kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }} cosign sign kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }} --yes - docker manifest create kubeshop/testkube-cypress-executor:latest --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress12-amd64 --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress12-arm64v8 + docker manifest create kubeshop/testkube-cypress-executor:latest --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress13-amd64 --amend kubeshop/testkube-cypress-executor:${{ steps.tag.outputs.tag }}-cypress13-arm64v8 docker manifest push -p kubeshop/testkube-cypress-executor:latest cosign sign kubeshop/testkube-cypress-executor:latest --yes diff --git a/.github/workflows/docker-build-develop.yaml b/.github/workflows/docker-build-develop.yaml index e16a038523a..99db6d7fb9c 100644 --- a/.github/workflows/docker-build-develop.yaml +++ b/.github/workflows/docker-build-develop.yaml @@ -6,7 +6,7 @@ on: paths-ignore: - 'docs/**' env: - ALPINE_IMAGE: alpine:3.18.0 + ALPINE_IMAGE: alpine:3.19.0 GO_VERSION: 1.21.5 jobs: diff --git a/.github/workflows/docker-build-release.yaml b/.github/workflows/docker-build-release.yaml index 4f390271356..efbd76e5ad1 100644 --- a/.github/workflows/docker-build-release.yaml +++ b/.github/workflows/docker-build-release.yaml @@ -7,7 +7,7 @@ on: paths-ignore: - 'docs/**' env: - ALPINE_IMAGE: alpine:3.18.0 + ALPINE_IMAGE: alpine:3.19.0 GO_VERSION: 1.21.5 jobs: diff --git a/.github/workflows/release-dev.yaml b/.github/workflows/release-dev.yaml index 8ea1c9ec477..656fec54f57 100644 --- a/.github/workflows/release-dev.yaml +++ b/.github/workflows/release-dev.yaml @@ -71,7 +71,7 @@ jobs: with: distribution: goreleaser-pro version: latest - args: release -f ${{ matrix.path }} --snapshot + args: release -f ${{ matrix.path }} --skip-publish env: GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }} ANALYTICS_TRACKING_ID: "${{secrets.TESTKUBE_CLI_GA_MEASUREMENT_ID}}" @@ -116,7 +116,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - uses: sigstore/cosign-installer@v3.0.5 @@ -158,7 +158,7 @@ jobs: with: distribution: goreleaser-pro version: latest - args: release -f .goreleaser-dev.yml --rm-dist + args: release -f .goreleaser-dev.yml env: GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }} ANALYTICS_TRACKING_ID: "${{secrets.TESTKUBE_CLI_GA_MEASUREMENT_ID}}" @@ -180,7 +180,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 @@ -231,6 +231,13 @@ jobs: $hash=Get-FileHash testkube.msi $hash.Hash + " " + $installer_name + ".msi" >> msi_checksum.txt echo "::set-output name=INSTALLER_NAME::${installer_name}" + + #export MSI hash to environment + $hashsum = $hash.Hash + echo "::set-output name=CHECKSUM::${hashsum}" + + #copy MSI to choco directory to build a nuget package + Copy-Item -Path "testkube.msi" -Destination ".\choco\tools\$env:MSI_NAME.msi" env: MSI_NAME: testkube_${{steps.tag.outputs.tag}}_Windows_i386 diff --git a/Makefile b/Makefile index b83962b9d56..7d43529ebbe 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ refresh-config: wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/job-container-template.yml" -O config/job-container-template.yml & wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/job-scraper-template.yml" -O config/job-scraper-template.yml & wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/job-template.yml" -O config/job-template.yml & - wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/pvc-container-template.yml" -O config/pvc-container-template.yml & + wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/pvc-template.yml" -O config/pvc-template.yml & wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/slack-config.json" -O config/slack-config.json & wget "https://raw.githubusercontent.com/kubeshop/helm-charts/develop/charts/testkube-api/slack-template.json" -O config/slack-template.json diff --git a/api/v1/testkube.yaml b/api/v1/testkube.yaml index d05c059fa34..ba7b5601660 100644 --- a/api/v1/testkube.yaml +++ b/api/v1/testkube.yaml @@ -3542,6 +3542,11 @@ components: description: previous step numbers starting from 1 items: type: integer + previousTestNames: + type: array + description: previous test names + items: + type: string TestSuiteStep: type: object @@ -3739,6 +3744,18 @@ components: type: array items: $ref: "#/components/schemas/TestSuiteStepExecutionResult" + startTime: + type: string + description: "step start time" + format: date-time + endTime: + type: string + description: "step end time" + format: date-time + duration: + type: string + description: "step duration" + example: "2m" TestSuiteExecutionsResult: description: the result for a page of executions @@ -4266,6 +4283,11 @@ components: description: "execution ids for artifacts to download" items: type: string + downloadArtifactTestNames: + type: array + description: "test names for artifacts to download from latest executions" + items: + type: string slavePodRequest: $ref: "#/components/schemas/PodRequest" description: configuration parameters for executed slave pods @@ -4615,6 +4637,11 @@ components: items: type: string description: artifact directories for scraping + masks: + type: array + items: + type: string + description: regexp to filter scraped artifacts, single or comma separated storageBucket: type: string description: artifact bucket storage @@ -4622,6 +4649,9 @@ components: omitFolderPerExecution: type: boolean description: don't use a separate folder for execution artifacts + sharedBetweenPods: + type: boolean + description: whether to share volume between pods ArtifactUpdateRequest: description: artifact request update body @@ -4886,6 +4916,11 @@ components: description: "execution ids for artifacts to download" items: type: string + downloadArtifactTestNames: + type: array + description: "test names for artifacts to download from latest executions" + items: + type: string slavePodRequest: $ref: "#/components/schemas/PodRequest" description: configuration parameters for executed slave pods @@ -5360,6 +5395,7 @@ components: - webhook - testexecution - testsuiteexecution + - testsource EventType: type: string diff --git a/cmd/api-server/main.go b/cmd/api-server/main.go index a63ca795e9c..435f9ee0af8 100644 --- a/cmd/api-server/main.go +++ b/cmd/api-server/main.go @@ -53,12 +53,11 @@ import ( "github.com/kubeshop/testkube/internal/app/api/debug" "github.com/kubeshop/testkube/internal/app/api/metrics" "github.com/kubeshop/testkube/pkg/agent" + "github.com/kubeshop/testkube/pkg/event" + "github.com/kubeshop/testkube/pkg/event/bus" kubeexecutor "github.com/kubeshop/testkube/pkg/executor" "github.com/kubeshop/testkube/pkg/executor/client" "github.com/kubeshop/testkube/pkg/executor/containerexecutor" - - "github.com/kubeshop/testkube/pkg/event" - "github.com/kubeshop/testkube/pkg/event/bus" "github.com/kubeshop/testkube/pkg/scheduler" testkubeclientset "github.com/kubeshop/testkube-operator/pkg/clientset/versioned" @@ -359,7 +358,7 @@ func main() { ui.ExitOnError("Sync default executors", err) } - jobTemplate, slavePodTemplate, err := parser.ParseJobTemplates(cfg) + jobTemplates, err := parser.ParseJobTemplates(cfg) if err != nil { ui.ExitOnError("Creating job templates", err) } @@ -368,8 +367,7 @@ func main() { resultsRepository, cfg.TestkubeNamespace, images, - jobTemplate, - slavePodTemplate, + jobTemplates, cfg.JobServiceAccountName, metrics, eventsEmitter, @@ -390,7 +388,7 @@ func main() { ui.ExitOnError("Creating executor client", err) } - containerTemplates, err := parseContainerTemplates(cfg) + containerTemplates, err := parser.ParseContainerTemplates(cfg) if err != nil { ui.ExitOnError("Creating container job templates", err) } @@ -576,40 +574,6 @@ func main() { } } -func parseContainerTemplates(cfg *config.Config) (t kubeexecutor.Templates, err error) { - t.Job, err = parser.LoadConfigFromStringOrFile( - cfg.TestkubeContainerTemplateJob, - cfg.TestkubeConfigDir, - "job-container-template.yml", - "job container template", - ) - if err != nil { - return t, err - } - - t.Scraper, err = parser.LoadConfigFromStringOrFile( - cfg.TestkubeContainerTemplateScraper, - cfg.TestkubeConfigDir, - "job-scraper-template.yml", - "job scraper template", - ) - if err != nil { - return t, err - } - - t.PVC, err = parser.LoadConfigFromStringOrFile( - cfg.TestkubeContainerTemplatePVC, - cfg.TestkubeConfigDir, - "pvc-container-template.yml", - "pvc container template", - ) - if err != nil { - return t, err - } - - return t, nil -} - func parseDefaultExecutors(cfg *config.Config) (executors []testkube.ExecutorDetails, err error) { rawExecutors, err := parser.LoadConfigFromStringOrFile( cfg.TestkubeDefaultExecutors, @@ -625,9 +589,23 @@ func parseDefaultExecutors(cfg *config.Config) (executors []testkube.ExecutorDet return nil, err } + enabledExecutors, err := parser.LoadConfigFromStringOrFile( + cfg.TestkubeEnabledExecutors, + cfg.TestkubeConfigDir, + "enabledExecutors", + "enabled executors", + ) + if err != nil { + return nil, err + } + specifiedExecutors := make(map[string]struct{}) - if cfg.TestkubeSpecifiedExecutors != "" { - for _, executor := range strings.Split(cfg.TestkubeSpecifiedExecutors, ",") { + if enabledExecutors != "" { + for _, executor := range strings.Split(enabledExecutors, ",") { + if strings.TrimSpace(executor) == "" { + continue + } + specifiedExecutors[strings.TrimSpace(executor)] = struct{}{} } diff --git a/cmd/kubectl-testkube/commands/context/get.go b/cmd/kubectl-testkube/commands/context/get.go index 19327a42ec5..0a20353c050 100644 --- a/cmd/kubectl-testkube/commands/context/get.go +++ b/cmd/kubectl-testkube/commands/context/get.go @@ -12,7 +12,7 @@ func NewGetContextCmd() *cobra.Command { cmd := &cobra.Command{ Use: "context ", - Short: "Set context for Testkube Cloud", + Short: "Set context for Testkube Pro", Run: func(cmd *cobra.Command, args []string) { cfg, err := config.Load() diff --git a/cmd/kubectl-testkube/commands/context/set.go b/cmd/kubectl-testkube/commands/context/set.go index b3959579f30..e72aeee774f 100644 --- a/cmd/kubectl-testkube/commands/context/set.go +++ b/cmd/kubectl-testkube/commands/context/set.go @@ -19,7 +19,7 @@ func NewSetContextCmd() *cobra.Command { cmd := &cobra.Command{ Use: "context ", - Short: "Set context data for Testkube Cloud", + Short: "Set context data for Testkube Pro", Run: func(cmd *cobra.Command, args []string) { cfg, err := config.Load() diff --git a/cmd/kubectl-testkube/commands/tests/common.go b/cmd/kubectl-testkube/commands/tests/common.go index c4880ca9d6c..adf08934b62 100644 --- a/cmd/kubectl-testkube/commands/tests/common.go +++ b/cmd/kubectl-testkube/commands/tests/common.go @@ -228,20 +228,32 @@ func newArtifactRequestFromFlags(cmd *cobra.Command) (request *testkube.Artifact return nil, err } + masks, err := cmd.Flags().GetStringArray("artifact-mask") + if err != nil { + return nil, err + } + artifactStorageBucket := cmd.Flag("artifact-storage-bucket").Value.String() artifactOmitFolderPerExecution, err := cmd.Flags().GetBool("artifact-omit-folder-per-execution") if err != nil { return nil, err } - if artifactStorageClassName != "" || artifactVolumeMountPath != "" || len(dirs) != 0 || - artifactStorageBucket != "" || artifactOmitFolderPerExecution { + artifactSharedBetweenPods, err := cmd.Flags().GetBool("artifact-shared-between-pods") + if err != nil { + return nil, err + } + + if artifactStorageClassName != "" || artifactVolumeMountPath != "" || len(dirs) != 0 || len(masks) != 0 || + artifactStorageBucket != "" || artifactOmitFolderPerExecution || artifactSharedBetweenPods { request = &testkube.ArtifactRequest{ StorageClassName: artifactStorageClassName, VolumeMountPath: artifactVolumeMountPath, Dirs: dirs, + Masks: masks, StorageBucket: artifactStorageBucket, OmitFolderPerExecution: artifactOmitFolderPerExecution, + SharedBetweenPods: artifactSharedBetweenPods, } } @@ -1127,6 +1139,16 @@ func newArtifactUpdateRequestFromFlags(cmd *cobra.Command) (request *testkube.Ar nonEmpty = true } + if cmd.Flag("artifact-mask").Changed { + masks, err := cmd.Flags().GetStringArray("artifact-mask") + if err != nil { + return nil, err + } + + request.Masks = &masks + nonEmpty = true + } + if cmd.Flag("artifact-omit-folder-per-execution").Changed { value, err := cmd.Flags().GetBool("artifact-omit-folder-per-execution") if err != nil { @@ -1137,6 +1159,16 @@ func newArtifactUpdateRequestFromFlags(cmd *cobra.Command) (request *testkube.Ar nonEmpty = true } + if cmd.Flag("artifact-shared-between-pods").Changed { + value, err := cmd.Flags().GetBool("artifact-shared-between-pods") + if err != nil { + return nil, err + } + + request.SharedBetweenPods = &value + nonEmpty = true + } + if nonEmpty { return request, nil } diff --git a/cmd/kubectl-testkube/commands/tests/create.go b/cmd/kubectl-testkube/commands/tests/create.go index c6a8dd104d8..4a4ca6e0d95 100644 --- a/cmd/kubectl-testkube/commands/tests/create.go +++ b/cmd/kubectl-testkube/commands/tests/create.go @@ -39,6 +39,7 @@ type CreateCommonFlags struct { ArtifactStorageClassName string ArtifactVolumeMountPath string ArtifactDirs []string + ArtifactMasks []string JobTemplate string JobTemplateReference string CronJobTemplate string @@ -58,6 +59,7 @@ type CreateCommonFlags struct { UploadTimeout string ArtifactStorageBucket string ArtifactOmitFolderPerExecution bool + ArtifactSharedBetweenPods bool Description string SlavePodRequestsCpu string SlavePodRequestsMemory string @@ -246,6 +248,7 @@ func AddCreateFlags(cmd *cobra.Command, flags *CreateCommonFlags) { cmd.Flags().StringVar(&flags.ArtifactStorageClassName, "artifact-storage-class-name", "", "artifact storage class name for container executor") cmd.Flags().StringVar(&flags.ArtifactVolumeMountPath, "artifact-volume-mount-path", "", "artifact volume mount path for container executor") cmd.Flags().StringArrayVarP(&flags.ArtifactDirs, "artifact-dir", "", []string{}, "artifact dirs for scraping") + cmd.Flags().StringArrayVarP(&flags.ArtifactMasks, "artifact-mask", "", []string{}, "regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\\.json,.*\\.js$") cmd.Flags().StringVar(&flags.JobTemplate, "job-template", "", "job template file path for extensions to job template") cmd.Flags().StringVar(&flags.JobTemplateReference, "job-template-reference", "", "reference to job template to use for the test") cmd.Flags().StringVar(&flags.CronJobTemplate, "cronjob-template", "", "cron job template file path for extensions to cron job template") @@ -263,8 +266,9 @@ func AddCreateFlags(cmd *cobra.Command, flags *CreateCommonFlags) { cmd.Flags().StringToStringVarP(&flags.MountSecrets, "mount-secret", "", map[string]string{}, "secret value pair for mounting it to executor pod: --mount-secret secret_name=secret_mountpath") cmd.Flags().StringArrayVar(&flags.VariableSecrets, "variable-secret", []string{}, "secret name used to map all keys to secret variables") cmd.Flags().StringVar(&flags.UploadTimeout, "upload-timeout", "", "timeout to use when uploading files, example: 30s") - cmd.Flags().StringVar(&flags.ArtifactStorageBucket, "artifact-storage-bucket", "", "artifact storage class name for container executor") + cmd.Flags().StringVar(&flags.ArtifactStorageBucket, "artifact-storage-bucket", "", "artifact storage bucket") cmd.Flags().BoolVarP(&flags.ArtifactOmitFolderPerExecution, "artifact-omit-folder-per-execution", "", false, "don't store artifacts in execution folder") + cmd.Flags().BoolVarP(&flags.ArtifactSharedBetweenPods, "artifact-shared-between-pods", "", false, "whether to share volume between pods") cmd.Flags().StringVarP(&flags.Description, "description", "", "", "test description") cmd.Flags().StringVar(&flags.SlavePodRequestsCpu, "slave-pod-requests-cpu", "", "slave pod resource requests cpu") cmd.Flags().StringVar(&flags.SlavePodRequestsMemory, "slave-pod-requests-memory", "", "slave pod resource requests memory") diff --git a/cmd/kubectl-testkube/commands/tests/renderer/test_obj.go b/cmd/kubectl-testkube/commands/tests/renderer/test_obj.go index 1fc15166ec9..2b8b49264d7 100644 --- a/cmd/kubectl-testkube/commands/tests/renderer/test_obj.go +++ b/cmd/kubectl-testkube/commands/tests/renderer/test_obj.go @@ -129,8 +129,10 @@ func TestRenderer(client client.Client, ui *ui.UI, obj interface{}) error { ui.Warn(" Storage class name: ", test.ExecutionRequest.ArtifactRequest.StorageClassName) ui.Warn(" Volume mount path: ", test.ExecutionRequest.ArtifactRequest.VolumeMountPath) ui.Warn(" Dirs: ", strings.Join(test.ExecutionRequest.ArtifactRequest.Dirs, ",")) + ui.Warn(" Masks: ", strings.Join(test.ExecutionRequest.ArtifactRequest.Masks, ",")) ui.Warn(" Storage bucket: ", test.ExecutionRequest.ArtifactRequest.StorageBucket) ui.Warn(" Omit folder per execution: ", fmt.Sprint(test.ExecutionRequest.ArtifactRequest.OmitFolderPerExecution)) + ui.Warn(" Shared between pods: ", fmt.Sprint(test.ExecutionRequest.ArtifactRequest.SharedBetweenPods)) } if test.ExecutionRequest.JobTemplate != "" { diff --git a/cmd/kubectl-testkube/commands/tests/run.go b/cmd/kubectl-testkube/commands/tests/run.go index d6be1db8cf9..360966a1acd 100644 --- a/cmd/kubectl-testkube/commands/tests/run.go +++ b/cmd/kubectl-testkube/commands/tests/run.go @@ -41,6 +41,7 @@ func NewRunTestCmd() *cobra.Command { artifactStorageClassName string artifactVolumeMountPath string artifactDirs []string + artifactMasks []string jobTemplate string jobTemplateReference string gitBranch string @@ -67,6 +68,7 @@ func NewRunTestCmd() *cobra.Command { argsMode string artifactStorageBucket string artifactOmitFolderPerExecution bool + artifactSharedBetweenPods bool silentMode bool slavePodRequestsCpu string slavePodRequestsMemory string @@ -354,6 +356,7 @@ func NewRunTestCmd() *cobra.Command { cmd.Flags().StringVar(&artifactStorageClassName, "artifact-storage-class-name", "", "artifact storage class name for container executor") cmd.Flags().StringVar(&artifactVolumeMountPath, "artifact-volume-mount-path", "", "artifact volume mount path for container executor") cmd.Flags().StringArrayVarP(&artifactDirs, "artifact-dir", "", []string{}, "artifact dirs for scraping") + cmd.Flags().StringArrayVarP(&artifactMasks, "artifact-mask", "", []string{}, "regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\\.json,.*\\.js$") cmd.Flags().StringVar(&jobTemplate, "job-template", "", "job template file path for extensions to job template") cmd.Flags().StringVar(&jobTemplateReference, "job-template-reference", "", "reference to job template to use for the test") cmd.Flags().StringVarP(&gitBranch, "git-branch", "", "", "if uri is git repository we can set additional branch parameter") @@ -378,8 +381,9 @@ func NewRunTestCmd() *cobra.Command { cmd.Flags().StringVar(&format, "format", "folder", "data format for storing files, one of folder|archive") cmd.Flags().StringArrayVarP(&masks, "mask", "", []string{}, "regexp to filter downloaded files, single or comma separated, like report/.* or .*\\.json,.*\\.js$") cmd.Flags().StringVar(&runningContext, "context", "", "running context description for test execution") - cmd.Flags().StringVar(&artifactStorageBucket, "artifact-storage-bucket", "", "artifact storage class name for container executor") + cmd.Flags().StringVar(&artifactStorageBucket, "artifact-storage-bucket", "", "artifact storage bucket") cmd.Flags().BoolVarP(&artifactOmitFolderPerExecution, "artifact-omit-folder-per-execution", "", false, "don't store artifacts in execution folder") + cmd.Flags().BoolVarP(&artifactSharedBetweenPods, "artifact-shared-between-pods", "", false, "whether to share volume between pods") cmd.Flags().BoolVarP(&silentMode, "silent", "", false, "don't print intermediate test execution") cmd.Flags().StringVar(&slavePodRequestsCpu, "slave-pod-requests-cpu", "", "slave pod resource requests cpu") cmd.Flags().StringVar(&slavePodRequestsMemory, "slave-pod-requests-memory", "", "slave pod resource requests memory") diff --git a/cmd/kubectl-testkube/commands/testsuites/renderer/testsuite_obj.go b/cmd/kubectl-testkube/commands/testsuites/renderer/testsuite_obj.go index f4d55fd8c32..3a4926f6ef7 100644 --- a/cmd/kubectl-testkube/commands/testsuites/renderer/testsuite_obj.go +++ b/cmd/kubectl-testkube/commands/testsuites/renderer/testsuite_obj.go @@ -99,7 +99,13 @@ func TestSuiteRenderer(client client.Client, ui *ui.UI, obj interface{}) error { if batch.DownloadArtifacts.AllPreviousSteps { downloadArtifacts = "all previous steps" } else { - downloadArtifacts = fmt.Sprintf("previous step numbers: %v", batch.DownloadArtifacts.PreviousStepNumbers) + if len(batch.DownloadArtifacts.PreviousStepNumbers) != 0 { + downloadArtifacts = fmt.Sprintf("previous step numbers: %v", batch.DownloadArtifacts.PreviousStepNumbers) + } + + if len(batch.DownloadArtifacts.PreviousTestNames) != 0 { + downloadArtifacts = fmt.Sprintf("previous test names: %v", batch.DownloadArtifacts.PreviousTestNames) + } } } diff --git a/cmd/kubectl-testkube/commands/testsuites/run.go b/cmd/kubectl-testkube/commands/testsuites/run.go index 45b585ac0c8..ef85cb3d0b7 100644 --- a/cmd/kubectl-testkube/commands/testsuites/run.go +++ b/cmd/kubectl-testkube/commands/testsuites/run.go @@ -150,9 +150,9 @@ func NewRunTestSuiteCmd() *cobra.Command { if execution.Id != "" { if watchEnabled && len(args) > 0 { - executionCh, err := client.WatchTestSuiteExecution(execution.Id) - for execution := range executionCh { - ui.ExitOnError("watching test execution", err) + watchResp := client.WatchTestSuiteExecution(execution.Id) + for resp := range watchResp { + ui.ExitOnError("watching test suite execution", resp.Error) if !silentMode { execution.TruncateErrorMessages(maxErrorMessageLength) printExecution(execution, startTime) diff --git a/cmd/kubectl-testkube/commands/testsuites/watch.go b/cmd/kubectl-testkube/commands/testsuites/watch.go index 7726b758379..6b9fc80aacc 100644 --- a/cmd/kubectl-testkube/commands/testsuites/watch.go +++ b/cmd/kubectl-testkube/commands/testsuites/watch.go @@ -26,14 +26,14 @@ func NewWatchTestSuiteExecutionCmd() *cobra.Command { startTime := time.Now() executionID := args[0] - executionCh, err := client.WatchTestSuiteExecution(executionID) - for execution := range executionCh { - ui.ExitOnError("watching test execution", err) - printExecution(execution, startTime) + watchResp := client.WatchTestSuiteExecution(executionID) + for resp := range watchResp { + ui.ExitOnError("watching test suite execution", resp.Error) + printExecution(resp.Execution, startTime) } execution, err := client.GetTestSuiteExecution(executionID) - ui.ExitOnError("getting test excecution", err) + ui.ExitOnError("getting test suite excecution", err) printExecution(execution, startTime) ui.ExitOnError("getting recent execution data id:"+execution.Id, err) diff --git a/config/job-container-template.yml b/config/job-container-template.yml index 1ecb62530fe..f3372643357 100644 --- a/config/job-container-template.yml +++ b/config/job-container-template.yml @@ -29,7 +29,7 @@ spec: mountPath: /etc/certs {{- end }} {{- if .ArtifactRequest }} - {{- if .ArtifactRequest.VolumeMountPath }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} - name: artifact-volume mountPath: {{ .ArtifactRequest.VolumeMountPath }} {{- end }} @@ -78,7 +78,7 @@ spec: mountPath: /etc/certs {{- end }} {{- if .ArtifactRequest }} - {{- if .ArtifactRequest.VolumeMountPath }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} - name: artifact-volume mountPath: {{ .ArtifactRequest.VolumeMountPath }} {{- end }} diff --git a/config/job-template.yml b/config/job-template.yml index 63913f04fdc..4525c298616 100644 --- a/config/job-template.yml +++ b/config/job-template.yml @@ -27,6 +27,12 @@ spec: - name: {{ .CertificateSecret }} mountPath: /etc/certs {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + mountPath: {{ .ArtifactRequest.VolumeMountPath }} + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} @@ -70,6 +76,12 @@ spec: - name: {{ .CertificateSecret }} mountPath: /etc/certs {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + mountPath: {{ .ArtifactRequest.VolumeMountPath }} + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} @@ -90,6 +102,13 @@ spec: secret: secretName: {{ .CertificateSecret }} {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + persistentVolumeClaim: + claimName: {{ .Name }}-pvc + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} diff --git a/config/pvc-container-template.yml b/config/pvc-template.yml similarity index 72% rename from config/pvc-container-template.yml rename to config/pvc-template.yml index 7b1a0a214d7..7c85aa8301f 100644 --- a/config/pvc-container-template.yml +++ b/config/pvc-template.yml @@ -6,7 +6,11 @@ metadata: spec: storageClassName: {{ .ArtifactRequest.StorageClassName }} accessModes: + {{- if .ArtifactRequest.SharedBetweenPods }} + - ReadWriteMany + {{- else }} - ReadWriteOnce + {{- end }} resources: requests: storage: 1Gi diff --git a/config/slave-pod-template.yml b/config/slave-pod-template.yml index 9aaf62ec27e..0530fd864ac 100644 --- a/config/slave-pod-template.yml +++ b/config/slave-pod-template.yml @@ -32,6 +32,12 @@ spec: - name: {{ .CertificateSecret }} mountPath: /etc/certs {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + mountPath: {{ .ArtifactRequest.VolumeMountPath }} + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} @@ -103,6 +109,12 @@ spec: - name: {{ .CertificateSecret }} mountPath: /etc/certs {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + mountPath: {{ .ArtifactRequest.VolumeMountPath }} + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} @@ -123,6 +135,13 @@ spec: secret: secretName: {{ .CertificateSecret }} {{- end }} + {{- if .ArtifactRequest }} + {{- if and .ArtifactRequest.VolumeMountPath .ArtifactRequest.StorageClassName }} + - name: artifact-volume + persistentVolumeClaim: + claimName: {{ .Name }}-pvc + {{- end }} + {{- end }} {{- range $configmap := .EnvConfigMaps }} {{- if and $configmap.Mount $configmap.Reference }} - name: {{ $configmap.Reference.Name }} diff --git a/contrib/executor/artillery/pkg/runner/artillery.go b/contrib/executor/artillery/pkg/runner/artillery.go index 9a652366860..f5f3c2c591c 100644 --- a/contrib/executor/artillery/pkg/runner/artillery.go +++ b/contrib/executor/artillery/pkg/runner/artillery.go @@ -150,11 +150,13 @@ func (r *ArtilleryRunner) Run(ctx context.Context, execution testkube.Execution) directories := []string{ testReportFile, } - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - err = r.Scraper.Scrape(ctx, directories, execution) + err = r.Scraper.Scrape(ctx, directories, masks, execution) if err != nil { return *result.Err(err), errors.Wrap(err, "error scraping artifacts for Artillery executor") } diff --git a/contrib/executor/curl/pkg/runner/runner.go b/contrib/executor/curl/pkg/runner/runner.go index c5d83d4db6a..5d094589e1c 100644 --- a/contrib/executor/curl/pkg/runner/runner.go +++ b/contrib/executor/curl/pkg/runner/runner.go @@ -160,9 +160,9 @@ func (r *CurlRunner) Run(ctx context.Context, execution testkube.Execution) (res // scrape artifacts first even if there are errors above if r.Params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - outputPkg.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + outputPkg.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/cypress/pkg/runner/cypress.go b/contrib/executor/cypress/pkg/runner/cypress.go index 605e0e212b7..dcc2076de7d 100644 --- a/contrib/executor/cypress/pkg/runner/cypress.go +++ b/contrib/executor/cypress/pkg/runner/cypress.go @@ -196,13 +196,15 @@ func (r *CypressRunner) Run(ctx context.Context, execution testkube.Execution) ( filepath.Join(projectPath, "cypress/screenshots"), } - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } output.PrintLogf("Scraping directories: %v", directories) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/ginkgo/pkg/runner/runner.go b/contrib/executor/ginkgo/pkg/runner/runner.go index 66134a7a6cc..bef375bb999 100644 --- a/contrib/executor/ginkgo/pkg/runner/runner.go +++ b/contrib/executor/ginkgo/pkg/runner/runner.go @@ -175,11 +175,13 @@ func (r *GinkgoRunner) Run(ctx context.Context, execution testkube.Execution) (r reportsPath, } - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *result.Err(err), errors.Wrap(err, "error scraping artifacts for Ginkgo executor") } } diff --git a/contrib/executor/gradle/pkg/runner/runner.go b/contrib/executor/gradle/pkg/runner/runner.go index 256b2e7cedc..850699f9f67 100644 --- a/contrib/executor/gradle/pkg/runner/runner.go +++ b/contrib/executor/gradle/pkg/runner/runner.go @@ -177,9 +177,9 @@ func (r *GradleRunner) Run(ctx context.Context, execution testkube.Execution) (r // scrape artifacts first even if there are errors above if r.params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - output.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + output.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/init/pkg/runner/runner.go b/contrib/executor/init/pkg/runner/runner.go index 48c15df532d..5db22700520 100755 --- a/contrib/executor/init/pkg/runner/runner.go +++ b/contrib/executor/init/pkg/runner/runner.go @@ -159,7 +159,7 @@ func (r *InitRunner) Run(ctx context.Context, execution testkube.Execution) (res } output.PrintLogf("%s Access to files enabled", ui.IconCheckMark) - if len(execution.DownloadArtifactExecutionIDs) != 0 { + if len(execution.DownloadArtifactExecutionIDs) != 0 || len(execution.DownloadArtifactTestNames) != 0 { downloadedArtifacts := filepath.Join(r.Params.DataDir, "downloaded-artifacts") options := client.Options{ ApiUri: r.Params.APIURI, @@ -170,8 +170,29 @@ func (r *InitRunner) Run(ctx context.Context, execution testkube.Execution) (res output.PrintLogf("%s Could not get client: %s", ui.IconCross, err.Error()) } else { for _, id := range execution.DownloadArtifactExecutionIDs { - if err = downloadArtifacts(id, filepath.Join(downloadedArtifacts, id), c); err != nil { - output.PrintLogf("%s Could not download artifact: %s", ui.IconCross, err.Error()) + execution, err := c.GetExecution(id) + if err != nil { + output.PrintLogf("%s Could not get execution: %s", ui.IconCross, err.Error()) + continue + } + + if err = downloadArtifacts(id, filepath.Join(downloadedArtifacts, execution.TestName+"-"+id), c); err != nil { + output.PrintLogf("%s Could not download execution artifact: %s", ui.IconCross, err.Error()) + } + } + + for _, name := range execution.DownloadArtifactTestNames { + test, err := c.GetTestWithExecution(name) + if err != nil { + output.PrintLogf("%s Could not get test with execution: %s", ui.IconCross, err.Error()) + continue + } + + if test.LatestExecution != nil { + id := test.LatestExecution.Id + if err = downloadArtifacts(id, filepath.Join(downloadedArtifacts, name+"-"+id), c); err != nil { + output.PrintLogf("%s Could not download test artifact: %s", ui.IconCross, err.Error()) + } } } } diff --git a/contrib/executor/jmeter/pkg/runner/runner.go b/contrib/executor/jmeter/pkg/runner/runner.go index fc5640786fc..9cb299c7fd3 100644 --- a/contrib/executor/jmeter/pkg/runner/runner.go +++ b/contrib/executor/jmeter/pkg/runner/runner.go @@ -226,12 +226,14 @@ func (r *JMeterRunner) Run(ctx context.Context, execution testkube.Execution) (r directories := []string{ outputDir, } - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - output.PrintLogf("Scraping directories: %v", directories) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + output.PrintLogf("Scraping directories: %v with masks: %v", directories, masks) + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *executionResult.Err(err), errors.Wrap(err, "error scraping artifacts for JMeter executor") } } diff --git a/contrib/executor/jmeterd/pkg/runner/runner.go b/contrib/executor/jmeterd/pkg/runner/runner.go index f069b5d69ae..ea0c96d4004 100644 --- a/contrib/executor/jmeterd/pkg/runner/runner.go +++ b/contrib/executor/jmeterd/pkg/runner/runner.go @@ -291,12 +291,14 @@ func runPostRunScriptIfEnabled(execution testkube.Execution, workingDir string) func runScraperIfEnabled(ctx context.Context, enabled bool, scraper scraper.Scraper, dirs []string, execution testkube.Execution) (err error) { if enabled { directories := dirs - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - output.PrintLogf("%s Running scraper to scrape for the following directories: %v", ui.IconTruck, directories) - if err = scraper.Scrape(ctx, directories, execution); err != nil { + output.PrintLogf("%s Running scraper to scrape for the following directories: %v with masks: %v", ui.IconTruck, directories, masks) + if err = scraper.Scrape(ctx, directories, masks, execution); err != nil { output.PrintLogf("%s Failed to scrape artifacts %s", ui.IconWarning, err) } output.PrintLogf("%s Tests artifacts scrapped successfully!", ui.IconCheckMark) diff --git a/contrib/executor/jmeterd/pkg/slaves/client.go b/contrib/executor/jmeterd/pkg/slaves/client.go index 31b931a7d78..2f015773e9c 100644 --- a/contrib/executor/jmeterd/pkg/slaves/client.go +++ b/contrib/executor/jmeterd/pkg/slaves/client.go @@ -57,6 +57,7 @@ type PodOptions struct { Ports []v1.ContainerPort Resources *testkube.PodResourcesRequest ImagePullSecrets []string + ArtifactRequest *testkube.ArtifactRequest } // NewClient is a method to create new slave client @@ -157,10 +158,10 @@ func (c *Client) getSlavePodConfiguration(ctx context.Context, currentSlavesCoun output.PrintLogf("%s Failed to fetch Test Job info: %v", ui.IconWarning, err.Error()) } - return c.createSlavePodObject(runnerExecutionStr, podName, executorJob) + return c.createSlavePodObject(runnerExecutionStr, podName, executorJob, currentSlavesCount) } -func (c *Client) createSlavePodObject(runnerExecutionStr []byte, podName string, executorJob *batchv1.Job) (*v1.Pod, error) { +func (c *Client) createSlavePodObject(runnerExecutionStr []byte, podName string, executorJob *batchv1.Job, currentSlavesCount int) (*v1.Pod, error) { tmpl, err := utils. NewTemplate("pod"). Funcs(template.FuncMap{"vartypeptrtostring": testkube.VariableTypeString}). @@ -223,7 +224,7 @@ func (c *Client) createSlavePodObject(runnerExecutionStr []byte, podName string, } for i := range pod.Spec.Containers { - pod.Spec.Containers[i].Env = append(pod.Spec.Containers[i].Env, getSlaveConfigurationEnv(c.envVariables)...) + pod.Spec.Containers[i].Env = append(pod.Spec.Containers[i].Env, getSlaveConfigurationEnv(c.envVariables, currentSlavesCount)...) } return &pod, nil @@ -248,6 +249,11 @@ func (c *Client) newPodOptions(runnerExecutionStr []byte, podName string, execut resources = c.execution.SlavePodRequest.Resources } + var artifactRequest *testkube.ArtifactRequest + if c.execution.ArtifactRequest != nil && c.execution.ArtifactRequest.SharedBetweenPods { + artifactRequest = c.execution.ArtifactRequest + } + return &PodOptions{ Name: podName, Namespace: c.namespace, @@ -273,6 +279,7 @@ func (c *Client) newPodOptions(runnerExecutionStr []byte, podName string, execut }, Resources: resources, ImagePullSecrets: c.slavesConfigs.ImagePullSecrets, + ArtifactRequest: artifactRequest, } } diff --git a/contrib/executor/jmeterd/pkg/slaves/utils.go b/contrib/executor/jmeterd/pkg/slaves/utils.go index a5cf55260c2..1c7d2af724f 100644 --- a/contrib/executor/jmeterd/pkg/slaves/utils.go +++ b/contrib/executor/jmeterd/pkg/slaves/utils.go @@ -13,7 +13,6 @@ import ( "k8s.io/client-go/kubernetes" "github.com/kubeshop/testkube/pkg/api/v1/testkube" - "github.com/kubeshop/testkube/pkg/executor" ) const ( @@ -49,14 +48,21 @@ func getSlaveRunnerEnv(envs map[string]string, runnerExecution testkube.Executio ) } - return append(executor.RunnerEnvVars, gitEnvs...) + var runnerEnvVars []v1.EnvVar + for key, value := range envs { + runnerEnvVars = append(runnerEnvVars, v1.EnvVar{Name: key, Value: value}) + } + + return append(runnerEnvVars, gitEnvs...) } -func getSlaveConfigurationEnv(slaveEnv map[string]testkube.Variable) []v1.EnvVar { +func getSlaveConfigurationEnv(slaveEnv map[string]testkube.Variable, currentSlavesCount int) []v1.EnvVar { var envVars []v1.EnvVar for envKey, t := range slaveEnv { envVars = append(envVars, v1.EnvVar{Name: envKey, Value: t.Value}) } + + envVars = append(envVars, v1.EnvVar{Name: "SLAVE_POD_NUMBER", Value: strconv.Itoa(currentSlavesCount)}) return envVars } diff --git a/contrib/executor/k6/pkg/runner/runner.go b/contrib/executor/k6/pkg/runner/runner.go index 24037cf8fee..e80b203bb93 100644 --- a/contrib/executor/k6/pkg/runner/runner.go +++ b/contrib/executor/k6/pkg/runner/runner.go @@ -194,9 +194,9 @@ func (r *K6Runner) Run(ctx context.Context, execution testkube.Execution) (resul // scrape artifacts first even if there are errors above if r.Params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - outputPkg.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + outputPkg.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/kubepug/pkg/runner/runner.go b/contrib/executor/kubepug/pkg/runner/runner.go index 1ead3a458a7..89714369500 100644 --- a/contrib/executor/kubepug/pkg/runner/runner.go +++ b/contrib/executor/kubepug/pkg/runner/runner.go @@ -102,9 +102,9 @@ func (r *KubepugRunner) Run(ctx context.Context, execution testkube.Execution) ( // scrape artifacts first even if there are errors above if r.params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - output.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + output.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return testkube.ExecutionResult{}, fmt.Errorf("could not scrape kubepug directories: %w", err) } } diff --git a/contrib/executor/maven/pkg/runner/runner.go b/contrib/executor/maven/pkg/runner/runner.go index 1af456d4d0c..1e5a35c160c 100644 --- a/contrib/executor/maven/pkg/runner/runner.go +++ b/contrib/executor/maven/pkg/runner/runner.go @@ -198,9 +198,9 @@ func (r *MavenRunner) Run(ctx context.Context, execution testkube.Execution) (re // scrape artifacts first even if there are errors above if r.params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - outputPkg.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + outputPkg.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/playwright/pkg/runner/playwright.go b/contrib/executor/playwright/pkg/runner/playwright.go index 3a975391b9a..09948c40fe0 100644 --- a/contrib/executor/playwright/pkg/runner/playwright.go +++ b/contrib/executor/playwright/pkg/runner/playwright.go @@ -177,13 +177,15 @@ func scrapeArtifacts(ctx context.Context, r *PlaywrightRunner, execution testkub filepath.Join(projectPath, compressedName), } - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - output.PrintLogf("Scraping directories: %v", directories) + output.PrintLogf("Scraping directories: %v with masks: %v", directories, masks) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return errors.Wrap(err, "error scraping artifacts") } diff --git a/contrib/executor/postman/build/agent/Dockerfile b/contrib/executor/postman/build/agent/Dockerfile index a0e53a95992..18b7f3d2129 100644 --- a/contrib/executor/postman/build/agent/Dockerfile +++ b/contrib/executor/postman/build/agent/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1 -FROM postman/newman:6-alpine +FROM postman/newman:6.0.0-alpine COPY postman /bin/runner RUN npm install -g newman diff --git a/contrib/executor/postman/pkg/runner/newman/newman.go b/contrib/executor/postman/pkg/runner/newman/newman.go index 83818c72531..ba55be878e8 100644 --- a/contrib/executor/postman/pkg/runner/newman/newman.go +++ b/contrib/executor/postman/pkg/runner/newman/newman.go @@ -175,9 +175,9 @@ func (r *NewmanRunner) Run(ctx context.Context, execution testkube.Execution) (r // scrape artifacts first even if there are errors above if r.Params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - output.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + output.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return *result.WithErrors(err), nil } } diff --git a/contrib/executor/scraper/pkg/runner/runner.go b/contrib/executor/scraper/pkg/runner/runner.go index 4df3b5f7980..0a9d80fdd21 100644 --- a/contrib/executor/scraper/pkg/runner/runner.go +++ b/contrib/executor/scraper/pkg/runner/runner.go @@ -73,9 +73,10 @@ func (r *ScraperRunner) Run(ctx context.Context, execution testkube.Execution) ( directories[i] = filepath.Join(mountPath, directories[i]) } - output.PrintLog(fmt.Sprintf("Scraping directories: %v", directories)) + masks := execution.ArtifactRequest.Masks + output.PrintLog(fmt.Sprintf("Scraping directories: %v with masks: %v", directories, masks)) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *result.Err(err), errors.Wrap(err, "error scraping artifacts from container executor") } } diff --git a/contrib/executor/scraper/pkg/runner/runner_test.go b/contrib/executor/scraper/pkg/runner/runner_test.go index 6f1205e2c4c..d4949cdf864 100644 --- a/contrib/executor/scraper/pkg/runner/runner_test.go +++ b/contrib/executor/scraper/pkg/runner/runner_test.go @@ -23,7 +23,7 @@ func TestRun(t *testing.T) { e := testkube.Execution{ArtifactRequest: &testkube.ArtifactRequest{VolumeMountPath: ".", StorageClassName: "standard"}} tests := []struct { name string - scraper func(id string, directories []string) error + scraper func(id string, directories, masks []string) error execution testkube.Execution expectedError string expectedStatus *testkube.ExecutionStatus @@ -31,26 +31,26 @@ func TestRun(t *testing.T) { }{ { name: "successful scraper", - scraper: func(id string, directories []string) error { return nil }, + scraper: func(id string, directories, masks []string) error { return nil }, execution: e, expectedError: "", expectedStatus: nil, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"."}, gomock.Eq(e)).Return(nil) + s.EXPECT().Scrape(gomock.Any(), []string{"."}, gomock.Any(), gomock.Eq(e)).Return(nil) s.EXPECT().Close().Return(nil) return s }, }, { name: "failing scraper", - scraper: func(id string, directories []string) error { return errors.New("Scraping failed") }, + scraper: func(id string, directories, masks []string) error { return errors.New("Scraping failed") }, execution: testkube.Execution{ArtifactRequest: &testkube.ArtifactRequest{VolumeMountPath: ".", StorageClassName: "standard"}}, expectedError: "error scraping artifacts from container executor: Scraping failed", expectedStatus: testkube.ExecutionStatusFailed, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"."}, gomock.Eq(e)).Return(errors.New("Scraping failed")) + s.EXPECT().Scrape(gomock.Any(), []string{"."}, gomock.Any(), gomock.Eq(e)).Return(errors.New("Scraping failed")) s.EXPECT().Close().Return(nil) return s }, @@ -82,12 +82,12 @@ func TestRun(t *testing.T) { // Scraper implements a mock for the Scraper from "github.com/kubeshop/testkube/pkg/executor/scraper" type Scraper struct { - ScrapeFn func(id string, directories []string) error + ScrapeFn func(id string, directories, masks []string) error } -func (s Scraper) Scrape(id string, directories []string) error { +func (s Scraper) Scrape(id string, directories, masks []string) error { if s.ScrapeFn == nil { log.Fatal("not implemented") } - return s.ScrapeFn(id, directories) + return s.ScrapeFn(id, directories, masks) } diff --git a/contrib/executor/soapui/build/agent/Dockerfile b/contrib/executor/soapui/build/agent/Dockerfile index d02f0354999..62b99bf8855 100644 --- a/contrib/executor/soapui/build/agent/Dockerfile +++ b/contrib/executor/soapui/build/agent/Dockerfile @@ -1,13 +1,10 @@ -# Base image consists of: - -# FROM smartbear/soapuios-testrunner -# RUN apt-get update && apt-get install -y git \ -# curl && \ - # chmod 777 /usr/local/SmartBear && \ - # useradd -m -d /home/soapui -s /bin/bash -u 1001 -r -g root soapui - # syntax=docker/dockerfile:1 -FROM kubeshop/testkube-soapui-executor:base +FROM smartbear/soapuios-testrunner:5.7.2 +RUN apt-get update && apt-get install -y git \ + curl && \ + chmod 777 /usr/local/SmartBear && \ + useradd -m -d /home/soapui -s /bin/bash -u 1001 -r -g root soapui + COPY soapui /bin/runner USER 1001 diff --git a/contrib/executor/soapui/pkg/runner/runner.go b/contrib/executor/soapui/pkg/runner/runner.go index 52e934fdd11..f8b625418fb 100644 --- a/contrib/executor/soapui/pkg/runner/runner.go +++ b/contrib/executor/soapui/pkg/runner/runner.go @@ -107,13 +107,15 @@ func (r *SoapUIRunner) Run(ctx context.Context, execution testkube.Execution) (r if r.Params.ScrapperEnabled { directories := []string{r.SoapUILogsPath} - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - output.PrintLogf("Scraping directories: %v", directories) + output.PrintLogf("Scraping directories: %v with masks: %v", directories, masks) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *result.Err(err), errors.Wrap(err, "error scraping artifacts from SoapUI executor") } } diff --git a/contrib/executor/soapui/pkg/runner/runner_test.go b/contrib/executor/soapui/pkg/runner/runner_test.go index 097aa20ae8c..457031fc982 100644 --- a/contrib/executor/soapui/pkg/runner/runner_test.go +++ b/contrib/executor/soapui/pkg/runner/runner_test.go @@ -56,7 +56,7 @@ func TestRun_Integration(t *testing.T) { expectedStatus: *testkube.ExecutionStatusPassed, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, gomock.Eq(e)).Return(nil) + s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, []string{}, gomock.Eq(e)).Return(nil) return s }, }, @@ -68,7 +68,7 @@ func TestRun_Integration(t *testing.T) { expectedStatus: *testkube.ExecutionStatusFailed, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, gomock.Eq(e)).Return(nil) + s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, []string{}, gomock.Eq(e)).Return(nil) return s }, }, @@ -80,7 +80,7 @@ func TestRun_Integration(t *testing.T) { expectedStatus: *testkube.ExecutionStatusPassed, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, gomock.Eq(e)).Return(errors.New("Scraping failed")) + s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, []string{}, gomock.Eq(e)).Return(errors.New("Scraping failed")) return s }, }, @@ -92,7 +92,7 @@ func TestRun_Integration(t *testing.T) { expectedStatus: *testkube.ExecutionStatusFailed, scraperBuilder: func() scraper.Scraper { s := scraper.NewMockScraper(mockCtrl) - s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, gomock.Eq(e)).Return(errors.New("Scraping failed")) + s.EXPECT().Scrape(gomock.Any(), []string{"/logs"}, []string{}, gomock.Eq(e)).Return(errors.New("Scraping failed")) return s }, }, diff --git a/contrib/executor/tracetest/pkg/runner/runner.go b/contrib/executor/tracetest/pkg/runner/runner.go index 444e6997693..fc463f3ede8 100644 --- a/contrib/executor/tracetest/pkg/runner/runner.go +++ b/contrib/executor/tracetest/pkg/runner/runner.go @@ -89,9 +89,9 @@ func (r *TracetestRunner) Run(ctx context.Context, execution testkube.Execution) // scrape artifacts first even if there are errors above if r.Params.ScrapperEnabled && execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { - outputPkg.PrintLogf("Scraping directories: %v", execution.ArtifactRequest.Dirs) + outputPkg.PrintLogf("Scraping directories: %v with masks: %v", execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks) - if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution); err != nil { + if err := r.Scraper.Scrape(ctx, execution.ArtifactRequest.Dirs, execution.ArtifactRequest.Masks, execution); err != nil { return testkube.ExecutionResult{}, fmt.Errorf("could not scrape tracetest directories: %w", err) } } diff --git a/contrib/executor/zap/pkg/runner/runner.go b/contrib/executor/zap/pkg/runner/runner.go index b8145e35770..6d283031a26 100644 --- a/contrib/executor/zap/pkg/runner/runner.go +++ b/contrib/executor/zap/pkg/runner/runner.go @@ -175,13 +175,15 @@ func (r *ZapRunner) Run(ctx context.Context, execution testkube.Execution) (resu if r.Params.ScrapperEnabled { directories := []string{reportFolder} - if execution.ArtifactRequest != nil && len(execution.ArtifactRequest.Dirs) != 0 { + var masks []string + if execution.ArtifactRequest != nil { directories = append(directories, execution.ArtifactRequest.Dirs...) + masks = execution.ArtifactRequest.Masks } - output.PrintLogf("%s Scraping directories: %v", ui.IconCabinet, directories) + output.PrintLogf("%s Scraping directories: %v with masks: %v", ui.IconCabinet, directories, masks) - if err := r.Scraper.Scrape(ctx, directories, execution); err != nil { + if err := r.Scraper.Scrape(ctx, directories, masks, execution); err != nil { return *result.Err(err), errors.Wrap(err, "error scraping artifacts from ZAP executor") } } diff --git a/docs/docs/articles/artifacts-storage.md b/docs/docs/articles/artifacts-storage.md deleted file mode 100644 index 066da24d91d..00000000000 --- a/docs/docs/articles/artifacts-storage.md +++ /dev/null @@ -1,48 +0,0 @@ -# Artifacts Storage - -Testkube allows you to save supported files generated by your tests, which we call **Artifacts**. - -The executor will scrape the files and store them in [Minio](https://min.io/). The executor will create a bucket named by execution ID and collect all files that are stored in the location specific to each executor. - -The available configuration parameters in Helm charts are: - -| Parameter | Is optional | Default | Default | -| -------------------------------------- | ----------- | ------------------------------------ | ----------------------------------------------------- | -| testkube-api.storage.endpoint | yes | testkube-minio-service-testkube:9000 | URL of the S3 bucket | -| testkube-api.storage.accessKeyId | yes | minio | Access Key ID | -| testkube-api.storage.accessKey | yes | minio123 | Access Key | -| testkube-api.storage.location | yes | | Region | -| testkube-api.storage.token | yes | | S3 Token | -| testkube-api.storage.SSL | yes | false | Indicates whether SSL communication is to be enabled. | -| testkube-api.storage.scrapperEnabled | yes | true | Indicates whether executors should scrape artifacts. | -| testkube-api.storage.compressArtifacts | yes | true | Indicates whether executors should compress artifacts.| - -The API Server accepts the following environment variables: - -```sh -STORAGE_ENDPOINT -STORAGE_BUCKET -STORAGE_ACCESSKEYID -STORAGE_SECRETACCESSKEY -STORAGE_LOCATION -STORAGE_REGION -STORAGE_TOKEN -STORAGE_SSL -SCRAPPERENABLED -COMPRESSARTIFACTS -``` - -Which can be set while installing with Helm: - -```sh -helm install --create-namespace my-testkube kubeshop/testkube --set STORAGE_ENDPOINT=custom_value -``` - -Alternatively, these values can be read from Kubernetes secrets and set: - -```yaml -- env: - - name: STORAGE_ENDPOINT - secret: - secretName: test-secret -``` diff --git a/docs/docs/articles/artifacts.md b/docs/docs/articles/artifacts.md new file mode 100644 index 00000000000..c53aa7cd304 --- /dev/null +++ b/docs/docs/articles/artifacts.md @@ -0,0 +1,118 @@ +# Artifacts + +## Storing Test Artifacts + +Testkube allows you to save supported files generated by your tests, which we call **Artifacts**. + +The executor will scrape the files and store them in [Minio](https://min.io/). The executor will create a bucket named by execution ID and collect all files that are stored in the location specific to each executor. + +The available configuration parameters in Helm charts are: + +| Parameter | Is optional | Default | Default | +| -------------------------------------- | ----------- | ------------------------------------ | ----------------------------------------------------- | +| testkube-api.storage.endpoint | yes | testkube-minio-service-testkube:9000 | URL of the S3 bucket | +| testkube-api.storage.accessKeyId | yes | minio | Access Key ID | +| testkube-api.storage.accessKey | yes | minio123 | Access Key | +| testkube-api.storage.location | yes | | Region | +| testkube-api.storage.token | yes | | S3 Token | +| testkube-api.storage.SSL | yes | false | Indicates whether SSL communication is to be enabled. | +| testkube-api.storage.scrapperEnabled | yes | true | Indicates whether executors should scrape artifacts. | +| testkube-api.storage.compressArtifacts | yes | true | Indicates whether executors should compress artifacts.| + +The API Server accepts the following environment variables: + +```sh +STORAGE_ENDPOINT +STORAGE_BUCKET +STORAGE_ACCESSKEYID +STORAGE_SECRETACCESSKEY +STORAGE_LOCATION +STORAGE_REGION +STORAGE_TOKEN +STORAGE_SSL +SCRAPPERENABLED +COMPRESSARTIFACTS +``` + +Which can be set while installing with Helm: + +```sh +helm install --create-namespace my-testkube kubeshop/testkube --set STORAGE_ENDPOINT=custom_value +``` + +Alternatively, these values can be read from Kubernetes secrets and set: + +```yaml +- env: + - name: STORAGE_ENDPOINT + secret: + secretName: test-secret +``` + +## Collecting Test Artifacts + +For executors that produce files during test execution, Testkube supports collecting (scraping) these artifacts and storing them in our S3 compatible file storage. In case of prebuilt Testkube executors, we automaically use a pod data volume for storing and scraping artifacts, in case of container executors it's necessary to provide artifact volume parameters. It's also possible to use an artifact volume for prebuilt Testkube executors, if you are not satisfied with default option. + +You need to save test related files into specified directories on the dynamically created volume. They will be uploaded from there to Testkube file storage and available later for downloading using standard Testkube CLI or Testkube Dashboard commands. For example: + +```yaml +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: cli-container + namespace: testkube +spec: + type: cli/container + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - test/reports + masks: + - .*\.txt,result.* + sharedBetweenPods: false +``` + +You have to define the storage class name, volume mount path and directories in this volume with test artifacts. +Default volume mount path is `/data/artifacts` and directory is `.` . +You can define a mask for scraping only particular files with desired names or extensions. +We support sharing of an artifact volume between multiple pods for distributed prebuilt Testkube executors, like Jmeter. Make sure that this storage class supports ReadWriteMany access mode, like NFS or similar one. +Make sure your container executor definition has `artifacts` feature. For example: + +```yaml +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: cli-container-executor + namespace: testkube +spec: + types: + - cli/container + executor_type: container + image: soleware/nx-cli:8.5.2 + command: + - /bin/bash + - -c + - pwd; echo 'Change dir to /share'; cd /share; echo 'create test/reports'; mkdir -p test/reports; echo 'test data' > test/reports/result.txt + features: + - artifacts +``` + +Run your test using the CLI command: + +```sh +testkube run test cli-container +``` + +Then get available artifacts for your test execution id: + +```sh +testkube get artifact 638a08b94ff1d2c694aeebf2 +``` + +```sh title="Expected output:" + NAME | SIZE (KB) +-------------+------------ + result.txt | 10 +``` diff --git a/docs/docs/articles/creating-test-suites.md b/docs/docs/articles/creating-test-suites.md index dd7961096d7..672aaaca33e 100644 --- a/docs/docs/articles/creating-test-suites.md +++ b/docs/docs/articles/creating-test-suites.md @@ -13,7 +13,7 @@ By default the concurrency level for parallel tests is set to 10, you can redefi ## Passing Test Suite Artifacts between Steps -In some scenarios you need to access artifacts generated on previous steps of the test suite. Testkube provides two options to define which artifacts to download in the init container: all previous step artifacts or artifacts for selected steps (step number is started from 1). All downloaded artifacts are stored in /data/downloaded-artifacts/{execution id} folder. See a few examples below. +In some scenarios you need to access artifacts generated on previous steps of the test suite. Testkube provides two options to define which artifacts to download in the init container: all previous step artifacts or artifacts for selected steps (step number is started from 1) or artifacts for latest executions of previously executed tests (identified by names). All downloaded artifacts are stored in /data/downloaded-artifacts/{execution id} folder. See a few examples below. ## Test Suite Creation @@ -29,7 +29,7 @@ echo ' "steps": [ {"execute": [{"test": "testkube-api"}, {""test": "testkube-dashboard"}]}, {"execute": [{"delay": "1s"}]}, - {"execute": [{"test": "testkube-dashboard"}, {"delay": "1s"}, {""test": "testkube-homepage"}]}, + {"downloadArtifacts": {"previousTestNames": ["testkube-api"]}, "execute": [{"test": "testkube-dashboard"}, {"delay": "1s"}, {""test": "testkube-homepage"}]}, {"execute": [{"delay": "1s"}]}, {"downloadArtifacts": {"previousStepNumbers": [1, 3]}, "execute": [{"test": "testkube-api-performance"}]}, {"execute": [{"delay": "1s"}]}, @@ -77,6 +77,10 @@ spec: execute: - delay: 1s - stopOnFailure: false + downloadArtifacts: + allPreviousSteps: false + previousTestNames: + - testkube-api execute: - test: testkube-dashboard - delay: 1s diff --git a/docs/docs/articles/helm-chart.md b/docs/docs/articles/helm-chart.md index 342328b80b9..a441a4f1ae6 100644 --- a/docs/docs/articles/helm-chart.md +++ b/docs/docs/articles/helm-chart.md @@ -118,6 +118,7 @@ The following Helm defaults are used in the `testkube` chart: | testkube-api.storage.compressArtifacts | yes | true | | testkube-api.enableSecretsEndpoint | yes | false | | testkube-api.disableMongoMigrations | yes | false | +| testkube-api.enabledExecutors | no | "" | >For more configuration parameters of a `MongoDB` chart please visit: diff --git a/docs/docs/articles/running-tests.md b/docs/docs/articles/running-tests.md index 76d1e457e4a..5d2a7490192 100644 --- a/docs/docs/articles/running-tests.md +++ b/docs/docs/articles/running-tests.md @@ -107,14 +107,14 @@ For some 'real world' tests, configuration variables are passed in order to run Let's assume that our example Cypress test needs the `testparam` parameter with the value `testvalue`. -This is done by using the `-p` parameter. If you need to pass more parameters, simply pass multiple `-p` flags. +This is done by using the `--variable` flag (or just `-v`). If you need to pass more parameters, either pass the values as a comma-separated string or simply pass multiple `-v` flags. It's possible to pass parameters securely to the executed test. It's necessary to use the `--secret` flag, which contains a key value pair - a name of the Kubernetes secret and a secret key. It can be passed multiple times if needed. ```sh -kubectl testkube run test kubeshop-cypress -p testparam=testvalue -f --secret secret-name=secret-key +kubectl testkube run test kubeshop-cypress -v testparam=testvalue -f --secret secret-name=secret-key ``` ```sh title="Expected output:" diff --git a/docs/docs/articles/testkube-oss.md b/docs/docs/articles/testkube-oss.md index a934aab386e..00d0d3d1ac9 100644 --- a/docs/docs/articles/testkube-oss.md +++ b/docs/docs/articles/testkube-oss.md @@ -34,3 +34,8 @@ Verify Your Installation: Ensure that Testkube is up and running with: Once set up, you're ready to unleash the full potential of Testkube in your environment. Whether you opt for the Open Source or Pro variant, Testkube is committed to powering your development and testing workflows seamlessly. +## Minimum Resource Requirements + +To ensure optimal performance, the initial setup requires a minimum of **2 CPU cores** and **8 GB of RAM**. This configuration is suitable for basic operations. + +For environments with higher demands or fluctuating workloads, we recommend implementing an **autoscaler**. This allows for dynamic scaling of resources based on actual usage, ensuring both efficient performance and cost-effectiveness. Users can configure the autoscaler according to their specific needs, adapting to varying workloads seamlessly. diff --git a/docs/docs/cli/testkube.md b/docs/docs/cli/testkube.md index bc755dc4965..6a8ae3ccc98 100644 --- a/docs/docs/cli/testkube.md +++ b/docs/docs/cli/testkube.md @@ -1,6 +1,6 @@ ## testkube -Testkube entrypoint for kubectl plugin. +Testkube entrypoint for kubectl plugin ``` testkube [flags] diff --git a/docs/docs/cli/testkube_create_test.md b/docs/docs/cli/testkube_create_test.md index a5c90e3fd28..0015a3a7f70 100644 --- a/docs/docs/cli/testkube_create_test.md +++ b/docs/docs/cli/testkube_create_test.md @@ -15,8 +15,10 @@ testkube create test [flags] ``` --args-mode string usage mode for arguments. one of append|override (default "append") --artifact-dir stringArray artifact dirs for scraping + --artifact-mask stringArray regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\.json,.*\.js$ --artifact-omit-folder-per-execution don't store artifacts in execution folder - --artifact-storage-bucket string artifact storage class name for container executor + --artifact-shared-between-pods whether to share volume between pods + --artifact-storage-bucket string artifact storage bucket --artifact-storage-class-name string artifact storage class name for container executor --artifact-volume-mount-path string artifact volume mount path for container executor --command stringArray command passed to image in executor diff --git a/docs/docs/cli/testkube_generate_tests-crds.md b/docs/docs/cli/testkube_generate_tests-crds.md index 7a18c79b489..f34efd49b9a 100644 --- a/docs/docs/cli/testkube_generate_tests-crds.md +++ b/docs/docs/cli/testkube_generate_tests-crds.md @@ -15,8 +15,10 @@ testkube generate tests-crds [flags] ``` --args-mode string usage mode for arguments. one of append|override (default "append") --artifact-dir stringArray artifact dirs for scraping + --artifact-mask stringArray regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\.json,.*\.js$ --artifact-omit-folder-per-execution don't store artifacts in execution folder - --artifact-storage-bucket string artifact storage class name for container executor + --artifact-shared-between-pods whether to share volume between pods + --artifact-storage-bucket string artifact storage bucket --artifact-storage-class-name string artifact storage class name for container executor --artifact-volume-mount-path string artifact volume mount path for container executor --command stringArray command passed to image in executor diff --git a/docs/docs/cli/testkube_get.md b/docs/docs/cli/testkube_get.md index 3cb8083172f..c5d70315948 100644 --- a/docs/docs/cli/testkube_get.md +++ b/docs/docs/cli/testkube_get.md @@ -33,7 +33,7 @@ testkube get [flags] * [testkube](testkube.md) - Testkube entrypoint for kubectl plugin * [testkube get artifact](testkube_get_artifact.md) - List artifacts of the given test or test suite execution name -* [testkube get context](testkube_get_context.md) - Set context for Testkube Cloud +* [testkube get context](testkube_get_context.md) - Set context for Testkube Pro * [testkube get execution](testkube_get_execution.md) - Lists or gets test executions * [testkube get executor](testkube_get_executor.md) - Gets executor details * [testkube get template](testkube_get_template.md) - Get template details. diff --git a/docs/docs/cli/testkube_get_context.md b/docs/docs/cli/testkube_get_context.md index ccfd7d88bb9..58cb6eb95a2 100644 --- a/docs/docs/cli/testkube_get_context.md +++ b/docs/docs/cli/testkube_get_context.md @@ -1,6 +1,6 @@ ## testkube get context -Set context for Testkube Cloud +Set context for Testkube Pro ``` testkube get context [flags] diff --git a/docs/docs/cli/testkube_run_test.md b/docs/docs/cli/testkube_run_test.md index 61bdd25eb93..62b186732b0 100644 --- a/docs/docs/cli/testkube_run_test.md +++ b/docs/docs/cli/testkube_run_test.md @@ -16,8 +16,10 @@ testkube run test [flags] --args stringArray executor binary additional arguments --args-mode string usage mode for argumnets. one of append|override (default "append") --artifact-dir stringArray artifact dirs for scraping + --artifact-mask stringArray regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\.json,.*\.js$ --artifact-omit-folder-per-execution don't store artifacts in execution folder - --artifact-storage-bucket string artifact storage class name for container executor + --artifact-shared-between-pods whether to share volume between pods + --artifact-storage-bucket string artifact storage bucket --artifact-storage-class-name string artifact storage class name for container executor --artifact-volume-mount-path string artifact volume mount path for container executor --command stringArray command passed to image in executor diff --git a/docs/docs/cli/testkube_set.md b/docs/docs/cli/testkube_set.md index 23a4e75f7cd..8a65c5dd470 100644 --- a/docs/docs/cli/testkube_set.md +++ b/docs/docs/cli/testkube_set.md @@ -30,5 +30,5 @@ testkube set [flags] ### SEE ALSO * [testkube](testkube.md) - Testkube entrypoint for kubectl plugin -* [testkube set context](testkube_set_context.md) - Set context data for Testkube Cloud +* [testkube set context](testkube_set_context.md) - Set context data for Testkube Pro diff --git a/docs/docs/cli/testkube_set_context.md b/docs/docs/cli/testkube_set_context.md index a768bbd3605..326cd19f277 100644 --- a/docs/docs/cli/testkube_set_context.md +++ b/docs/docs/cli/testkube_set_context.md @@ -1,6 +1,6 @@ ## testkube set context -Set context data for Testkube Cloud +Set context data for Testkube Pro ``` testkube set context [flags] diff --git a/docs/docs/cli/testkube_update_test.md b/docs/docs/cli/testkube_update_test.md index 9c5fc744c37..cc472b3af10 100644 --- a/docs/docs/cli/testkube_update_test.md +++ b/docs/docs/cli/testkube_update_test.md @@ -15,8 +15,10 @@ testkube update test [flags] ``` --args-mode string usage mode for arguments. one of append|override (default "append") --artifact-dir stringArray artifact dirs for scraping + --artifact-mask stringArray regexp to filter scraped artifacts, single or comma separated, like report/.* or .*\.json,.*\.js$ --artifact-omit-folder-per-execution don't store artifacts in execution folder - --artifact-storage-bucket string artifact storage class name for container executor + --artifact-shared-between-pods whether to share volume between pods + --artifact-storage-bucket string artifact storage bucket --artifact-storage-class-name string artifact storage class name for container executor --artifact-volume-mount-path string artifact volume mount path for container executor --command stringArray command passed to image in executor diff --git a/docs/docs/img/log-highlighting-filtering.png b/docs/docs/img/log-highlighting-filtering.png new file mode 100644 index 00000000000..d00fbb1f336 Binary files /dev/null and b/docs/docs/img/log-highlighting-filtering.png differ diff --git a/docs/docs/img/log-highlighting.png b/docs/docs/img/log-highlighting.png new file mode 100644 index 00000000000..c1a7896b14f Binary files /dev/null and b/docs/docs/img/log-highlighting.png differ diff --git a/docs/docs/test-types/container-executor.mdx b/docs/docs/test-types/container-executor.mdx index 2630e031b8a..2a975d82e48 100644 --- a/docs/docs/test-types/container-executor.mdx +++ b/docs/docs/test-types/container-executor.mdx @@ -301,64 +301,3 @@ Downloads into the `/data/repo` directory. $ ls /data/repO CODE_OF_CONDUCT.md CONTRIBUTING.md LICENSE Makefile README.md build cmd go.mod go.sum pkg ``` - -## Collecting Test Artifacts - -For container executors that produce files during test execution, Testkube supports collecting (scraping) these artifacts and storing them in our S3 compatible file storage. You need to save test related files into specified directories on the dynamically created volume. They will be uploaded from there to Testkube file storage and available later for downloading using standard Testkube CLI or Testkube Dashboard commands. For example: - -```yaml -apiVersion: tests.testkube.io/v3 -kind: Test -metadata: - name: cli-container - namespace: testkube -spec: - type: cli/container - executionRequest: - artifactRequest: - storageClassName: standard - volumeMountPath: /share - dirs: - - test/reports -``` - -You have to define the storage class name, volume mount path and directories in this volume with test artifacts. -Default volume mount path is `/data/artifacts` and directory is `.` . -Make sure your container executor definition has `artifacts` feature. For example: - -```yaml -apiVersion: executor.testkube.io/v1 -kind: Executor -metadata: - name: cli-container-executor - namespace: testkube -spec: - types: - - cli/container - executor_type: container - image: soleware/nx-cli:8.5.2 - command: - - /bin/bash - - -c - - pwd; echo 'Change dir to /share'; cd /share; echo 'create test/reports'; mkdir -p test/reports; echo 'test data' > test/reports/result.txt - features: - - artifacts -``` - -Run your test using the CLI command: - -```sh -testkube run test cli-container -``` - -Then get available artifacts for your test execution id: - -```sh -testkube get artifact 638a08b94ff1d2c694aeebf2 -``` - -```sh title="Expected output:" - NAME | SIZE (KB) --------------+------------ - result.txt | 10 -``` diff --git a/docs/docs/testkube-pro/articles/log-highlighting.md b/docs/docs/testkube-pro/articles/log-highlighting.md new file mode 100644 index 00000000000..9db9b20632c --- /dev/null +++ b/docs/docs/testkube-pro/articles/log-highlighting.md @@ -0,0 +1,38 @@ +# Log Highlighting + +export const ProBadge = () => { + return ( + +

PRO FEATURE

+
+ ); +} + + + +## Overview + +In Testkube Pro, we highlight relevant keywords in logs for faster debugging. To use this feature, open execution details. + +On this screen, all the lines that may be relevant will be highlighted in the interface. + +![log-highlighting.png](../../img/log-highlighting.png) + +You may navigate through the highlighted lines with the arrows on top of the interface +or use the scrollbar where all relevant lines are marked. + +## Filtering + +To decide on the active highlight categories, you may click the "Highlight for keywords" button. +By default, all the categories are active. + +![log-highlighting-filtering.png](../../img/log-highlighting-filtering.png) + +There are 4 categories at the moment, represented with few keywords each: + +| Category | Keywords | +|----------------------------|---------------------------------------------------------------------| +| **Error Keywords** | Error, Exception, Fail, Critical, Fatal | +| **Connection** | Connection, Disconnect, Lost, Timeout, Refused, Handshake, Retrying | +| **Resource Issues** | OutOfMemory, MemoryLeak, ResourceExhausted, LimitExceeded, Quota | +| **Access & Authorization** | Denied, Unauthorized, Forbidden, Invalid, Invalid Token, Expired | \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json index 39ffa61ae48..7c5ed49d3d0 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -219,17 +219,62 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "license": "MIT", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/@babel/compat-data": { "version": "7.19.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz", @@ -293,13 +338,13 @@ "license": "MIT" }, "node_modules/@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", - "license": "MIT", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dependencies": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { @@ -427,10 +472,9 @@ "license": "MIT" }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } @@ -448,25 +492,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", - "license": "MIT", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "license": "MIT", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -595,31 +637,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "license": "MIT", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", - "license": "MIT", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", - "license": "MIT", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -663,13 +702,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "license": "MIT", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -680,7 +718,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -692,7 +729,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -706,7 +742,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -714,23 +749,20 @@ "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==", - "license": "MIT", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -2046,34 +2078,32 @@ } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", - "license": "MIT", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -2104,13 +2134,12 @@ "license": "MIT" }, "node_modules/@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", - "license": "MIT", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dependencies": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2892,13 +2921,12 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", - "license": "MIT", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@leichtgewicht/ip-codec": { @@ -8804,10 +8832,15 @@ } }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", - "license": "MIT", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -9618,9 +9651,9 @@ } }, "node_modules/postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "funding": [ { "type": "opencollective", @@ -9629,11 +9662,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -14073,11 +14109,50 @@ } }, "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "requires": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + } } }, "@babel/compat-data": { @@ -14123,12 +14198,13 @@ } }, "@babel/generator": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz", - "integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "requires": { - "@babel/types": "^7.19.0", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" } }, @@ -14212,9 +14288,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -14225,20 +14301,20 @@ } }, "@babel/helper-function-name": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "requires": { - "@babel/template": "^7.18.10", - "@babel/types": "^7.19.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" } }, "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-member-expression-to-functions": { @@ -14325,22 +14401,22 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" } }, "@babel/helper-string-parser": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", - "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==" }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" }, "@babel/helper-validator-option": { "version": "7.18.6", @@ -14369,12 +14445,12 @@ } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "dependencies": { @@ -14417,9 +14493,9 @@ } }, "@babel/parser": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz", - "integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==" + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", @@ -15217,29 +15293,29 @@ } }, "@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" } }, "@babel/traverse": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz", - "integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.19.0", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.19.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.19.0", - "@babel/types": "^7.19.0", - "debug": "^4.1.0", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "dependencies": { @@ -15259,12 +15335,12 @@ } }, "@babel/types": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz", - "integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "requires": { - "@babel/helper-string-parser": "^7.18.10", - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" } }, @@ -15841,12 +15917,12 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" }, "@jridgewell/trace-mapping": { - "version": "0.3.15", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz", - "integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "@leichtgewicht/ip-codec": { @@ -19778,9 +19854,9 @@ } }, "nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" }, "negotiator": { "version": "0.6.3", @@ -20325,11 +20401,11 @@ } }, "postcss": { - "version": "8.4.16", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", - "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "requires": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } diff --git a/docs/redirects.js b/docs/redirects.js index 892bf826c8a..46f9a796e71 100644 --- a/docs/redirects.js +++ b/docs/redirects.js @@ -179,8 +179,8 @@ const redirects = [ to: "/articles/scheduling-tests", }, { - from: ["/concepts/artifacts-storage", "/using-testkube/artifacts-storage"], - to: "/articles/artifacts-storage", + from: ["/concepts/artifacts", "/using-testkube/artifacts"], + to: "/articles/artifacts", }, { from: "/concepts/metrics", diff --git a/docs/sidebars.js b/docs/sidebars.js index ff1d51cbfec..1a55ea7b7f9 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -184,6 +184,7 @@ const sidebars = { "testkube-pro/articles/AI-test-insights", "testkube-pro/articles/status-pages", "testkube-pro/articles/cached-results", + "testkube-pro/articles/log-highlighting", ], }, { @@ -217,7 +218,7 @@ const sidebars = { }, "openapi", "articles/metrics", - "articles/artifacts-storage", + "articles/artifacts", "articles/testkube-dependencies", "articles/architecture", "articles/telemetry", diff --git a/docs/static/img/test-status/created.png b/docs/static/img/test-status/created.png new file mode 100644 index 00000000000..5e8bc3ef03f Binary files /dev/null and b/docs/static/img/test-status/created.png differ diff --git a/docs/static/img/test-status/deleted.png b/docs/static/img/test-status/deleted.png new file mode 100644 index 00000000000..d729c527f9a Binary files /dev/null and b/docs/static/img/test-status/deleted.png differ diff --git a/docs/static/img/test-status/end-test-aborted.png b/docs/static/img/test-status/end-test-aborted.png new file mode 100644 index 00000000000..06c964da9df Binary files /dev/null and b/docs/static/img/test-status/end-test-aborted.png differ diff --git a/docs/static/img/test-status/end-test-failed.png b/docs/static/img/test-status/end-test-failed.png new file mode 100644 index 00000000000..e95c2d9e4c9 Binary files /dev/null and b/docs/static/img/test-status/end-test-failed.png differ diff --git a/docs/static/img/test-status/end-test-success.png b/docs/static/img/test-status/end-test-success.png new file mode 100644 index 00000000000..06c964da9df Binary files /dev/null and b/docs/static/img/test-status/end-test-success.png differ diff --git a/docs/static/img/test-status/end-test-timeout.png b/docs/static/img/test-status/end-test-timeout.png new file mode 100644 index 00000000000..06c964da9df Binary files /dev/null and b/docs/static/img/test-status/end-test-timeout.png differ diff --git a/docs/static/img/test-status/start-test.png b/docs/static/img/test-status/start-test.png new file mode 100644 index 00000000000..9a55a9faf74 Binary files /dev/null and b/docs/static/img/test-status/start-test.png differ diff --git a/docs/static/img/test-status/updated.png b/docs/static/img/test-status/updated.png new file mode 100644 index 00000000000..d3a8e1ee062 Binary files /dev/null and b/docs/static/img/test-status/updated.png differ diff --git a/go.mod b/go.mod index 0c473aa5542..7426d8c6e6d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/joshdk/go-junit v1.0.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/kubepug/kubepug v1.7.1 - github.com/kubeshop/testkube-operator v1.16.11 + github.com/kubeshop/testkube-operator v1.16.21 github.com/minio/minio-go/v7 v7.0.47 github.com/montanaflynn/stats v0.6.6 github.com/moogar0880/problems v0.1.1 @@ -178,13 +178,13 @@ require ( github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect golang.org/x/oauth2 v0.13.0 golang.org/x/sync v0.4.0 - golang.org/x/sys v0.14.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.13.0 + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/go.sum b/go.sum index e8e5b6887d6..74af23eb2ff 100644 --- a/go.sum +++ b/go.sum @@ -354,8 +354,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kubepug/kubepug v1.7.1 h1:LKhfSxS8Y5mXs50v+3Lpyec+cogErDLcV7CMUuiaisw= github.com/kubepug/kubepug v1.7.1/go.mod h1:lv+HxD0oTFL7ZWjj0u6HKhMbbTIId3eG7aWIW0gyF8g= -github.com/kubeshop/testkube-operator v1.16.11 h1:EKqTnPH4HP+PH8cWbgkQsHxFx1CAOjDTQyqSFv0gjhA= -github.com/kubeshop/testkube-operator v1.16.11/go.mod h1:P47tw1nKQFufdsZndyq2HG2MSa0zK/lU0XpRfZtEmIk= +github.com/kubeshop/testkube-operator v1.16.21 h1:PEZqCM96Q2hx56qut4jdSjgYXkxbytnvtalgSIxTSwA= +github.com/kubeshop/testkube-operator v1.16.21/go.mod h1:P47tw1nKQFufdsZndyq2HG2MSa0zK/lU0XpRfZtEmIk= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4= @@ -602,8 +602,8 @@ golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -774,16 +774,16 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -795,8 +795,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/goreleaser_files/.goreleaser-docker-build-api.yml b/goreleaser_files/.goreleaser-docker-build-api.yml index 3be0d0775a8..86ac3a75ec7 100644 --- a/goreleaser_files/.goreleaser-docker-build-api.yml +++ b/goreleaser_files/.goreleaser-docker-build-api.yml @@ -96,4 +96,3 @@ docker_signs: snapshot: name_template: "{{ .ShortCommit }}" - diff --git a/goreleaser_files/.goreleaser-docker-build-executor-cypress.yml b/goreleaser_files/.goreleaser-docker-build-executor-cypress.yml index aaea31ae21a..d8a6053b93a 100644 --- a/goreleaser_files/.goreleaser-docker-build-executor-cypress.yml +++ b/goreleaser_files/.goreleaser-docker-build-executor-cypress.yml @@ -52,6 +52,16 @@ dockers: - "--builder={{ .Env.DOCKER_BUILDX_BUILDER }}" - "--cache-to={{ .Env.DOCKER_BUILDX_CACHE_TO }}" - "--cache-from={{ .Env.DOCKER_BUILDX_CACHE_FROM }}" + - +docker_manifests: + - name_template: "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Version }}-{{ .Env.EXECUTOR_VERSION }}-{{ end }}" + image_templates: + - "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Version }}-{{ .Env.EXECUTOR_VERSION }}-arm64v8{{ end }}" + - "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Version }}-{{ .Env.EXECUTOR_VERSION }}-amd64{{ end }}" + - name_template: "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Env.EXECUTOR_VERSION }}-{{ end }}" + image_templates: + - "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Version }}-{{ .Env.EXECUTOR_VERSION }}-arm64v8{{ end }}" + - "{{ if not .Env.IMAGE_TAG_SHA }}{{ .Env.DOCKER_REPO }}/testkube-cypress-executor:{{ .Version }}-{{ .Env.EXECUTOR_VERSION }}-amd64{{ end }}" snapshot: name_template: '{{ .Version }}' diff --git a/install.sh b/install.sh index 350bd1dbd78..349621366cc 100644 --- a/install.sh +++ b/install.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash echo "Getting kubectl-testkube plugin" if [ ! -z "${DEBUG}" ]; @@ -20,14 +20,14 @@ _detect_arch() { } _detect_os(){ - case $(uname) in - Linux) echo "Linux" - ;; + case $(uname) in + Linux) echo "Linux" + ;; Darwin) echo "Darwin" - ;; - Windows) echo "Windows" - ;; - esac + ;; + Windows) echo "Windows" + ;; + esac } _download_url() { @@ -46,6 +46,14 @@ _download_url() { | jq -r '.[].tag_name | select(test("beta"))' \ | head -n 1 \ )" + if [ -z "$tag" ]; then + echo "No beta releases found. Installing latest release" >&2 + tag="$( + curl -s "https://api.github.com/repos/kubeshop/testkube/releases/latest" \ + 2>/dev/null \ + | jq -r '.tag_name' \ + )" + fi else tag="$( curl -s "https://api.github.com/repos/kubeshop/testkube/releases/latest" \ @@ -62,14 +70,15 @@ _download_url() { } if [ "$1" = "beta" ]; then - echo "Downloading testkube from URL: $(_download_url "beta")" - curl -sSLf "$(_download_url "beta")" > testkube.tar.gz + url="$(_download_url "beta")" + echo "Downloading testkube from URL: $url" + curl -sSLf "$url" > testkube.tar.gz else echo "Downloading testkube from URL: $(_download_url)" curl -sSLf "$(_download_url)" > testkube.tar.gz fi -tar -xzf testkube.tar.gz kubectl-testkube +tar -xzf testkube.tar.gz kubectl-testkube rm testkube.tar.gz mv kubectl-testkube /usr/local/bin/kubectl-testkube ln -s /usr/local/bin/kubectl-testkube /usr/local/bin/testkube @@ -79,7 +88,7 @@ echo "kubectl-testkube installed in:" echo "- /usr/local/bin/kubectl-testkube" echo "- /usr/local/bin/testkube" echo "- /usr/local/bin/tk" -echo "" +echo "" echo "You'll also need `helm` and Kubernetes `kubectl` installed." echo "- Install Helm: https://helm.sh/docs/intro/install/" echo "- Install kubectl: https://kubernetes.io/docs/tasks/tools/#kubectl" \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index cdd7da60e62..01d1f9c9bb7 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -47,7 +47,7 @@ type Config struct { JobTemplateFile string `envconfig:"JOB_TEMPLATE_FILE" default:""` DisableTestTriggers bool `envconfig:"DISABLE_TEST_TRIGGERS" default:"false"` TestkubeDefaultExecutors string `envconfig:"TESTKUBE_DEFAULT_EXECUTORS" default:""` - TestkubeSpecifiedExecutors string `envconfig:"TESTKUBE_SPECIFIED_EXECUTORS" default:""` + TestkubeEnabledExecutors string `envconfig:"TESTKUBE_ENABLED_EXECUTORS" default:""` TestkubeTemplateJob string `envconfig:"TESTKUBE_TEMPLATE_JOB" default:""` TestkubeContainerTemplateJob string `envconfig:"TESTKUBE_CONTAINER_TEMPLATE_JOB" default:""` TestkubeContainerTemplateScraper string `envconfig:"TESTKUBE_CONTAINER_TEMPLATE_SCRAPER" default:""` diff --git a/internal/template/parser.go b/internal/template/parser.go index 6ad8ed9b089..722d07df59a 100644 --- a/internal/template/parser.go +++ b/internal/template/parser.go @@ -9,32 +9,77 @@ import ( "github.com/pkg/errors" "github.com/kubeshop/testkube/internal/config" + "github.com/kubeshop/testkube/pkg/executor" "github.com/kubeshop/testkube/pkg/log" "github.com/kubeshop/testkube/pkg/utils" ) -func ParseJobTemplates(cfg *config.Config) (jobTemplate, slavePodTemplate string, err error) { - jobTemplate, err = LoadConfigFromStringOrFile( +func ParseJobTemplates(cfg *config.Config) (t executor.Templates, err error) { + t.Job, err = LoadConfigFromStringOrFile( cfg.TestkubeTemplateJob, cfg.TestkubeConfigDir, "job-template.yml", "job template", ) if err != nil { - return "", "", err + return t, err } - slavePodTemplate, err = LoadConfigFromStringOrFile( + t.Slave, err = LoadConfigFromStringOrFile( cfg.TestkubeTemplateSlavePod, cfg.TestkubeConfigDir, "slave-pod-template.yml", "slave pod template", ) if err != nil { - return "", "", err + return t, err } - return jobTemplate, slavePodTemplate, nil + t.PVC, err = LoadConfigFromStringOrFile( + cfg.TestkubeContainerTemplatePVC, + cfg.TestkubeConfigDir, + "pvc-template.yml", + "pvc template", + ) + if err != nil { + return t, err + } + + return t, nil +} + +func ParseContainerTemplates(cfg *config.Config) (t executor.Templates, err error) { + t.Job, err = LoadConfigFromStringOrFile( + cfg.TestkubeContainerTemplateJob, + cfg.TestkubeConfigDir, + "job-container-template.yml", + "job container template", + ) + if err != nil { + return t, err + } + + t.Scraper, err = LoadConfigFromStringOrFile( + cfg.TestkubeContainerTemplateScraper, + cfg.TestkubeConfigDir, + "job-scraper-template.yml", + "job scraper template", + ) + if err != nil { + return t, err + } + + t.PVC, err = LoadConfigFromStringOrFile( + cfg.TestkubeContainerTemplatePVC, + cfg.TestkubeConfigDir, + "pvc-template.yml", + "pvc template", + ) + if err != nil { + return t, err + } + + return t, nil } func LoadConfigFromStringOrFile(inputString, configDir, filename, configType string) (raw string, err error) { diff --git a/internal/template/parser_test.go b/internal/template/parser_test.go index 6cd4b005049..70842f9c45b 100644 --- a/internal/template/parser_test.go +++ b/internal/template/parser_test.go @@ -19,11 +19,13 @@ func TestParseJobTemplate(t *testing.T) { cfg, err := config.Get() assertion.NoError(err) - jobTemplate, slavePodTemplate, err := ParseJobTemplates(cfg) + templates, err := ParseJobTemplates(cfg) assertion.NoError(err) // t.Log(jobTemplate) - assertion.NotEmpty(jobTemplate) + assertion.NotEmpty(templates.Job) // t.Log(slavePodTemplate) - assertion.NotEmpty(slavePodTemplate) + assertion.NotEmpty(templates.Slave) + // t.Log(pvcTemplate) + assertion.NotEmpty(templates.PVC) } diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 80160b1f818..69219565377 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -8,6 +8,8 @@ import ( "os" "time" + "google.golang.org/grpc/keepalive" + "github.com/kubeshop/testkube/pkg/executor/output" "github.com/kubeshop/testkube/pkg/version" @@ -27,6 +29,7 @@ import ( ) const ( + timeout = 10 * time.Second apiKeyMeta = "api-key" clusterIDMeta = "cluster-id" cloudMigrateMeta = "migrate" @@ -43,6 +46,8 @@ const ( const bufferSizePerWorker = 5 func NewGRPCConnection(ctx context.Context, isInsecure bool, skipVerify bool, server string, logger *zap.SugaredLogger) (*grpc.ClientConn, error) { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() var tlsConfig *tls.Config if skipVerify { tlsConfig = &tls.Config{InsecureSkipVerify: true} @@ -52,9 +57,26 @@ func NewGRPCConnection(ctx context.Context, isInsecure bool, skipVerify bool, se creds = insecure.NewCredentials() } + kacp := keepalive.ClientParameters{ + Time: 10 * time.Second, + Timeout: 5 * time.Second, + PermitWithoutStream: true, + } + userAgent := version.Version + "/" + version.Commit - logger.Infow("initiating connection with Cloud API", "userAgent", userAgent) - return grpc.DialContext(ctx, server, grpc.WithBlock(), grpc.WithUserAgent(userAgent), grpc.WithTransportCredentials(creds)) + logger.Infow("initiating connection with agent api", "userAgent", userAgent) + // WithBlock, WithReturnConnectionError and FailOnNonTempDialError are recommended not to be used by gRPC go docs + // but given that Agent will not work if gRPC connection cannot be established, it is ok to use them and assert issues at dial time + return grpc.DialContext( + ctx, + server, + grpc.WithBlock(), + grpc.WithReturnConnectionError(), + grpc.FailOnNonTempDialError(true), + grpc.WithUserAgent(userAgent), + grpc.WithTransportCredentials(creds), + grpc.WithKeepaliveParams(kacp), + ) } type Agent struct { diff --git a/pkg/api/v1/client/interface.go b/pkg/api/v1/client/interface.go index 0afa7298d9c..33c46305682 100644 --- a/pkg/api/v1/client/interface.go +++ b/pkg/api/v1/client/interface.go @@ -66,7 +66,7 @@ type TestSuiteAPI interface { type TestSuiteExecutionAPI interface { GetTestSuiteExecution(executionID string) (execution testkube.TestSuiteExecution, err error) ListTestSuiteExecutions(testsuite string, limit int, selector string) (executions testkube.TestSuiteExecutionsResult, err error) - WatchTestSuiteExecution(executionID string) (execution chan testkube.TestSuiteExecution, err error) + WatchTestSuiteExecution(executionID string) (resp chan testkube.WatchTestSuiteExecutionResponse) AbortTestSuiteExecution(executionID string) error AbortTestSuiteExecutions(testSuiteName string) error GetTestSuiteExecutionArtifacts(executionID string) (artifacts testkube.Artifacts, err error) diff --git a/pkg/api/v1/client/testsuite.go b/pkg/api/v1/client/testsuite.go index bc8387d7a61..20d904ee166 100644 --- a/pkg/api/v1/client/testsuite.go +++ b/pkg/api/v1/client/testsuite.go @@ -206,33 +206,46 @@ func (c TestSuiteClient) ExecuteTestSuites(selector string, concurrencyLevel int } // WatchTestSuiteExecution watches for changes in channels of test suite executions steps -func (c TestSuiteClient) WatchTestSuiteExecution(executionID string) (executionCh chan testkube.TestSuiteExecution, err error) { - executionCh = make(chan testkube.TestSuiteExecution) +func (c TestSuiteClient) WatchTestSuiteExecution(executionID string) (respCh chan testkube.WatchTestSuiteExecutionResponse) { + respCh = make(chan testkube.WatchTestSuiteExecutionResponse) go func() { + defer close(respCh) + execution, err := c.GetTestSuiteExecution(executionID) if err != nil { - close(executionCh) + respCh <- testkube.WatchTestSuiteExecutionResponse{ + Error: err, + } return } - executionCh <- execution + respCh <- testkube.WatchTestSuiteExecutionResponse{ + Execution: execution, + } + for range time.NewTicker(time.Second).C { execution, err = c.GetTestSuiteExecution(executionID) if err != nil { - close(executionCh) + respCh <- testkube.WatchTestSuiteExecutionResponse{ + Error: err, + } return } if execution.IsCompleted() { - close(executionCh) + respCh <- testkube.WatchTestSuiteExecutionResponse{ + Execution: execution, + } return } - executionCh <- execution + respCh <- testkube.WatchTestSuiteExecutionResponse{ + Execution: execution, + } } }() - return + return respCh } // ListTestSuiteExecutions list all executions for given test suite diff --git a/pkg/api/v1/testkube/model_artifact_request.go b/pkg/api/v1/testkube/model_artifact_request.go index 301cfd3a01d..c8a45a77149 100644 --- a/pkg/api/v1/testkube/model_artifact_request.go +++ b/pkg/api/v1/testkube/model_artifact_request.go @@ -17,8 +17,12 @@ type ArtifactRequest struct { VolumeMountPath string `json:"volumeMountPath,omitempty"` // artifact directories for scraping Dirs []string `json:"dirs,omitempty"` + // regexp to filter scraped artifacts, single or comma separated + Masks []string `json:"masks,omitempty"` // artifact bucket storage StorageBucket string `json:"storageBucket,omitempty"` // don't use a separate folder for execution artifacts OmitFolderPerExecution bool `json:"omitFolderPerExecution,omitempty"` + // whether to share volume between pods + SharedBetweenPods bool `json:"sharedBetweenPods,omitempty"` } diff --git a/pkg/api/v1/testkube/model_artifact_update_request.go b/pkg/api/v1/testkube/model_artifact_update_request.go index b8f2b4f4b7b..76e1d17c096 100644 --- a/pkg/api/v1/testkube/model_artifact_update_request.go +++ b/pkg/api/v1/testkube/model_artifact_update_request.go @@ -17,8 +17,12 @@ type ArtifactUpdateRequest struct { VolumeMountPath *string `json:"volumeMountPath,omitempty"` // artifact directories for scraping Dirs *[]string `json:"dirs,omitempty"` + // regexp to filter scraped artifacts, single or comma separated + Masks *[]string `json:"masks,omitempty"` // artifact bucket storage StorageBucket *string `json:"storageBucket,omitempty"` // don't use a separate folder for execution artifacts OmitFolderPerExecution *bool `json:"omitFolderPerExecution,omitempty"` + // whether to share volume between pods + SharedBetweenPods *bool `json:"sharedBetweenPods,omitempty"` } diff --git a/pkg/api/v1/testkube/model_artifact_updt_request_extended.go b/pkg/api/v1/testkube/model_artifact_updt_request_extended.go index 92ad25b2078..4ef9dbb8962 100644 --- a/pkg/api/v1/testkube/model_artifact_updt_request_extended.go +++ b/pkg/api/v1/testkube/model_artifact_updt_request_extended.go @@ -2,7 +2,8 @@ package testkube // IsEmpty check if request is empty func (a *ArtifactUpdateRequest) IsEmpty() bool { - if a.StorageClassName != nil || a.VolumeMountPath != nil || a.Dirs != nil || a.StorageBucket != nil || a.OmitFolderPerExecution != nil { + if a.StorageClassName != nil || a.VolumeMountPath != nil || a.Dirs != nil || a.Masks != nil || + a.StorageBucket != nil || a.OmitFolderPerExecution != nil || a.SharedBetweenPods != nil { return false } diff --git a/pkg/api/v1/testkube/model_download_artifact_options.go b/pkg/api/v1/testkube/model_download_artifact_options.go index af444f81f31..348034398ce 100644 --- a/pkg/api/v1/testkube/model_download_artifact_options.go +++ b/pkg/api/v1/testkube/model_download_artifact_options.go @@ -14,4 +14,6 @@ type DownloadArtifactOptions struct { AllPreviousSteps bool `json:"allPreviousSteps,omitempty"` // previous step numbers starting from 1 PreviousStepNumbers []int32 `json:"previousStepNumbers,omitempty"` + // previous test names + PreviousTestNames []string `json:"previousTestNames,omitempty"` } diff --git a/pkg/api/v1/testkube/model_event_resource.go b/pkg/api/v1/testkube/model_event_resource.go index 7eaec800623..34acdae7ffc 100644 --- a/pkg/api/v1/testkube/model_event_resource.go +++ b/pkg/api/v1/testkube/model_event_resource.go @@ -20,4 +20,5 @@ const ( WEBHOOK_EventResource EventResource = "webhook" TESTEXECUTION_EventResource EventResource = "testexecution" TESTSUITEEXECUTION_EventResource EventResource = "testsuiteexecution" + TESTSOURCE_EventResource EventResource = "testsource" ) diff --git a/pkg/api/v1/testkube/model_event_resource_extended.go b/pkg/api/v1/testkube/model_event_resource_extended.go index ce96f754e9f..3c0b15a9855 100644 --- a/pkg/api/v1/testkube/model_event_resource_extended.go +++ b/pkg/api/v1/testkube/model_event_resource_extended.go @@ -12,4 +12,5 @@ var ( EventResourceWebhook = EventResourcePtr(WEBHOOK_EventResource) EventResourceTestexecution = EventResourcePtr(TESTEXECUTION_EventResource) EventResourceTestsuiteexecution = EventResourcePtr(TESTSUITEEXECUTION_EventResource) + EventResourceTestsource = EventResourcePtr(TESTSOURCE_EventResource) ) diff --git a/pkg/api/v1/testkube/model_execution.go b/pkg/api/v1/testkube/model_execution.go index f9c847af023..77cc094d517 100644 --- a/pkg/api/v1/testkube/model_execution.go +++ b/pkg/api/v1/testkube/model_execution.go @@ -76,6 +76,8 @@ type Execution struct { // test execution name started the test execution TestExecutionName string `json:"testExecutionName,omitempty"` // execution ids for artifacts to download - DownloadArtifactExecutionIDs []string `json:"downloadArtifactExecutionIDs,omitempty"` - SlavePodRequest *PodRequest `json:"slavePodRequest,omitempty"` + DownloadArtifactExecutionIDs []string `json:"downloadArtifactExecutionIDs,omitempty"` + // test names for artifacts to download from latest executions + DownloadArtifactTestNames []string `json:"downloadArtifactTestNames,omitempty"` + SlavePodRequest *PodRequest `json:"slavePodRequest,omitempty"` } diff --git a/pkg/api/v1/testkube/model_execution_request.go b/pkg/api/v1/testkube/model_execution_request.go index 19e57329c75..e6a8334c3af 100644 --- a/pkg/api/v1/testkube/model_execution_request.go +++ b/pkg/api/v1/testkube/model_execution_request.go @@ -96,6 +96,8 @@ type ExecutionRequest struct { // test execution name started the test execution TestExecutionName string `json:"testExecutionName,omitempty"` // execution ids for artifacts to download - DownloadArtifactExecutionIDs []string `json:"downloadArtifactExecutionIDs,omitempty"` - SlavePodRequest *PodRequest `json:"slavePodRequest,omitempty"` + DownloadArtifactExecutionIDs []string `json:"downloadArtifactExecutionIDs,omitempty"` + // test names for artifacts to download from latest executions + DownloadArtifactTestNames []string `json:"downloadArtifactTestNames,omitempty"` + SlavePodRequest *PodRequest `json:"slavePodRequest,omitempty"` } diff --git a/pkg/api/v1/testkube/model_execution_update_request.go b/pkg/api/v1/testkube/model_execution_update_request.go index f89b05a51da..13f762d2087 100644 --- a/pkg/api/v1/testkube/model_execution_update_request.go +++ b/pkg/api/v1/testkube/model_execution_update_request.go @@ -96,6 +96,8 @@ type ExecutionUpdateRequest struct { // test execution name started the test execution TestExecutionName *string `json:"testExecutionName,omitempty"` // execution ids for artifacts to download - DownloadArtifactExecutionIDs *[]string `json:"downloadArtifactExecutionIDs,omitempty"` - SlavePodRequest **PodUpdateRequest `json:"slavePodRequest,omitempty"` + DownloadArtifactExecutionIDs *[]string `json:"downloadArtifactExecutionIDs,omitempty"` + // test names for artifacts to download from latest executions + DownloadArtifactTestNames *[]string `json:"downloadArtifactTestNames,omitempty"` + SlavePodRequest **PodUpdateRequest `json:"slavePodRequest,omitempty"` } diff --git a/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result.go b/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result.go index d72e0ccc2fb..27e4d14667f 100644 --- a/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result.go +++ b/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result.go @@ -9,8 +9,18 @@ */ package testkube +import ( + "time" +) + // execution result returned from executor type TestSuiteBatchStepExecutionResult struct { Step *TestSuiteBatchStep `json:"step,omitempty"` Execute []TestSuiteStepExecutionResult `json:"execute,omitempty"` + // step start time + StartTime time.Time `json:"startTime,omitempty"` + // step end time + EndTime time.Time `json:"endTime,omitempty"` + // step duration + Duration string `json:"duration,omitempty"` } diff --git a/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result_extended.go b/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result_extended.go new file mode 100644 index 00000000000..01bd32ce03c --- /dev/null +++ b/pkg/api/v1/testkube/model_test_suite_batch_step_execution_result_extended.go @@ -0,0 +1,31 @@ +package testkube + +import ( + "time" + + "github.com/kubeshop/testkube/pkg/utils" +) + +func (e *TestSuiteBatchStepExecutionResult) Start() { + e.StartTime = time.Now() +} + +func (e *TestSuiteBatchStepExecutionResult) Stop() { + e.EndTime = time.Now() + e.Duration = utils.RoundDuration(e.CalculateDuration()).String() +} + +func (e *TestSuiteBatchStepExecutionResult) CalculateDuration() time.Duration { + end := e.EndTime + start := e.StartTime + + if start.UnixNano() <= 0 && end.UnixNano() <= 0 { + return time.Duration(0) + } + + if end.UnixNano() <= 0 { + end = time.Now() + } + + return end.Sub(e.StartTime) +} diff --git a/pkg/api/v1/testkube/model_test_suite_execution_extended.go b/pkg/api/v1/testkube/model_test_suite_execution_extended.go index 33cd1cccbf8..d1d078e55e7 100644 --- a/pkg/api/v1/testkube/model_test_suite_execution_extended.go +++ b/pkg/api/v1/testkube/model_test_suite_execution_extended.go @@ -11,6 +11,11 @@ import ( "github.com/kubeshop/testkube/pkg/utils" ) +type WatchTestSuiteExecutionResponse struct { + Execution TestSuiteExecution + Error error +} + func NewQueuedTestSuiteExecution(name, namespace string) *TestSuiteExecution { return &TestSuiteExecution{ TestSuite: &ObjectRef{ diff --git a/pkg/cloud/data/artifact/scraper_integration_test.go b/pkg/cloud/data/artifact/scraper_integration_test.go index a88b6cece9d..0eda10921bb 100644 --- a/pkg/cloud/data/artifact/scraper_integration_test.go +++ b/pkg/cloud/data/artifact/scraper_integration_test.go @@ -102,7 +102,7 @@ func TestCloudScraper_ArchiveFilesystemExtractor_Integration(t *testing.T) { TestName: "my-test", TestSuiteName: "my-test-suite", } - err = s.Scrape(context.Background(), []string{tempDir}, execution) + err = s.Scrape(context.Background(), []string{tempDir}, []string{".*"}, execution) assert.NoError(t, err) assert.Equal(t, 2, testServerRequests) @@ -201,7 +201,7 @@ func TestCloudScraper_RecursiveFilesystemExtractor_Integration(t *testing.T) { TestName: "my-test", TestSuiteName: "my-test-suite", } - err = s.Scrape(context.Background(), []string{tempDir}, execution) + err = s.Scrape(context.Background(), []string{tempDir}, []string{".*"}, execution) assert.NoError(t, err) assert.Equal(t, 3, testServerRequests) } diff --git a/pkg/crd/templates/test.tmpl b/pkg/crd/templates/test.tmpl index 06ea6d2ba36..0eb3e951765 100644 --- a/pkg/crd/templates/test.tmpl +++ b/pkg/crd/templates/test.tmpl @@ -188,12 +188,21 @@ spec: - {{ . }} {{- end }} {{- end }} + {{- if gt (len .ExecutionRequest.ArtifactRequest.Masks) 0 }} + masks: + {{- range .ExecutionRequest.ArtifactRequest.Masks }} + - {{ . }} + {{- end }} + {{- end }} {{- if .ExecutionRequest.ArtifactRequest.StorageBucket }} storageBucket: {{ .ExecutionRequest.ArtifactRequest.StorageBucket }} {{- end }} {{- if .ExecutionRequest.ArtifactRequest.OmitFolderPerExecution }} omitFolderPerExecution: {{ .ExecutionRequest.ArtifactRequest.OmitFolderPerExecution }} {{- end }} + {{- if .ExecutionRequest.ArtifactRequest.SharedBetweenPods }} + sharedBetweenPods: {{ .ExecutionRequest.ArtifactRequest.SharedBetweenPods }} + {{- end }} {{- end }} {{- if .ExecutionRequest.JobTemplate }} jobTemplate: {{ .ExecutionRequest.JobTemplate }} diff --git a/pkg/crd/templates/testsuite.tmpl b/pkg/crd/templates/testsuite.tmpl index 675d2c84c77..6e26a4bf19f 100644 --- a/pkg/crd/templates/testsuite.tmpl +++ b/pkg/crd/templates/testsuite.tmpl @@ -26,6 +26,12 @@ spec: - {{ . }} {{- end }} {{- end }} + {{- if ne (len .DownloadArtifacts.PreviousTestNames) 0 }} + previousTestNames: + {{- range .DownloadArtifacts.PreviousTestNames }} + - {{ . }} + {{- end }} + {{- end }} {{- end }} {{- if ne (len .Execute) 0 }} execute: @@ -53,6 +59,12 @@ spec: - {{ . }} {{- end }} {{- end }} + {{- if ne (len .DownloadArtifacts.PreviousTestNames) 0 }} + previousTestNames: + {{- range .DownloadArtifacts.PreviousTestNames }} + - {{ . }} + {{- end }} + {{- end }} {{- end }} {{- if ne (len .Execute) 0 }} execute: @@ -80,6 +92,12 @@ spec: - {{ . }} {{- end }} {{- end }} + {{- if ne (len .DownloadArtifacts.PreviousTestNames) 0 }} + previousTestNames: + {{- range .DownloadArtifacts.PreviousTestNames }} + - {{ . }} + {{- end }} + {{- end }} {{- end }} {{- if ne (len .Execute) 0 }} execute: diff --git a/pkg/executor/client/common.go b/pkg/executor/client/common.go index 31f4d6cae85..a88be2ff854 100644 --- a/pkg/executor/client/common.go +++ b/pkg/executor/client/common.go @@ -1,12 +1,21 @@ package client import ( + "bytes" + "fmt" "time" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/yaml" + kyaml "sigs.k8s.io/kustomize/kyaml/yaml" + "sigs.k8s.io/kustomize/kyaml/yaml/merge2" + executorv1 "github.com/kubeshop/testkube-operator/api/executor/v1" testsv3 "github.com/kubeshop/testkube-operator/api/tests/v3" "github.com/kubeshop/testkube/internal/featureflags" "github.com/kubeshop/testkube/pkg/api/v1/testkube" + "github.com/kubeshop/testkube/pkg/utils" ) const ( @@ -29,3 +38,50 @@ type ExecuteOptions struct { ImagePullSecretNames []string Features featureflags.FeatureFlags } + +type PVCOptions struct { + Name string + Namespace string + PvcTemplate string + PvcTemplateExtensions string + ArtifactRequest *testkube.ArtifactRequest +} + +// NewPersistentVolumeClaimSpec is a method to create new persistent volume claim spec +func NewPersistentVolumeClaimSpec(log *zap.SugaredLogger, options PVCOptions) (*corev1.PersistentVolumeClaim, error) { + tmpl, err := utils.NewTemplate("volume-claim").Parse(options.PvcTemplate) + if err != nil { + return nil, fmt.Errorf("creating volume claim spec from pvc template error: %w", err) + } + + var buffer bytes.Buffer + if err = tmpl.ExecuteTemplate(&buffer, "volume-claim", options); err != nil { + return nil, fmt.Errorf("executing volume claim spec pvc template: %w", err) + } + + var pvc corev1.PersistentVolumeClaim + pvcSpec := buffer.String() + if options.PvcTemplateExtensions != "" { + tmplExt, err := utils.NewTemplate("jobExt").Parse(options.PvcTemplateExtensions) + if err != nil { + return nil, fmt.Errorf("creating pvc extensions spec from executor template error: %w", err) + } + + var bufferExt bytes.Buffer + if err = tmplExt.ExecuteTemplate(&bufferExt, "jobExt", options); err != nil { + return nil, fmt.Errorf("executing pvc extensions spec executor template: %w", err) + } + + if pvcSpec, err = merge2.MergeStrings(bufferExt.String(), pvcSpec, false, kyaml.MergeOptions{}); err != nil { + return nil, fmt.Errorf("merging spvc spec executor templates: %w", err) + } + } + + log.Debug("Volume claim specification", pvcSpec) + decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(pvcSpec), len(pvcSpec)) + if err := decoder.Decode(&pvc); err != nil { + return nil, fmt.Errorf("decoding pvc spec error: %w", err) + } + + return &pvc, nil +} diff --git a/pkg/executor/client/job.go b/pkg/executor/client/job.go index 55c69ee8655..26f1813f96a 100644 --- a/pkg/executor/client/job.go +++ b/pkg/executor/client/job.go @@ -33,6 +33,7 @@ import ( kyaml "sigs.k8s.io/kustomize/kyaml/yaml" + executorv1 "github.com/kubeshop/testkube-operator/api/executor/v1" templatesv1 "github.com/kubeshop/testkube-operator/pkg/client/templates/v1" testexecutionsv1 "github.com/kubeshop/testkube-operator/pkg/client/testexecutions/v1" testsv3 "github.com/kubeshop/testkube-operator/pkg/client/tests/v3" @@ -76,8 +77,7 @@ func NewJobExecutor( repo result.Repository, namespace string, images executor.Images, - jobTemplate string, - slavePodTemplate string, + templates executor.Templates, serviceAccountName string, metrics ExecutionCounter, emiter *event.Emitter, @@ -100,8 +100,7 @@ func NewJobExecutor( Log: log.DefaultLogger, Namespace: namespace, images: images, - jobTemplate: jobTemplate, - slavePodTemplate: slavePodTemplate, + templates: templates, serviceAccountName: serviceAccountName, metrics: metrics, Emitter: emiter, @@ -131,8 +130,7 @@ type JobExecutor struct { Namespace string Cmd string images executor.Images - jobTemplate string - slavePodTemplate string + templates executor.Templates serviceAccountName string metrics ExecutionCounter Emitter *event.Emitter @@ -185,6 +183,8 @@ type JobOptions struct { APIURI string SlavePodTemplate string Features featureflags.FeatureFlags + PvcTemplate string + PvcTemplateExtensions string } // Logs returns job logs stream channel using kubernetes api @@ -309,12 +309,27 @@ func (c *JobExecutor) MonitorJobForTimeout(ctx context.Context, jobName string) // CreateJob creates new Kubernetes job based on execution and execute options func (c *JobExecutor) CreateJob(ctx context.Context, execution testkube.Execution, options ExecuteOptions) error { jobs := c.ClientSet.BatchV1().Jobs(c.Namespace) - jobOptions, err := NewJobOptions(c.Log, c.templatesClient, c.images, c.jobTemplate, c.slavePodTemplate, + jobOptions, err := NewJobOptions(c.Log, c.templatesClient, c.images, c.templates, c.serviceAccountName, c.registry, c.clusterID, c.apiURI, execution, options, c.natsURI, c.debug) if err != nil { return err } + if jobOptions.ArtifactRequest != nil && + jobOptions.ArtifactRequest.StorageClassName != "" { + c.Log.Debug("creating persistent volume claim with options", "options", jobOptions) + pvcsClient := c.ClientSet.CoreV1().PersistentVolumeClaims(c.Namespace) + pvcSpec, err := NewPersistentVolumeClaimSpec(c.Log, NewPVCOptionsFromJobOptions(jobOptions)) + if err != nil { + return err + } + + _, err = pvcsClient.Create(ctx, pvcSpec, metav1.CreateOptions{}) + if err != nil { + return err + } + } + c.Log.Debug("creating job with options", "options", jobOptions) jobSpec, err := NewJobSpec(c.Log, jobOptions) if err != nil { @@ -352,6 +367,15 @@ func (c *JobExecutor) updateResultsFromPod(ctx context.Context, pod corev1.Pod, } l.Debug("poll immediate end") + if execution.ArtifactRequest != nil && + execution.ArtifactRequest.StorageClassName != "" { + pvcsClient := c.ClientSet.CoreV1().PersistentVolumeClaims(c.Namespace) + err = pvcsClient.Delete(ctx, execution.Id+"-pvc", metav1.DeleteOptions{}) + if err != nil { + return execution.ExecutionResult, err + } + } + var logs []byte logs, err = executor.GetPodLogs(ctx, c.ClientSet, c.Namespace, pod) if err != nil { @@ -565,6 +589,7 @@ func NewJobOptionsFromExecutionOptions(options ExecuteOptions) JobOptions { ContextType: contextType, ContextData: contextData, Features: options.Features, + PvcTemplateExtensions: options.Request.PvcTemplate, } } @@ -817,7 +842,7 @@ func NewJobSpec(log *zap.SugaredLogger, options JobOptions) (*batchv1.Job, error } func NewJobOptions(log *zap.SugaredLogger, templatesClient templatesv1.Interface, images executor.Images, - jobTemplate, slavePodTemplate, serviceAccountName, registry, clusterID, apiURI string, + templates executor.Templates, serviceAccountName, registry, clusterID, apiURI string, execution testkube.Execution, options ExecuteOptions, natsURI string, debug bool) (jobOptions JobOptions, err error) { jsn, err := json.Marshal(execution) if err != nil { @@ -841,7 +866,7 @@ func NewJobOptions(log *zap.SugaredLogger, templatesClient templatesv1.Interface } if jobOptions.JobTemplate == "" { - jobOptions.JobTemplate = jobTemplate + jobOptions.JobTemplate = templates.Job } if options.ExecutorSpec.JobTemplateReference != "" { @@ -874,7 +899,19 @@ func NewJobOptions(log *zap.SugaredLogger, templatesClient templatesv1.Interface jobOptions.ServiceAccountName = serviceAccountName jobOptions.Registry = registry jobOptions.ClusterID = clusterID - jobOptions.ArtifactRequest = execution.ArtifactRequest + + supportArtifacts := false + for _, feature := range options.ExecutorSpec.Features { + if feature == executorv1.FeatureArtifacts { + supportArtifacts = true + break + } + } + + if supportArtifacts { + jobOptions.ArtifactRequest = execution.ArtifactRequest + } + workingDir := agent.GetDefaultWorkingDir(executor.VolumeDir, execution) if execution.Content != nil && execution.Content.Repository != nil && execution.Content.Repository.WorkingDir != "" { workingDir = filepath.Join(executor.VolumeDir, "repo", execution.Content.Repository.WorkingDir) @@ -883,7 +920,7 @@ func NewJobOptions(log *zap.SugaredLogger, templatesClient templatesv1.Interface jobOptions.WorkingDir = workingDir jobOptions.APIURI = apiURI - jobOptions.SlavePodTemplate = slavePodTemplate + jobOptions.SlavePodTemplate = templates.Slave if options.Request.SlavePodRequest != nil && options.Request.SlavePodRequest.PodTemplateReference != "" { template, err := templatesClient.Get(options.Request.SlavePodRequest.PodTemplateReference) if err != nil { @@ -917,5 +954,29 @@ func NewJobOptions(log *zap.SugaredLogger, templatesClient templatesv1.Interface jobOptions.Variables[executor.SlavesConfigsEnv] = testkube.NewBasicVariable(executor.SlavesConfigsEnv, string(slvesConfigs)) } + jobOptions.PvcTemplate = templates.PVC + if options.Request.PvcTemplateReference != "" { + template, err := templatesClient.Get(options.Request.PvcTemplateReference) + if err != nil { + return jobOptions, err + } + + if template.Spec.Type_ != nil && testkube.TemplateType(*template.Spec.Type_) == testkube.PVC_TemplateType { + jobOptions.PvcTemplate = template.Spec.Body + } else { + log.Warnw("Not matched template type", "template", options.Request.PvcTemplateReference) + } + } + return } + +func NewPVCOptionsFromJobOptions(options JobOptions) PVCOptions { + return PVCOptions{ + Name: options.Name, + Namespace: options.Namespace, + PvcTemplate: options.PvcTemplate, + PvcTemplateExtensions: options.PvcTemplateExtensions, + ArtifactRequest: options.ArtifactRequest, + } +} diff --git a/pkg/executor/common.go b/pkg/executor/common.go index 0decd02bf7e..9d7deda4f62 100644 --- a/pkg/executor/common.go +++ b/pkg/executor/common.go @@ -196,6 +196,7 @@ type Templates struct { Job string `json:"job"` PVC string `json:"pvc"` Scraper string `json:"scraper"` + Slave string `json:"slave"` } // Images contains images for executor diff --git a/pkg/executor/containerexecutor/containerexecutor.go b/pkg/executor/containerexecutor/containerexecutor.go index 48366323609..875825fed1e 100644 --- a/pkg/executor/containerexecutor/containerexecutor.go +++ b/pkg/executor/containerexecutor/containerexecutor.go @@ -288,7 +288,7 @@ func (c *ContainerExecutor) createJob(ctx context.Context, execution testkube.Ex jobOptions.ArtifactRequest.StorageClassName != "" { c.log.Debug("creating persistent volume claim with options", "options", jobOptions) pvcsClient := c.clientSet.CoreV1().PersistentVolumeClaims(c.namespace) - pvcSpec, err := NewPersistentVolumeClaimSpec(c.log, jobOptions) + pvcSpec, err := client.NewPersistentVolumeClaimSpec(c.log, NewPVCOptionsFromJobOptions(*jobOptions)) if err != nil { return nil, err } @@ -685,3 +685,13 @@ func NewJobOptionsFromExecutionOptions(options client.ExecuteOptions) *JobOption func (c *ContainerExecutor) Abort(ctx context.Context, execution *testkube.Execution) (*testkube.ExecutionResult, error) { return executor.AbortJob(ctx, c.clientSet, c.namespace, execution.Id) } + +func NewPVCOptionsFromJobOptions(options JobOptions) client.PVCOptions { + return client.PVCOptions{ + Name: options.Name, + Namespace: options.Namespace, + PvcTemplate: options.PvcTemplate, + PvcTemplateExtensions: options.PvcTemplateExtensions, + ArtifactRequest: options.ArtifactRequest, + } +} diff --git a/pkg/executor/containerexecutor/tmpl.go b/pkg/executor/containerexecutor/tmpl.go index fd58b0eaa74..31dbe9bae35 100644 --- a/pkg/executor/containerexecutor/tmpl.go +++ b/pkg/executor/containerexecutor/tmpl.go @@ -203,45 +203,6 @@ func NewScraperJobSpec(log *zap.SugaredLogger, options *JobOptions) (*batchv1.Jo return &job, nil } -// NewPersistentVolumeClaimSpec is a method to create new persistent volume claim spec -func NewPersistentVolumeClaimSpec(log *zap.SugaredLogger, options *JobOptions) (*corev1.PersistentVolumeClaim, error) { - tmpl, err := utils.NewTemplate("volume-claim").Parse(options.PvcTemplate) - if err != nil { - return nil, fmt.Errorf("creating volume claim spec from pvc template error: %w", err) - } - - var buffer bytes.Buffer - if err = tmpl.ExecuteTemplate(&buffer, "volume-claim", options); err != nil { - return nil, fmt.Errorf("executing volume claim spec pvc template: %w", err) - } - - var pvc corev1.PersistentVolumeClaim - pvcSpec := buffer.String() - if options.PvcTemplateExtensions != "" { - tmplExt, err := utils.NewTemplate("jobExt").Parse(options.PvcTemplateExtensions) - if err != nil { - return nil, fmt.Errorf("creating pvc extensions spec from executor template error: %w", err) - } - - var bufferExt bytes.Buffer - if err = tmplExt.ExecuteTemplate(&bufferExt, "jobExt", options); err != nil { - return nil, fmt.Errorf("executing pvc extensions spec executor template: %w", err) - } - - if pvcSpec, err = merge2.MergeStrings(bufferExt.String(), pvcSpec, false, kyaml.MergeOptions{}); err != nil { - return nil, fmt.Errorf("merging spvc spec executor templates: %w", err) - } - } - - log.Debug("Volume claim specification", pvcSpec) - decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(pvcSpec), len(pvcSpec)) - if err := decoder.Decode(&pvc); err != nil { - return nil, fmt.Errorf("decoding pvc spec error: %w", err) - } - - return &pvc, nil -} - // InspectDockerImage inspects docker image func InspectDockerImage(namespace, registry, image string, imageSecrets []string) ([]string, string, error) { inspector := skopeo.NewClient() diff --git a/pkg/executor/scraper/extractor.go b/pkg/executor/scraper/extractor.go index 00d83680c17..63ce3b5ed04 100644 --- a/pkg/executor/scraper/extractor.go +++ b/pkg/executor/scraper/extractor.go @@ -16,7 +16,7 @@ const ( //go:generate mockgen -destination=./mock_extractor.go -package=scraper "github.com/kubeshop/testkube/pkg/executor/scraper" Extractor type Extractor interface { - Extract(ctx context.Context, paths []string, process ProcessFn, notify NotifyFn) error + Extract(ctx context.Context, paths, masks []string, process ProcessFn, notify NotifyFn) error } type ProcessFn func(ctx context.Context, object *Object) error diff --git a/pkg/executor/scraper/factory/factory.go b/pkg/executor/scraper/factory/factory.go index 5a17bcb813c..e9b95968a7e 100644 --- a/pkg/executor/scraper/factory/factory.go +++ b/pkg/executor/scraper/factory/factory.go @@ -70,14 +70,14 @@ func GetScraper(ctx context.Context, params envs.Params, extractorType Extractor var loader scraper.Uploader switch uploaderType { case MinIOUploader: - loader, err = getMinIOLoader(params) + loader, err = getMinIOUploader(params) if err != nil { - return nil, errors.Wrap(err, "error creating minio loader") + return nil, errors.Wrap(err, "error creating minio uploader") } case CloudUploader: - loader, err = getCloudLoader(ctx, params) + loader, err = getRemoteStorageUploader(ctx, params) if err != nil { - return nil, errors.Wrap(err, "error creating cloud loader") + return nil, errors.Wrap(err, "error creating remote storage uploader") } default: return nil, errors.Errorf("unknown uploader type: %s", uploaderType) @@ -87,31 +87,33 @@ func GetScraper(ctx context.Context, params envs.Params, extractorType Extractor if params.CDEventsTarget != "" { cdeventsClient, err = cloudevents.NewClientHTTP(cloudevents.WithTarget(params.CDEventsTarget)) if err != nil { - log.DefaultLogger.Warnf("failed to create cloud event client %w", err) + log.DefaultLogger.Warnf("failed to create cloud event client: %v", err) } } return scraper.NewExtractLoadScraper(extractor, loader, cdeventsClient, params.ClusterID, params.DashboardURI), nil } -func getCloudLoader(ctx context.Context, params envs.Params) (uploader *cloudscraper.CloudUploader, err error) { +func getRemoteStorageUploader(ctx context.Context, params envs.Params) (uploader *cloudscraper.CloudUploader, err error) { // timeout blocking connection to cloud ctxTimeout, cancel := context.WithTimeout(ctx, time.Duration(params.CloudConnectionTimeoutSec)*time.Second) defer cancel() - output.PrintLogf("%s Uploading artifacts using Cloud Uploader (timeout:%ds)", ui.IconCheckMark, params.CloudConnectionTimeoutSec) - grpcConn, err := agent.NewGRPCConnection(ctxTimeout, params.CloudAPITLSInsecure, params.SkipVerify, params.CloudAPIURL, log.DefaultLogger) + output.PrintLogf( + "%s Uploading artifacts using Remote Storage Uploader (timeout:%ds, insecure:%v, skipVerify: %v, url: %s)", + ui.IconCheckMark, params.CloudConnectionTimeoutSec, params.CloudAPITLSInsecure, params.CloudAPISkipVerify, params.CloudAPIURL) + grpcConn, err := agent.NewGRPCConnection(ctxTimeout, params.CloudAPITLSInsecure, params.CloudAPISkipVerify, params.CloudAPIURL, log.DefaultLogger) if err != nil { return nil, err } - output.PrintLogf("%s Connected to Testkube Cloud", ui.IconCheckMark) + output.PrintLogf("%s Connected to Agent API", ui.IconCheckMark) grpcClient := cloud.NewTestKubeCloudAPIClient(grpcConn) cloudExecutor := cloudexecutor.NewCloudGRPCExecutor(grpcClient, grpcConn, params.CloudAPIKey) return cloudscraper.NewCloudUploader(cloudExecutor), nil } -func getMinIOLoader(params envs.Params) (*scraper.MinIOUploader, error) { +func getMinIOUploader(params envs.Params) (*scraper.MinIOUploader, error) { output.PrintLog(fmt.Sprintf("%s Uploading artifacts using MinIO Uploader", ui.IconCheckMark)) return scraper.NewMinIOUploader( params.Endpoint, diff --git a/pkg/executor/scraper/filesystem_extractor.go b/pkg/executor/scraper/filesystem_extractor.go index cff2e84e5e6..d814ddb2834 100644 --- a/pkg/executor/scraper/filesystem_extractor.go +++ b/pkg/executor/scraper/filesystem_extractor.go @@ -7,6 +7,8 @@ import ( "io" "os" "path/filepath" + "regexp" + "strings" "github.com/kubeshop/testkube/pkg/archive" "github.com/kubeshop/testkube/pkg/log" @@ -44,7 +46,7 @@ func GenerateTarballMetaFile() ArchiveFilesystemExtractorOpts { } } -func (e *ArchiveFilesystemExtractor) Extract(ctx context.Context, paths []string, process ProcessFn, notify NotifyFn) error { +func (e *ArchiveFilesystemExtractor) Extract(ctx context.Context, paths, masks []string, process ProcessFn, notify NotifyFn) error { var archiveFiles []*archive.File for _, dir := range paths { log.DefaultLogger.Infof("scraping artifacts in directory: %v", dir) @@ -67,6 +69,30 @@ func (e *ArchiveFilesystemExtractor) Extract(ctx context.Context, paths []string return nil } + var regexps []*regexp.Regexp + for _, mask := range masks { + values := strings.Split(mask, ",") + for _, value := range values { + re, err := regexp.Compile(value) + if err != nil { + return errors.Wrap(err, "regexp compilation error") + } + + regexps = append(regexps, re) + } + } + + found := len(regexps) == 0 + for i := range regexps { + if found = regexps[i].MatchString(path); found { + break + } + } + + if !found { + return nil + } + if err := notify(ctx, path); err != nil { log.DefaultLogger.Warnf("error notifying for file %s", path) } @@ -194,7 +220,7 @@ func NewRecursiveFilesystemExtractor(fs filesystem.FileSystem) *RecursiveFilesys return &RecursiveFilesystemExtractor{fs: fs} } -func (e *RecursiveFilesystemExtractor) Extract(ctx context.Context, paths []string, process ProcessFn, notify NotifyFn) error { +func (e *RecursiveFilesystemExtractor) Extract(ctx context.Context, paths, masks []string, process ProcessFn, notify NotifyFn) error { for _, dir := range paths { log.DefaultLogger.Infof("scraping artifacts in directory: %v", dir) @@ -216,6 +242,30 @@ func (e *RecursiveFilesystemExtractor) Extract(ctx context.Context, paths []stri return nil } + var regexps []*regexp.Regexp + for _, mask := range masks { + values := strings.Split(mask, ",") + for _, value := range values { + re, err := regexp.Compile(value) + if err != nil { + return errors.Wrap(err, "regexp compilation error") + } + + regexps = append(regexps, re) + } + } + + found := len(regexps) == 0 + for i := range regexps { + if found = regexps[i].MatchString(path); found { + break + } + } + + if !found { + return nil + } + if err := notify(ctx, path); err != nil { log.DefaultLogger.Warnf("error notifying for file %s", path) } diff --git a/pkg/executor/scraper/filesystem_extractor_integration_test.go b/pkg/executor/scraper/filesystem_extractor_integration_test.go index d7e0e000291..cd530e13b0b 100644 --- a/pkg/executor/scraper/filesystem_extractor_integration_test.go +++ b/pkg/executor/scraper/filesystem_extractor_integration_test.go @@ -61,7 +61,8 @@ func TestArchiveFilesystemExtractor_Extract_NoMeta_Integration(t *testing.T) { extractor := scraper.NewArchiveFilesystemExtractor(filesystem.NewOSFileSystem()) scrapeDirs := []string{tempDir} - err = extractor.Extract(context.Background(), scrapeDirs, processFn, notifyFn) + masks := []string{".*"} + err = extractor.Extract(context.Background(), scrapeDirs, masks, processFn, notifyFn) require.NoError(t, err) assert.Equal(t, 1, processCallCount) } @@ -133,7 +134,8 @@ func TestArchiveFilesystemExtractor_Extract_Meta_Integration(t *testing.T) { extractor := scraper.NewArchiveFilesystemExtractor(filesystem.NewOSFileSystem(), scraper.GenerateTarballMetaFile()) scrapeDirs := []string{tempDir} - err = extractor.Extract(context.Background(), scrapeDirs, processFn, notifyFn) + masks := []string{".*"} + err = extractor.Extract(context.Background(), scrapeDirs, masks, processFn, notifyFn) require.NoError(t, err) assert.Equal(t, 2, processCallCount) } @@ -195,7 +197,8 @@ func TestRecursiveFilesystemExtractor_Extract_Integration(t *testing.T) { extractor := scraper.NewRecursiveFilesystemExtractor(filesystem.NewOSFileSystem()) scrapeDirs := []string{tempDir, "/nonexistent"} - err = extractor.Extract(context.Background(), scrapeDirs, processFn, notifyFn) + masks := []string{".*"} + err = extractor.Extract(context.Background(), scrapeDirs, masks, processFn, notifyFn) require.NoError(t, err) assert.Equal(t, processCallCount, 3) } @@ -238,7 +241,8 @@ func TestRecursiveFilesystemExtractor_Extract_RelPath_Integration(t *testing.T) extractor := scraper.NewRecursiveFilesystemExtractor(filesystem.NewOSFileSystem()) scrapeDirs := []string{filepath.Join(tempDir, "file1.txt"), "/nonexistent"} - err = extractor.Extract(context.Background(), scrapeDirs, processFn, notifyFn) + masks := []string{".*"} + err = extractor.Extract(context.Background(), scrapeDirs, masks, processFn, notifyFn) require.NoError(t, err) assert.Equal(t, processCallCount, 1) } diff --git a/pkg/executor/scraper/filesystem_extractor_test.go b/pkg/executor/scraper/filesystem_extractor_test.go index da3937ee9f4..c623352434d 100644 --- a/pkg/executor/scraper/filesystem_extractor_test.go +++ b/pkg/executor/scraper/filesystem_extractor_test.go @@ -50,7 +50,7 @@ func TestRecursiveFilesystemExtractor_Extract(t *testing.T) { } // Call the Extract function - err := extractor.Extract(context.Background(), []string{"/my/directory"}, processFn, notifyFn) + err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) assert.NoErrorf(t, err, "Extract failed: %v", err) } @@ -102,7 +102,7 @@ func TestArchiveFilesystemExtractor_Extract_NoMeta(t *testing.T) { } // Call the Extract function - err := extractor.Extract(context.Background(), []string{"/my/directory"}, processFn, notifyFn) + err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) assert.NoErrorf(t, err, "Extract failed: %v", err) assert.Equal(t, 1, processFnCallCount) } @@ -170,7 +170,7 @@ func TestArchiveFilesystemExtractor_Extract_Meta(t *testing.T) { } // Call the Extract function - err := extractor.Extract(context.Background(), []string{"/my/directory"}, processFn, notifyFn) + err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) assert.NoErrorf(t, err, "Extract failed: %v", err) assert.Equal(t, 2, processFnCallCount) } @@ -196,7 +196,7 @@ func TestRecursiveFilesystemExtractor_ExtractEmpty(t *testing.T) { } // Call the Extract function - err := extractor.Extract(context.Background(), []string{"/my/directory"}, processFn, notifyFn) + err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) assert.NoErrorf(t, err, "Extract failed: %v", err) } @@ -221,6 +221,6 @@ func TestArchiveFilesystemExtractor_ExtractEmpty(t *testing.T) { } // Call the Extract function - err := extractor.Extract(context.Background(), []string{"/my/directory"}, processFn, notifyFn) + err := extractor.Extract(context.Background(), []string{"/my/directory"}, []string{".*"}, processFn, notifyFn) assert.NoErrorf(t, err, "Extract failed: %v", err) } diff --git a/pkg/executor/scraper/minio_scraper_integration_test.go b/pkg/executor/scraper/minio_scraper_integration_test.go index 4102821f46d..1192eec0411 100644 --- a/pkg/executor/scraper/minio_scraper_integration_test.go +++ b/pkg/executor/scraper/minio_scraper_integration_test.go @@ -84,7 +84,7 @@ func TestMinIOScraper_Archive_Integration(t *testing.T) { assert.NoError(t, err) s := scraper.NewExtractLoadScraper(extractor, loader, client, "", "") - err = s.Scrape(context.Background(), []string{tempDir}, execution) + err = s.Scrape(context.Background(), []string{tempDir}, []string{".*"}, execution) if err != nil { t.Fatalf("error scraping: %v", err) } @@ -164,7 +164,7 @@ func TestMinIOScraper_Recursive_Integration(t *testing.T) { assert.NoError(t, err) s := scraper.NewExtractLoadScraper(extractor, loader, client, "", "") - err = s.Scrape(context.Background(), []string{tempDir}, execution) + err = s.Scrape(context.Background(), []string{tempDir}, []string{".*"}, execution) if err != nil { t.Fatalf("error scraping: %v", err) } diff --git a/pkg/executor/scraper/mock_extractor.go b/pkg/executor/scraper/mock_extractor.go index 25b9b80416f..cb266c52a5d 100644 --- a/pkg/executor/scraper/mock_extractor.go +++ b/pkg/executor/scraper/mock_extractor.go @@ -35,15 +35,15 @@ func (m *MockExtractor) EXPECT() *MockExtractorMockRecorder { } // Extract mocks base method. -func (m *MockExtractor) Extract(arg0 context.Context, arg1 []string, arg2 ProcessFn, arg3 NotifyFn) error { +func (m *MockExtractor) Extract(arg0 context.Context, arg1, arg2 []string, arg3 ProcessFn, arg4 NotifyFn) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Extract", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "Extract", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) return ret0 } // Extract indicates an expected call of Extract. -func (mr *MockExtractorMockRecorder) Extract(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockExtractorMockRecorder) Extract(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Extract", reflect.TypeOf((*MockExtractor)(nil).Extract), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Extract", reflect.TypeOf((*MockExtractor)(nil).Extract), arg0, arg1, arg2, arg3, arg4) } diff --git a/pkg/executor/scraper/mock_scraper.go b/pkg/executor/scraper/mock_scraper.go index 0827078e29e..5092e04414a 100644 --- a/pkg/executor/scraper/mock_scraper.go +++ b/pkg/executor/scraper/mock_scraper.go @@ -51,15 +51,15 @@ func (mr *MockScraperMockRecorder) Close() *gomock.Call { } // Scrape mocks base method. -func (m *MockScraper) Scrape(arg0 context.Context, arg1 []string, arg2 testkube.Execution) error { +func (m *MockScraper) Scrape(arg0 context.Context, arg1, arg2 []string, arg3 testkube.Execution) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Scrape", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "Scrape", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(error) return ret0 } // Scrape indicates an expected call of Scrape. -func (mr *MockScraperMockRecorder) Scrape(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockScraperMockRecorder) Scrape(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scrape", reflect.TypeOf((*MockScraper)(nil).Scrape), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Scrape", reflect.TypeOf((*MockScraper)(nil).Scrape), arg0, arg1, arg2, arg3) } diff --git a/pkg/executor/scraper/scraper.go b/pkg/executor/scraper/scraper.go index ac60db90ba7..2f7387332f0 100644 --- a/pkg/executor/scraper/scraper.go +++ b/pkg/executor/scraper/scraper.go @@ -18,7 +18,7 @@ import ( //go:generate mockgen -destination=./mock_scraper.go -package=scraper "github.com/kubeshop/testkube/pkg/executor/scraper" Scraper type Scraper interface { // Scrape gets artifacts from the provided paths and the provided execution - Scrape(ctx context.Context, paths []string, execution testkube.Execution) error + Scrape(ctx context.Context, paths, masks []string, execution testkube.Execution) error Close() error } @@ -41,10 +41,10 @@ func NewExtractLoadScraper(extractor Extractor, loader Uploader, cdeventsClient } } -func (s *ExtractLoadScraper) Scrape(ctx context.Context, paths []string, execution testkube.Execution) error { +func (s *ExtractLoadScraper) Scrape(ctx context.Context, paths, masks []string, execution testkube.Execution) error { return s. extractor. - Extract(ctx, paths, + Extract(ctx, paths, masks, func(ctx context.Context, object *Object) error { return s.loader.Upload(ctx, object, execution) }, diff --git a/pkg/logs/sidecar/proxy.go b/pkg/logs/sidecar/proxy.go index f2b674b22b6..ad99a2388c9 100644 --- a/pkg/logs/sidecar/proxy.go +++ b/pkg/logs/sidecar/proxy.go @@ -7,6 +7,7 @@ import ( "io" "os" "os/signal" + "strings" "syscall" "time" @@ -151,7 +152,12 @@ func (p *Proxy) streamLogsFromPod(pod corev1.Pod, logs chan events.Log) (err err } for _, container := range containers { - + // We skip logsidecar container logs, + // because following the logs for it will never finish + // and the sidecar will run forever. + if strings.HasSuffix(container, "-logs") { + continue + } req := p.podsClient.GetLogs( pod.Name, &corev1.PodLogOptions{ diff --git a/pkg/mapper/testexecutions/mapper.go b/pkg/mapper/testexecutions/mapper.go index ae39129f2b9..f7fcc8d36ec 100644 --- a/pkg/mapper/testexecutions/mapper.go +++ b/pkg/mapper/testexecutions/mapper.go @@ -140,8 +140,10 @@ func MapAPIToCRD(request *testkube.Execution, generation int64) testexecutionv1. StorageClassName: request.ArtifactRequest.StorageClassName, VolumeMountPath: request.ArtifactRequest.VolumeMountPath, Dirs: request.ArtifactRequest.Dirs, + Masks: request.ArtifactRequest.Masks, StorageBucket: request.ArtifactRequest.StorageBucket, OmitFolderPerExecution: request.ArtifactRequest.OmitFolderPerExecution, + SharedBetweenPods: request.ArtifactRequest.SharedBetweenPods, } } diff --git a/pkg/mapper/tests/kube_openapi.go b/pkg/mapper/tests/kube_openapi.go index 67acd84858e..fbe4baae632 100644 --- a/pkg/mapper/tests/kube_openapi.go +++ b/pkg/mapper/tests/kube_openapi.go @@ -122,8 +122,10 @@ func MapExecutionRequestFromSpec(specExecutionRequest *testsv3.ExecutionRequest) StorageClassName: specExecutionRequest.ArtifactRequest.StorageClassName, VolumeMountPath: specExecutionRequest.ArtifactRequest.VolumeMountPath, Dirs: specExecutionRequest.ArtifactRequest.Dirs, + Masks: specExecutionRequest.ArtifactRequest.Masks, StorageBucket: specExecutionRequest.ArtifactRequest.StorageBucket, OmitFolderPerExecution: specExecutionRequest.ArtifactRequest.OmitFolderPerExecution, + SharedBetweenPods: specExecutionRequest.ArtifactRequest.SharedBetweenPods, } } @@ -522,8 +524,10 @@ func MapSpecExecutionRequestToExecutionUpdateRequest( StorageClassName: &request.ArtifactRequest.StorageClassName, VolumeMountPath: &request.ArtifactRequest.VolumeMountPath, Dirs: &request.ArtifactRequest.Dirs, + Masks: &request.ArtifactRequest.Masks, StorageBucket: &request.ArtifactRequest.StorageBucket, OmitFolderPerExecution: &request.ArtifactRequest.OmitFolderPerExecution, + SharedBetweenPods: &request.ArtifactRequest.SharedBetweenPods, } executionRequest.ArtifactRequest = &artifactRequest diff --git a/pkg/mapper/tests/openapi_kube.go b/pkg/mapper/tests/openapi_kube.go index 631e4ab7d99..5f09bf5ca86 100644 --- a/pkg/mapper/tests/openapi_kube.go +++ b/pkg/mapper/tests/openapi_kube.go @@ -134,8 +134,10 @@ func MapExecutionRequestToSpecExecutionRequest(executionRequest *testkube.Execut StorageClassName: executionRequest.ArtifactRequest.StorageClassName, VolumeMountPath: executionRequest.ArtifactRequest.VolumeMountPath, Dirs: executionRequest.ArtifactRequest.Dirs, + Masks: executionRequest.ArtifactRequest.Masks, StorageBucket: executionRequest.ArtifactRequest.StorageBucket, OmitFolderPerExecution: executionRequest.ArtifactRequest.OmitFolderPerExecution, + SharedBetweenPods: executionRequest.ArtifactRequest.SharedBetweenPods, } } @@ -647,6 +649,11 @@ func MapExecutionUpdateRequestToSpecExecutionRequest(executionRequest *testkube. emptyArtifact = false } + if (*executionRequest.ArtifactRequest).Masks != nil { + request.ArtifactRequest.Masks = *(*executionRequest.ArtifactRequest).Masks + emptyArtifact = false + } + if (*executionRequest.ArtifactRequest).StorageBucket != nil { request.ArtifactRequest.StorageBucket = *(*executionRequest.ArtifactRequest).StorageBucket emptyArtifact = false @@ -656,6 +663,12 @@ func MapExecutionUpdateRequestToSpecExecutionRequest(executionRequest *testkube. request.ArtifactRequest.OmitFolderPerExecution = *(*executionRequest.ArtifactRequest).OmitFolderPerExecution emptyArtifact = false } + + if (*executionRequest.ArtifactRequest).SharedBetweenPods != nil { + request.ArtifactRequest.SharedBetweenPods = *(*executionRequest.ArtifactRequest).SharedBetweenPods + emptyArtifact = false + } + } if emptyArtifact { diff --git a/pkg/mapper/testsuiteexecutions/mapper.go b/pkg/mapper/testsuiteexecutions/mapper.go index 93d342b0732..80fd67f8f32 100644 --- a/pkg/mapper/testsuiteexecutions/mapper.go +++ b/pkg/mapper/testsuiteexecutions/mapper.go @@ -2,6 +2,7 @@ package testsuiteexecutions import ( corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" testsuiteexecutionv1 "github.com/kubeshop/testkube-operator/api/testsuiteexecution/v1" "github.com/kubeshop/testkube/pkg/api/v1/testkube" @@ -144,8 +145,10 @@ func MapExecutionCRD(request *testkube.Execution) *testsuiteexecutionv1.Executio StorageClassName: request.ArtifactRequest.StorageClassName, VolumeMountPath: request.ArtifactRequest.VolumeMountPath, Dirs: request.ArtifactRequest.Dirs, + Masks: request.ArtifactRequest.Masks, StorageBucket: request.ArtifactRequest.StorageBucket, OmitFolderPerExecution: request.ArtifactRequest.OmitFolderPerExecution, + SharedBetweenPods: request.ArtifactRequest.SharedBetweenPods, } } @@ -334,8 +337,11 @@ func MapAPIToCRD(request *testkube.TestSuiteExecution, generation int64) testsui } executeStepResults = append(executeStepResults, testsuiteexecutionv1.TestSuiteBatchStepExecutionResult{ - Step: MapTestSuiteBatchStepToCRD(stepResult.Step), - Execute: steps, + Step: MapTestSuiteBatchStepToCRD(stepResult.Step), + Execute: steps, + StartTime: metav1.Time{Time: stepResult.StartTime}, + EndTime: metav1.Time{Time: stepResult.EndTime}, + Duration: stepResult.Duration, }) } diff --git a/pkg/mapper/testsuites/kube_openapi.go b/pkg/mapper/testsuites/kube_openapi.go index 9036514abef..c845608de7b 100644 --- a/pkg/mapper/testsuites/kube_openapi.go +++ b/pkg/mapper/testsuites/kube_openapi.go @@ -52,6 +52,7 @@ func MapCRToAPI(cr testsuitesv3.TestSuite) (test testkube.TestSuite) { downloadArtifacts = &testkube.DownloadArtifactOptions{ AllPreviousSteps: b.DownloadArtifacts.AllPreviousSteps, PreviousStepNumbers: b.DownloadArtifacts.PreviousStepNumbers, + PreviousTestNames: b.DownloadArtifacts.PreviousTestNames, } } diff --git a/pkg/mapper/testsuites/openapi_kube.go b/pkg/mapper/testsuites/openapi_kube.go index 5b58c725769..f3ba5892363 100644 --- a/pkg/mapper/testsuites/openapi_kube.go +++ b/pkg/mapper/testsuites/openapi_kube.go @@ -170,6 +170,7 @@ func mapTestBatchStepsToCRD(batches []testkube.TestSuiteBatchStep) (out []testsu downloadArtifacts = &testsuitesv3.DownloadArtifactOptions{ AllPreviousSteps: batch.DownloadArtifacts.AllPreviousSteps, PreviousStepNumbers: batch.DownloadArtifacts.PreviousStepNumbers, + PreviousTestNames: batch.DownloadArtifacts.PreviousTestNames, } } diff --git a/pkg/reconciler/reconciler.go b/pkg/reconciler/reconciler.go index 7a338d9e05b..6766014f789 100644 --- a/pkg/reconciler/reconciler.go +++ b/pkg/reconciler/reconciler.go @@ -21,6 +21,7 @@ import ( const ( reconciliationInterval = 5 * time.Minute + delayTimeout = time.Minute ) var ( @@ -166,36 +167,62 @@ OuterLoop: status := testkube.TestSuiteExecutionStatusPassed InnerLoop: for _, step := range execution.ExecuteStepResults { + if step.StartTime.IsZero() { + continue + } + + var stepDuration time.Duration for _, execute := range step.Execute { - if execute.Step != nil && execute.Step.Type() == testkube.TestSuiteStepTypeExecuteTest && execute.Execution != nil { - exec, err := client.resultRepository.Get(ctx, execute.Execution.Id) - if err != nil && err != mongo.ErrNoDocuments { - return err - } + if execute.Step != nil { + if execute.Step.Type() == testkube.TestSuiteStepTypeExecuteTest && execute.Execution != nil { + exec, err := client.resultRepository.Get(ctx, execute.Execution.Id) + if err != nil && err != mongo.ErrNoDocuments { + return err + } - if exec.ExecutionResult == nil { - continue - } + if exec.ExecutionResult == nil { + continue + } - if exec.ExecutionResult.IsRunning() || exec.ExecutionResult.IsQueued() { - continue OuterLoop - } + if exec.ExecutionResult.IsRunning() || exec.ExecutionResult.IsQueued() { + continue OuterLoop + } - if exec.ExecutionResult.IsFailed() { - status = testkube.TestSuiteExecutionStatusFailed - } + if exec.ExecutionResult.IsFailed() { + status = testkube.TestSuiteExecutionStatusFailed + } - if exec.ExecutionResult.IsAborted() { - status = testkube.TestSuiteExecutionStatusAborted - break InnerLoop + if exec.ExecutionResult.IsAborted() { + status = testkube.TestSuiteExecutionStatusAborted + break InnerLoop + } + + if exec.ExecutionResult.IsTimeout() { + status = testkube.TestSuiteExecutionStatusTimeout + break InnerLoop + } } - if exec.ExecutionResult.IsTimeout() { - status = testkube.TestSuiteExecutionStatusTimeout - break InnerLoop + if execute.Step.Type() == testkube.TestSuiteStepTypeDelay { + duration, err := time.ParseDuration(execute.Step.Delay) + if err != nil { + return err + } + + if duration > stepDuration { + stepDuration = duration + } } } } + + if step.EndTime.IsZero() && stepDuration != 0 { + if time.Since(step.StartTime) < stepDuration+delayTimeout { + continue OuterLoop + } + + status = testkube.TestSuiteExecutionStatusFailed + } } execution.Status = status diff --git a/pkg/scheduler/test_scheduler.go b/pkg/scheduler/test_scheduler.go index 3dabfc4acab..4bfbcd97b92 100644 --- a/pkg/scheduler/test_scheduler.go +++ b/pkg/scheduler/test_scheduler.go @@ -228,6 +228,7 @@ func newExecutionFromExecutionOptions(options client.ExecuteOptions) testkube.Ex execution.RunningContext = options.Request.RunningContext execution.TestExecutionName = options.Request.TestExecutionName execution.DownloadArtifactExecutionIDs = options.Request.DownloadArtifactExecutionIDs + execution.DownloadArtifactTestNames = options.Request.DownloadArtifactTestNames execution.SlavePodRequest = options.Request.SlavePodRequest return execution @@ -602,11 +603,16 @@ func mergeArtifacts(artifactBase *testkube.ArtifactRequest, artifactAdjust *test return artifactBase default: artifactBase.Dirs = append(artifactBase.Dirs, artifactAdjust.Dirs...) + artifactBase.Masks = append(artifactBase.Masks, artifactAdjust.Masks...) if !artifactBase.OmitFolderPerExecution && artifactAdjust.OmitFolderPerExecution { artifactBase.OmitFolderPerExecution = artifactAdjust.OmitFolderPerExecution } + if !artifactBase.SharedBetweenPods && artifactAdjust.SharedBetweenPods { + artifactBase.SharedBetweenPods = artifactAdjust.SharedBetweenPods + } + var fields = []struct { source string destination *string diff --git a/pkg/scheduler/testsuite_scheduler.go b/pkg/scheduler/testsuite_scheduler.go index fb068be912f..ba564919051 100644 --- a/pkg/scheduler/testsuite_scheduler.go +++ b/pkg/scheduler/testsuite_scheduler.go @@ -385,22 +385,31 @@ func (s *Scheduler) executeTestStep(ctx context.Context, testsuiteExecution test testSuiteName = testsuiteExecution.TestSuite.Name } - var ids []string + ids := make(map[string]struct{}) + testNames := make(map[string]struct{}) if result.Step != nil && result.Step.DownloadArtifacts != nil { + for _, testName := range result.Step.DownloadArtifacts.PreviousTestNames { + testNames[testName] = struct{}{} + } + for i := range previousSteps { for j := range previousSteps[i].Execute { if previousSteps[i].Execute[j].Execution != nil && previousSteps[i].Execute[j].Step != nil && previousSteps[i].Execute[j].Step.Test != "" { if previousSteps[i].Execute[j].Execution.IsPassed() || previousSteps[i].Execute[j].Execution.IsFailed() { if result.Step.DownloadArtifacts.AllPreviousSteps { - ids = append(ids, previousSteps[i].Execute[j].Execution.Id) + ids[previousSteps[i].Execute[j].Execution.Id] = struct{}{} } else { for _, n := range result.Step.DownloadArtifacts.PreviousStepNumbers { if n == int32(i+1) { - ids = append(ids, previousSteps[i].Execute[j].Execution.Id) + ids[previousSteps[i].Execute[j].Execution.Id] = struct{}{} break } } + + if _, ok := testNames[previousSteps[i].Execute[j].Step.Test]; ok { + ids[previousSteps[i].Execute[j].Execution.Id] = struct{}{} + } } } } @@ -465,6 +474,11 @@ func (s *Scheduler) executeTestStep(ctx context.Context, testsuiteExecution test workerpoolService := workerpool.New[testkube.Test, testkube.ExecutionRequest, testkube.Execution](concurrencyLevel) if len(testTuples) != 0 { + var executionIDs []string + for id := range ids { + executionIDs = append(executionIDs, id) + } + req := testkube.ExecutionRequest{ TestSuiteName: testSuiteName, Variables: testsuiteExecution.Variables, @@ -485,7 +499,7 @@ func (s *Scheduler) executeTestStep(ctx context.Context, testsuiteExecution test ScraperTemplateReference: request.ScraperTemplateReference, PvcTemplate: request.PvcTemplate, PvcTemplateReference: request.PvcTemplateReference, - DownloadArtifactExecutionIDs: ids, + DownloadArtifactExecutionIDs: executionIDs, } requests := make([]workerpool.Request[testkube.Test, testkube.ExecutionRequest, testkube.Execution], len(testTuples)) @@ -503,6 +517,11 @@ func (s *Scheduler) executeTestStep(ctx context.Context, testsuiteExecution test go workerpoolService.Run(ctx) } + result.Start() + if err := s.testExecutionResults.Update(ctx, testsuiteExecution); err != nil { + s.logger.Errorw("saving test suite execution start time error", "error", err) + } + if duration != 0 { s.delayWithAbortionCheck(duration, testsuiteExecution.Id, result) } @@ -531,6 +550,11 @@ func (s *Scheduler) executeTestStep(ctx context.Context, testsuiteExecution test } } } + + result.Stop() + if err := s.testExecutionResults.Update(ctx, testsuiteExecution); err != nil { + s.logger.Errorw("saving test suite execution end time error", "error", err) + } } func (s *Scheduler) delayWithAbortionCheck(duration time.Duration, testSuiteId string, result *testkube.TestSuiteBatchStepExecutionResult) { diff --git a/pkg/triggers/watcher.go b/pkg/triggers/watcher.go index 0c79e0e2cb3..7413671c264 100644 --- a/pkg/triggers/watcher.go +++ b/pkg/triggers/watcher.go @@ -17,14 +17,21 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/cache" + executorv1 "github.com/kubeshop/testkube-operator/api/executor/v1" + testsourcev1 "github.com/kubeshop/testkube-operator/api/testsource/v1" + testsv3 "github.com/kubeshop/testkube-operator/api/tests/v3" + testsuitev3 "github.com/kubeshop/testkube-operator/api/testsuite/v3" testtriggersv1 "github.com/kubeshop/testkube-operator/api/testtriggers/v1" "github.com/kubeshop/testkube-operator/pkg/clientset/versioned" "github.com/kubeshop/testkube-operator/pkg/informers/externalversions" + testkubeexecutorinformerv1 "github.com/kubeshop/testkube-operator/pkg/informers/externalversions/executor/v1" testkubeinformerv1 "github.com/kubeshop/testkube-operator/pkg/informers/externalversions/tests/v1" + testkubeinformerv3 "github.com/kubeshop/testkube-operator/pkg/informers/externalversions/tests/v3" "github.com/kubeshop/testkube-operator/pkg/validation/tests/v1/testtrigger" + "github.com/kubeshop/testkube/pkg/api/v1/testkube" "github.com/kubeshop/testkube/pkg/executor" ) @@ -41,6 +48,9 @@ type k8sInformers struct { testTriggerInformer testkubeinformerv1.TestTriggerInformer testSuiteInformer testkubeinformerv3.TestSuiteInformer testInformer testkubeinformerv3.TestInformer + executorInformer testkubeexecutorinformerv1.ExecutorInformer + webhookInformer testkubeexecutorinformerv1.WebhookInformer + testSourceInformer testkubeinformerv1.TestSourceInformer } func newK8sInformers(clientset kubernetes.Interface, testKubeClientset versioned.Interface, @@ -67,6 +77,9 @@ func newK8sInformers(clientset kubernetes.Interface, testKubeClientset versioned k8sInformers.testTriggerInformer = testkubeInformerFactory.Tests().V1().TestTriggers() k8sInformers.testSuiteInformer = testkubeInformerFactory.Tests().V3().TestSuites() k8sInformers.testInformer = testkubeInformerFactory.Tests().V3().Tests() + k8sInformers.executorInformer = testkubeInformerFactory.Executor().V1().Executor() + k8sInformers.webhookInformer = testkubeInformerFactory.Executor().V1().Webhook() + k8sInformers.testSourceInformer = testkubeInformerFactory.Tests().V1().TestSource() return &k8sInformers } @@ -145,6 +158,9 @@ func (s *Service) runInformers(ctx context.Context, stop <-chan struct{}) { s.informers.testTriggerInformer.Informer().AddEventHandler(s.testTriggerEventHandler()) s.informers.testSuiteInformer.Informer().AddEventHandler(s.testSuiteEventHandler()) s.informers.testInformer.Informer().AddEventHandler(s.testEventHandler()) + s.informers.executorInformer.Informer().AddEventHandler(s.executorEventHandler()) + s.informers.webhookInformer.Informer().AddEventHandler(s.webhookEventHandler()) + s.informers.testSourceInformer.Informer().AddEventHandler(s.testSourceEventHandler()) s.logger.Debugf("trigger service: starting pod informers") for i := range s.informers.podInformers { @@ -192,6 +208,12 @@ func (s *Service) runInformers(ctx context.Context, stop <-chan struct{}) { go s.informers.testSuiteInformer.Informer().Run(stop) s.logger.Debugf("trigger service: starting test informer") go s.informers.testInformer.Informer().Run(stop) + s.logger.Debugf("trigger service: starting executor informer") + go s.informers.executorInformer.Informer().Run(stop) + s.logger.Debugf("trigger service: starting webhook informer") + go s.informers.webhookInformer.Informer().Run(stop) + s.logger.Debugf("trigger service: starting test source informer") + go s.informers.testSourceInformer.Informer().Run(stop) } func (s *Service) podEventHandler(ctx context.Context) cache.ResourceEventHandlerFuncs { @@ -709,6 +731,12 @@ func (s *Service) testTriggerEventHandler() cache.ResourceEventHandlerFuncs { t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, ) s.addTrigger(t) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for created testtrigger %s/%s for resource %s on event %s", + t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceTrigger, t.Name)) }, UpdateFunc: func(oldObj, newObj interface{}) { t, ok := newObj.(*testtriggersv1.TestTrigger) @@ -724,6 +752,12 @@ func (s *Service) testTriggerEventHandler() cache.ResourceEventHandlerFuncs { t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, ) s.updateTrigger(t) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for updated testtrigger %s/%s for resource %s on event %s", + t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceTrigger, t.Name)) }, DeleteFunc: func(obj interface{}) { t, ok := obj.(*testtriggersv1.TestTrigger) @@ -736,6 +770,12 @@ func (s *Service) testTriggerEventHandler() cache.ResourceEventHandlerFuncs { t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, ) s.removeTrigger(t) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleted testtrigger %s/%s for resource %s on event %s", + t.Namespace, t.Name, t.Spec.Resource, t.Spec.Event, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceTrigger, t.Name)) }, } } @@ -760,6 +800,36 @@ func (s *Service) testSuiteEventHandler() cache.ResourceEventHandlerFuncs { testSuite.Namespace, testSuite.Name, ) s.addTestSuite(testSuite) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for creating testsuite %s/%s", + testSuite.Namespace, testSuite.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceTestsuite, testSuite.Name)) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + testSuite, ok := newObj.(*testsuitev3.TestSuite) + if !ok { + s.logger.Errorf("failed to process update testsuite event due to it being an unexpected type, received type %+v", newObj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for updating testsuite %s/%s", + testSuite.Namespace, testSuite.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceTestsuite, testSuite.Name)) + }, + DeleteFunc: func(obj interface{}) { + testSuite, ok := obj.(*testsuitev3.TestSuite) + if !ok { + s.logger.Errorf("failed to process delete testsuite event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleting testsuite %s/%s", + testSuite.Namespace, testSuite.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceTestsuite, testSuite.Name)) }, } } @@ -784,6 +854,12 @@ func (s *Service) testEventHandler() cache.ResourceEventHandlerFuncs { test.Namespace, test.Name, ) s.addTest(test) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for test %s/%s", + test.Namespace, test.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceTest, test.Name)) }, UpdateFunc: func(oldObj, newObj interface{}) { test, ok := newObj.(*testsv3.Test) @@ -796,6 +872,150 @@ func (s *Service) testEventHandler() cache.ResourceEventHandlerFuncs { test.Namespace, test.Name, ) s.updateTest(test) + + s.logger.Debugf( + "trigger service: watcher component: emitting event for updating test %s/%s", + test.Namespace, test.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceTest, test.Name)) + }, + DeleteFunc: func(obj interface{}) { + test, ok := obj.(*testsv3.Test) + if !ok { + s.logger.Errorf("failed to process delete test event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleting test %s/%s", + test.Namespace, test.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceTest, test.Name)) + }, + } +} + +func (s *Service) executorEventHandler() cache.ResourceEventHandlerFuncs { + return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + executor, ok := obj.(*executorv1.Executor) + if !ok { + s.logger.Errorf("failed to process create executor event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for executor %s/%s", + executor.Namespace, executor.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceExecutor, executor.Name)) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + executor, ok := newObj.(*executorv1.Executor) + if !ok { + s.logger.Errorf("failed to process update executor event due to it being an unexpected type, received type %+v", newObj) + return + } + + s.logger.Debugf( + "trigger service: watcher component: emitting event for updating executor %s/%s", + executor.Namespace, executor.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceExecutor, executor.Name)) + }, + DeleteFunc: func(obj interface{}) { + executor, ok := obj.(*executorv1.Executor) + if !ok { + s.logger.Errorf("failed to process delete executor event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleting executor %s/%s", + executor.Namespace, executor.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceExecutor, executor.Name)) + }, + } +} + +func (s *Service) webhookEventHandler() cache.ResourceEventHandlerFuncs { + return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + webhook, ok := obj.(*executorv1.Webhook) + if !ok { + s.logger.Errorf("failed to process create webhook event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for webhook %s/%s", + webhook.Namespace, webhook.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceWebhook, webhook.Name)) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + webhook, ok := newObj.(*executorv1.Webhook) + if !ok { + s.logger.Errorf("failed to process update webhook event due to it being an unexpected type, received type %+v", newObj) + return + } + + s.logger.Debugf( + "trigger service: watcher component: emitting event for updating webhook %s/%s", + webhook.Namespace, webhook.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceWebhook, webhook.Name)) + }, + DeleteFunc: func(obj interface{}) { + webhook, ok := obj.(*executorv1.Webhook) + if !ok { + s.logger.Errorf("failed to process delete webhook event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleting webhook %s/%s", + webhook.Namespace, webhook.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceWebhook, webhook.Name)) + }, + } +} + +func (s *Service) testSourceEventHandler() cache.ResourceEventHandlerFuncs { + return cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + testSource, ok := obj.(*testsourcev1.TestSource) + if !ok { + s.logger.Errorf("failed to process create test source event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for test source %s/%s", + testSource.Namespace, testSource.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventCreated, testkube.EventResourceTestsource, testSource.Name)) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + testSource, ok := newObj.(*testsourcev1.TestSource) + if !ok { + s.logger.Errorf("failed to process update test source event due to it being an unexpected type, received type %+v", newObj) + return + } + + s.logger.Debugf( + "trigger service: watcher component: emitting event for updating test source %s/%s", + testSource.Namespace, testSource.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventUpdated, testkube.EventResourceTestsource, testSource.Name)) + }, + DeleteFunc: func(obj interface{}) { + testSource, ok := obj.(*testsourcev1.TestSource) + if !ok { + s.logger.Errorf("failed to process delete test source event due to it being an unexpected type, received type %+v", obj) + return + } + s.logger.Debugf( + "trigger service: watcher component: emitting event for deleting test source %s/%s", + testSource.Namespace, testSource.Name, + ) + s.eventsBus.Publish(testkube.NewEvent(testkube.EventDeleted, testkube.EventResourceTestsource, testSource.Name)) }, } } diff --git a/pkg/triggers/watcher_test.go b/pkg/triggers/watcher_test.go index 7c7d56df5ff..d352e8d48fa 100644 --- a/pkg/triggers/watcher_test.go +++ b/pkg/triggers/watcher_test.go @@ -12,6 +12,7 @@ import ( testtriggersv1 "github.com/kubeshop/testkube-operator/api/testtriggers/v1" faketestkube "github.com/kubeshop/testkube-operator/pkg/clientset/versioned/fake" + "github.com/kubeshop/testkube/pkg/event/bus" "github.com/kubeshop/testkube/pkg/log" ) @@ -33,6 +34,7 @@ func TestService_runWatcher_lease(t *testing.T) { testKubeClientset: testKubeClientset, logger: log.DefaultLogger, informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), + eventsBus: &bus.EventBusMock{}, } leaseChan := make(chan bool) @@ -91,6 +93,7 @@ func TestService_runWatcher_lease(t *testing.T) { testKubeClientset: testKubeClientset, logger: log.DefaultLogger, informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), + eventsBus: &bus.EventBusMock{}, } leaseChan := make(chan bool) @@ -152,6 +155,7 @@ func TestService_runWatcher_noLease(t *testing.T) { testKubeClientset: testKubeClientset, logger: log.DefaultLogger, informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), + eventsBus: &bus.EventBusMock{}, } leaseChan := make(chan bool) @@ -192,6 +196,7 @@ func TestService_runWatcher_noLease(t *testing.T) { testKubeClientset: testKubeClientset, logger: log.DefaultLogger, informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), + eventsBus: &bus.EventBusMock{}, } leaseChan := make(chan bool) @@ -234,6 +239,7 @@ func TestService_runWatcher_noLease(t *testing.T) { testKubeClientset: testKubeClientset, logger: log.DefaultLogger, informers: newK8sInformers(clientset, testKubeClientset, "", []string{}), + eventsBus: &bus.EventBusMock{}, } leaseChan := make(chan bool) diff --git a/test/container-executor/executor-smoke/crd/postman.yaml b/test/container-executor/executor-smoke/crd/postman.yaml new file mode 100644 index 00000000000..872117c618d --- /dev/null +++ b/test/container-executor/executor-smoke/crd/postman.yaml @@ -0,0 +1,22 @@ +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: container-executor-postman-smoke + labels: + core-tests: executors +spec: + type: container-executor-postman-newman-6-alpine/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube + branch: main + path: test/postman/executor-tests/postman-executor-smoke.postman_collection.json + workingDir: test/postman/executor-tests + executionRequest: + args: ["run", "postman-executor-smoke.postman_collection.json", "--env-var", "TESTKUBE_POSTMAN_PARAM=TESTKUBE_POSTMAN_PARAM_value"] + preRunScript: "echo \"===== pre-run script\"" + postRunScript: "echo \"===== post-run script\"" + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 128Mi\n cpu: 256m\n" + activeDeadlineSeconds: 180 diff --git a/test/executors/container-executor-large-artifacts.yaml b/test/executors/container-executor-large-artifacts.yaml new file mode 100644 index 00000000000..bebd4255bdf --- /dev/null +++ b/test/executors/container-executor-large-artifacts.yaml @@ -0,0 +1,79 @@ +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-1gb-artifact +spec: + types: + - container-executor-1gb-artifact/test + executor_type: container + image: alpine:3.17.2 + command: + - /bin/sh + - -c + - cd /share; mkdir artifacts; cd artifacts; dd if=/dev/zero of=1g.img bs=1 count=0 seek=1G; ls -lah + features: + - artifacts +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-1mb-artifact +spec: + types: + - container-executor-1mb-artifact/test + executor_type: container + image: alpine:3.17.2 + command: + - /bin/sh + - -c + - cd /share; mkdir artifacts; cd artifacts; dd if=/dev/zero of=1mb.img bs=1024 count=0 seek=1024; ls -lah + features: + - artifacts +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-1gb-urandom-artifact +spec: + types: + - container-executor-1gb-urandom-artifact/test + executor_type: container + image: alpine:3.17.2 + command: + - /bin/sh + - -c + - cd /share; mkdir artifacts; cd artifacts; dd if=/dev/urandom of=1g.img bs=64M count=16; ls -lah + features: + - artifacts +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-1mb-urandom-artifact +spec: + types: + - container-executor-1mb-urandom-artifact/test + executor_type: container + image: alpine:3.17.2 + command: + - /bin/sh + - -c + - cd /share; mkdir artifacts; cd artifacts; dd if=/dev/urandom of=1mb.img bs=1024 count=0 seek=1024; ls -lah + features: + - artifacts +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-1gb-openssl-artifact +spec: + types: + - container-executor-1gb-openssl-artifact/test + executor_type: container + image: alpine/openssl:latest + command: + - /bin/sh + - -c + - cd /share && mkdir artifacts && cd artifacts && openssl rand -out 1g.txt -base64 $(( 2**30 * 3/4 )) ; ls -lah && echo "File generated - OK" + features: + - artifacts diff --git a/test/executors/container-executor-large-logs.yaml b/test/executors/container-executor-large-logs.yaml new file mode 100644 index 00000000000..db670c2458e --- /dev/null +++ b/test/executors/container-executor-large-logs.yaml @@ -0,0 +1,55 @@ +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-large-logs-1mb +spec: + types: + - container-executor-large-logs-1mb/test + executor_type: container + image: bash:5.1 + command: + - bash + - -c + - 'for iteration in {1..100}; do printf "\niteration $iteration\n"; for sets in {1..20}; do printf "LINE_BEGINNING_"; printf "abc DEFghi JKL ASDF BBB CCC%.0s" {1..20}; printf "_LINE_END"; printf "\n"; done; done' # 100 iterations - about 1.1MB +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-large-logs-11mb +spec: + types: + - container-executor-large-logs-11mb/test + executor_type: container + image: bash:5.1 + command: + - bash + - -c + - 'for iteration in {1..1000}; do sleep 2; printf "\niteration $iteration\n"; for sets in {1..20}; do printf "LINE_BEGINNING_"; printf "abc DEFghi JKL ASDF BBB CCC%.0s" {1..20}; printf "_LINE_END"; printf "\n"; done; done' # 1000 iterations - about 11MB +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-large-logs-22mb +spec: + types: + - container-executor-large-logs-22mb/test + executor_type: container + image: bash:5.1 + command: + - bash + - -c + - 'for iteration in {1..2000}; do sleep 1; printf "\niteration $iteration\n"; for sets in {1..20}; do printf "LINE_BEGINNING_"; printf "abc DEFghi JKL ASDF BBB CCC%.0s" {1..20}; printf "_LINE_END"; printf "\n"; done; done' # 2000 iterations - about 22MB +--- +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-large-logs-long-lines +spec: + types: + - container-executor-large-logs-long-lines/test + executor_type: container + image: bash:5.1 + command: + - bash + - -c + - 'for iteration in {1..100}; do printf "\niteration $iteration\n"; for sets in {1..1}; do printf "LINE_BEGINNING_"; printf "abc DEFghi JKL ASDF BBB CCC%.0s" {1..3000}; printf "_LINE_END"; printf "\n"; done; done' # 100 lines with 81k characters each diff --git a/test/executors/container-executor-postman.yaml b/test/executors/container-executor-postman.yaml new file mode 100644 index 00000000000..8e40636595c --- /dev/null +++ b/test/executors/container-executor-postman.yaml @@ -0,0 +1,9 @@ +apiVersion: executor.testkube.io/v1 +kind: Executor +metadata: + name: container-executor-postman-newman-6-alpine +spec: + image: postman/newman:6-alpine + executor_type: container + types: + - container-executor-postman-newman-6-alpine/test diff --git a/test/executors/gradle.yaml b/test/executors/gradle.yaml index 0cbf48141bb..9c563477f6f 100644 --- a/test/executors/gradle.yaml +++ b/test/executors/gradle.yaml @@ -3,7 +3,7 @@ kind: Executor metadata: name: gradle-jdk18-executor spec: - image: kubeshop/testkube-gradle-executor:0.1-jdk18 + image: kubeshop/testkube-gradle-executor:jdk18 types: - gradle:jdk18/project - gradle:jdk18/test @@ -14,7 +14,7 @@ kind: Executor metadata: name: gradle-jdk17-executor spec: - image: kubeshop/testkube-gradle-executor:0.1-jdk17 + image: kubeshop/testkube-gradle-executor:jdk17 types: - gradle:jdk17/project - gradle:jdk17/test @@ -25,7 +25,7 @@ kind: Executor metadata: name: gradle-jdk11-executor spec: - image: kubeshop/testkube-gradle-executor:0.1-jdk11 + image: kubeshop/testkube-gradle-executor:jdk11 types: - gradle:jdk11/project - gradle:jdk11/test @@ -36,7 +36,7 @@ kind: Executor metadata: name: gradle-jdk8-executor spec: - image: kubeshop/testkube-gradle-executor:0.1-jdk8 + image: kubeshop/testkube-gradle-executor:jdk8 types: - gradle:jdk8/project - gradle:jdk8/test diff --git a/test/executors/maven.yaml b/test/executors/maven.yaml index 2a2f97f1a9e..1f106339b19 100644 --- a/test/executors/maven.yaml +++ b/test/executors/maven.yaml @@ -3,7 +3,7 @@ kind: Executor metadata: name: maven-jdk18-executor spec: - image: kubeshop/testkube-maven-executor:0.1-jdk18 + image: kubeshop/testkube-maven-executor:jdk18 types: - maven:jdk18/project - maven:jdk18/test @@ -14,7 +14,7 @@ kind: Executor metadata: name: maven-jdk11-executor spec: - image: kubeshop/testkube-maven-executor:0.1-jdk11 + image: kubeshop/testkube-maven-executor:jdk11 types: - maven:jdk11/project - maven:jdk11/test @@ -25,7 +25,7 @@ kind: Executor metadata: name: maven-jdk8-executor spec: - image: kubeshop/testkube-maven-executor:0.1-jdk8 + image: kubeshop/testkube-maven-executor:jdk8 types: - maven:jdk8/project - maven:jdk8/test diff --git a/test/ginkgo/executor-tests/smoke-negative/go.mod b/test/ginkgo/executor-tests/smoke-negative/go.mod index 03e157b8c17..830b386a84a 100644 --- a/test/ginkgo/executor-tests/smoke-negative/go.mod +++ b/test/ginkgo/executor-tests/smoke-negative/go.mod @@ -3,20 +3,18 @@ module test go 1.19 require ( - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/onsi/ginkgo/v2 v2.9.1 + github.com/onsi/gomega v1.27.4 +) + +require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo/v2 v2.9.1 // indirect - github.com/onsi/gomega v1.27.4 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.7.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/ginkgo/executor-tests/smoke-negative/go.sum b/test/ginkgo/executor-tests/smoke-negative/go.sum index 71d63c6ae96..2bfbce06dd3 100644 --- a/test/ginkgo/executor-tests/smoke-negative/go.sum +++ b/test/ginkgo/executor-tests/smoke-negative/go.sum @@ -2,102 +2,40 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/ginkgo/executor-tests/smoke/go.mod b/test/ginkgo/executor-tests/smoke/go.mod index 03e157b8c17..830b386a84a 100644 --- a/test/ginkgo/executor-tests/smoke/go.mod +++ b/test/ginkgo/executor-tests/smoke/go.mod @@ -3,20 +3,18 @@ module test go 1.19 require ( - github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/onsi/ginkgo/v2 v2.9.1 + github.com/onsi/gomega v1.27.4 +) + +require ( github.com/go-logr/logr v1.2.3 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect - github.com/golang/protobuf v1.5.3 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/nxadm/tail v1.4.8 // indirect - github.com/onsi/ginkgo/v2 v2.9.1 // indirect - github.com/onsi/gomega v1.27.4 // indirect - golang.org/x/net v0.8.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/text v0.8.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/tools v0.7.0 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/ginkgo/executor-tests/smoke/go.sum b/test/ginkgo/executor-tests/smoke/go.sum index 71d63c6ae96..2bfbce06dd3 100644 --- a/test/ginkgo/executor-tests/smoke/go.sum +++ b/test/ginkgo/executor-tests/smoke/go.sum @@ -2,102 +2,40 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo/v2 v2.9.1 h1:zie5Ly042PD3bsCvsSOPvRnFwyo3rKe64TJlD6nu0mk= github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.27.4 h1:Z2AnStgsdSayCMDiCU42qIz+HLqEPcgiOCXjAU/w+8E= github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/jmeter/executor-tests/crd/other.yaml b/test/jmeter/executor-tests/crd/other.yaml new file mode 100644 index 00000000000..845797cdf83 --- /dev/null +++ b/test/jmeter/executor-tests/crd/other.yaml @@ -0,0 +1,153 @@ +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeter-executor-smoke-incorrect-url-assertion-negative + labels: + core-tests: executors +spec: + type: jmeter/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx + executionRequest: + negativeTest: true + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeterd-executor-smoke-incorrect-url-assertion-negative + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx + executionRequest: + negativeTest: true + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeterd-executor-smoke-incorrect-url-assertion-slaves-negative + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx + executionRequest: + negativeTest: true + variables: + SLAVES_COUNT: + name: SLAVES_COUNT + value: "2" + type: basic + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 + slavePodRequest: + resources: + requests: + cpu: 400m + memory: 512Mi + limits: + cpu: 500m + memory: 512Mi +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeterd-executor-smoke-correct-url-failed-assertion-negative + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-correct-url-failed-assertion.jmx + executionRequest: + negativeTest: true + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeterd-executor-smoke-failed-assertion-slaves-negative + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-correct-url-failed-assertion.jmx + executionRequest: + negativeTest: true + variables: + SLAVES_COUNT: + name: SLAVES_COUNT + value: "2" + type: basic + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 + slavePodRequest: + resources: + requests: + cpu: 400m + memory: 512Mi + limits: + cpu: 500m + memory: 512Mi +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: jmeterd-executor-smoke-failure-exit-code-0-negative + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: contrib/executor/jmeterd/examples/gitflow/jmeter-properties-external.jmx + executionRequest: + negativeTest: true + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 + slavePodRequest: + resources: + requests: + cpu: 400m + memory: 512Mi + limits: + cpu: 500m + memory: 512Mi diff --git a/test/jmeter/executor-tests/crd/smoke.yaml b/test/jmeter/executor-tests/crd/smoke.yaml index bf2841de1a6..67b174a63f4 100644 --- a/test/jmeter/executor-tests/crd/smoke.yaml +++ b/test/jmeter/executor-tests/crd/smoke.yaml @@ -113,6 +113,38 @@ spec: --- apiVersion: tests.testkube.io/v3 kind: Test +metadata: + name: jmeterd-executor-smoke-slave-1 + labels: + core-tests: executors +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke.jmx + executionRequest: + variables: + SLAVES_COUNT: + name: SLAVES_COUNT + value: "1" + type: basic + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 512Mi\n cpu: 512m\n" + activeDeadlineSeconds: 180 + slavePodRequest: + resources: + requests: + cpu: 400m + memory: 512Mi + limits: + cpu: 500m + memory: 512Mi +--- +apiVersion: tests.testkube.io/v3 +kind: Test metadata: name: jmeterd-executor-smoke-slaves labels: diff --git a/test/jmeter/executor-tests/jmeter-executor-smoke-correct-url-failed-assertion.jmx b/test/jmeter/executor-tests/jmeter-executor-smoke-correct-url-failed-assertion.jmx new file mode 100644 index 00000000000..c7823bc7839 --- /dev/null +++ b/test/jmeter/executor-tests/jmeter-executor-smoke-correct-url-failed-assertion.jmx @@ -0,0 +1,80 @@ + + + + + + + + + + + + 1 + + 1 + 1 + 1668426657000 + 1668426657000 + false + + + stoptest + + + + + + + testkube.io + GET + true + true + + + + + some-non-existing-text + + Assertion.response_data + false + 8 + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + + diff --git a/test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx b/test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx new file mode 100644 index 00000000000..57db72b0610 --- /dev/null +++ b/test/jmeter/executor-tests/jmeter-executor-smoke-incorrect-url.jmx @@ -0,0 +1,94 @@ + + + + + + false + false + + + + + + + + continue + + false + 1 + + 1 + 1 + 1668426657000 + 1668426657000 + false + + + + + + + + + some.incorrect.url.testkube.example + + + + + + + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 8 + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + false + false + false + false + false + 0 + true + true + + + + + + + + + diff --git a/test/postman/executor-tests/crd/crd.yaml b/test/postman/executor-tests/crd/crd.yaml index b558f941551..93203c6e4f2 100644 --- a/test/postman/executor-tests/crd/crd.yaml +++ b/test/postman/executor-tests/crd/crd.yaml @@ -40,6 +40,29 @@ spec: - TESTKUBE_POSTMAN_PARAM=TESTKUBE_POSTMAN_PARAM_value jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 128Mi\n cpu: 256m\n" --- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: postman-executor-smoke-pre-post-run-scripts + labels: + core-tests: executors +spec: + type: postman/collection + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/postman/executor-tests/postman-executor-smoke.postman_collection.json + executionRequest: + args: + - --env-var + - TESTKUBE_POSTMAN_PARAM=TESTKUBE_POSTMAN_PARAM_value + preRunScript: "echo \"===== pre-run script\"" + postRunScript: "echo \"===== post-run script\"" + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 128Mi\n cpu: 256m\n" +--- # postman-executor-smoke-testsource - TestSource apiVersion: tests.testkube.io/v1 kind: TestSource diff --git a/test/scripts/executor-tests/run.sh b/test/scripts/executor-tests/run.sh index da1fcd711fd..a5919a28e9e 100755 --- a/test/scripts/executor-tests/run.sh +++ b/test/scripts/executor-tests/run.sh @@ -164,6 +164,17 @@ container-playwright-smoke() { common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" "$custom_executor_crd_file" } +container-postman-smoke() { + name="Container executor - Postman" + test_crd_file="test/container-executor/executor-smoke/crd/postman.yaml" + testsuite_name="executor-container-postman-smoke-tests" + testsuite_file="test/suites/executor-container-postman-smoke-tests.yaml" + + custom_executor_crd_file="test/executors/container-executor-postman.yaml" + + common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" "$custom_executor_crd_file" +} + curl-smoke() { name="curl" test_crd_file="test/curl/executor-tests/crd/smoke.yaml" @@ -213,6 +224,15 @@ jmeter-smoke() { common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" } +jmeter-other() { + name="JMeter" + test_crd_file="test/jmeter/executor-tests/crd/other.yaml" + testsuite_name="executor-jmeter-other-tests" + testsuite_file="test/suites/executor-jmeter-other-tests.yaml" + + common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" +} + k6-smoke() { name="k6 smoke" test_crd_file="test/k6/executor-tests/crd/smoke.yaml" @@ -278,15 +298,37 @@ soapui-smoke() { common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" } -edge-cases-failures() { - name="Edge Cases - Failures" - test_crd_file="test/edge-cases/failures.yaml" +special-cases-failures() { + name="Special Cases - Edge Cases - Expected Failures" + test_crd_file="test/special-cases/edge-cases-expected-fails.yaml" testsuite_name="expected-fail" - testsuite_file="test/suites/edge-cases-expected-failures.yaml" + testsuite_file="test/suites/special-cases/edge-cases-expected-fails.yaml" common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" } +special-cases-large-logs() { + name="Special Cases - Large logs" + test_crd_file="test/special-cases/large-logs.yaml" + testsuite_name="large-logs" + testsuite_file="test/suites/special-cases/large-logs.yaml" + + custom_executor_crd_file="test/executors/container-executor-large-logs.yaml" + + common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" "$custom_executor_crd_file" +} + +special-cases-large-artifacts() { + name="Special Cases - Large artifacts" + test_crd_file="test/special-cases/large-artifacts.yaml" + testsuite_name="large-artifacts" + testsuite_file="test/suites/special-cases/large-artifacts.yaml" + + custom_executor_crd_file="test/executors/container-executor-large-artifacts.yaml" + + common_run "$name" "$test_crd_file" "$testsuite_name" "$testsuite_file" "$custom_executor_crd_file" +} + main() { case $executor_type in all) @@ -294,12 +336,14 @@ main() { container-curl-smoke container-cypress-smoke container-k6-smoke + container-postman-smoke container-playwright-smoke curl-smoke cypress-smoke ginkgo-smoke gradle-smoke jmeter-smoke + jmeter-other k6-smoke k6-other kubepug-smoke @@ -307,13 +351,13 @@ main() { postman-smoke playwright-smoke soapui-smoke - edge-cases-failures ;; smoke) artillery-smoke container-curl-smoke container-cypress-smoke container-k6-smoke + container-postman-smoke container-playwright-smoke curl-smoke cypress-smoke @@ -327,6 +371,11 @@ main() { postman-smoke soapui-smoke ;; + special) + special-cases-failures + special-cases-large-logs + special-cases-large-artifacts + ;; *) $executor_type ;; diff --git a/test/edge-cases/failures.yaml b/test/special-cases/edge-cases-expected-fails.yaml similarity index 75% rename from test/edge-cases/failures.yaml rename to test/special-cases/edge-cases-expected-fails.yaml index 64cfc876cd5..3dcf831b28c 100644 --- a/test/edge-cases/failures.yaml +++ b/test/special-cases/edge-cases-expected-fails.yaml @@ -175,6 +175,30 @@ spec: --- apiVersion: tests.testkube.io/v3 kind: Test +metadata: + name: expected-fail-jmeterd-executor-jsr223 + labels: + core-tests: expected-fail +spec: + type: jmeterd/test + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/jmeter/executor-tests/jmeter-executor-smoke-env-and-property.jmx + executionRequest: + variables: + URL_ENV: + name: expected-fail-URL_ENV + value: "testkube.io" + type: basic + args: + - "-JURL_PROPERTY=testkube.kubeshop.io" +--- +apiVersion: tests.testkube.io/v3 +kind: Test metadata: name: expected-fail-kubepug-executor labels: @@ -266,7 +290,7 @@ kind: Test metadata: name: expected-fail-cypress-oomkilled labels: - core-tests: executors + core-tests: expected-fail spec: type: cypress:v12/test content: @@ -289,3 +313,49 @@ spec: - video=true jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n limits:\n memory: 30Mi\n cpu: 1\n" activeDeadlineSeconds: 600 +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: expected-fail-pre-run-script + labels: + core-tests: expected-fail +spec: + type: postman/collection + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/postman/executor-tests/postman-executor-smoke.postman_collection.json + executionRequest: + args: + - --env-var + - TESTKUBE_POSTMAN_PARAM=TESTKUBE_POSTMAN_PARAM_value + preRunScript: "echo \"===== pre-run script - EXPECTED FAIL\" && exit 128" + postRunScript: "echo \"===== post-run script\"" + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 128Mi\n cpu: 256m\n" +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: expected-fail-post-run-script + labels: + core-tests: expected-fail +spec: + type: postman/collection + content: + type: git + repository: + type: git + uri: https://github.com/kubeshop/testkube.git + branch: main + path: test/postman/executor-tests/postman-executor-smoke.postman_collection.json + executionRequest: + args: + - --env-var + - TESTKUBE_POSTMAN_PARAM=TESTKUBE_POSTMAN_PARAM_value + preRunScript: "echo \"===== pre-run script\"" + postRunScript: "echo \"===== post-run script - EXPECTED FAIL\" && exit 128" + jobTemplate: "apiVersion: batch/v1\nkind: Job\nspec:\n template:\n spec:\n containers:\n - name: \"{{ .Name }}\"\n image: {{ .Image }}\n resources:\n requests:\n memory: 128Mi\n cpu: 256m\n" diff --git a/test/special-cases/large-artifacts.yaml b/test/special-cases/large-artifacts.yaml new file mode 100644 index 00000000000..40ee52cfe94 --- /dev/null +++ b/test/special-cases/large-artifacts.yaml @@ -0,0 +1,75 @@ + +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-artifacts-1gb-test + labels: + core-tests: special-cases-large-artifacts +spec: + type: container-executor-1gb-artifact/test + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - artifacts +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-artifacts-1mb-test + labels: + core-tests: special-cases-large-artifacts +spec: + type: container-executor-1mb-artifact/test + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - artifacts +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-artifacts-1gb-urandom-test + labels: + core-tests: special-cases-large-artifacts +spec: + type: container-executor-1gb-urandom-artifact/test + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - artifacts +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-artifacts-1mb-urandom-test + labels: + core-tests: special-cases-large-artifacts +spec: + type: container-executor-1mb-urandom-artifact/test + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - artifacts +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-artifacts-1gb-openssl-test + labels: + core-tests: special-cases-large-artifacts +spec: + type: container-executor-1gb-openssl-artifact/test + executionRequest: + artifactRequest: + storageClassName: standard + volumeMountPath: /share + dirs: + - artifacts diff --git a/test/special-cases/large-logs.yaml b/test/special-cases/large-logs.yaml new file mode 100644 index 00000000000..6cdee9753db --- /dev/null +++ b/test/special-cases/large-logs.yaml @@ -0,0 +1,36 @@ + +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-logs-1mb-test + labels: + core-tests: special-cases-large-logs +spec: + type: container-executor-large-logs-1mb/test +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-logs-11mb-test + labels: + core-tests: special-cases-large-logs +spec: + type: container-executor-large-logs-11mb/test +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-logs-22mb-test + labels: + core-tests: special-cases-large-logs +spec: + type: container-executor-large-logs-22mb/test +--- +apiVersion: tests.testkube.io/v3 +kind: Test +metadata: + name: large-logs-long-lines-81k-test + labels: + core-tests: special-cases-large-logs +spec: + type: container-executor-large-logs-long-lines/test \ No newline at end of file diff --git a/test/suites/executor-artillery-smoke-tests.yaml b/test/suites/executor-artillery-smoke-tests.yaml index cca70c6c64c..35821ee992b 100644 --- a/test/suites/executor-artillery-smoke-tests.yaml +++ b/test/suites/executor-artillery-smoke-tests.yaml @@ -2,6 +2,8 @@ apiVersion: tests.testkube.io/v3 kind: TestSuite metadata: name: executor-artillery-smoke-tests + labels: + core-tests: executors spec: description: artillery executor smoke tests steps: diff --git a/test/suites/executor-container-curl-smoke-tests.yaml b/test/suites/executor-container-curl-smoke-tests.yaml index de099457d7c..1ca847786ab 100644 --- a/test/suites/executor-container-curl-smoke-tests.yaml +++ b/test/suites/executor-container-curl-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-container-curl-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "container executor curl smoke tests" steps: diff --git a/test/suites/executor-container-cypress-smoke-tests.yaml b/test/suites/executor-container-cypress-smoke-tests.yaml index 510c2bdd6ac..950c7abb34b 100644 --- a/test/suites/executor-container-cypress-smoke-tests.yaml +++ b/test/suites/executor-container-cypress-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-container-cypress-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "container executor cypress smoke tests" steps: diff --git a/test/suites/executor-container-k6-smoke-tests.yaml b/test/suites/executor-container-k6-smoke-tests.yaml index a1507d38055..be78b84cc9e 100644 --- a/test/suites/executor-container-k6-smoke-tests.yaml +++ b/test/suites/executor-container-k6-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-container-k6-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "container executor k6 smoke tests" steps: diff --git a/test/suites/executor-container-playwright-smoke-tests.yaml b/test/suites/executor-container-playwright-smoke-tests.yaml index 67334779cea..020bb045f2d 100644 --- a/test/suites/executor-container-playwright-smoke-tests.yaml +++ b/test/suites/executor-container-playwright-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-container-playwright-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "container executor playwright smoke tests" steps: diff --git a/test/suites/executor-container-postman-smoke-tests.yaml b/test/suites/executor-container-postman-smoke-tests.yaml new file mode 100644 index 00000000000..935dc1c573d --- /dev/null +++ b/test/suites/executor-container-postman-smoke-tests.yaml @@ -0,0 +1,12 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: executor-container-postman-smoke-tests + labels: + core-tests: executors +spec: + description: "container executor postman smoke tests" + steps: + - stopOnFailure: false + execute: + - test: container-executor-postman-smoke diff --git a/test/suites/executor-curl-smoke-tests.yaml b/test/suites/executor-curl-smoke-tests.yaml index a74127ac21f..5720f63229a 100644 --- a/test/suites/executor-curl-smoke-tests.yaml +++ b/test/suites/executor-curl-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-curl-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "curl executor smoke tests" steps: diff --git a/test/suites/executor-cypress-smoke-tests.yaml b/test/suites/executor-cypress-smoke-tests.yaml index 0666b05422d..63085908b9b 100644 --- a/test/suites/executor-cypress-smoke-tests.yaml +++ b/test/suites/executor-cypress-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-cypress-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "Cypress executor smoke tests" steps: diff --git a/test/suites/executor-ginkgo-smoke-tests.yaml b/test/suites/executor-ginkgo-smoke-tests.yaml index b938300d09c..561f2430218 100644 --- a/test/suites/executor-ginkgo-smoke-tests.yaml +++ b/test/suites/executor-ginkgo-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-ginkgo-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "ginkgo executor smoke tests" steps: diff --git a/test/suites/executor-gradle-smoke-tests.yaml b/test/suites/executor-gradle-smoke-tests.yaml index a103bab26a8..592d3875bdf 100644 --- a/test/suites/executor-gradle-smoke-tests.yaml +++ b/test/suites/executor-gradle-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-gradle-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "gradle executor smoke tests" steps: diff --git a/test/suites/executor-jmeter-other-tests.yaml b/test/suites/executor-jmeter-other-tests.yaml new file mode 100644 index 00000000000..6ed16725314 --- /dev/null +++ b/test/suites/executor-jmeter-other-tests.yaml @@ -0,0 +1,27 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: executor-jmeter-other-tests + labels: + core-tests: executors +spec: + description: "jmeter and jmeterd executor - other tests and edge-cases" + steps: + - stopOnFailure: false + execute: + - test: jmeter-executor-smoke-incorrect-url-assertion-negative + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-incorrect-url-assertion-negative + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-incorrect-url-assertion-slaves-negative + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-correct-url-failed-assertion-negative + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-failed-assertion-slaves-negative + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-failure-exit-code-0-negative diff --git a/test/suites/executor-jmeter-smoke-tests.yaml b/test/suites/executor-jmeter-smoke-tests.yaml index 2c42f56236d..f71f53907a5 100644 --- a/test/suites/executor-jmeter-smoke-tests.yaml +++ b/test/suites/executor-jmeter-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-jmeter-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "jmeter and jmeterd executor smoke tests" steps: @@ -22,6 +22,9 @@ spec: - stopOnFailure: false execute: - test: jmeterd-executor-smoke + - stopOnFailure: false + execute: + - test: jmeterd-executor-smoke-slave-1 - stopOnFailure: false execute: - test: jmeterd-executor-smoke-slaves diff --git a/test/suites/executor-k6-other-tests.yaml b/test/suites/executor-k6-other-tests.yaml index 946637c7ae9..325205229b1 100644 --- a/test/suites/executor-k6-other-tests.yaml +++ b/test/suites/executor-k6-other-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-k6-other-tests labels: - app: testkube + core-tests: executors spec: description: "k6 executor - other tests and edge-cases" steps: diff --git a/test/suites/executor-k6-smoke-tests.yaml b/test/suites/executor-k6-smoke-tests.yaml index 54ae126e7da..e08a7b150bf 100644 --- a/test/suites/executor-k6-smoke-tests.yaml +++ b/test/suites/executor-k6-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-k6-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "k6 executor smoke tests" steps: diff --git a/test/suites/executor-kubepug-smoke-tests.yaml b/test/suites/executor-kubepug-smoke-tests.yaml index bf7ec2469df..c485c465d58 100644 --- a/test/suites/executor-kubepug-smoke-tests.yaml +++ b/test/suites/executor-kubepug-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-kubepug-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "kubepug executor smoke tests" steps: diff --git a/test/suites/executor-maven-smoke-tests.yaml b/test/suites/executor-maven-smoke-tests.yaml index d1e609f0377..84dc640ca9a 100644 --- a/test/suites/executor-maven-smoke-tests.yaml +++ b/test/suites/executor-maven-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-maven-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "maven executor smoke tests" steps: diff --git a/test/suites/executor-playwright-smoke-tests.yaml b/test/suites/executor-playwright-smoke-tests.yaml index 9edfa01e2c2..e2dc1510b09 100644 --- a/test/suites/executor-playwright-smoke-tests.yaml +++ b/test/suites/executor-playwright-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-playwright-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "playwright executor smoke tests" steps: diff --git a/test/suites/executor-postman-smoke-tests.yaml b/test/suites/executor-postman-smoke-tests.yaml index 3eb3fec7fb6..842daff6f2a 100644 --- a/test/suites/executor-postman-smoke-tests.yaml +++ b/test/suites/executor-postman-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-postman-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "postman executor smoke tests" steps: @@ -13,6 +13,9 @@ spec: - stopOnFailure: false execute: - test: postman-executor-smoke-git-file + - stopOnFailure: false + execute: + - test: postman-executor-smoke-pre-post-run-scripts - stopOnFailure: false execute: - test: postman-executor-smoke-testsource diff --git a/test/suites/executor-soapui-smoke-tests.yaml b/test/suites/executor-soapui-smoke-tests.yaml index ab46046954d..9b4297581f0 100644 --- a/test/suites/executor-soapui-smoke-tests.yaml +++ b/test/suites/executor-soapui-smoke-tests.yaml @@ -3,7 +3,7 @@ kind: TestSuite metadata: name: executor-soapui-smoke-tests labels: - app: testkube + core-tests: executors spec: description: "soapui executor smoke tests" steps: diff --git a/test/suites/edge-cases-expected-failures.yaml b/test/suites/special-cases/edge-cases-expected-fails.yaml similarity index 86% rename from test/suites/edge-cases-expected-failures.yaml rename to test/suites/special-cases/edge-cases-expected-fails.yaml index 9b6c0dc19ca..555d9e66193 100644 --- a/test/suites/edge-cases-expected-failures.yaml +++ b/test/suites/special-cases/edge-cases-expected-fails.yaml @@ -3,7 +3,6 @@ kind: TestSuite metadata: name: expected-fail labels: - app: testkube core-tests: expected-fail spec: description: "Edge cases - expected failures" @@ -38,6 +37,9 @@ spec: - stopOnFailure: false execute: - test: expected-fail-jmeter-executor-JSR223 + - stopOnFailure: false + execute: + - test: expected-fail-jmeterd-executor-JSR223 - stopOnFailure: false execute: - test: expected-fail-kubepug-executor @@ -56,3 +58,9 @@ spec: - stopOnFailure: false execute: - test: expected-fail-cypress-oomkilled + - stopOnFailure: false + execute: + - test: expected-fail-pre-run-script + - stopOnFailure: false + execute: + - test: expected-fail-post-run-script diff --git a/test/suites/special-cases/expected-failure-parallel-testsuite-delays.yaml b/test/suites/special-cases/expected-failure-parallel-testsuite-delays.yaml new file mode 100644 index 00000000000..1dc2ecf111b --- /dev/null +++ b/test/suites/special-cases/expected-failure-parallel-testsuite-delays.yaml @@ -0,0 +1,23 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: expected-failure-parallel-testsuite-delays + labels: + core-tests: special-cases-expected-failure +spec: + steps: + - stopOnFailure: false + execute: + - test: k6-executor-smoke + - delay: 30s + - test: container-executor-curl-smoke + - stopOnFailure: false + execute: + - test: k6-executor-smoke + - test: postman-executor-smoke + - delay: 12s + - stopOnFailure: false + execute: + - test: soapui-executor-smoke + - delay: 2s + - delay: 1.223s \ No newline at end of file diff --git a/test/suites/special-cases/large-artifacts.yaml b/test/suites/special-cases/large-artifacts.yaml new file mode 100644 index 00000000000..571c3dc9d9e --- /dev/null +++ b/test/suites/special-cases/large-artifacts.yaml @@ -0,0 +1,24 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: large-artifacts + labels: + core-tests: special-cases-large-artifacts +spec: + description: "Special cases - large artifacts" + steps: + - stopOnFailure: false + execute: + - test: large-artifacts-1gb-test + - stopOnFailure: false + execute: + - test: large-artifacts-1mb-test + - stopOnFailure: false + execute: + - test: large-artifacts-1gb-urandom-test + - stopOnFailure: false + execute: + - test: large-artifacts-1mb-urandom-test + - stopOnFailure: false + execute: + - test: large-artifacts-1gb-openssl-test \ No newline at end of file diff --git a/test/suites/special-cases/large-logs.yaml b/test/suites/special-cases/large-logs.yaml new file mode 100644 index 00000000000..dd8f667e6be --- /dev/null +++ b/test/suites/special-cases/large-logs.yaml @@ -0,0 +1,21 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: large-logs + labels: + core-tests: special-cases-large-logs +spec: + description: "Special cases - large logs" + steps: + - stopOnFailure: false + execute: + - test: large-logs-1mb-test + - stopOnFailure: false + execute: + - test: large-logs-11mb-test + - stopOnFailure: false + execute: + - test: large-logs-22mb-test + - stopOnFailure: false + execute: + - test: large-logs-long-lines-81k-test \ No newline at end of file diff --git a/test/suites/special-cases/parallel-testsuite-2.yaml b/test/suites/special-cases/parallel-testsuite-2.yaml new file mode 100644 index 00000000000..f19ff0dde64 --- /dev/null +++ b/test/suites/special-cases/parallel-testsuite-2.yaml @@ -0,0 +1,20 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: parallel-testsuite-2 + labels: + core-tests: special-cases +spec: + description: "parallel testsuite 2" + steps: + - stopOnFailure: false + execute: + - test: artillery-executor-smoke + - test: k6-executor-smoke + - stopOnFailure: false + execute: + - test: k6-executor-smoke-git-file + - stopOnFailure: false + execute: + - test: artillery-executor-smoke-negative + - test: container-executor-curl-smoke diff --git a/test/suites/special-cases/parallel-testsuite-delays.yaml b/test/suites/special-cases/parallel-testsuite-delays.yaml new file mode 100644 index 00000000000..b6d9fb26779 --- /dev/null +++ b/test/suites/special-cases/parallel-testsuite-delays.yaml @@ -0,0 +1,23 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: parallel-testsuite-delays + labels: + core-tests: special-cases +spec: + steps: + - stopOnFailure: false + execute: + - test: k6-executor-smoke + - test: container-executor-curl-smoke + - delay: 10s + - stopOnFailure: false + execute: + - test: k6-executor-smoke + - test: postman-executor-smoke + - delay: 12s + - stopOnFailure: false + execute: + - test: soapui-executor-smoke + - delay: 2s + - delay: 1.223s \ No newline at end of file diff --git a/test/suites/special-cases/parallel-testsuite-downloadArtifacts.yaml b/test/suites/special-cases/parallel-testsuite-downloadArtifacts.yaml new file mode 100644 index 00000000000..bdd39bdbe42 --- /dev/null +++ b/test/suites/special-cases/parallel-testsuite-downloadArtifacts.yaml @@ -0,0 +1,24 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: parallel-testsuite-downloadartifacts + labels: + core-tests: special-cases +spec: + steps: + - stopOnFailure: false + execute: + - test: artillery-executor-smoke + - test: soapui-executor-smoke + - stopOnFailure: false + execute: + - test: container-executor-curl-smoke + - test: container-executor-curl-smoke + - test: soapui-executor-smoke + - stopOnFailure: false + downloadArtifacts: + previousStepNumbers: [] + previousTestNames: [] + execute: + - test: expected-fail-container-executor-k6-wrong-dir + - test: soapui-executor-smoke \ No newline at end of file diff --git a/test/suites/special-cases/parallel-testsuite-downloadArtifacts2.yaml b/test/suites/special-cases/parallel-testsuite-downloadArtifacts2.yaml new file mode 100644 index 00000000000..cda6fd1c9fc --- /dev/null +++ b/test/suites/special-cases/parallel-testsuite-downloadArtifacts2.yaml @@ -0,0 +1,20 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: parallel-testsuite-downloadartifacts2 + labels: + core-tests: special-cases +spec: + description: "standard" + steps: + - stopOnFailure: false + execute: + - test: artillery-executor-smoke + - stopOnFailure: false + execute: + - test: container-executor-curl-smoke + - stopOnFailure: false + downloadArtifacts: + allPreviousSteps: true + execute: + - test: container-executor-curl-smoke \ No newline at end of file diff --git a/test/suites/special-cases/parallel-testsuite-large-logs.yaml b/test/suites/special-cases/parallel-testsuite-large-logs.yaml new file mode 100644 index 00000000000..cb97a2478d9 --- /dev/null +++ b/test/suites/special-cases/parallel-testsuite-large-logs.yaml @@ -0,0 +1,30 @@ +apiVersion: tests.testkube.io/v3 +kind: TestSuite +metadata: + name: parallel-large-logs + labels: + core-tests: special-cases +spec: + steps: + - stopOnFailure: false + execute: + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-11mb-test + - test: large-logs-22mb-test + - test: large-logs-22mb-test + - test: large-logs-22mb-test + - test: large-logs-22mb-test \ No newline at end of file