github.com/kubeshop/testkube@v1.17.23/pkg/tcl/apitcl/v1/testworkflowwithexecutions.go (about) 1 // Copyright 2024 Testkube. 2 // 3 // Licensed as a Testkube Pro file under the Testkube Community 4 // License (the "License"); you may not use this file except in compliance with 5 // the License. You may obtain a copy of the License at 6 // 7 // https://github.com/kubeshop/testkube/blob/main/licenses/TCL.txt 8 9 package v1 10 11 import ( 12 "errors" 13 "fmt" 14 "net/http" 15 "sort" 16 "strconv" 17 18 "github.com/gofiber/fiber/v2" 19 20 "github.com/kubeshop/testkube/pkg/api/v1/testkube" 21 "github.com/kubeshop/testkube/pkg/repository/result" 22 testworkflowmappers "github.com/kubeshop/testkube/pkg/tcl/mapperstcl/testworkflows" 23 ) 24 25 func (s *apiTCL) GetTestWorkflowWithExecutionHandler() fiber.Handler { 26 return func(c *fiber.Ctx) error { 27 name := c.Params("id") 28 errPrefix := fmt.Sprintf("failed to get test workflow '%s' with execution", name) 29 if name == "" { 30 return s.Error(c, http.StatusBadRequest, errors.New(errPrefix+": id cannot be empty")) 31 } 32 crWorkflow, err := s.TestWorkflowsClient.Get(name) 33 if err != nil { 34 return s.ClientError(c, errPrefix, err) 35 } 36 37 workflow := testworkflowmappers.MapKubeToAPI(crWorkflow) 38 39 ctx := c.Context() 40 execution, err := s.TestWorkflowResults.GetLatestByTestWorkflow(ctx, name) 41 if err != nil && !IsNotFound(err) { 42 return s.ClientError(c, errPrefix, err) 43 } 44 45 return c.JSON(testkube.TestWorkflowWithExecution{ 46 Workflow: workflow, 47 LatestExecution: execution, 48 }) 49 } 50 } 51 52 func (s *apiTCL) ListTestWorkflowWithExecutionsHandler() fiber.Handler { 53 return func(c *fiber.Ctx) error { 54 errPrefix := "failed to list test workflows with executions" 55 crWorkflows, err := s.getFilteredTestWorkflowList(c) 56 if err != nil { 57 return s.ClientError(c, errPrefix+": get filtered workflows", err) 58 } 59 60 workflows := testworkflowmappers.MapListKubeToAPI(crWorkflows) 61 ctx := c.Context() 62 results := make([]testkube.TestWorkflowWithExecutionSummary, 0, len(workflows)) 63 workflowNames := make([]string, len(workflows)) 64 for i := range workflows { 65 workflowNames[i] = workflows[i].Name 66 } 67 68 executions, err := s.TestWorkflowResults.GetLatestByTestWorkflows(ctx, workflowNames) 69 if err != nil { 70 return s.ClientError(c, errPrefix+": getting latest executions", err) 71 } 72 executionMap := make(map[string]testkube.TestWorkflowExecutionSummary, len(executions)) 73 for i := range executions { 74 executionMap[executions[i].Workflow.Name] = executions[i] 75 } 76 77 for i := range workflows { 78 if execution, ok := executionMap[workflows[i].Name]; ok { 79 results = append(results, testkube.TestWorkflowWithExecutionSummary{ 80 Workflow: &workflows[i], 81 LatestExecution: &execution, 82 }) 83 } else { 84 results = append(results, testkube.TestWorkflowWithExecutionSummary{ 85 Workflow: &workflows[i], 86 }) 87 } 88 } 89 90 sort.Slice(results, func(i, j int) bool { 91 iTime := results[i].Workflow.Created 92 if results[i].LatestExecution != nil { 93 iTime = results[i].LatestExecution.StatusAt 94 } 95 jTime := results[j].Workflow.Created 96 if results[j].LatestExecution != nil { 97 jTime = results[j].LatestExecution.StatusAt 98 } 99 return iTime.After(jTime) 100 }) 101 102 status := c.Query("status") 103 if status != "" { 104 statusList, err := testkube.ParseTestWorkflowStatusList(status, ",") 105 if err != nil { 106 return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: execution status filter invalid: %w", errPrefix, err)) 107 } 108 109 statusMap := statusList.ToMap() 110 // filter items array 111 for i := len(results) - 1; i >= 0; i-- { 112 if results[i].LatestExecution != nil && results[i].LatestExecution.Result.Status != nil { 113 if _, ok := statusMap[*results[i].LatestExecution.Result.Status]; ok { 114 continue 115 } 116 } 117 118 results = append(results[:i], results[i+1:]...) 119 } 120 } 121 122 var page, pageSize int 123 pageParam := c.Query("page", "") 124 if pageParam != "" { 125 pageSize = result.PageDefaultLimit 126 page, err = strconv.Atoi(pageParam) 127 if err != nil { 128 return s.BadRequest(c, errPrefix, "workflow page filter invalid", err) 129 } 130 } 131 132 pageSizeParam := c.Query("pageSize", "") 133 if pageSizeParam != "" { 134 pageSize, err = strconv.Atoi(pageSizeParam) 135 if err != nil { 136 return s.BadRequest(c, errPrefix, "workflow page size filter invalid", err) 137 } 138 } 139 140 if pageParam != "" || pageSizeParam != "" { 141 startPos := page * pageSize 142 endPos := (page + 1) * pageSize 143 if startPos < len(results) { 144 if endPos > len(results) { 145 endPos = len(results) 146 } 147 148 results = results[startPos:endPos] 149 } 150 } 151 152 return c.JSON(results) 153 } 154 }