Skip to content

Commit

Permalink
feat: add endpoint to list resources (#1454)
Browse files Browse the repository at this point in the history
* feat: add endpoint to list resources

* fix endpoint

* add tracetest
  • Loading branch information
mathnogueira committed Nov 3, 2022
1 parent f93b770 commit f7e29e1
Show file tree
Hide file tree
Showing 14 changed files with 310 additions and 83 deletions.
52 changes: 52 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -842,3 +842,55 @@ paths:
application/json:
schema:
$ref: "./expressions.yaml#/components/schemas/ResolveResponseInfo"

/resources:
get:
tags:
- api
summary: "Get resources"
description: "get resources"
operationId: getResources
parameters:
- in: query
name: take
description: "indicates how many transactions can be returned by each page"
schema:
type: integer
default: 20
- in: query
name: skip
description: "indicates how many transactions will be skipped when paginating"
schema:
type: integer
default: 0
- in: query
name: query
description: "query to search transactions, based on transaction name and description"
schema:
type: string
- in: query
name: sortBy
description: "indicates the sort field for the transactions"
schema:
type: string
enum: [created, name, last_run]
- in: query
name: sortDirection
description: "indicates the sort direction for the transactions"
schema:
type: string
enum: [asc, desc]
responses:
200:
description: successful operation
headers:
X-Total-Count:
schema:
type: integer
description: Total records count
content:
application/json:
schema:
type: array
items:
$ref: "./resources.yaml#/components/schemas/Resource"
15 changes: 15 additions & 0 deletions api/resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
openapi: 3.0.0
components:
schemas:

Resource:
type: object
required:
- type
- item
nullable: false
properties:
type:
type: string
readOnly: true
item: {}
3 changes: 3 additions & 0 deletions api/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ components:
version:
type: integer
description: version number of the test
createdAt:
type: string
format: date-time
serviceUnderTest:
$ref: "./triggers.yaml#/components/schemas/Trigger"
specs:
Expand Down
3 changes: 3 additions & 0 deletions api/transactions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ components:
type: array
items:
type: string
createdAt:
type: string
format: date-time
89 changes: 89 additions & 0 deletions server/http/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -838,3 +838,92 @@ func (c *controller) UpdateTransaction(ctx context.Context, tID string, transact

return openapi.Response(http.StatusNoContent, nil), nil
}

// GetResources implements openapi.ApiApiServicer
func (c *controller) GetResources(ctx context.Context, take, skip int32, query, sortBy, sortDirection string) (openapi.ImplResponse, error) {
// TODO: this is endpoint is a hack to unblock the team quickly.
// This is not production ready because it might take too long to respond if there are numerous
// transactions and tests.

if take == 0 {
take = 20
}

newTake := take + skip

getTransactionsReponse, err := c.GetTransactions(ctx, newTake, 0, query, sortBy, sortDirection)
if err != nil {
return getTransactionsReponse, err
}

getTestsResponse, err := c.GetTests(ctx, newTake, 0, query, sortBy, sortDirection)
if err != nil {
return getTestsResponse, err
}

transactionPaginatedResponse := getTransactionsReponse.Body.(paginated[openapi.Transaction])
transactions := transactionPaginatedResponse.items
testPaginatedResponse := getTestsResponse.Body.(paginated[openapi.Test])
tests := testPaginatedResponse.items

totalResources := transactionPaginatedResponse.count + testPaginatedResponse.count

items := takeResources(transactions, tests, take, skip)

paginatedResponse := paginated[openapi.Resource]{
items: items,
count: totalResources,
}

return openapi.Response(http.StatusOK, paginatedResponse), nil
}

func takeResources(transactions []openapi.Transaction, tests []openapi.Test, take, skip int32) []openapi.Resource {
numItems := len(transactions) + len(tests)
items := make([]openapi.Resource, numItems)
maxNumItems := len(transactions) + len(tests)
currentNumberItens := 0

var i, j int
for currentNumberItens < int(numItems) && currentNumberItens < maxNumItems {
if i >= len(transactions) {
test := tests[j]
testInterface := any(test)
items[currentNumberItens] = openapi.Resource{Type: "test", Item: &testInterface}
j++
currentNumberItens++
continue
}

if j >= len(tests) {
transaction := transactions[i]
transactionInterface := any(transaction)
items[currentNumberItens] = openapi.Resource{Type: "transaction", Item: &transactionInterface}
i++
currentNumberItens++
continue
}

transaction := transactions[i]
test := tests[j]
transactionInterface := any(transaction)
testInterface := any(test)

if transaction.CreatedAt.After(test.CreatedAt) {
items[currentNumberItens] = openapi.Resource{Type: "transaction", Item: &transactionInterface}
i++
} else {
items[currentNumberItens] = openapi.Resource{Type: "test", Item: &testInterface}
i++
}

currentNumberItens++
}

upperLimit := int(skip + take)
if upperLimit > currentNumberItens {
upperLimit = currentNumberItens
}

return items[skip:upperLimit]
}
118 changes: 35 additions & 83 deletions server/http/custom_routes.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package http

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -35,10 +36,12 @@ func (c *customController) Routes() openapi.Routes {

routes[c.getRouteIndex("GetRunResultJUnit")].HandlerFunc = c.GetRunResultJUnit
routes[c.getRouteIndex("GetTestVersionDefinitionFile")].HandlerFunc = c.GetTestVersionDefinitionFile
routes[c.getRouteIndex("GetTests")].HandlerFunc = c.GetTests
routes[c.getRouteIndex("GetTestRuns")].HandlerFunc = c.GetTestRuns
routes[c.getRouteIndex("GetEnvironments")].HandlerFunc = c.GetEnvironments
routes[c.getRouteIndex("GetTransactions")].HandlerFunc = c.GetTransactions

routes[c.getRouteIndex("GetTests")].HandlerFunc = paginatedEndpoint[openapi.Test](c.service.GetTests, c.errorHandler)
routes[c.getRouteIndex("GetEnvironments")].HandlerFunc = paginatedEndpoint[openapi.Environment](c.service.GetEnvironments, c.errorHandler)
routes[c.getRouteIndex("GetTransactions")].HandlerFunc = paginatedEndpoint[openapi.Transaction](c.service.GetTransactions, c.errorHandler)
routes[c.getRouteIndex("GetResources")].HandlerFunc = paginatedEndpoint[openapi.Resource](c.service.GetResources, c.errorHandler)

for index, route := range routes {
routeName := fmt.Sprintf("%s %s", route.Method, route.Pattern)
Expand All @@ -55,34 +58,6 @@ func (c *customController) Routes() openapi.Routes {
return routes
}

// GetTests - Get tests
func (c *customController) GetTests(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
takeParam, err := parseInt32Parameter(query.Get("take"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
skipParam, err := parseInt32Parameter(query.Get("skip"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
queryParam := query.Get("query")
sortByParam := query.Get("sortBy")
sortDirectionParam := query.Get("sortDirection")
result, err := c.service.GetTests(r.Context(), takeParam, skipParam, queryParam, sortByParam, sortDirectionParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
res := result.Body.(paginated[openapi.Test])

w.Header().Set("X-Total-Count", strconv.Itoa(res.count))
openapi.EncodeJSONResponse(res.items, &result.Code, w)
}

// GetTestRuns - get the runs for a test
func (c *customController) GetTestRuns(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
Expand Down Expand Up @@ -111,34 +86,6 @@ func (c *customController) GetTestRuns(w http.ResponseWriter, r *http.Request) {
openapi.EncodeJSONResponse(res.items, &result.Code, w)
}

// GetEnvironments - Get environments
func (c *customController) GetEnvironments(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
takeParam, err := parseInt32Parameter(query.Get("take"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
skipParam, err := parseInt32Parameter(query.Get("skip"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
queryParam := query.Get("query")
sortByParam := query.Get("sortBy")
sortDirectionParam := query.Get("sortDirection")
result, err := c.service.GetEnvironments(r.Context(), takeParam, skipParam, queryParam, sortByParam, sortDirectionParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
res := result.Body.(paginated[openapi.Environment])

w.Header().Set("X-Total-Count", strconv.Itoa(res.count))
openapi.EncodeJSONResponse(res.items, &result.Code, w)
}

// GetRunResultJUnit - get test run results in JUnit xml format
func (c *customController) GetRunResultJUnit(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
Expand Down Expand Up @@ -177,31 +124,36 @@ func (c *customController) GetTestVersionDefinitionFile(w http.ResponseWriter, r
w.Write(result.Body.([]byte))
}

func (c *customController) GetTransactions(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
takeParam, err := parseInt32Parameter(query.Get("take"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
skipParam, err := parseInt32Parameter(query.Get("skip"), false)
if err != nil {
c.errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
queryParam := query.Get("query")
sortByParam := query.Get("sortBy")
sortDirectionParam := query.Get("sortDirection")
result, err := c.service.GetTransactions(r.Context(), takeParam, skipParam, queryParam, sortByParam, sortDirectionParam)
// If an error occurred, encode the error with the status code
if err != nil {
c.errorHandler(w, r, err, &result)
return
}
res := result.Body.(paginated[openapi.Transaction])
func paginatedEndpoint[T any](
f func(c context.Context, take, skip int32, query string, sortBy string, sortDirection string) (openapi.ImplResponse, error),
errorHandler openapi.ErrorHandler,
) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
query := r.URL.Query()
takeParam, err := parseInt32Parameter(query.Get("take"), false)
if err != nil {
errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
skipParam, err := parseInt32Parameter(query.Get("skip"), false)
if err != nil {
errorHandler(w, r, &openapi.ParsingError{Err: err}, nil)
return
}
queryParam := query.Get("query")
sortByParam := query.Get("sortBy")
sortDirectionParam := query.Get("sortDirection")
result, err := f(r.Context(), takeParam, skipParam, queryParam, sortByParam, sortDirectionParam)
// If an error occurred, encode the error with the status code
if err != nil {
errorHandler(w, r, err, &result)
return
}
res := result.Body.(paginated[T])

w.Header().Set("X-Total-Count", strconv.Itoa(res.count))
openapi.EncodeJSONResponse(res.items, &result.Code, w)
w.Header().Set("X-Total-Count", strconv.Itoa(res.count))
openapi.EncodeJSONResponse(res.items, &result.Code, w)
}
}

const errMsgRequiredMissing = "required parameter is missing"
Expand Down
2 changes: 2 additions & 0 deletions server/http/mappings/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func (m OpenAPI) Transaction(in model.Transaction) openapi.Transaction {
Description: in.Description,
Version: int32(in.Version),
Steps: testIds,
CreatedAt: in.CreatedAt,
}
}

Expand All @@ -43,6 +44,7 @@ func (m OpenAPI) Test(in model.Test) openapi.Test {
ServiceUnderTest: m.Trigger(in.ServiceUnderTest),
Specs: m.Specs(in.Specs),
Version: int32(in.Version),
CreatedAt: in.CreatedAt,
Outputs: m.Outputs(in.Outputs),
Summary: openapi.TestSummary{
Runs: int32(in.Summary.Runs),
Expand Down
2 changes: 2 additions & 0 deletions server/openapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type ApiApiRouter interface {
ExpressionResolve(http.ResponseWriter, *http.Request)
GetEnvironment(http.ResponseWriter, *http.Request)
GetEnvironments(http.ResponseWriter, *http.Request)
GetResources(http.ResponseWriter, *http.Request)
GetRunResultJUnit(http.ResponseWriter, *http.Request)
GetTest(http.ResponseWriter, *http.Request)
GetTestResultSelectedSpans(http.ResponseWriter, *http.Request)
Expand Down Expand Up @@ -70,6 +71,7 @@ type ApiApiServicer interface {
ExpressionResolve(context.Context, ResolveRequestInfo) (ImplResponse, error)
GetEnvironment(context.Context, string) (ImplResponse, error)
GetEnvironments(context.Context, int32, int32, string, string, string) (ImplResponse, error)
GetResources(context.Context, int32, int32, string, string, string) (ImplResponse, error)
GetRunResultJUnit(context.Context, string, string) (ImplResponse, error)
GetTest(context.Context, string) (ImplResponse, error)
GetTestResultSelectedSpans(context.Context, string, string, string) (ImplResponse, error)
Expand Down

0 comments on commit f7e29e1

Please sign in to comment.