github.com/kubeshop/testkube@v1.17.23/pkg/cloud/data/result/result.go (about)

     1  package result
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"time"
     7  
     8  	"go.mongodb.org/mongo-driver/mongo"
     9  	"google.golang.org/grpc"
    10  
    11  	"github.com/kubeshop/testkube/pkg/cloud/data/executor"
    12  
    13  	"github.com/pkg/errors"
    14  
    15  	"github.com/kubeshop/testkube/pkg/repository/result"
    16  
    17  	"github.com/kubeshop/testkube/pkg/cloud"
    18  
    19  	"github.com/kubeshop/testkube/pkg/api/v1/testkube"
    20  )
    21  
    22  var _ result.Repository = (*CloudRepository)(nil)
    23  
    24  type CloudRepository struct {
    25  	executor executor.Executor
    26  }
    27  
    28  func NewCloudResultRepository(cloudClient cloud.TestKubeCloudAPIClient, grpcConn *grpc.ClientConn, apiKey string) *CloudRepository {
    29  	return &CloudRepository{executor: executor.NewCloudGRPCExecutor(cloudClient, grpcConn, apiKey)}
    30  }
    31  
    32  func (r *CloudRepository) GetNextExecutionNumber(ctx context.Context, testName string) (int32, error) {
    33  	req := NextExecutionNumberRequest{TestName: testName}
    34  	response, err := r.executor.Execute(ctx, CmdResultGetNextExecutionNumber, req)
    35  	if err != nil {
    36  		return 0, err
    37  	}
    38  	var commandResponse NextExecutionNumberResponse
    39  	if err := json.Unmarshal(response, &commandResponse); err != nil {
    40  		return 0, err
    41  	}
    42  	return commandResponse.TestNumber, nil
    43  }
    44  
    45  func (r *CloudRepository) GetExecution(ctx context.Context, id string) (testkube.Execution, error) {
    46  	req := GetRequest{ID: id}
    47  	response, err := r.executor.Execute(ctx, CmdResultGet, req)
    48  	if err != nil {
    49  		return testkube.Execution{}, err
    50  	}
    51  	var commandResponse GetResponse
    52  	if err := json.Unmarshal(response, &commandResponse); err != nil {
    53  		return testkube.Execution{}, err
    54  	}
    55  	return commandResponse.Execution, nil
    56  }
    57  
    58  func (r *CloudRepository) Get(ctx context.Context, id string) (testkube.Execution, error) {
    59  	req := GetRequest{ID: id}
    60  	response, err := r.executor.Execute(ctx, CmdResultGet, req)
    61  	if err != nil {
    62  		return testkube.Execution{}, err
    63  	}
    64  	var commandResponse GetResponse
    65  	if err := json.Unmarshal(response, &commandResponse); err != nil {
    66  		return testkube.Execution{}, err
    67  	}
    68  	return commandResponse.Execution, nil
    69  }
    70  
    71  func (r *CloudRepository) GetByNameAndTest(ctx context.Context, name, testName string) (testkube.Execution, error) {
    72  	req := GetByNameAndTestRequest{Name: name, TestName: testName}
    73  	response, err := r.executor.Execute(ctx, CmdResultGetByNameAndTest, req)
    74  	if err != nil {
    75  		return testkube.Execution{}, err
    76  	}
    77  	var commandResponse GetByNameAndTestResponse
    78  	if err := json.Unmarshal(response, &commandResponse); err != nil {
    79  		return testkube.Execution{}, err
    80  	}
    81  	return commandResponse.Execution, nil
    82  }
    83  
    84  func (r *CloudRepository) getLatestByTest(ctx context.Context, testName, sortField string) (testkube.Execution, error) {
    85  	req := GetLatestByTestRequest{TestName: testName, SortField: sortField}
    86  	response, err := r.executor.Execute(ctx, CmdResultGetLatestByTest, req)
    87  	if err != nil {
    88  		return testkube.Execution{}, err
    89  	}
    90  	var commandResponse GetLatestByTestResponse
    91  	if err := json.Unmarshal(response, &commandResponse); err != nil {
    92  		return testkube.Execution{}, err
    93  	}
    94  	return commandResponse.Execution, nil
    95  }
    96  
    97  // TODO: When it will be implemented, replace with a new Cloud command, to avoid 2 calls with 2 sort fields
    98  func (r *CloudRepository) GetLatestByTest(ctx context.Context, testName string) (*testkube.Execution, error) {
    99  	startExecution, startErr := r.getLatestByTest(ctx, testName, "starttime")
   100  	if startErr != nil && startErr != mongo.ErrNoDocuments {
   101  		return nil, startErr
   102  	}
   103  	endExecution, endErr := r.getLatestByTest(ctx, testName, "endtime")
   104  	if endErr != nil && endErr != mongo.ErrNoDocuments {
   105  		return nil, endErr
   106  	}
   107  
   108  	if startErr == nil && endErr == nil {
   109  		if startExecution.StartTime.After(endExecution.EndTime) {
   110  			return &startExecution, nil
   111  		} else {
   112  			return &endExecution, nil
   113  		}
   114  	} else if startErr == nil {
   115  		return &startExecution, nil
   116  	} else if endErr == nil {
   117  		return &endExecution, nil
   118  	}
   119  	return nil, startErr
   120  }
   121  
   122  // TODO: When it will be implemented, replace with a new Cloud command, to avoid 2 calls with 2 sort fields
   123  func (r *CloudRepository) getLatestByTests(ctx context.Context, testNames []string, sortField string) ([]testkube.Execution, error) {
   124  	req := GetLatestByTestsRequest{TestNames: testNames, SortField: sortField}
   125  	response, err := r.executor.Execute(ctx, CmdResultGetLatestByTests, req)
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	var commandResponse GetLatestByTestsResponse
   130  	if err := json.Unmarshal(response, &commandResponse); err != nil {
   131  		return nil, err
   132  	}
   133  	return commandResponse.Executions, nil
   134  }
   135  
   136  // TODO: When it will be implemented, replace with a new Cloud command, to avoid 2 calls with 2 sort fields
   137  func (r *CloudRepository) GetLatestByTests(ctx context.Context, testNames []string) ([]testkube.Execution, error) {
   138  	startExecutions, err := r.getLatestByTests(ctx, testNames, "starttime")
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  	endExecutions, err := r.getLatestByTests(ctx, testNames, "endtime")
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	executionsCount := len(startExecutions)
   147  	if len(endExecutions) > executionsCount {
   148  		executionsCount = len(endExecutions)
   149  	}
   150  	executionsMap := make(map[string]*testkube.Execution, executionsCount)
   151  	for i := range startExecutions {
   152  		executionsMap[startExecutions[i].TestName] = &startExecutions[i]
   153  	}
   154  	for i := range endExecutions {
   155  		startExecution, ok := executionsMap[endExecutions[i].TestName]
   156  		if ok {
   157  			if endExecutions[i].EndTime.After(startExecution.StartTime) {
   158  				executionsMap[endExecutions[i].TestName] = &endExecutions[i]
   159  			}
   160  		} else {
   161  			executionsMap[endExecutions[i].TestName] = &endExecutions[i]
   162  		}
   163  	}
   164  	executions := make([]testkube.Execution, 0, executionsCount)
   165  	for _, value := range executionsMap {
   166  		executions = append(executions, *value)
   167  	}
   168  	return executions, nil
   169  }
   170  
   171  func (r *CloudRepository) GetExecutions(ctx context.Context, filter result.Filter) ([]testkube.Execution, error) {
   172  	filterImpl, ok := filter.(*result.FilterImpl)
   173  	if !ok {
   174  		return nil, errors.New("invalid filter")
   175  	}
   176  	req := GetExecutionsRequest{Filter: filterImpl}
   177  	response, err := r.executor.Execute(ctx, CmdResultGetExecutions, req)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	var commandResponse GetLatestByTestsResponse
   182  	if err := json.Unmarshal(response, &commandResponse); err != nil {
   183  		return nil, err
   184  	}
   185  	return commandResponse.Executions, nil
   186  }
   187  
   188  func (r *CloudRepository) GetExecutionTotals(ctx context.Context, paging bool, filters ...result.Filter) (testkube.ExecutionsTotals, error) {
   189  	var filterImpls []*result.FilterImpl
   190  	for _, f := range filters {
   191  		filterImpl, ok := f.(*result.FilterImpl)
   192  		if !ok {
   193  			return testkube.ExecutionsTotals{}, errors.New("invalid filter")
   194  		}
   195  		filterImpls = append(filterImpls, filterImpl)
   196  	}
   197  	req := GetExecutionTotalsRequest{Paging: paging, Filter: filterImpls}
   198  	response, err := r.executor.Execute(ctx, CmdResultGetExecutionTotals, req)
   199  	if err != nil {
   200  		return testkube.ExecutionsTotals{}, err
   201  	}
   202  	var commandResponse GetExecutionTotalsResponse
   203  	if err := json.Unmarshal(response, &commandResponse); err != nil {
   204  		return testkube.ExecutionsTotals{}, err
   205  	}
   206  	return commandResponse.Result, nil
   207  }
   208  
   209  func (r *CloudRepository) Insert(ctx context.Context, result testkube.Execution) error {
   210  	req := InsertRequest{Result: result}
   211  	_, err := r.executor.Execute(ctx, CmdResultInsert, req)
   212  	if err != nil {
   213  		return err
   214  	}
   215  	return nil
   216  }
   217  
   218  func (r *CloudRepository) Update(ctx context.Context, result testkube.Execution) error {
   219  	req := UpdateRequest{Result: result}
   220  	_, err := r.executor.Execute(ctx, CmdResultUpdate, req)
   221  	if err != nil {
   222  		return err
   223  	}
   224  	return nil
   225  }
   226  
   227  func (r *CloudRepository) UpdateResult(ctx context.Context, id string, execution testkube.Execution) error {
   228  	req := UpdateResultInExecutionRequest{ID: id, Execution: execution}
   229  	_, err := r.executor.Execute(ctx, CmdResultUpdateResult, req)
   230  	if err != nil {
   231  		return err
   232  	}
   233  	return nil
   234  }
   235  
   236  func (r *CloudRepository) StartExecution(ctx context.Context, id string, startTime time.Time) error {
   237  	req := StartExecutionRequest{ID: id, StartTime: startTime}
   238  	_, err := r.executor.Execute(ctx, CmdResultStartExecution, req)
   239  	if err != nil {
   240  		return err
   241  	}
   242  	return nil
   243  }
   244  
   245  func (r *CloudRepository) EndExecution(ctx context.Context, execution testkube.Execution) error {
   246  	req := EndExecutionRequest{Execution: execution}
   247  	_, err := r.executor.Execute(ctx, CmdResultEndExecution, req)
   248  	if err != nil {
   249  		return err
   250  	}
   251  	return nil
   252  }
   253  
   254  func (r *CloudRepository) GetLabels(ctx context.Context) (map[string][]string, error) {
   255  	response, err := r.executor.Execute(ctx, CmdResultGetLabels, nil)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	var commandResponse GetLabelsResponse
   260  	if err := json.Unmarshal(response, &commandResponse); err != nil {
   261  		return nil, err
   262  	}
   263  	return nil, nil
   264  }
   265  
   266  func (r *CloudRepository) DeleteByTest(ctx context.Context, testName string) error {
   267  	req := DeleteByTestRequest{TestName: testName}
   268  	_, err := r.executor.Execute(ctx, CmdResultDeleteByTest, req)
   269  	if err != nil {
   270  		return err
   271  	}
   272  	return nil
   273  }
   274  
   275  func (r *CloudRepository) DeleteByTestSuite(ctx context.Context, testSuiteName string) error {
   276  	req := DeleteByTestSuiteRequest{TestSuiteName: testSuiteName}
   277  	_, err := r.executor.Execute(ctx, CmdResultDeleteByTestSuite, req)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	return nil
   282  }
   283  
   284  func (r *CloudRepository) DeleteAll(ctx context.Context) error {
   285  	req := DeleteAllRequest{}
   286  	_, err := r.executor.Execute(ctx, CmdResultDeleteAll, req)
   287  	if err != nil {
   288  		return err
   289  	}
   290  	return nil
   291  }
   292  
   293  func (r *CloudRepository) DeleteByTests(ctx context.Context, testNames []string) error {
   294  	req := DeleteByTestsRequest{TestNames: testNames}
   295  	_, err := r.executor.Execute(ctx, CmdResultDeleteByTests, req)
   296  	if err != nil {
   297  		return err
   298  	}
   299  	return nil
   300  }
   301  
   302  func (r *CloudRepository) DeleteByTestSuites(ctx context.Context, testSuiteNames []string) error {
   303  	req := DeleteByTestSuitesRequest{TestSuiteNames: testSuiteNames}
   304  	_, err := r.executor.Execute(ctx, CmdResultDeleteByTestSuites, req)
   305  	if err != nil {
   306  		return err
   307  	}
   308  	return nil
   309  }
   310  
   311  func (r *CloudRepository) DeleteForAllTestSuites(ctx context.Context) error {
   312  	req := DeleteForAllTestSuitesResponse{}
   313  	_, err := r.executor.Execute(ctx, CmdResultDeleteForAllTestSuites, req)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	return nil
   318  }
   319  
   320  func (r *CloudRepository) GetTestMetrics(ctx context.Context, name string, limit, last int) (testkube.ExecutionsMetrics, error) {
   321  	req := GetTestMetricsRequest{Name: name, Limit: limit, Last: last}
   322  	response, err := r.executor.Execute(ctx, CmdResultGetTestMetrics, req)
   323  	if err != nil {
   324  		return testkube.ExecutionsMetrics{}, err
   325  	}
   326  	var commandResponse GetTestMetricsResponse
   327  	if err := json.Unmarshal(response, &commandResponse); err != nil {
   328  		return testkube.ExecutionsMetrics{}, err
   329  	}
   330  	return commandResponse.Metrics, nil
   331  }
   332  
   333  func (r *CloudRepository) Count(ctx context.Context, filter result.Filter) (int64, error) {
   334  	return 0, nil
   335  }