From 02d4e2d6137ab4127318451ba68861108de016bd Mon Sep 17 00:00:00 2001 From: Vladislav Sukhin Date: Fri, 21 Jul 2023 12:53:33 +0300 Subject: [PATCH] fix: output parsing test (#4196) * fix: successful output parsing test * fix: check if executor log is already in json output * fix: ignore queued * fix: change container logs * fixL ignore scraper result * fix: add nil checks * fix: add unit tests * fix: golint * fix: change condition * fix: update execution result on failure --- .../containerexecutor/containerexecutor.go | 19 +- pkg/executor/output/parser.go | 125 +++++++- pkg/executor/output/parser_test.go | 279 ++++++++++++++++++ pkg/reconciler/reconciler.go | 2 +- 4 files changed, 421 insertions(+), 4 deletions(-) diff --git a/pkg/executor/containerexecutor/containerexecutor.go b/pkg/executor/containerexecutor/containerexecutor.go index dc2fda2fb22..eae1fe599fe 100644 --- a/pkg/executor/containerexecutor/containerexecutor.go +++ b/pkg/executor/containerexecutor/containerexecutor.go @@ -425,7 +425,24 @@ func (c *ContainerExecutor) updateResultsFromPod( } executorLogs = append(executorLogs, scraperLogs...) - execution.ExecutionResult.Output = string(executorLogs) + + // parse container output log (mixed JSON and plain text stream) + executionResult, output, err := output.ParseContainerOutput(executorLogs) + if err != nil { + l.Errorw("parse output error", "error", err) + execution.ExecutionResult.Output = output + execution.ExecutionResult.Err(err) + err = c.repository.UpdateResult(ctx, execution.Id, *execution) + if err != nil { + l.Infow("Update result", "error", err) + } + return execution.ExecutionResult, err + } + + if executionResult != nil { + execution.ExecutionResult = executionResult + } + execution.ExecutionResult.Output = output if execution.ExecutionResult.IsFailed() && execution.ExecutionResult.ErrorMessage == "" { execution.ExecutionResult.ErrorMessage = executor.GetPodErrorMessage(latestExecutorPod) diff --git a/pkg/executor/output/parser.go b/pkg/executor/output/parser.go index c0c75e71aa6..c3445334e8f 100644 --- a/pkg/executor/output/parser.go +++ b/pkg/executor/output/parser.go @@ -74,6 +74,40 @@ func ParseRunnerOutput(b []byte) (*testkube.ExecutionResult, error) { return result, nil } +// ParseContainerOutput goes over the raw logs in b and parses possible container output +// The input is a mixed stream of the json form and plain text +// runner execution started ------------ +// {"type": "result", "result": {"id": "2323", "output": "-----"}, "time": "..."} +func ParseContainerOutput(b []byte) (*testkube.ExecutionResult, string, error) { + result := &testkube.ExecutionResult{} + if len(b) == 0 { + return nil, "", nil + } + + logs, err := parseContainerLogs(b) + if err != nil { + err = fmt.Errorf("could not parse logs \"%s\": %v", b, err.Error()) + return nil, err.Error(), err + } + + output := sanitizeLogs(logs) + log := getDecidingContainerLogLine(logs) + if log == nil { + return nil, output, nil + } + + switch log.Type_ { + case TypeResult: + if log.Result != nil { + result = log.Result + } + case TypeError: + result.Err(fmt.Errorf(log.Content)) + } + + return result, output, nil +} + // sanitizeLogs creates a human-readable string from a list of Outputs func sanitizeLogs(logs []Output) string { var sb strings.Builder @@ -138,6 +172,52 @@ func parseLogs(b []byte) ([]Output, error) { return logs, nil } +// parseContainerLogs gets a list of Outputs from raw logs +func parseContainerLogs(b []byte) ([]Output, error) { + logs := []Output{} + reader := bufio.NewReader(bytes.NewReader(b)) + + for { + b, err := utils.ReadLongLine(reader) + if err != nil { + if err == io.EOF { + err = nil + break + } + + return logs, fmt.Errorf("could not read line: %w", err) + } + + log, err := GetLogEntry(b) + if log.Type_ == TypeParsingError || log.Type_ == TypeUnknown || err != nil { + // try to read in case of some lines which we couldn't parse + // sometimes we're not able to control all stdout messages from libs + logs = append(logs, Output{ + Type_: TypeLogLine, + Content: string(b), + }) + + continue + } + + if log.Type_ == TypeResult && + log.Result != nil && log.Result.Status != nil { + message := getResultMessage(*log.Result) + logs = append(logs, Output{ + Type_: TypeResult, + Content: message, + Result: log.Result, + }) + + continue + } + + logs = append(logs, log) + } + + return logs, nil +} + // getDecidingLogLine returns the log line of type result // if there is no log line of type result it will return the last log based on time // if there are no timestamps, it will return the last error log from the list, @@ -178,6 +258,47 @@ func getDecidingLogLine(logs []Output) *Output { return &resultLog } +// getDecidingContainerLogLine returns the log line of type result +// if there are no timestamps, it will return the last error log from the list, +// if there are no errors, nothing is returned +func getDecidingContainerLogLine(logs []Output) *Output { + if len(logs) == 0 { + return nil + } + + resultLog := Output{ + Type_: TypeLogLine, + Time: time.Time{}, + } + + for _, log := range logs { + if log.Type_ == TypeResult && + (log.Result == nil || log.Result.Status == nil || log.Result.IsRunning()) { + // this is the result of the init-container or scraper pod on success, let's ignore it + continue + } + + if moreSevere(log.Type_, resultLog.Type_) { + resultLog = log + continue + } + + if sameSeverity(log.Type_, resultLog.Type_) { + if log.Time.Before(resultLog.Time) { + continue + } + + resultLog = log + } + } + + if resultLog.Type_ != TypeResult && resultLog.Type_ != TypeError { + return nil + } + + return &resultLog +} + // getResultMessage returns a message from the result regardless of its type func getResultMessage(result testkube.ExecutionResult) string { if result.IsFailed() { @@ -187,7 +308,7 @@ func getResultMessage(result testkube.ExecutionResult) string { return result.Output } - return fmt.Sprintf("%v", result.Status) + return fmt.Sprintf("%s", *result.Status) } // sameSeverity decides if a and b are of the same severity type @@ -210,5 +331,5 @@ func moreSevere(a string, b string) bool { } // a is either log or event - return !(b == TypeResult || b == TypeError) + return b != TypeResult && b != TypeError } diff --git a/pkg/executor/output/parser_test.go b/pkg/executor/output/parser_test.go index 465337ff7a2..045d3f033b3 100644 --- a/pkg/executor/output/parser_test.go +++ b/pkg/executor/output/parser_test.go @@ -108,6 +108,55 @@ func TestParseRunnerOutput(t *testing.T) { assert.Equal(t, "process error: exit status 1", result.ErrorMessage) }) + t.Run("Runner output with passed status", func(t *testing.T) { + t.Parallel() + + var exampleOutput = []byte(` +{"type":"line","content":"๐ŸŒ Reading environment variables...","time":"2023-07-18T19:12:44.065916596Z"} +{"type":"line","content":"โœ… Environment variables read successfully","time":"2023-07-18T19:12:44.066174662Z"} +{"type":"line","content":"RUNNER_ENDPOINT=\"testkube-minio-service-shared:9000\"","time":"2023-07-18T19:12:44.066185893Z"} +{"type":"line","content":"RUNNER_ACCESSKEYID=\"********\"","time":"2023-07-18T19:12:44.066190525Z"} +{"type":"line","content":"RUNNER_SECRETACCESSKEY=\"********\"","time":"2023-07-18T19:12:44.066198451Z"} +{"type":"line","content":"RUNNER_REGION=\"\"","time":"2023-07-18T19:12:44.066202295Z"} +{"type":"line","content":"RUNNER_TOKEN=\"\"","time":"2023-07-18T19:12:44.066206054Z"} +{"type":"line","content":"RUNNER_BUCKET=\"testkube-artifacts\"","time":"2023-07-18T19:12:44.066209522Z"} +{"type":"line","content":"RUNNER_SSL=false","time":"2023-07-18T19:12:44.066215367Z"} +{"type":"line","content":"RUNNER_SCRAPPERENABLED=\"true\"","time":"2023-07-18T19:12:44.066218487Z"} +{"type":"line","content":"RUNNER_GITUSERNAME=\"********\"","time":"2023-07-18T19:12:44.066222184Z"} +{"type":"line","content":"RUNNER_GITTOKEN=\"********\"","time":"2023-07-18T19:12:44.066226231Z"} +{"type":"line","content":"RUNNER_DATADIR=\"/data\"","time":"2023-07-18T19:12:44.066229687Z"} +{"type":"line","content":"RUNNER_CLUSTERID=\"clusterf83c3172f255fad68c2ab1a59be52916\"","time":"2023-07-18T19:12:44.066233268Z"} +{"type":"line","content":"RUNNER_CDEVENTS_TARGET=\"\"","time":"2023-07-18T19:12:44.066237063Z"} +{"type":"line","content":"RUNNER_DASHBOARD_URI=\"\"","time":"2023-07-18T19:12:44.066240323Z"} +{"type":"line","content":"RUNNER_CLOUD_MODE=\"false\"","time":"2023-07-18T19:12:44.066244115Z"} +{"type":"line","content":"RUNNER_CLOUD_API_TLS_INSECURE=\"false\"","time":"2023-07-18T19:12:44.066247795Z"} +{"type":"line","content":"RUNNER_CLOUD_API_URL=\"agent.testkube.io:443\"","time":"2023-07-18T19:12:44.066251778Z"} +{"type":"line","content":"RUNNER_CLOUD_API_KEY=\"\"","time":"2023-07-18T19:12:44.066255395Z"} +{"type":"line","content":"RUNNER_CLOUD_CONNECTION_TIMEOUT=10","time":"2023-07-18T19:12:44.066259384Z"} +{"type":"line","content":"๐Ÿšš Preparing test runner","time":"2023-07-18T19:12:44.066263179Z"} +{"type":"line","content":"โœ… Uploading artifacts using MinIO Uploader","time":"2023-07-18T19:12:44.066269065Z"} +{"type":"event","content":"running test [64b6e3f0530875ebaf73794f]","time":"2023-07-18T19:12:44.06658648Z"} +{"type":"line","content":"๐Ÿšš Preparing for test run","time":"2023-07-18T19:12:44.066599252Z"} +{"type":"line","content":"๐Ÿš€ Test run command newman run /data/repo/Core App Tests - WebPlayer.postman_collection.json -e /tmp/testkube-tmp1897306484 --reporters cli,json --reporter-json-export /tmp/testkube-tmp4151526495.json","time":"2023-07-18T19:12:44.066856036Z"} +{"type":"line","content":"๐Ÿ”ฌ Executing in directory : \n $ newman run /data/repo/Core App Tests - WebPlayer.postman_collection.json -e /tmp/testkube-tmp1897306484 --reporters cli,json --reporter-json-export /tmp/testkube-tmp4151526495.json","time":"2023-07-18T19:12:44.066872166Z"} +{"type":"line","content":"newman\n\n","time":"2023-07-18T19:12:45.654031992Z"} +{"type":"line","content":"Core App Tests - WebPlayer\n","time":"2023-07-18T19:12:45.654989975Z"} +{"type":"line","content":"\nโ†’ na.com client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12\n","time":"2023-07-18T19:12:45.658607412Z"} +{"type":"line","content":" GET https://na.com/v6-wplt/?client=testdb\u0026sign=testct1\u0026company=41574150-b952-413b-898b-dc5336b4bd12 ","time":"2023-07-18T19:12:45.685011667Z"} +{"type":"line","content":"[200 OK, 33.9kB, 326ms]\n","time":"2023-07-18T19:12:46.014247794Z"} +{"type":"line","content":" โœ“ Status code is 200\n","time":"2023-07-18T19:12:46.076176552Z"} +{"type":"line","content":"\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 429ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 33.45kB (approx) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ average response time: 326ms [min: 326ms, max: 326ms, s.d.: 0ยตs] โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n","time":"2023-07-18T19:12:46.104174132Z"} +{"type":"line","content":"โœ… Execution succeeded","time":"2023-07-18T19:12:46.114565626Z"} +{"type":"line","content":"โœ… Got Newman result successfully","time":"2023-07-18T19:12:46.126116248Z"} +{"type":"line","content":"โœ… Mapped Newman result successfully","time":"2023-07-18T19:12:46.126152021Z"} +{"type":"result","result":{"status":"passed","output":"newman\n\nCore App Tests - WebPlayer\n\nโ†’ core-eks-test.poppcore.co client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12\n GET https://na.com/v6-wplt/?client=testdb\u0026sign=testct1\u0026company=41574150-b952-413b-898b-dc5336b4bd12 [200 OK, 33.9kB, 326ms]\n โœ“ Status code is 200\n\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 429ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 33.45kB (approx) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ average response time: 326ms [min: 326ms, max: 326ms, s.d.: 0ยตs] โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n","outputType":"text/plain","steps":[{"name":"na.com client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12","duration":"326ms","status":"passed","assertionResults":[{"name":"Status code is 200","status":"passed"}]}]},"time":"2023-07-18T19:12:46.12615853Z"}`) + result, err := ParseRunnerOutput(exampleOutput) + + assert.Len(t, result.Output, 7304) + assert.NoError(t, err) + assert.Equal(t, testkube.ExecutionStatusPassed, result.Status) + }) + t.Run("Wrong order in logs", func(t *testing.T) { t.Parallel() @@ -352,3 +401,233 @@ running test [63ca8c8988564860327a16b5] }) } + +func TestParseContainerOutput(t *testing.T) { + t.Parallel() + + t.Run("Empty runner output", func(t *testing.T) { + t.Parallel() + + result, output, err := ParseContainerOutput([]byte{}) + + assert.Equal(t, "", output) + assert.NoError(t, err) + assert.Nil(t, result) + }) + + t.Run("Runner output with no timestamps", func(t *testing.T) { + t.Parallel() + + var exampleOutput = []byte(` +{"type":"event","message":"running postman/collection from testkube.Execution","content":["{\n\t\"id\": \"blablablablabla\",\n\t\"name\": \"some-testing-exec\",\n\t\"scriptContent\": \"{\\n\\t\\\"info\\\": {\\n\\t\\t\\\"_postman_id\\\": \\\"97b67bfb-c1ca-4572-af46-06cab8f68998\\\",\\n\\t\\t\\\"name\\\": \\\"Local-API-Health\\\",\\n\\t\\t\\\"schema\\\": \\\"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\\\"\\n\\t},\\n\\t\\\"item\\\": [\\n\\t\\t{\\n\\t\\t\\t\\\"name\\\": \\\"Health\\\",\\n\\t\\t\\t\\\"event\\\": [\\n\\t\\t\\t\\t{\\n\\t\\t\\t\\t\\t\\\"listen\\\": \\\"test\\\",\\n\\t\\t\\t\\t\\t\\\"script\\\": {\\n\\t\\t\\t\\t\\t\\t\\\"exec\\\": [\\n\\t\\t\\t\\t\\t\\t\\t\\\"pm.test(\\\\\\\"Status code is 200\\\\\\\", function () {\\\",\\n\\t\\t\\t\\t\\t\\t\\t\\\" pm.response.to.have.status(200);\\\",\\n\\t\\t\\t\\t\\t\\t\\t\\\"});\\\"\\n\\t\\t\\t\\t\\t\\t],\\n\\t\\t\\t\\t\\t\\t\\\"type\\\": \\\"text/javascript\\\"\\n\\t\\t\\t\\t\\t}\\n\\t\\t\\t\\t}\\n\\t\\t\\t],\\n\\t\\t\\t\\\"request\\\": {\\n\\t\\t\\t\\t\\\"method\\\": \\\"GET\\\",\\n\\t\\t\\t\\t\\\"header\\\": [],\\n\\t\\t\\t\\t\\\"url\\\": {\\n\\t\\t\\t\\t\\t\\\"raw\\\": \\\"http://localhost:8088/health\\\",\\n\\t\\t\\t\\t\\t\\\"protocol\\\": \\\"http\\\",\\n\\t\\t\\t\\t\\t\\\"host\\\": [\\n\\t\\t\\t\\t\\t\\t\\\"localhost\\\"\\n\\t\\t\\t\\t\\t],\\n\\t\\t\\t\\t\\t\\\"port\\\": \\\"8088\\\",\\n\\t\\t\\t\\t\\t\\\"path\\\": [\\n\\t\\t\\t\\t\\t\\t\\\"health\\\"\\n\\t\\t\\t\\t\\t]\\n\\t\\t\\t\\t}\\n\\t\\t\\t},\\n\\t\\t\\t\\\"response\\\": []\\n\\t\\t}\\n\\t],\\n\\t\\\"event\\\": []\\n}\"\n}"]} +{"type":"line","content":"newman\n\n"} +{"type":"line","content":"Local-API-Health\n"} +{"type":"line","content":"\nโ†’ Health\n"} +{"type":"line","content":" GET http://localhost:8088/health "} +{"type":"line","content":"[errored]\n"} +{"type":"line","content":" connect ECONNREFUSED 127.0.0.1:8088\n"} +{"type":"line","content":" 2. Status code is 200\n"} +{"type":"line","content":"\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 1 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 1 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 1012ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 0B (approx) โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n"} +{"type":"line","content":"\n # failure detail \n \n 1. Error \n connect ECONNREFUSED 127.0.0.1:8088 \n at request \n inside \"Health\" \n \n 2. AssertionError Status code is 200 \n expected { Object (id, _details, ...) } to have property 'code' \n at assertion:0 in test-script \n inside \"Health\" \n"} +{"type":"result","result":{"status":"failed","startTime":"2021-10-29T11:35:35.759Z","endTime":"2021-10-29T11:35:36.771Z","output":"newman\n\nLocal-API-Health\n\nโ†’ Health\n GET http://localhost:8088/health [errored]\n connect ECONNREFUSED 127.0.0.1:8088\n 2. Status code is 200\n\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 1 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 1 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 1012ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 0B (approx) โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n\n # failure detail \n \n 1. Error \n connect ECONNREFUSED 127.0.0.1:8088 \n at request \n inside \"Health\" \n \n 2. AssertionError Status code is 200 \n expected { Object (id, _details, ...) } to have property 'code' \n at assertion:0 in test-script \n inside \"Health\" \n","outputType":"text/plain","errorMessage":"process error: exit status 1","steps":[{"name":"Health","duration":"0s","status":"failed","assertionResults":[{"name":"Status code is 200","status":"failed","errorMessage":"expected { Object (id, _details, ...) } to have property 'code'"}]}]}} +`) + result, output, err := ParseContainerOutput(exampleOutput) + + assert.Len(t, output, 4511) + assert.NoError(t, err) + assert.Equal(t, testkube.ExecutionStatusFailed, result.Status) + assert.Equal(t, "process error: exit status 1", result.ErrorMessage) + }) + + t.Run("Runner output with passed status", func(t *testing.T) { + t.Parallel() + + var exampleOutput = []byte(` +{"type":"line","content":"๐ŸŒ Reading environment variables...","time":"2023-07-18T19:12:44.065916596Z"} +{"type":"line","content":"โœ… Environment variables read successfully","time":"2023-07-18T19:12:44.066174662Z"} +{"type":"line","content":"RUNNER_ENDPOINT=\"testkube-minio-service-shared:9000\"","time":"2023-07-18T19:12:44.066185893Z"} +{"type":"line","content":"RUNNER_ACCESSKEYID=\"********\"","time":"2023-07-18T19:12:44.066190525Z"} +{"type":"line","content":"RUNNER_SECRETACCESSKEY=\"********\"","time":"2023-07-18T19:12:44.066198451Z"} +{"type":"line","content":"RUNNER_REGION=\"\"","time":"2023-07-18T19:12:44.066202295Z"} +{"type":"line","content":"RUNNER_TOKEN=\"\"","time":"2023-07-18T19:12:44.066206054Z"} +{"type":"line","content":"RUNNER_BUCKET=\"testkube-artifacts\"","time":"2023-07-18T19:12:44.066209522Z"} +{"type":"line","content":"RUNNER_SSL=false","time":"2023-07-18T19:12:44.066215367Z"} +{"type":"line","content":"RUNNER_SCRAPPERENABLED=\"true\"","time":"2023-07-18T19:12:44.066218487Z"} +{"type":"line","content":"RUNNER_GITUSERNAME=\"********\"","time":"2023-07-18T19:12:44.066222184Z"} +{"type":"line","content":"RUNNER_GITTOKEN=\"********\"","time":"2023-07-18T19:12:44.066226231Z"} +{"type":"line","content":"RUNNER_DATADIR=\"/data\"","time":"2023-07-18T19:12:44.066229687Z"} +{"type":"line","content":"RUNNER_CLUSTERID=\"clusterf83c3172f255fad68c2ab1a59be52916\"","time":"2023-07-18T19:12:44.066233268Z"} +{"type":"line","content":"RUNNER_CDEVENTS_TARGET=\"\"","time":"2023-07-18T19:12:44.066237063Z"} +{"type":"line","content":"RUNNER_DASHBOARD_URI=\"\"","time":"2023-07-18T19:12:44.066240323Z"} +{"type":"line","content":"RUNNER_CLOUD_MODE=\"false\"","time":"2023-07-18T19:12:44.066244115Z"} +{"type":"line","content":"RUNNER_CLOUD_API_TLS_INSECURE=\"false\"","time":"2023-07-18T19:12:44.066247795Z"} +{"type":"line","content":"RUNNER_CLOUD_API_URL=\"agent.testkube.io:443\"","time":"2023-07-18T19:12:44.066251778Z"} +{"type":"line","content":"RUNNER_CLOUD_API_KEY=\"\"","time":"2023-07-18T19:12:44.066255395Z"} +{"type":"line","content":"RUNNER_CLOUD_CONNECTION_TIMEOUT=10","time":"2023-07-18T19:12:44.066259384Z"} +{"type":"line","content":"๐Ÿšš Preparing test runner","time":"2023-07-18T19:12:44.066263179Z"} +{"type":"line","content":"โœ… Uploading artifacts using MinIO Uploader","time":"2023-07-18T19:12:44.066269065Z"} +{"type":"event","content":"running test [64b6e3f0530875ebaf73794f]","time":"2023-07-18T19:12:44.06658648Z"} +{"type":"line","content":"๐Ÿšš Preparing for test run","time":"2023-07-18T19:12:44.066599252Z"} +{"type":"line","content":"๐Ÿš€ Test run command newman run /data/repo/Core App Tests - WebPlayer.postman_collection.json -e /tmp/testkube-tmp1897306484 --reporters cli,json --reporter-json-export /tmp/testkube-tmp4151526495.json","time":"2023-07-18T19:12:44.066856036Z"} +{"type":"line","content":"๐Ÿ”ฌ Executing in directory : \n $ newman run /data/repo/Core App Tests - WebPlayer.postman_collection.json -e /tmp/testkube-tmp1897306484 --reporters cli,json --reporter-json-export /tmp/testkube-tmp4151526495.json","time":"2023-07-18T19:12:44.066872166Z"} +{"type":"line","content":"newman\n\n","time":"2023-07-18T19:12:45.654031992Z"} +{"type":"line","content":"Core App Tests - WebPlayer\n","time":"2023-07-18T19:12:45.654989975Z"} +{"type":"line","content":"\nโ†’ na.com client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12\n","time":"2023-07-18T19:12:45.658607412Z"} +{"type":"line","content":" GET https://na.com/v6-wplt/?client=testdb\u0026sign=testct1\u0026company=41574150-b952-413b-898b-dc5336b4bd12 ","time":"2023-07-18T19:12:45.685011667Z"} +{"type":"line","content":"[200 OK, 33.9kB, 326ms]\n","time":"2023-07-18T19:12:46.014247794Z"} +{"type":"line","content":" โœ“ Status code is 200\n","time":"2023-07-18T19:12:46.076176552Z"} +{"type":"line","content":"\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 429ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 33.45kB (approx) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ average response time: 326ms [min: 326ms, max: 326ms, s.d.: 0ยตs] โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n","time":"2023-07-18T19:12:46.104174132Z"} +{"type":"line","content":"โœ… Execution succeeded","time":"2023-07-18T19:12:46.114565626Z"} +{"type":"line","content":"โœ… Got Newman result successfully","time":"2023-07-18T19:12:46.126116248Z"} +{"type":"line","content":"โœ… Mapped Newman result successfully","time":"2023-07-18T19:12:46.126152021Z"} +{"type":"result","result":{"status":"passed","output":"newman\n\nCore App Tests - WebPlayer\n\nโ†’ core-eks-test.poppcore.co client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12\n GET https://na.com/v6-wplt/?client=testdb\u0026sign=testct1\u0026company=41574150-b952-413b-898b-dc5336b4bd12 [200 OK, 33.9kB, 326ms]\n โœ“ Status code is 200\n\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”\nโ”‚ โ”‚ executed โ”‚ failed โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ iterations โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ requests โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ test-scripts โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ prerequest-scripts โ”‚ 0 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ assertions โ”‚ 1 โ”‚ 0 โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total run duration: 429ms โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ total data received: 33.45kB (approx) โ”‚\nโ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค\nโ”‚ average response time: 326ms [min: 326ms, max: 326ms, s.d.: 0ยตs] โ”‚\nโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n","outputType":"text/plain","steps":[{"name":"na.com client=testdb sign=testct1 company=41574150-b952-413b-898b-dc5336b4bd12","duration":"326ms","status":"passed","assertionResults":[{"name":"Status code is 200","status":"passed"}]}]},"time":"2023-07-18T19:12:46.12615853Z"}`) + result, output, err := ParseContainerOutput(exampleOutput) + + assert.Len(t, output, 7305) + assert.NoError(t, err) + assert.Equal(t, testkube.ExecutionStatusPassed, result.Status) + }) + + t.Run("Output with failed result", func(t *testing.T) { + t.Parallel() + + output := []byte(`{"type":"event","content":"running test [63c9606d7104b0fa0b7a45f1]"} +{"type":"event","content":"Running [ ./zap-api-scan.py [-t https://www.example.com/openapi.json -f openapi -c examples/zap-api.conf -d -D 5 -I -l INFO -n examples/context.config -S -T 60 -U anonymous -O https://www.example.com -z -config aaa=bbb -r api-test-report.html]]"} +{"type":"result","result":{"status":"failed","errorMessage":"could not start process: fork/exec ./zap-api-scan.py: no such file or directory"}}`) + expectedOutput := `running test [63c9606d7104b0fa0b7a45f1] +Running [ ./zap-api-scan.py [-t https://www.example.com/openapi.json -f openapi -c examples/zap-api.conf -d -D 5 -I -l INFO -n examples/context.config -S -T 60 -U anonymous -O https://www.example.com -z -config aaa=bbb -r api-test-report.html]] +could not start process: fork/exec ./zap-api-scan.py: no such file or directory +` + result, data, err := ParseContainerOutput(output) + + assert.Equal(t, expectedOutput, data) + assert.NoError(t, err) + assert.Equal(t, testkube.ExecutionStatusFailed, result.Status) + assert.Equal(t, "could not start process: fork/exec ./zap-api-scan.py: no such file or directory", result.ErrorMessage) + }) + + t.Run("Output with error", func(t *testing.T) { + t.Parallel() + + output := []byte(` +{"type":"line","content":"๐Ÿšš Preparing test runner","time":"2023-01-19T15:22:25.867379429Z"} +{"type":"line","content":"๐ŸŒ Reading environment variables...","time":"2023-01-19T15:22:25.867927513Z"} +{"type":"line","content":"โœ… Environment variables read successfully","time":"2023-01-19T15:22:25.867944763Z"} +{"type":"line","content":"RUNNER_ENDPOINT=\"testkube-minio-service-testkube:9000\"","time":"2023-01-19T15:22:25.867946929Z"} +{"type":"line","content":"RUNNER_ACCESSKEYID=\"********\"","time":"2023-01-19T15:22:25.867948804Z"} +{"type":"line","content":"RUNNER_SECRETACCESSKEY=\"********\"","time":"2023-01-19T15:22:25.867955263Z"} +{"type":"line","content":"RUNNER_REGION=\"\"","time":"2023-01-19T15:22:25.867962596Z"} +{"type":"line","content":"RUNNER_TOKEN=\"\"","time":"2023-01-19T15:22:25.867967971Z"} +{"type":"line","content":"RUNNER_SSL=false","time":"2023-01-19T15:22:25.867974013Z"} +{"type":"line","content":"RUNNER_SCRAPPERENABLED=\"true\"","time":"2023-01-19T15:22:25.867978888Z"} +{"type":"line","content":"RUNNER_GITUSERNAME=\"\"","time":"2023-01-19T15:22:25.867984179Z"} +{"type":"line","content":"RUNNER_GITTOKEN=\"\"","time":"2023-01-19T15:22:25.867986013Z"} +{"type":"line","content":"RUNNER_DATADIR=\"/data\"","time":"2023-01-19T15:22:25.867987596Z"} +{"type":"line","content":"RUNNER_CDEVENTS_TARGET=\"\"","time":"2023-01-17T15:29:17.921801596Z"} +{"type":"line","content":"RUNNER_DASHBOARD_URI=\"\"","time":"2023-01-17T15:29:17.921801596Z"} +{"type":"line","content":"RUNNER_CLUSTERID=\"\"","time":"2023-01-17T15:29:17.921801596Z"} +{"type":"event","content":"running test [63c960287104b0fa0b7a45ef]","time":"2023-01-19T15:22:25.868132888Z"} +{"type":"line","content":"๐Ÿšš Preparing for test run","time":"2023-01-19T15:22:25.868161346Z"} +{"type":"line","content":"โŒ can't find branch or commit in params, repo:\u0026{Type_:git-file Uri:https://github.com/kubeshop/testkube.git Branch: Commit: Path:test/cypress/executor-smoke/cypress-11 Username: Token: UsernameSecret:\u003cnil\u003e TokenSecret:\u003cnil\u003e WorkingDir:}","time":"2023-01-19T15:22:25.868183971Z"} +{"type":"error","content":"can't find branch or commit in params, repo:\u0026{Type_:git-file Uri:https://github.com/kubeshop/testkube.git Branch: Commit: Path:test/cypress/executor-smoke/cypress-11 Username: Token: UsernameSecret:\u003cnil\u003e TokenSecret:\u003cnil\u003e WorkingDir:}","time":"2023-01-19T15:22:25.868198429Z"} +`) + expectedOutput := ` +๐Ÿšš Preparing test runner +๐ŸŒ Reading environment variables... +โœ… Environment variables read successfully +RUNNER_ENDPOINT="testkube-minio-service-testkube:9000" +RUNNER_ACCESSKEYID="********" +RUNNER_SECRETACCESSKEY="********" +RUNNER_REGION="" +RUNNER_TOKEN="" +RUNNER_SSL=false +RUNNER_SCRAPPERENABLED="true" +RUNNER_GITUSERNAME="" +RUNNER_GITTOKEN="" +RUNNER_DATADIR="/data" +RUNNER_CDEVENTS_TARGET="" +RUNNER_DASHBOARD_URI="" +RUNNER_CLUSTERID="" +running test [63c960287104b0fa0b7a45ef] +๐Ÿšš Preparing for test run +โŒ can't find branch or commit in params, repo:&{Type_:git-file Uri:https://github.com/kubeshop/testkube.git Branch: Commit: Path:test/cypress/executor-smoke/cypress-11 Username: Token: UsernameSecret: TokenSecret: WorkingDir:} +can't find branch or commit in params, repo:&{Type_:git-file Uri:https://github.com/kubeshop/testkube.git Branch: Commit: Path:test/cypress/executor-smoke/cypress-11 Username: Token: UsernameSecret: TokenSecret: WorkingDir:} +` + + result, data, err := ParseContainerOutput(output) + + assert.Equal(t, expectedOutput, data) + assert.NoError(t, err) + assert.Equal(t, testkube.ExecutionStatusFailed, result.Status) + assert.Equal(t, "can't find branch or commit in params, repo:&{Type_:git-file Uri:https://github.com/kubeshop/testkube.git Branch: Commit: Path:test/cypress/executor-smoke/cypress-11 Username: Token: UsernameSecret: TokenSecret: WorkingDir:}", result.ErrorMessage) + }) + + t.Run("Output ignore empty result", func(t *testing.T) { + t.Parallel() + + output := []byte(` +{"type":"result","result":{"status":"running"},"time":"2023-07-19T17:15:20.400138Z"} +{"type":"result","result":{"status":null},"time":"2023-07-19T17:15:38.313334598Z"} +`) + expectedOutput := ` +running + +` + + result, data, err := ParseContainerOutput(output) + + assert.Equal(t, expectedOutput, data) + assert.NoError(t, err) + assert.Nil(t, result) + }) + + t.Run("Output random json format", func(t *testing.T) { + t.Parallel() + + output := []byte(` +{"level":"info","ts":1689786938.2338681,"caller":"scraper/filesystem_extractor.go:50","msg":"scraping artifacts in directory: /data/artifacts"} +{"level":"info","ts":1689786938.234103,"caller":"scraper/filesystem_extractor.go:96","msg":"creating artifacts tarball with 1 files"} +{"level":"info","ts":1689786938.234986,"caller":"scraper/minio_uploader.go:47","msg":"MinIO loader is uploading file","file":"artifacts.tar.gz","folder":"64b81a176ebd74e68253f73e","size":12181} +`) + expectedOutput := ` +{"level":"info","ts":1689786938.2338681,"caller":"scraper/filesystem_extractor.go:50","msg":"scraping artifacts in directory: /data/artifacts"} +{"level":"info","ts":1689786938.234103,"caller":"scraper/filesystem_extractor.go:96","msg":"creating artifacts tarball with 1 files"} +{"level":"info","ts":1689786938.234986,"caller":"scraper/minio_uploader.go:47","msg":"MinIO loader is uploading file","file":"artifacts.tar.gz","folder":"64b81a176ebd74e68253f73e","size":12181} +` + result, data, err := ParseContainerOutput(output) + + assert.Equal(t, expectedOutput, data) + assert.NoError(t, err) + assert.Nil(t, result) + }) + + t.Run("Output random text format", func(t *testing.T) { + t.Parallel() + + output := []byte(` +[STARTED] Task without title. +[SUCCESS] Task without title. +[203:0719/171524.648215:ERROR:zygote_host_impl_linux.cc(263)] Failed to adjust OOM score of renderer with pid 374: Permission denied (13) +libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null) +[374:0719/171524.697752:ERROR:gpu_memory_buffer_support_x11.cc(44)] dri3 extension not supported. +[374:0719/171524.697752:ERROR:gpu_memory_buffer_support_x11.cc(44)] dri3 extension not supported. + +==================================================================================================== +`) + expectedOutput := ` +[STARTED] Task without title. +[SUCCESS] Task without title. +[203:0719/171524.648215:ERROR:zygote_host_impl_linux.cc(263)] Failed to adjust OOM score of renderer with pid 374: Permission denied (13) +libva error: vaGetDriverNameByIndex() failed with unknown libva error, driver_name = (null) +[374:0719/171524.697752:ERROR:gpu_memory_buffer_support_x11.cc(44)] dri3 extension not supported. +[374:0719/171524.697752:ERROR:gpu_memory_buffer_support_x11.cc(44)] dri3 extension not supported. + +==================================================================================================== +` + result, data, err := ParseContainerOutput(output) + + assert.Equal(t, expectedOutput, data) + assert.NoError(t, err) + assert.Nil(t, result) + }) +} diff --git a/pkg/reconciler/reconciler.go b/pkg/reconciler/reconciler.go index 0381051a241..542c8ebe9e1 100644 --- a/pkg/reconciler/reconciler.go +++ b/pkg/reconciler/reconciler.go @@ -177,7 +177,7 @@ OuterLoop: continue OuterLoop } - if exec.ExecutionResult.IsRunning() { + if exec.ExecutionResult.IsRunning() || exec.ExecutionResult.IsQueued() { continue OuterLoop }