From 10c8d9740e1d111c522e1df307cda215989abbdb Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Fri, 1 Sep 2023 16:05:44 -0300 Subject: [PATCH] feat(server): add endpoint to update test trigger response (#3117) feat(server): add endpoint to update test trigger --- api/grpc.yaml | 2 - api/openapi.yaml | 23 +++++ cli/openapi/api_api.go | 116 ++++++++++++++++++++++++++ cli/openapi/model_grpc_response.go | 39 +++++---- server/http/controller.go | 22 +++++ server/openapi/api.go | 2 + server/openapi/api_api.go | 39 +++++++++ server/openapi/model_grpc_response.go | 11 +-- web/src/types/Generated.types.ts | 21 ++++- 9 files changed, 248 insertions(+), 27 deletions(-) diff --git a/api/grpc.yaml b/api/grpc.yaml index 912e66dca0..07e2d3c3a7 100644 --- a/api/grpc.yaml +++ b/api/grpc.yaml @@ -31,8 +31,6 @@ components: GRPCResponse: type: object - required: - - statusCode properties: statusCode: type: integer diff --git a/api/openapi.yaml b/api/openapi.yaml index 254274fa0d..7ed668b4b9 100644 --- a/api/openapi.yaml +++ b/api/openapi.yaml @@ -518,6 +518,29 @@ paths: responses: "204": description: OK + # TODO: remove this as soon as we refactor our queues + patch: + tags: + - api + parameters: + - $ref: "./parameters.yaml#/components/parameters/testId" + - $ref: "./parameters.yaml#/components/parameters/runId" + summary: "update a test run" + description: "update a test run" + operationId: updateTestRun + requestBody: + content: + application/json: + schema: + $ref: "./tests.yaml#/components/schemas/TestRun" + responses: + 200: + description: successfuly updated the test run + content: + application/json: + schema: + $ref: "./tests.yaml#/components/schemas/TestRun" + /tests/{testId}/definition: get: tags: diff --git a/cli/openapi/api_api.go b/cli/openapi/api_api.go index 21ed613205..795f7ce6b9 100644 --- a/cli/openapi/api_api.go +++ b/cli/openapi/api_api.go @@ -2567,3 +2567,119 @@ func (a *ApiApiService) TestConnectionExecute(r ApiTestConnectionRequest) (*Test return localVarReturnValue, localVarHTTPResponse, nil } + +type ApiUpdateTestRunRequest struct { + ctx context.Context + ApiService *ApiApiService + testId string + runId int32 + testRun *TestRun +} + +func (r ApiUpdateTestRunRequest) TestRun(testRun TestRun) ApiUpdateTestRunRequest { + r.testRun = &testRun + return r +} + +func (r ApiUpdateTestRunRequest) Execute() (*TestRun, *http.Response, error) { + return r.ApiService.UpdateTestRunExecute(r) +} + +/* +UpdateTestRun update a test run + +update a test run + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param testId id of the test + @param runId id of the run + @return ApiUpdateTestRunRequest +*/ +func (a *ApiApiService) UpdateTestRun(ctx context.Context, testId string, runId int32) ApiUpdateTestRunRequest { + return ApiUpdateTestRunRequest{ + ApiService: a, + ctx: ctx, + testId: testId, + runId: runId, + } +} + +// Execute executes the request +// +// @return TestRun +func (a *ApiApiService) UpdateTestRunExecute(r ApiUpdateTestRunRequest) (*TestRun, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPatch + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *TestRun + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "ApiApiService.UpdateTestRun") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/tests/{testId}/run/{runId}" + localVarPath = strings.Replace(localVarPath, "{"+"testId"+"}", url.PathEscape(parameterValueToString(r.testId, "testId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"runId"+"}", url.PathEscape(parameterValueToString(r.runId, "runId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.testRun + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/cli/openapi/model_grpc_response.go b/cli/openapi/model_grpc_response.go index beb725ff07..7f053b582d 100644 --- a/cli/openapi/model_grpc_response.go +++ b/cli/openapi/model_grpc_response.go @@ -19,7 +19,7 @@ var _ MappedNullable = &GRPCResponse{} // GRPCResponse struct for GRPCResponse type GRPCResponse struct { - StatusCode int32 `json:"statusCode"` + StatusCode *int32 `json:"statusCode,omitempty"` Metadata []GRPCHeader `json:"metadata,omitempty"` Body *string `json:"body,omitempty"` } @@ -28,9 +28,10 @@ type GRPCResponse struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewGRPCResponse(statusCode int32) *GRPCResponse { +func NewGRPCResponse() *GRPCResponse { this := GRPCResponse{} - this.StatusCode = statusCode + var statusCode int32 = 0 + this.StatusCode = &statusCode return &this } @@ -40,32 +41,40 @@ func NewGRPCResponse(statusCode int32) *GRPCResponse { func NewGRPCResponseWithDefaults() *GRPCResponse { this := GRPCResponse{} var statusCode int32 = 0 - this.StatusCode = statusCode + this.StatusCode = &statusCode return &this } -// GetStatusCode returns the StatusCode field value +// GetStatusCode returns the StatusCode field value if set, zero value otherwise. func (o *GRPCResponse) GetStatusCode() int32 { - if o == nil { + if o == nil || isNil(o.StatusCode) { var ret int32 return ret } - - return o.StatusCode + return *o.StatusCode } -// GetStatusCodeOk returns a tuple with the StatusCode field value +// GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GRPCResponse) GetStatusCodeOk() (*int32, bool) { - if o == nil { + if o == nil || isNil(o.StatusCode) { return nil, false } - return &o.StatusCode, true + return o.StatusCode, true } -// SetStatusCode sets field value +// HasStatusCode returns a boolean if a field has been set. +func (o *GRPCResponse) HasStatusCode() bool { + if o != nil && !isNil(o.StatusCode) { + return true + } + + return false +} + +// SetStatusCode gets a reference to the given int32 and assigns it to the StatusCode field. func (o *GRPCResponse) SetStatusCode(v int32) { - o.StatusCode = v + o.StatusCode = &v } // GetMetadata returns the Metadata field value if set, zero value otherwise. @@ -142,7 +151,9 @@ func (o GRPCResponse) MarshalJSON() ([]byte, error) { func (o GRPCResponse) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - toSerialize["statusCode"] = o.StatusCode + if !isNil(o.StatusCode) { + toSerialize["statusCode"] = o.StatusCode + } if !isNil(o.Metadata) { toSerialize["metadata"] = o.Metadata } diff --git a/server/http/controller.go b/server/http/controller.go index d93b8b3b5d..2f92ba31bf 100644 --- a/server/http/controller.go +++ b/server/http/controller.go @@ -708,3 +708,25 @@ func (c *controller) GetVersion(ctx context.Context) (openapi.ImplResponse, erro return openapi.Response(http.StatusOK, version), nil } + +func (c *controller) UpdateTestRun(ctx context.Context, testID string, runID int32, testRun openapi.TestRun) (openapi.ImplResponse, error) { + existingRun, err := c.testRunRepository.GetRun(ctx, id.ID(testID), int(runID)) + if err != nil { + return openapi.Response(http.StatusNotFound, err.Error()), err + } + + run, err := c.mappers.In.Run(testRun) + if err != nil { + return openapi.Response(http.StatusBadRequest, err.Error()), err + } + + // Prevents bad data in other fields to override correct data + existingRun.TriggerResult = run.TriggerResult + + err = c.testRunRepository.UpdateRun(ctx, existingRun) + if err != nil { + return openapi.Response(http.StatusInternalServerError, err.Error()), err + } + + return openapi.Response(http.StatusOK, run), err +} diff --git a/server/openapi/api.go b/server/openapi/api.go index 56a9fb4f02..a30d55e024 100644 --- a/server/openapi/api.go +++ b/server/openapi/api.go @@ -41,6 +41,7 @@ type ApiApiRouter interface { RunTestSuite(http.ResponseWriter, *http.Request) StopTestRun(http.ResponseWriter, *http.Request) TestConnection(http.ResponseWriter, *http.Request) + UpdateTestRun(http.ResponseWriter, *http.Request) } // ResourceApiApiRouter defines the required methods for binding the api requests to a responses for the ResourceApiApi @@ -112,6 +113,7 @@ type ApiApiServicer interface { RunTestSuite(context.Context, string, RunInformation) (ImplResponse, error) StopTestRun(context.Context, string, int32) (ImplResponse, error) TestConnection(context.Context, DataStore) (ImplResponse, error) + UpdateTestRun(context.Context, string, int32, TestRun) (ImplResponse, error) } // ResourceApiApiServicer defines the api actions for the ResourceApiApi service diff --git a/server/openapi/api_api.go b/server/openapi/api_api.go index 2cf6227871..b7309cec33 100644 --- a/server/openapi/api_api.go +++ b/server/openapi/api_api.go @@ -188,6 +188,12 @@ func (c *ApiApiController) Routes() Routes { "/api/config/connection", c.TestConnection, }, + { + "UpdateTestRun", + strings.ToUpper("Patch"), + "/api/tests/{testId}/run/{runId}", + c.UpdateTestRun, + }, } } @@ -725,3 +731,36 @@ func (c *ApiApiController) TestConnection(w http.ResponseWriter, r *http.Request EncodeJSONResponse(result.Body, &result.Code, w) } + +// UpdateTestRun - update a test run +func (c *ApiApiController) UpdateTestRun(w http.ResponseWriter, r *http.Request) { + params := mux.Vars(r) + testIdParam := params["testId"] + + runIdParam, err := parseInt32Parameter(params["runId"], true) + if err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + + testRunParam := TestRun{} + d := json.NewDecoder(r.Body) + d.DisallowUnknownFields() + if err := d.Decode(&testRunParam); err != nil { + c.errorHandler(w, r, &ParsingError{Err: err}, nil) + return + } + if err := AssertTestRunRequired(testRunParam); err != nil { + c.errorHandler(w, r, err, nil) + return + } + result, err := c.service.UpdateTestRun(r.Context(), testIdParam, runIdParam, testRunParam) + // If an error occurred, encode the error with the status code + if err != nil { + c.errorHandler(w, r, err, &result) + return + } + // If no error, encode the body and the result code + EncodeJSONResponse(result.Body, &result.Code, w) + +} diff --git a/server/openapi/model_grpc_response.go b/server/openapi/model_grpc_response.go index a2500a9970..70350f9bc4 100644 --- a/server/openapi/model_grpc_response.go +++ b/server/openapi/model_grpc_response.go @@ -10,7 +10,7 @@ package openapi type GrpcResponse struct { - StatusCode int32 `json:"statusCode"` + StatusCode int32 `json:"statusCode,omitempty"` Metadata []GrpcHeader `json:"metadata,omitempty"` @@ -19,15 +19,6 @@ type GrpcResponse struct { // AssertGrpcResponseRequired checks if the required fields are not zero-ed func AssertGrpcResponseRequired(obj GrpcResponse) error { - elements := map[string]interface{}{ - "statusCode": obj.StatusCode, - } - for name, el := range elements { - if isZero := IsZeroValue(el); isZero { - return &RequiredError{Field: name} - } - } - for _, el := range obj.Metadata { if err := AssertGrpcHeaderRequired(el); err != nil { return err diff --git a/web/src/types/Generated.types.ts b/web/src/types/Generated.types.ts index 5b59a25b3a..cb7c6157ca 100644 --- a/web/src/types/Generated.types.ts +++ b/web/src/types/Generated.types.ts @@ -95,6 +95,8 @@ export interface paths { get: operations["getTestRun"]; /** delete a test run */ delete: operations["deleteTestRun"]; + /** update a test run */ + patch: operations["updateTestRun"]; }; "/tests/{testId}/definition": { /** Gets definition for a test */ @@ -568,6 +570,23 @@ export interface operations { 204: never; }; }; + /** update a test run */ + updateTestRun: { + parameters: {}; + responses: { + /** successfuly updated the test run */ + 200: { + content: { + "application/json": external["tests.yaml"]["components"]["schemas"]["TestRun"]; + }; + }; + }; + requestBody: { + content: { + "application/json": external["tests.yaml"]["components"]["schemas"]["TestRun"]; + }; + }; + }; /** Gets definition for a test */ getTestSpecs: { parameters: {}; @@ -1425,7 +1444,7 @@ export interface external { request?: string; }; GRPCResponse: { - statusCode: number; + statusCode?: number; metadata?: external["grpc.yaml"]["components"]["schemas"]["GRPCHeader"][]; body?: string; };