From c98bb4dc71380038fa414b27ccc2aeb63affd816 Mon Sep 17 00:00:00 2001 From: Navin Shrinivas Date: Wed, 31 Jan 2024 12:04:11 +0530 Subject: [PATCH] Add fixtures and Unit tests for API Signed-off-by: Navin Shrinivas --- cmd/query/app/fixture/otlp2jaeger-in.json | 52 ++++++++++++++++ cmd/query/app/fixture/otlp2jaeger-out.json | 59 ++++++++++++++++++ cmd/query/app/http_handler.go | 6 +- cmd/query/app/http_handler_test.go | 51 ++++++++++++++++ cmd/query/app/otlp_translator.go | 51 +++++++--------- cmd/query/app/otlp_translator_test.go | 69 +--------------------- 6 files changed, 187 insertions(+), 101 deletions(-) create mode 100644 cmd/query/app/fixture/otlp2jaeger-in.json create mode 100644 cmd/query/app/fixture/otlp2jaeger-out.json diff --git a/cmd/query/app/fixture/otlp2jaeger-in.json b/cmd/query/app/fixture/otlp2jaeger-in.json new file mode 100644 index 00000000000..39577361e72 --- /dev/null +++ b/cmd/query/app/fixture/otlp2jaeger-in.json @@ -0,0 +1,52 @@ +{ + "resourceSpans":[ + { + "resource":{ + "attributes":[ + { + "key":"service.name", + "value":{ + "stringValue":"telemetrygen" + } + } + ] + }, + "scopeSpans":[ + { + "scope":{ + "name":"telemetrygen" + }, + "spans":[ + { + "traceId":"83a9efd15c1c98a977e0711cc93ee28b", + "spanId":"e127af99e3b3e074", + "parentSpanId":"909541b92cf05311", + "name":"okey-dokey-0", + "kind":2, + "startTimeUnixNano":"1706678909209712000", + "endTimeUnixNano":"1706678909209835000", + "attributes":[ + { + "key":"net.peer.ip", + "value":{ + "stringValue":"1.2.3.4" + } + }, + { + "key":"peer.service", + "value":{ + "stringValue":"telemetrygen-client" + } + } + ], + "status":{ + + } + } + ] + } + ], + "schemaUrl":"https://opentelemetry.io/schemas/1.4.0" + } + ] +} diff --git a/cmd/query/app/fixture/otlp2jaeger-out.json b/cmd/query/app/fixture/otlp2jaeger-out.json new file mode 100644 index 00000000000..3041467c0d4 --- /dev/null +++ b/cmd/query/app/fixture/otlp2jaeger-out.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "traceID": "83a9efd15c1c98a977e0711cc93ee28b", + "spans": [ + { + "traceID": "83a9efd15c1c98a977e0711cc93ee28b", + "spanID": "e127af99e3b3e074", + "operationName": "okey-dokey-0", + "references": [ + { + "refType": "CHILD_OF", + "traceID": "83a9efd15c1c98a977e0711cc93ee28b", + "spanID": "909541b92cf05311" + } + ], + "startTime": 1706678909209712, + "duration": 123, + "tags": [ + { + "key": "otel.library.name", + "type": "string", + "value": "telemetrygen" + }, + { + "key": "net.peer.ip", + "type": "string", + "value": "1.2.3.4" + }, + { + "key": "peer.service", + "type": "string", + "value": "telemetrygen-client" + }, + { + "key": "span.kind", + "type": "string", + "value": "server" + } + ], + "logs": [], + "processID": "p1", + "warnings": null + } + ], + "processes": { + "p1": { + "serviceName": "telemetrygen", + "tags": [] + } + }, + "warnings": null + } + ], + "total": 0, + "limit": 0, + "offset": 0, + "errors": null +} diff --git a/cmd/query/app/http_handler.go b/cmd/query/app/http_handler.go index 283703e24d7..bc769de0579 100644 --- a/cmd/query/app/http_handler.go +++ b/cmd/query/app/http_handler.go @@ -202,13 +202,13 @@ func (aH *APIHandler) transformOTLP(w http.ResponseWriter, r *http.Request) { } var uiErrors []structuredError - batches, err := OTLP2model(body) + batches, err := otlp2model(body) if aH.handleError(w, err, http.StatusInternalServerError) { return } - traces, err := BatchesToTraces(batches) + traces, err := batchesToTraces(batches) if aH.handleError(w, err, http.StatusInternalServerError) { return @@ -217,7 +217,7 @@ func (aH *APIHandler) transformOTLP(w http.ResponseWriter, r *http.Request) { uiTraces := make([]*ui.Trace, len(traces)) for i, v := range traces { - uiTrace, uiErr := aH.convertModelToUI(&v, false) + uiTrace, uiErr := aH.convertModelToUI(v, false) if uiErr != nil { uiErrors = append(uiErrors, *uiErr) } diff --git a/cmd/query/app/http_handler_test.go b/cmd/query/app/http_handler_test.go index d3d1507078e..3602cd18f77 100644 --- a/cmd/query/app/http_handler_test.go +++ b/cmd/query/app/http_handler_test.go @@ -25,6 +25,7 @@ import ( "math" "net/http" "net/http/httptest" + "os" "testing" "time" @@ -270,6 +271,33 @@ func TestWriteJSON(t *testing.T) { } } +func readOTLPTraces(t *testing.T) (interface{}, error) { + dat, err := os.ReadFile("./fixture/otlp2jaeger-in.json") + if err != nil { + return nil, err + } else { + require.NoError(t, err) + var out interface{} + err := json.Unmarshal(dat, out) + require.NoError(t, err) + return out, nil + + } +} + +func readJaegerTraces(t *testing.T) (interface{}, error) { + dat, err := os.ReadFile("./fixture/otlp2jaeger-out.json") + if err != nil { + return nil, err + } else { + var out interface{} + require.NoError(t, err) + err := json.Unmarshal(dat, out) + require.NoError(t, err) + return out, nil + } +} + func TestGetTrace(t *testing.T) { testCases := []struct { suffix string @@ -623,6 +651,29 @@ func TestGetOperationsLegacyStorageFailure(t *testing.T) { require.Error(t, err) } +func TestTransformOTLPSuccess(t *testing.T) { + withTestServer(func(ts *testServer) { + var response interface{} + request, err := readOTLPTraces(t) + require.NoError(t, err) + err = postJSON(ts.server.URL+"/api/transform", request, response) + require.NoError(t, err) + corectResponse, err := readJaegerTraces(t) + require.NoError(t, err) + assert.Equal(t, response, corectResponse) + }, querysvc.QueryServiceOptions{}) +} + +func TestTransformOTLPEmptyFailure(t *testing.T) { + withTestServer(func(ts *testServer) { + var response interface{} + var request interface{} // Keeping request empty for checking behaviour + request = "" + err := postJSON(ts.server.URL+"/api/transform", request, response) + require.Error(t, err) + }, querysvc.QueryServiceOptions{}) +} + func TestGetMetricsSuccess(t *testing.T) { mr := &metricsmocks.Reader{} apiHandlerOptions := []HandlerOption{ diff --git a/cmd/query/app/otlp_translator.go b/cmd/query/app/otlp_translator.go index 1e2d1494f82..26a4728c92c 100644 --- a/cmd/query/app/otlp_translator.go +++ b/cmd/query/app/otlp_translator.go @@ -23,7 +23,7 @@ import ( "github.com/jaegertracing/jaeger/model" ) -func OTLP2model(OTLPSpans []byte) ([]*model.Batch, error) { +func otlp2model(OTLPSpans []byte) ([]*model.Batch, error) { ptraceUnmarshaler := ptrace.JSONUnmarshaler{} otlpTraces, err := ptraceUnmarshaler.UnmarshalTraces(OTLPSpans) if err != nil { @@ -33,39 +33,28 @@ func OTLP2model(OTLPSpans []byte) ([]*model.Batch, error) { if err != nil { return nil, fmt.Errorf("cannot transform OTLP to Jaeger: %w", err) } - return jaegerBatches, nil } -func BatchesToTraces(jaegerBatches []*model.Batch) ([]model.Trace, error) { - var jaegerTraces []model.Trace - spanMap := make(map[model.TraceID][]*model.Span) - for _, v := range jaegerBatches { - DenormalizeProcess(v) - FlattenToSpansMaps(v, spanMap) - } - for _, v := range spanMap { - jaegerTrace := model.Trace{ - Spans: v, - } - jaegerTraces = append(jaegerTraces, jaegerTrace) - } - return jaegerTraces, nil -} - -func DenormalizeProcess(m *model.Batch) { - for _, v := range m.Spans { - v.Process = m.Process - } -} - -func FlattenToSpansMaps(m *model.Batch, spanMap map[model.TraceID][]*model.Span) { - for _, v := range m.Spans { - val, ok := spanMap[v.TraceID] - if !ok { - spanMap[v.TraceID] = []*model.Span{v} - } else { - spanMap[v.TraceID] = append(val, v) +func batchesToTraces(jaegerBatches []*model.Batch) ([]*model.Trace, error) { + var traces []*model.Trace + traceMap := make(map[model.TraceID]*model.Trace) + for _, batch := range jaegerBatches { + for _, span := range batch.Spans { + if span.Process == nil { + span.Process = batch.Process + } + trace, ok := traceMap[span.TraceID] + if !ok { + newtrace := model.Trace{ + Spans: []*model.Span{span}, + } + traceMap[span.TraceID] = &newtrace + traces = append(traces, &newtrace) + } else { + trace.Spans = append(trace.Spans, span) + } } } + return traces, nil } diff --git a/cmd/query/app/otlp_translator_test.go b/cmd/query/app/otlp_translator_test.go index 56edc6ba0cf..60b6fd77286 100644 --- a/cmd/query/app/otlp_translator_test.go +++ b/cmd/query/app/otlp_translator_test.go @@ -30,7 +30,7 @@ func TestBatchesToTraces(t *testing.T) { mainBatch := []*model.Batch{b1, b2} - traces, err := BatchesToTraces(mainBatch) + traces, err := batchesToTraces(mainBatch) require.Nil(t, err) s1 := []*model.Span{ @@ -63,71 +63,6 @@ func TestBatchesToTraces(t *testing.T) { t2 := model.Trace{ Spans: s2, } - mainTrace := []model.Trace{t1, t2} + mainTrace := []*model.Trace{&t1, &t2} assert.Equal(t, mainTrace, traces) } - -func TestFlattenToSpanMaps(t *testing.T) { - b1 := &model.Batch{ - Spans: []*model.Span{ - {TraceID: model.NewTraceID(1, 2), SpanID: model.NewSpanID(1), OperationName: "x"}, - {TraceID: model.NewTraceID(1, 3), SpanID: model.NewSpanID(2), OperationName: "y"}, - }, - } - - b2 := &model.Batch{ - Spans: []*model.Span{ - {TraceID: model.NewTraceID(1, 2), SpanID: model.NewSpanID(2), OperationName: "z"}, - }, - } - - t1 := []*model.Span{ - {TraceID: model.NewTraceID(1, 2), SpanID: model.NewSpanID(1), OperationName: "x"}, - {TraceID: model.NewTraceID(1, 2), SpanID: model.NewSpanID(2), OperationName: "z"}, - } - - t2 := []*model.Span{{TraceID: model.NewTraceID(1, 3), SpanID: model.NewSpanID(2), OperationName: "y"}} - spanMap := make(map[model.TraceID][]*model.Span) - FlattenToSpansMaps(b1, spanMap) - FlattenToSpansMaps(b2, spanMap) - assert.Equal(t, t1, spanMap[model.NewTraceID(1, 2)]) - assert.Equal(t, t2, spanMap[model.NewTraceID(1, 3)]) -} - -func TestDenormalizeProcess(t *testing.T) { - b1 := &model.Batch{ - Spans: []*model.Span{ - { - TraceID: model.NewTraceID(1, 2), - SpanID: model.NewSpanID(1), - OperationName: "x", - }, - { - TraceID: model.NewTraceID(1, 3), - SpanID: model.NewSpanID(2), - OperationName: "y", - }, - }, - Process: model.NewProcess("process1", model.KeyValues{}), - } - - b2 := &model.Batch{ - Spans: []*model.Span{ - { - TraceID: model.NewTraceID(1, 2), - SpanID: model.NewSpanID(1), - OperationName: "x", - Process: model.NewProcess("process1", model.KeyValues{}), - }, - { - TraceID: model.NewTraceID(1, 3), - SpanID: model.NewSpanID(2), - OperationName: "y", - Process: model.NewProcess("process1", model.KeyValues{}), - }, - }, - Process: model.NewProcess("process1", model.KeyValues{}), - } - DenormalizeProcess(b1) - assert.Equal(t, b1, b2) -}