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  }