From 0fe5e80b258ac59c2199525ebda9d044eb5576e7 Mon Sep 17 00:00:00 2001 From: Oscar Reyes Date: Fri, 20 Jan 2023 14:54:37 -0600 Subject: [PATCH] allowing variable name for tests --- examples/test-from-id.js | 55 +++++------ .../options.go => models/apiOptions.go | 8 +- models/httpClientOptions.go | 58 ++++++++++++ models/job.go | 34 ++++--- models/tracetestOptions.go | 35 +++++++ modules/httpClient/enhancers.go | 30 ++++-- modules/httpClient/httpClient.go | 5 +- modules/httpClient/options.go | 94 ------------------- modules/output/processor.go | 9 +- modules/tracetest/api.go | 17 ++-- modules/tracetest/queue.go | 5 +- modules/tracetest/tracetest.go | 13 +-- 12 files changed, 189 insertions(+), 174 deletions(-) rename modules/tracetest/options.go => models/apiOptions.go (84%) create mode 100644 models/httpClientOptions.go create mode 100644 models/tracetestOptions.go delete mode 100644 modules/httpClient/options.go diff --git a/examples/test-from-id.js b/examples/test-from-id.js index 68f6757..7e33ea8 100644 --- a/examples/test-from-id.js +++ b/examples/test-from-id.js @@ -1,52 +1,45 @@ +import { check } from 'k6'; import { Http, Tracetest } from "k6/x/tracetest"; import { sleep } from "k6"; export const options = { vus: 1, - duration: "5s", + duration: "6s", }; -const http = new Http(); const tracetest = Tracetest({ serverUrl: "http://localhost:3000", }); -const testId = "J0d887oVR"; +const testId = "kc_MgKoVR"; +const pokemonId = 6; +const http = new Http(); export default function () { - /// successful test run - http.get("http://localhost:8081/pokemon?take=5", { + const url = "http://localhost:8081/pokemon/import"; + const payload = JSON.stringify({ + id: pokemonId, + }); + const params = { tracetest: { testId, }, - }); - - /// failed test specs test run - http.get("http://localhost:8081/pokemon?take=10", { - tracetest: { - testId: "nDdBCnoVg", + headers: { + 'Content-Type': 'application/json', }, - }); - - /// not existing test - // http.get("http://localhost:8081/pokemon?take=10", { - // tracetest: { - // testId: "doesnt-exist", - // }, - // }); + }; - /// wrong endpoint - // http.get("http://localhost:8081/wrong", { - // tracetest: { - // testId: "nDdBCnoVg", - // }, - // }); + const response = http.post(url, payload, params); + check(response, { + 'is status 200': (r) => r.status === 200, + 'body matches de id': (r) => JSON.parse(r.body).id === pokemonId, + }); sleep(1); } -export function handleSummary() { - return { - stdout: tracetest.summary(), - 'tracetest.json': tracetest.json(), - }; -} +// export function handleSummary() { +// return { +// stdout: tracetest.summary(), +// "tracetest.json": tracetest.json(), +// }; +// } diff --git a/modules/tracetest/options.go b/models/apiOptions.go similarity index 84% rename from modules/tracetest/options.go rename to models/apiOptions.go index 7f8474b..93d6a49 100644 --- a/modules/tracetest/options.go +++ b/models/apiOptions.go @@ -1,4 +1,4 @@ -package tracetest +package models import ( "fmt" @@ -8,7 +8,7 @@ import ( "go.k6.io/k6/js/modules" ) -type Options struct { +type ApiOptions struct { ServerUrl string ServerPath string } @@ -19,9 +19,9 @@ const ( ServerPath = "serverPath" ) -func getOptions(vu modules.VU, val goja.Value) (Options, error) { +func NewApiOptions(vu modules.VU, val goja.Value) (ApiOptions, error) { rawOptions := utils.ParseOptions(vu, val) - options := Options{ + options := ApiOptions{ ServerUrl: DefaultServerUrl, ServerPath: "", } diff --git a/models/httpClientOptions.go b/models/httpClientOptions.go new file mode 100644 index 0000000..0334150 --- /dev/null +++ b/models/httpClientOptions.go @@ -0,0 +1,58 @@ +package models + +import ( + "fmt" + "strings" + + "github.com/dop251/goja" + "github.com/kubeshop/xk6-tracetest/utils" + "go.k6.io/k6/js/modules" +) + +var defaultPropagatorList = []PropagatorName{ + TraceContext, + Baggage, + PropagatorB3, + OT, + Jaeger, + XRay, +} + +type HttpClientOptions struct { + Propagator Propagator + Tracetest TracetestOptions +} + +func NewHttpClientOptions(vu modules.VU, val goja.Value) (HttpClientOptions, error) { + rawOptions := utils.ParseOptions(vu, val) + options := HttpClientOptions{ + Propagator: NewPropagator(defaultPropagatorList), + Tracetest: TracetestOptions{ + ShouldWait: true, + VariableName: "TRACE_ID", + }, + } + + if len(rawOptions) == 0 { + return options, nil + } + + for key, value := range rawOptions { + switch key { + case "propagator": + rawPropagatorList := strings.Split(value.ToString().String(), ",") + propagatorList := make([]PropagatorName, len(rawPropagatorList)) + for i, propagator := range rawPropagatorList { + propagatorList[i] = PropagatorName(propagator) + } + + options.Propagator = NewPropagator(propagatorList) + case "tracetest": + options.Tracetest = NewTracetestOptions(vu.Runtime(), val.ToObject(vu.Runtime())) + default: + return options, fmt.Errorf("unknown HTTP tracing option '%s'", key) + } + } + + return options, nil +} diff --git a/models/job.go b/models/job.go index 78b7b21..7fe8c6e 100644 --- a/models/job.go +++ b/models/job.go @@ -22,29 +22,33 @@ const ( ) type Job struct { - TraceID string - TestID string - JobType JobType - Request Request - Run *TracetestRun - JobStatus JobStatus - ShouldWait bool + TraceID string + TestID string + VariableName string + JobType JobType + Request Request + Run *TracetestRun + JobStatus JobStatus + TracetestOptions TracetestOptions + Error string } -func NewJob(traceID, testID string, jobType JobType, shouldWait bool, request Request) Job { +func NewJob(traceId string, options TracetestOptions, request Request) Job { return Job{ - TraceID: traceID, - TestID: testID, - JobType: jobType, - Request: request, - JobStatus: Pending, - ShouldWait: shouldWait, + JobType: RunTestFromId, + Request: request, + JobStatus: Pending, + + TraceID: traceId, + TestID: options.TestID, + TracetestOptions: options, } } func (job Job) HandleRunResponse(run *openapi.TestRun, err error) Job { if run == nil { job.JobStatus = Failed + job.Error = err.Error() } else { job.JobStatus = Success job.Run = &TracetestRun{ @@ -57,7 +61,7 @@ func (job Job) HandleRunResponse(run *openapi.TestRun, err error) Job { } func (job Job) Summary(baseUrl string) string { - runSummary := "JobStatus=" + string(job.JobStatus) + runSummary := fmt.Sprintf("JobStatus=%s, Error=%s", string(job.JobStatus), job.Error) if job.Run != nil { runSummary = job.Run.Summary(baseUrl) } diff --git a/models/tracetestOptions.go b/models/tracetestOptions.go new file mode 100644 index 0000000..5b0fea8 --- /dev/null +++ b/models/tracetestOptions.go @@ -0,0 +1,35 @@ +package models + +import "github.com/dop251/goja" + +type TracetestOptions struct { + TestID string + ShouldWait bool + VariableName string +} + +func NewTracetestOptions(runTime *goja.Runtime, params *goja.Object) TracetestOptions { + rawOptions := params.Get("tracetest") + options := TracetestOptions{ + ShouldWait: true, + VariableName: "TRACE_ID", + } + + if rawOptions == nil { + return options + } + + optionsObject := rawOptions.ToObject(runTime) + for _, key := range optionsObject.Keys() { + switch key { + case "testId": + options.TestID = optionsObject.Get(key).String() + case "shouldWait": + options.ShouldWait = optionsObject.Get(key).ToBoolean() + case "variableName": + options.VariableName = optionsObject.Get(key).ToString().String() + } + } + + return options +} diff --git a/modules/httpClient/enhancers.go b/modules/httpClient/enhancers.go index 2eba607..2aa32d3 100644 --- a/modules/httpClient/enhancers.go +++ b/modules/httpClient/enhancers.go @@ -1,20 +1,23 @@ package httpClient import ( + "context" "fmt" "time" "github.com/dop251/goja" "github.com/kubeshop/xk6-tracetest/models" "github.com/kubeshop/xk6-tracetest/utils" + k6HTTP "go.k6.io/k6/js/modules/k6/http" "go.k6.io/k6/lib" "go.k6.io/k6/metrics" ) const ( - TraceID = "trace_id" - TestID = "test_id" - ShouldWait = "should_wait" + TraceID = "trace_id" + TestID = "test_id" + ShouldWait = "should_wait" + VariableName = "variable_name" ) func (c *HttpClient) WithTrace(fn HttpFunc, url goja.Value, args ...goja.Value) (*HTTPResponse, error) { @@ -72,19 +75,21 @@ func (c *HttpClient) WithTrace(fn HttpFunc, url goja.Value, args ...goja.Value) } func (c *HttpClient) setTags(rt *goja.Runtime, state *lib.State, traceID string, params *goja.Object) { - tracetestOptions := parseTracetestOptions(rt, params) + tracetestOptions := models.NewTracetestOptions(rt, params) state.Tags.Modify(func(tagsAndMeta *metrics.TagsAndMeta) { tagsAndMeta.SetMetadata(TraceID, traceID) - if tracetestOptions.testID != "" { - tagsAndMeta.SetMetadata(TestID, tracetestOptions.testID) - } else if c.options.Tracetest.testID != "" { - tagsAndMeta.SetMetadata(TestID, c.options.Tracetest.testID) + if tracetestOptions.TestID != "" { + tagsAndMeta.SetMetadata(TestID, tracetestOptions.TestID) + } else if c.options.Tracetest.TestID != "" { + tagsAndMeta.SetMetadata(TestID, c.options.Tracetest.TestID) } - if tracetestOptions.shouldWait || c.options.Tracetest.shouldWait { + if tracetestOptions.ShouldWait || c.options.Tracetest.ShouldWait { tagsAndMeta.SetMetadata(ShouldWait, "true") } + + tagsAndMeta.SetMetadata(VariableName, tracetestOptions.VariableName) }) } @@ -93,5 +98,12 @@ func (c *HttpClient) deleteTags(state *lib.State) { tagsAndMeta.DeleteMetadata(TraceID) tagsAndMeta.DeleteMetadata(TestID) tagsAndMeta.DeleteMetadata(ShouldWait) + tagsAndMeta.DeleteMetadata(VariableName) }) } + +func requestToHttpFunc(method string, request HttpRequestFunc) HttpFunc { + return func(ctx context.Context, url goja.Value, args ...goja.Value) (*k6HTTP.Response, error) { + return request(method, url, args...) + } +} diff --git a/modules/httpClient/httpClient.go b/modules/httpClient/httpClient.go index 7ee5c69..da6e286 100644 --- a/modules/httpClient/httpClient.go +++ b/modules/httpClient/httpClient.go @@ -5,6 +5,7 @@ import ( "net/http" "github.com/dop251/goja" + "github.com/kubeshop/xk6-tracetest/models" "go.k6.io/k6/js/common" "go.k6.io/k6/js/modules" k6HTTP "go.k6.io/k6/js/modules/k6/http" @@ -14,7 +15,7 @@ type HttpClient struct { vu modules.VU httpRequest HttpRequestFunc - options Options + options models.HttpClientOptions } type HTTPResponse struct { @@ -46,7 +47,7 @@ func New(vu modules.VU) *HttpClient { func (h *HttpClient) Constructor(call goja.ConstructorCall) *goja.Object { rt := h.vu.Runtime() - options, err := getOptions(h.vu, call.Argument(0)) + options, err := models.NewHttpClientOptions(h.vu, call.Argument(0)) if err != nil { common.Throw(rt, err) } diff --git a/modules/httpClient/options.go b/modules/httpClient/options.go deleted file mode 100644 index 329b6c6..0000000 --- a/modules/httpClient/options.go +++ /dev/null @@ -1,94 +0,0 @@ -package httpClient - -import ( - "context" - "fmt" - "strings" - - "github.com/dop251/goja" - "github.com/kubeshop/xk6-tracetest/models" - "github.com/kubeshop/xk6-tracetest/utils" - "go.k6.io/k6/js/modules" - k6HTTP "go.k6.io/k6/js/modules/k6/http" -) - -var defaultPropagatorList = []models.PropagatorName{ - models.TraceContext, - models.Baggage, - models.PropagatorB3, - models.OT, - models.Jaeger, - models.XRay, -} - -type Options struct { - Propagator models.Propagator - Tracetest TracetestOptions -} - -type TracetestOptions struct { - testID string - shouldWait bool -} - -func getOptions(vu modules.VU, val goja.Value) (Options, error) { - rawOptions := utils.ParseOptions(vu, val) - options := Options{ - Propagator: models.NewPropagator(defaultPropagatorList), - Tracetest: TracetestOptions{ - shouldWait: true, - }, - } - - if len(rawOptions) == 0 { - return options, nil - } - - for key, value := range rawOptions { - switch key { - case "propagator": - rawPropagatorList := strings.Split(value.ToString().String(), ",") - propagatorList := make([]models.PropagatorName, len(rawPropagatorList)) - for i, propagator := range rawPropagatorList { - propagatorList[i] = models.PropagatorName(propagator) - } - - options.Propagator = models.NewPropagator(propagatorList) - case "tracetest": - options.Tracetest = parseTracetestOptions(vu.Runtime(), val.ToObject(vu.Runtime())) - default: - return options, fmt.Errorf("unknown HTTP tracing option '%s'", key) - } - } - - return options, nil -} - -func requestToHttpFunc(method string, request HttpRequestFunc) HttpFunc { - return func(ctx context.Context, url goja.Value, args ...goja.Value) (*k6HTTP.Response, error) { - return request(method, url, args...) - } -} - -func parseTracetestOptions(runTime *goja.Runtime, params *goja.Object) TracetestOptions { - rawOptions := params.Get("tracetest") - options := TracetestOptions{ - shouldWait: true, - } - - if rawOptions == nil { - return options - } - - optionsObject := rawOptions.ToObject(runTime) - for _, key := range optionsObject.Keys() { - switch key { - case "testId": - options.testID = optionsObject.Get(key).String() - case "shouldWait": - options.shouldWait = optionsObject.Get(key).ToBoolean() - } - } - - return options -} diff --git a/modules/output/processor.go b/modules/output/processor.go index 08cb165..e968959 100644 --- a/modules/output/processor.go +++ b/modules/output/processor.go @@ -19,6 +19,7 @@ func (o *Output) handleSample(sample metrics.SampleContainer) { func (o *Output) handleHttpSample(trail *httpext.Trail) { traceID, hasTrace := trail.Metadata["trace_id"] testID, hasTestID := trail.Metadata["test_id"] + variableName, _ := trail.Metadata["variable_name"] _, hasShouldWait := trail.Metadata["should_wait"] if !hasTrace || !hasTestID { @@ -59,7 +60,13 @@ func (o *Output) handleHttpSample(trail *httpext.Trail) { Metadata: metadata, } + options := models.TracetestOptions{ + VariableName: variableName, + TestID: testID, + ShouldWait: hasShouldWait, + } + if hasTestID { - o.tracetest.RunTest(testID, traceID, hasShouldWait, request) + o.tracetest.RunTest(traceID, options, request) } } diff --git a/modules/tracetest/api.go b/modules/tracetest/api.go index 05680dd..8b6a7cb 100644 --- a/modules/tracetest/api.go +++ b/modules/tracetest/api.go @@ -11,7 +11,7 @@ import ( "github.com/kubeshop/xk6-tracetest/openapi" ) -func NewAPIClient(options Options) *openapi.APIClient { +func NewAPIClient(options models.ApiOptions) *openapi.APIClient { url, err := url.Parse(options.ServerUrl) if err != nil { @@ -33,15 +33,14 @@ func NewAPIClient(options Options) *openapi.APIClient { return openapi.NewAPIClient(config) } -func (t *Tracetest) runTest(testID, traceId string, metadata models.Metadata) (*openapi.TestRun, error) { - request := t.client.ApiApi.RunTest(context.Background(), testID) - key := "TRACE_ID" +func (t *Tracetest) runTest(job models.Job) (*openapi.TestRun, error) { + request := t.client.ApiApi.RunTest(context.Background(), job.TestID) request = request.RunInformation(openapi.RunInformation{ Variables: []openapi.EnvironmentValue{{ - Key: &key, - Value: &traceId, + Key: &job.TracetestOptions.VariableName, + Value: &job.TraceID, }}, - Metadata: metadata, + Metadata: job.Request.Metadata, }) run, _, err := t.client.ApiApi.RunTestExecute(request) @@ -112,10 +111,10 @@ func (t *Tracetest) stringSummary() string { if job, ok := value.(models.Job); ok { totalRuns += 1 if job.IsSuccessful() { - successfulSummary += fmt.Sprintf("[%s] \n", job.Summary(t.options.ServerUrl)) + successfulSummary += fmt.Sprintf("[%s] \n", job.Summary(t.apiOptions.ServerUrl)) successfulRuns += 1 } else { - failedSummary += fmt.Sprintf("[%s] \n", job.Summary(t.options.ServerUrl)) + failedSummary += fmt.Sprintf("[%s] \n", job.Summary(t.apiOptions.ServerUrl)) failedRuns += 1 } } diff --git a/modules/tracetest/queue.go b/modules/tracetest/queue.go index 48d8417..038660e 100644 --- a/modules/tracetest/queue.go +++ b/modules/tracetest/queue.go @@ -32,10 +32,9 @@ func (t *Tracetest) parallelJobProcessor(jobs []models.Job) { go func(job models.Job) { defer waitGroup.Done() - run, err := t.runTest(job.TestID, job.TraceID, job.Request.Metadata) + run, err := t.runTest(job) job = job.HandleRunResponse(run, err) - - if job.ShouldWait && run != nil { + if job.TracetestOptions.ShouldWait && run != nil { run, err := t.waitForTestResult(job.TestID, *run.Id) job = job.HandleRunResponse(&run, err) } diff --git a/modules/tracetest/tracetest.go b/modules/tracetest/tracetest.go index 7107526..e94fd10 100644 --- a/modules/tracetest/tracetest.go +++ b/modules/tracetest/tracetest.go @@ -22,7 +22,7 @@ type Tracetest struct { periodicFlusher *output.PeriodicFlusher logger logrus.FieldLogger client *openapi.APIClient - options Options + apiOptions models.ApiOptions } func New() *Tracetest { @@ -31,6 +31,7 @@ func New() *Tracetest { buffer: []models.Job{}, processedBuffer: sync.Map{}, logger: logger.WithField("component", "xk6-tracetest-tracing"), + client: NewAPIClient(models.ApiOptions{}), } duration := 1 * time.Second @@ -42,19 +43,19 @@ func New() *Tracetest { func (t *Tracetest) Constructor(call goja.ConstructorCall) *goja.Object { rt := t.Vu.Runtime() - options, err := getOptions(t.Vu, call.Argument(0)) + apiOptions, err := models.NewApiOptions(t.Vu, call.Argument(0)) if err != nil { common.Throw(rt, err) } - t.options = options - t.client = NewAPIClient(options) + t.apiOptions = apiOptions + t.client = NewAPIClient(apiOptions) return rt.ToValue(t).ToObject(rt) } -func (t *Tracetest) RunTest(testID, traceID string, shouldWait bool, request models.Request) { - t.queueJob(models.NewJob(traceID, testID, models.RunTestFromId, shouldWait, request)) +func (t *Tracetest) RunTest(traceID string, options models.TracetestOptions, request models.Request) { + t.queueJob(models.NewJob(traceID, options, request)) } func (t *Tracetest) Summary() string {