Skip to content

Commit

Permalink
feat: transaction crud (#1432)
Browse files Browse the repository at this point in the history
* remove dead code

* --wip-- [skip ci]

* generate api code and implement mapping

* write db queries

* implement api

* fix tests and migration number

* fix transaction steps order

* add transaction create test

* transactions tests

* exit with code

* fix env delete

* fix delete env endpoint

* rebuild api code

* use http status instead of int

* fix

* fix

* test

* begin transaction with context

* fix instrumentation

* add new tests

* fix test

* assert number of delete statements

* set step in test

* create test before creating the transaction

* debug

* fix

* remove debug message

* fix trace

* fix test

* drop env table on Drop

Co-authored-by: Sebastian Choren <sebastian.choren@gmail.com>
  • Loading branch information
mathnogueira and schoren committed Nov 2, 2022
1 parent ef2d6d9 commit 278d987
Show file tree
Hide file tree
Showing 31 changed files with 1,393 additions and 44 deletions.
133 changes: 133 additions & 0 deletions api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,139 @@ paths:
$ref: "./definition.yaml#/components/schemas/ExecuteDefinitionResponse"
422:
description: "trying to create a test with an already existing ID"
/transactions:
get:
tags:
- api
summary: "Get transactions"
description: "get transactions"
operationId: getTransactions
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: "./transactions.yaml#/components/schemas/Transaction"
500:
description: "problem with getting transactions"
post:
tags:
- api
summary: "Create new transaction"
description: "Create new transaction"
operationId: createTransaction
requestBody:
content:
application/json:
schema:
$ref: "./transactions.yaml#/components/schemas/Transaction"
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: "./transactions.yaml#/components/schemas/Transaction"
400:
description: "trying to create a transaction with an already existing ID"

/transactions/{transactionId}:
get:
tags:
- api
parameters:
- in: path
name: transactionId
schema:
type: string
required: true
summary: "get transaction"
description: "get transaction"
operationId: getTransaction
responses:
200:
description: successful operation
content:
application/json:
schema:
$ref: "./transactions.yaml#/components/schemas/Transaction"
500:
description: "problem with getting a transaction"
put:
tags:
- api
parameters:
- in: path
name: transactionId
schema:
type: string
required: true
summary: "update transaction"
description: "update transaction action"
operationId: updateTransaction
requestBody:
content:
application/json:
schema:
$ref: "./transactions.yaml#/components/schemas/Transaction"
responses:
204:
description: successful operation
500:
description: "problem with updating transaction"
delete:
tags:
- api
parameters:
- in: path
name: transactionId
schema:
type: string
required: true
summary: "delete a transaction"
description: "delete a transaction"
operationId: deleteTransaction
responses:
"204":
description: OK
/tests:
get:
tags:
Expand Down
2 changes: 1 addition & 1 deletion server/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (a *App) Start() error {
runner.Start(5) // worker count. should be configurable
defer runner.Stop()

mappers := mappings.New(traceConversionConfig, comparator.DefaultRegistry())
mappers := mappings.New(traceConversionConfig, comparator.DefaultRegistry(), a.db)

controller := httpServer.NewController(a.db, runner, assertionRunner, mappers)
apiApiController := openapi.NewApiApiController(controller)
Expand Down
76 changes: 75 additions & 1 deletion server/http/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,7 @@ func (c *controller) DeleteEnvironment(ctx context.Context, environmentId string
return handleDBError(err), err
}

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

func (c *controller) GetEnvironment(ctx context.Context, environmentId string) (openapi.ImplResponse, error) {
Expand Down Expand Up @@ -764,3 +764,77 @@ func (c *controller) buildDataStores(ctx context.Context, info openapi.ResolveRe

return ds, nil
}

func (c *controller) CreateTransaction(ctx context.Context, transaction openapi.Transaction) (openapi.ImplResponse, error) {
transactionModel, err := c.mappers.In.Transaction(ctx, transaction)
if err != nil {
return handleDBError(err), err
}

createdTransaction, err := c.testDB.CreateTransaction(ctx, transactionModel)
if err != nil {
return handleDBError(err), err
}

return openapi.Response(http.StatusOK, c.mappers.Out.Transaction(createdTransaction)), nil
}

func (c *controller) DeleteTransaction(ctx context.Context, tID string) (openapi.ImplResponse, error) {
transaction, err := c.testDB.GetLatestTransactionVersion(ctx, id.ID(tID))
if err != nil {
return handleDBError(err), err
}

err = c.testDB.DeleteTransaction(ctx, transaction)
if err != nil {
return handleDBError(err), err
}

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

func (c *controller) GetTransaction(ctx context.Context, tID string) (openapi.ImplResponse, error) {
transaction, err := c.testDB.GetLatestTransactionVersion(ctx, id.ID(tID))
if err != nil {
return handleDBError(err), err
}

return openapi.Response(http.StatusOK, c.mappers.Out.Transaction(transaction)), nil
}

func (c *controller) GetTransactions(ctx context.Context, take, skip int32, query, sortBy, sortDirection string) (openapi.ImplResponse, error) {
if take == 0 {
take = 20
}

transactions, err := c.testDB.GetTransactions(ctx, take, skip, query, sortBy, sortDirection)
if err != nil {
return handleDBError(err), err
}

apiTransactions := make([]openapi.Transaction, len(transactions.Items))
for i, transaction := range transactions.Items {
apiTransactions[i] = c.mappers.Out.Transaction(transaction)
}

return openapi.Response(http.StatusOK, paginated[openapi.Transaction]{
items: apiTransactions,
count: transactions.TotalCount,
}), nil
}

func (c *controller) UpdateTransaction(ctx context.Context, tID string, transaction openapi.Transaction) (openapi.ImplResponse, error) {
modelTransaction, err := c.mappers.In.Transaction(ctx, transaction)
if err != nil {
return openapi.Response(http.StatusBadRequest, err.Error()), err
}

modelTransaction.ID = id.ID(tID)

_, err = c.testDB.UpdateTransaction(ctx, modelTransaction)
if err != nil {
return handleDBError(err), err
}

return openapi.Response(http.StatusNoContent, nil), nil
}
2 changes: 1 addition & 1 deletion server/http/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func setupController(t *testing.T) controllerFixture {
mdb.Test(t)
return controllerFixture{
db: mdb,
c: http.NewController(mdb, nil, nil, mappings.New(traces.NewConversionConfig(), comparator.DefaultRegistry())),
c: http.NewController(mdb, nil, nil, mappings.New(traces.NewConversionConfig(), comparator.DefaultRegistry(), mdb)),
}
}

Expand Down
28 changes: 28 additions & 0 deletions server/http/custom_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func (c *customController) Routes() openapi.Routes {
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

for index, route := range routes {
routeName := fmt.Sprintf("%s %s", route.Method, route.Pattern)
Expand Down Expand Up @@ -176,6 +177,33 @@ 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])

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

const errMsgRequiredMissing = "required parameter is missing"

func parseInt32Parameter(param string, required bool) (int32, error) {
Expand Down
4 changes: 3 additions & 1 deletion server/http/mappings/mappings.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mappings

import (
"github.com/kubeshop/tracetest/server/assertions/comparator"
"github.com/kubeshop/tracetest/server/model"
"github.com/kubeshop/tracetest/server/traces"
)

Expand All @@ -10,11 +11,12 @@ type Mappings struct {
Out OpenAPI
}

func New(tcc traces.ConversionConfig, cr comparator.Registry) Mappings {
func New(tcc traces.ConversionConfig, cr comparator.Registry, tr model.TestRepository) Mappings {
return Mappings{
In: Model{
comparators: cr,
traceConversionConfig: tcc,
testRepository: tr,
},
Out: OpenAPI{
traceConversionConfig: tcc,
Expand Down
4 changes: 2 additions & 2 deletions server/http/mappings/mappings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestSpecOrder(t *testing.T) {
// try multiple times to hit the map iteration randomization
attempts := 50
for i := 0; i < attempts; i++ {
maps := mappings.New(traces.ConversionConfig{}, comparator.DefaultRegistry())
maps := mappings.New(traces.ConversionConfig{}, comparator.DefaultRegistry(), nil)
definition, err := maps.In.Definition(input)
require.NoError(t, err)
actual := maps.Out.Specs(definition)
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestResultsOrder(t *testing.T) {
// try multiple times to hit the map iteration randomization
attempts := 50
for i := 0; i < attempts; i++ {
maps := mappings.New(traces.ConversionConfig{}, comparator.DefaultRegistry())
maps := mappings.New(traces.ConversionConfig{}, comparator.DefaultRegistry(), nil)

result, err := maps.In.Result(input)
require.NoError(t, err)
Expand Down
37 changes: 37 additions & 0 deletions server/http/mappings/tests.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mappings

import (
"context"
"fmt"
"strconv"

Expand All @@ -19,6 +20,21 @@ type OpenAPI struct {
traceConversionConfig traces.ConversionConfig
}

func (m OpenAPI) Transaction(in model.Transaction) openapi.Transaction {
testIds := make([]string, len(in.Steps))
for i, step := range in.Steps {
testIds[i] = step.ID.String()
}

return openapi.Transaction{
Id: in.ID.String(),
Name: in.Name,
Description: in.Description,
Version: int32(in.Version),
Steps: testIds,
}
}

func (m OpenAPI) Test(in model.Test) openapi.Test {
return openapi.Test{
Id: string(in.ID),
Expand Down Expand Up @@ -282,6 +298,27 @@ func (m OpenAPI) Runs(in []model.Run) []openapi.TestRun {
type Model struct {
comparators comparator.Registry
traceConversionConfig traces.ConversionConfig
testRepository model.TestRepository
}

func (m Model) Transaction(ctx context.Context, in openapi.Transaction) (model.Transaction, error) {
tests := make([]model.Test, len(in.Steps))
for i, testID := range in.Steps {
test, err := m.testRepository.GetLatestTestVersion(ctx, id.ID(testID))
if err != nil {
return model.Transaction{}, err
}

tests[i] = test
}

return model.Transaction{
ID: id.ID(in.Id),
Name: in.Name,
Description: in.Description,
Version: int(in.Version),
Steps: tests,
}, nil
}

func (m Model) Test(in openapi.Test) (model.Test, error) {
Expand Down
2 changes: 1 addition & 1 deletion server/http/mappings/tests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func Test_OpenApiToModel_Outputs(t *testing.T) {
Value: "attr:tracetest.selected_spans.count",
})

m := mappings.New(traces.NewConversionConfig(), nil)
m := mappings.New(traces.NewConversionConfig(), nil, nil)

actual, err := m.In.Test(in)
require.NoError(t, err)
Expand Down

0 comments on commit 278d987

Please sign in to comment.