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  }