github.com/kubeshop/testkube@v1.17.23/cmd/kubectl-testkube/commands/testsuites/run.go (about) 1 package testsuites 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "strings" 8 "time" 9 10 "github.com/pkg/errors" 11 "github.com/spf13/cobra" 12 13 "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" 14 apiv1 "github.com/kubeshop/testkube/pkg/api/v1/client" 15 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 16 "github.com/kubeshop/testkube/pkg/ui" 17 ) 18 19 const ( 20 maxErrorMessageLength = 100000 21 ) 22 23 func NewRunTestSuiteCmd() *cobra.Command { 24 var ( 25 name string 26 watchEnabled bool 27 variables []string 28 secretVariables []string 29 executionLabels map[string]string 30 selectors []string 31 concurrencyLevel int 32 httpProxy, httpsProxy string 33 secretVariableReferences map[string]string 34 gitBranch string 35 gitCommit string 36 gitPath string 37 gitWorkingDir string 38 runningContext string 39 jobTemplate string 40 scraperTemplate string 41 pvcTemplate string 42 jobTemplateReference string 43 scraperTemplateReference string 44 pvcTemplateReference string 45 downloadArtifactsEnabled bool 46 downloadDir string 47 format string 48 masks []string 49 silentMode bool 50 ) 51 52 cmd := &cobra.Command{ 53 Use: "testsuite <testSuiteName>", 54 Aliases: []string{"ts"}, 55 Short: "Starts new test suite", 56 Long: `Starts new test suite based on TestSuite Custom Resource name, returns results to console`, 57 Run: func(cmd *cobra.Command, args []string) { 58 startTime := time.Now() 59 client, namespace, err := common.GetClient(cmd) 60 ui.ExitOnError("getting client", err) 61 62 var executions []testkube.TestSuiteExecution 63 64 options := apiv1.ExecuteTestSuiteOptions{ 65 HTTPProxy: httpProxy, 66 HTTPSProxy: httpsProxy, 67 ExecutionLabels: executionLabels, 68 RunningContext: &testkube.RunningContext{ 69 Type_: string(testkube.RunningContextTypeUserCLI), 70 Context: runningContext, 71 }, 72 ConcurrencyLevel: int32(concurrencyLevel), 73 JobTemplateReference: jobTemplateReference, 74 ScraperTemplateReference: scraperTemplateReference, 75 PvcTemplateReference: pvcTemplateReference, 76 } 77 78 var fields = []struct { 79 source string 80 title string 81 destination *string 82 }{ 83 { 84 jobTemplate, 85 "job template", 86 &options.JobTemplate, 87 }, 88 { 89 scraperTemplate, 90 "scraper template", 91 &options.ScraperTemplate, 92 }, 93 { 94 pvcTemplate, 95 "pvc template", 96 &options.PvcTemplate, 97 }, 98 } 99 100 for _, field := range fields { 101 if field.source != "" { 102 b, err := os.ReadFile(field.source) 103 ui.ExitOnError("reading "+field.title, err) 104 *field.destination = string(b) 105 } 106 } 107 108 info, err := client.GetServerInfo() 109 ui.ExitOnError("getting server info", err) 110 111 options.ExecutionVariables, err = common.CreateVariables(cmd, info.DisableSecretCreation) 112 ui.WarnOnError("getting variables", err) 113 114 if gitBranch != "" || gitCommit != "" || gitPath != "" || gitWorkingDir != "" { 115 options.ContentRequest = &testkube.TestContentRequest{ 116 Repository: &testkube.RepositoryParameters{ 117 Branch: gitBranch, 118 Commit: gitCommit, 119 Path: gitPath, 120 WorkingDir: gitWorkingDir, 121 }, 122 } 123 } 124 125 switch { 126 case len(args) > 0: 127 testSuiteName := args[0] 128 namespacedName := fmt.Sprintf("%s/%s", namespace, testSuiteName) 129 130 execution, err := client.ExecuteTestSuite(testSuiteName, name, options) 131 ui.ExitOnError("starting test suite execution "+namespacedName, err) 132 executions = append(executions, execution) 133 case len(selectors) != 0: 134 selector := strings.Join(selectors, ",") 135 executions, err = client.ExecuteTestSuites(selector, concurrencyLevel, options) 136 ui.ExitOnError("starting test suite executions "+selector, err) 137 default: 138 ui.Failf("Pass Test suite name or labels to run by labels ") 139 } 140 141 go func() { 142 <-cmd.Context().Done() 143 if errors.Is(cmd.Context().Err(), context.Canceled) { 144 os.Exit(0) 145 } 146 }() 147 148 var execErrors []error 149 for _, execution := range executions { 150 if execution.IsFailed() { 151 execErrors = append(execErrors, errors.New("failed execution")) 152 } 153 154 if execution.Id != "" { 155 if watchEnabled && len(args) > 0 { 156 watchResp := client.WatchTestSuiteExecution(execution.Id) 157 for resp := range watchResp { 158 ui.ExitOnError("watching test suite execution", resp.Error) 159 if !silentMode { 160 execution.TruncateErrorMessages(maxErrorMessageLength) 161 printExecution(execution, startTime) 162 } 163 } 164 } 165 166 execution, err = client.GetTestSuiteExecution(execution.Id) 167 } 168 169 execution.TruncateErrorMessages(maxErrorMessageLength) 170 printExecution(execution, startTime) 171 ui.ExitOnError("getting recent execution data id:"+execution.Id, err) 172 173 if err = uiPrintExecutionStatus(client, execution); err != nil { 174 execErrors = append(execErrors, err) 175 } 176 177 uiShellTestSuiteGetCommandBlock(execution.Id) 178 if execution.Id != "" { 179 if watchEnabled && len(args) > 0 { 180 if downloadArtifactsEnabled { 181 DownloadArtifacts(execution.Id, downloadDir, format, masks, client) 182 } 183 } 184 185 if !watchEnabled || len(args) == 0 { 186 uiShellTestSuiteWatchCommandBlock(execution.Id) 187 } 188 } 189 } 190 191 ui.ExitOnError("executions contain failed on errors", execErrors...) 192 }, 193 } 194 195 cmd.Flags().StringVarP(&name, "name", "n", "", "execution name, if empty will be autogenerated") 196 cmd.Flags().StringArrayVarP(&variables, "variable", "v", []string{}, "execution variables passed to executor") 197 cmd.Flags().StringArrayVarP(&secretVariables, "secret-variable", "s", []string{}, "execution variables passed to executor") 198 cmd.Flags().BoolVarP(&watchEnabled, "watch", "f", false, "watch for changes after start") 199 cmd.Flags().StringSliceVarP(&selectors, "label", "l", nil, "label key value pair: --label key1=value1") 200 cmd.Flags().IntVar(&concurrencyLevel, "concurrency", 10, "concurrency level for multiple test suite execution") 201 cmd.Flags().StringVar(&httpProxy, "http-proxy", "", "http proxy for executor containers") 202 cmd.Flags().StringVar(&httpsProxy, "https-proxy", "", "https proxy for executor containers") 203 cmd.Flags().StringToStringVarP(&executionLabels, "execution-label", "", nil, "execution-label adds a label to execution in form of key value pair: --execution-label key1=value1") 204 cmd.Flags().StringToStringVarP(&secretVariableReferences, "secret-variable-reference", "", nil, "secret variable references in a form name1=secret_name1=secret_key1") 205 cmd.Flags().StringVarP(&gitBranch, "git-branch", "", "", "if uri is git repository we can set additional branch parameter") 206 cmd.Flags().StringVarP(&gitCommit, "git-commit", "", "", "if uri is git repository we can use commit id (sha) parameter") 207 cmd.Flags().StringVarP(&gitPath, "git-path", "", "", "if repository is big we need to define additional path to directory/file to checkout partially") 208 cmd.Flags().StringVarP(&gitWorkingDir, "git-working-dir", "", "", "if repository contains multiple directories with tests (like monorepo) and one starting directory we can set working directory parameter") 209 cmd.Flags().StringVar(&runningContext, "context", "", "running context description for test suite execution") 210 cmd.Flags().StringVar(&jobTemplate, "job-template", "", "job template file path for extensions to job template") 211 cmd.Flags().StringVar(&scraperTemplate, "scraper-template", "", "scraper template file path for extensions to scraper template") 212 cmd.Flags().StringVar(&pvcTemplate, "pvc-template", "", "pvc template file path for extensions to pvc template") 213 cmd.Flags().StringVar(&jobTemplateReference, "job-template-reference", "", "reference to job template to use for the test") 214 cmd.Flags().StringVar(&scraperTemplateReference, "scraper-template-reference", "", "reference to scraper template to use for the test") 215 cmd.Flags().StringVar(&pvcTemplateReference, "pvc-template-reference", "", "reference to pvc template to use for the test") 216 cmd.Flags().StringVar(&downloadDir, "download-dir", "artifacts", "download dir") 217 cmd.Flags().BoolVarP(&downloadArtifactsEnabled, "download-artifacts", "d", false, "download artifacts automatically") 218 cmd.Flags().StringVar(&format, "format", "folder", "data format for storing files, one of folder|archive") 219 cmd.Flags().StringArrayVarP(&masks, "mask", "", []string{}, "regexp to filter downloaded files, single or comma separated, like report/.* or .*\\.json,.*\\.js$") 220 cmd.Flags().BoolVarP(&silentMode, "silent", "", false, "don't print intermediate test suite execution") 221 222 return cmd 223 }