github.com/kubeshop/testkube@v1.17.23/pkg/api/v1/testkube/model_test_suite_execution_extended.go (about) 1 package testkube 2 3 import ( 4 "fmt" 5 "strings" 6 "time" 7 8 "go.mongodb.org/mongo-driver/bson/primitive" 9 10 "github.com/kubeshop/testkube/internal/common" 11 "github.com/kubeshop/testkube/pkg/utils" 12 ) 13 14 type WatchTestSuiteExecutionResponse struct { 15 Execution TestSuiteExecution 16 Error error 17 } 18 19 func NewQueuedTestSuiteExecution(name, namespace string) *TestSuiteExecution { 20 return &TestSuiteExecution{ 21 TestSuite: &ObjectRef{ 22 Name: name, 23 Namespace: namespace, 24 }, 25 Status: TestSuiteExecutionStatusQueued, 26 } 27 } 28 29 func NewStartedTestSuiteExecution(testSuite TestSuite, request TestSuiteExecutionRequest) TestSuiteExecution { 30 31 testExecution := TestSuiteExecution{ 32 Id: primitive.NewObjectID().Hex(), 33 StartTime: time.Now(), 34 Name: request.Name, 35 Status: TestSuiteExecutionStatusRunning, 36 SecretUUID: request.SecretUUID, 37 TestSuite: testSuite.GetObjectRef(), 38 Labels: common.MergeMaps(testSuite.Labels, request.ExecutionLabels), 39 Variables: map[string]Variable{}, 40 RunningContext: request.RunningContext, 41 TestSuiteExecutionName: request.TestSuiteExecutionName, 42 } 43 44 if testSuite.ExecutionRequest != nil { 45 testExecution.Variables = testSuite.ExecutionRequest.Variables 46 } 47 48 // override variables from request 49 for k, v := range request.Variables { 50 testExecution.Variables[k] = v 51 } 52 53 // add queued execution steps 54 batches := append(testSuite.Before, testSuite.Steps...) 55 batches = append(batches, testSuite.After...) 56 57 for i := range batches { 58 var stepResults []TestSuiteStepExecutionResult 59 for j := range batches[i].Execute { 60 stepResults = append(stepResults, NewTestStepQueuedResult(&batches[i].Execute[j])) 61 } 62 63 testExecution.ExecuteStepResults = append(testExecution.ExecuteStepResults, TestSuiteBatchStepExecutionResult{ 64 Step: &batches[i], 65 Execute: stepResults, 66 }) 67 } 68 69 return testExecution 70 } 71 72 func (e TestSuiteExecution) FailedStepsCount() (count int) { 73 for _, stepResult := range e.StepResults { 74 if stepResult.Execution != nil && stepResult.Execution.IsFailed() { 75 count++ 76 } 77 } 78 79 for _, batchStepResult := range e.ExecuteStepResults { 80 for _, stepResult := range batchStepResult.Execute { 81 if stepResult.Execution != nil && stepResult.Execution.IsFailed() { 82 count++ 83 break 84 } 85 } 86 } 87 88 return 89 } 90 91 func (e TestSuiteExecution) IsCompleted() bool { 92 if e.Status == nil { 93 return false 94 } 95 96 return *e.Status == *TestSuiteExecutionStatusFailed || 97 *e.Status == *TestSuiteExecutionStatusPassed || 98 *e.Status == *TestSuiteExecutionStatusAborted || 99 *e.Status == *TestSuiteExecutionStatusTimeout 100 } 101 102 func (e *TestSuiteExecution) Stop() { 103 duration := e.CalculateDuration() 104 e.EndTime = time.Now() 105 e.Duration = utils.RoundDuration(duration).String() 106 e.DurationMs = int32(duration.Milliseconds()) 107 } 108 109 func (e *TestSuiteExecution) CalculateDuration() time.Duration { 110 end := e.EndTime 111 start := e.StartTime 112 113 if start.UnixNano() <= 0 && end.UnixNano() <= 0 { 114 return time.Duration(0) 115 } 116 117 if end.UnixNano() <= 0 { 118 end = time.Now() 119 } 120 121 return end.Sub(e.StartTime) 122 } 123 124 func (e TestSuiteExecution) Table() (header []string, output [][]string) { 125 if len(e.StepResults) != 0 { 126 header = []string{"Status", "Step", "ID", "Error"} 127 output = make([][]string, 0) 128 129 for _, sr := range e.StepResults { 130 status := "no-execution-result" 131 if sr.Execution != nil && sr.Execution.ExecutionResult != nil && sr.Execution.ExecutionResult.Status != nil { 132 status = string(*sr.Execution.ExecutionResult.Status) 133 } 134 135 if sr.Step == nil { 136 continue 137 } 138 139 switch sr.Step.Type() { 140 case TestSuiteStepTypeExecuteTest: 141 var id, errorMessage string 142 if sr.Execution != nil && sr.Execution.ExecutionResult != nil { 143 errorMessage = sr.Execution.ExecutionResult.ErrorMessage 144 id = sr.Execution.Id 145 } 146 row := []string{status, sr.Step.FullName(), id, errorMessage} 147 output = append(output, row) 148 case TestSuiteStepTypeDelay: 149 row := []string{status, sr.Step.FullName(), "", ""} 150 output = append(output, row) 151 } 152 } 153 } 154 155 if len(e.ExecuteStepResults) != 0 { 156 header = []string{"Statuses", "Step", "IDs", "Errors"} 157 output = make([][]string, 0) 158 159 for _, bs := range e.ExecuteStepResults { 160 var statuses, names, ids, errorMessages []string 161 162 for _, sr := range bs.Execute { 163 status := "no-execution-result" 164 if sr.Execution != nil && sr.Execution.ExecutionResult != nil && sr.Execution.ExecutionResult.Status != nil { 165 status = string(*sr.Execution.ExecutionResult.Status) 166 } 167 168 statuses = append(statuses, status) 169 if sr.Step == nil { 170 continue 171 } 172 173 switch sr.Step.Type() { 174 case TestSuiteStepTypeExecuteTest: 175 var id, errorMessage string 176 if sr.Execution != nil && sr.Execution.ExecutionResult != nil { 177 errorMessage = sr.Execution.ExecutionResult.ErrorMessage 178 id = sr.Execution.Id 179 } 180 181 names = append(names, sr.Step.FullName()) 182 ids = append(ids, id) 183 errorMessages = append(errorMessages, fmt.Sprintf("%q", errorMessage)) 184 case TestSuiteStepTypeDelay: 185 names = append(names, sr.Step.FullName()) 186 ids = append(ids, "\"\"") 187 errorMessages = append(errorMessages, "\"\"") 188 } 189 } 190 191 row := []string{strings.Join(statuses, ", "), strings.Join(names, ", "), strings.Join(ids, ", "), strings.Join(errorMessages, ", ")} 192 output = append(output, row) 193 } 194 } 195 196 return 197 } 198 199 func (e *TestSuiteExecution) IsRunning() bool { 200 return e.Status != nil && *e.Status == RUNNING_TestSuiteExecutionStatus 201 } 202 203 func (e *TestSuiteExecution) IsQueued() bool { 204 return e.Status != nil && *e.Status == QUEUED_TestSuiteExecutionStatus 205 } 206 207 func (e *TestSuiteExecution) IsPassed() bool { 208 return e.Status != nil && *e.Status == PASSED_TestSuiteExecutionStatus 209 } 210 211 func (e *TestSuiteExecution) IsFailed() bool { 212 return e.Status != nil && *e.Status == FAILED_TestSuiteExecutionStatus 213 } 214 215 func (e *TestSuiteExecution) IsAborted() bool { 216 return *e.Status == ABORTED_TestSuiteExecutionStatus 217 } 218 219 func (e *TestSuiteExecution) IsTimeout() bool { 220 return *e.Status == TIMEOUT_TestSuiteExecutionStatus 221 } 222 223 func (e *TestSuiteExecution) convertDots(fn func(string) string) *TestSuiteExecution { 224 labels := make(map[string]string, len(e.Labels)) 225 for key, value := range e.Labels { 226 labels[fn(key)] = value 227 } 228 e.Labels = labels 229 230 envs := make(map[string]string, len(e.Envs)) 231 for key, value := range e.Envs { 232 envs[fn(key)] = value 233 } 234 e.Envs = envs 235 236 vars := make(map[string]Variable, len(e.Variables)) 237 for key, value := range e.Variables { 238 vars[fn(key)] = value 239 } 240 e.Variables = vars 241 return e 242 } 243 244 func (e *TestSuiteExecution) EscapeDots() *TestSuiteExecution { 245 return e.convertDots(utils.EscapeDots) 246 } 247 248 func (e *TestSuiteExecution) UnscapeDots() *TestSuiteExecution { 249 return e.convertDots(utils.UnescapeDots) 250 } 251 252 func (e *TestSuiteExecution) CleanStepsOutput() *TestSuiteExecution { 253 for i := range e.StepResults { 254 if e.StepResults[i].Execution != nil && e.StepResults[i].Execution.ExecutionResult != nil { 255 e.StepResults[i].Execution.ExecutionResult.Output = "" 256 } 257 } 258 259 for i := range e.ExecuteStepResults { 260 for j := range e.ExecuteStepResults[i].Execute { 261 if e.ExecuteStepResults[i].Execute[j].Execution != nil && e.ExecuteStepResults[i].Execute[j].Execution.ExecutionResult != nil { 262 e.ExecuteStepResults[i].Execute[j].Execution.ExecutionResult.Output = "" 263 } 264 } 265 } 266 return e 267 } 268 269 func (e *TestSuiteExecution) TruncateErrorMessages(length int) *TestSuiteExecution { 270 for _, bs := range e.ExecuteStepResults { 271 for _, sr := range bs.Execute { 272 if sr.Execution != nil && sr.Execution.ExecutionResult != nil && len(sr.Execution.ExecutionResult.ErrorMessage) > length { 273 sr.Execution.ExecutionResult.ErrorMessage = sr.Execution.ExecutionResult.ErrorMessage[0:length] 274 } 275 } 276 } 277 return e 278 }