Skip to content

Commit 17cdd33

Browse files
Add unit test for OTLP receiver in jaeger-v1 (#6541)
## Which problem is this PR solving? - Resolves #6535 ## Description of the changes - Added unit test ## How was this change tested? - ## Checklist - [ ] I have read https://github.com/jaegertracing/jaeger/blob/master/CONTRIBUTING_GUIDELINES.md - [ ] I have signed all commits - [ ] I have added unit tests for the new functionality - [ ] I have run lint and test steps successfully - for `jaeger`: `make lint test` - for `jaeger-ui`: `npm run lint` and `npm run test` --------- Signed-off-by: chahatsagarmain <[email protected]> Signed-off-by: Yuri Shkuro <[email protected]> Signed-off-by: chahat sagar <[email protected]> Co-authored-by: Yuri Shkuro <[email protected]>
1 parent e04abb0 commit 17cdd33

File tree

5 files changed

+303
-50
lines changed

5 files changed

+303
-50
lines changed

cmd/collector/app/handler/grpc_handler.go

+1-19
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"go.uber.org/zap"
1111
"google.golang.org/grpc/codes"
1212
_ "google.golang.org/grpc/encoding/gzip" // register zip encoding
13-
"google.golang.org/grpc/metadata"
1413
"google.golang.org/grpc/status"
1514

1615
"github.com/jaegertracing/jaeger-idl/model/v1"
@@ -97,22 +96,5 @@ func (c *batchConsumer) validateTenant(ctx context.Context) (string, error) {
9796
if !c.tenancyMgr.Enabled {
9897
return "", nil
9998
}
100-
101-
md, ok := metadata.FromIncomingContext(ctx)
102-
if !ok {
103-
return "", status.Errorf(codes.PermissionDenied, "missing tenant header")
104-
}
105-
106-
tenants := md.Get(c.tenancyMgr.Header)
107-
if len(tenants) < 1 {
108-
return "", status.Errorf(codes.PermissionDenied, "missing tenant header")
109-
} else if len(tenants) > 1 {
110-
return "", status.Errorf(codes.PermissionDenied, "extra tenant header")
111-
}
112-
113-
if !c.tenancyMgr.Valid(tenants[0]) {
114-
return "", status.Errorf(codes.PermissionDenied, "unknown tenant")
115-
}
116-
117-
return tenants[0], nil
99+
return tenancy.GetValidTenant(ctx, c.tenancyMgr)
118100
}

cmd/collector/app/span_processor_test.go

+225
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,43 @@ import (
1010
"errors"
1111
"fmt"
1212
"io"
13+
"net/http"
1314
"reflect"
1415
"slices"
16+
"strings"
1517
"sync"
1618
"sync/atomic"
1719
"testing"
1820
"time"
1921

2022
"github.com/gogo/protobuf/jsonpb"
2123
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/mock"
2225
"github.com/stretchr/testify/require"
26+
"go.opentelemetry.io/collector/config/configgrpc"
27+
"go.opentelemetry.io/collector/config/confighttp"
28+
"go.opentelemetry.io/collector/config/confignet"
29+
"go.opentelemetry.io/collector/pdata/ptrace"
30+
otlptrace "go.opentelemetry.io/proto/otlp/collector/trace/v1"
31+
tracepb "go.opentelemetry.io/proto/otlp/trace/v1"
2332
"go.uber.org/zap"
33+
"go.uber.org/zap/zaptest"
34+
"google.golang.org/grpc"
35+
"google.golang.org/grpc/credentials/insecure"
36+
"google.golang.org/grpc/metadata"
2437

2538
"github.com/jaegertracing/jaeger-idl/model/v1"
2639
"github.com/jaegertracing/jaeger-idl/thrift-gen/jaeger"
2740
zc "github.com/jaegertracing/jaeger-idl/thrift-gen/zipkincore"
41+
cFlags "github.com/jaegertracing/jaeger/cmd/collector/app/flags"
2842
"github.com/jaegertracing/jaeger/cmd/collector/app/handler"
2943
"github.com/jaegertracing/jaeger/cmd/collector/app/processor"
3044
zipkinsanitizer "github.com/jaegertracing/jaeger/cmd/collector/app/sanitizer/zipkin"
3145
"github.com/jaegertracing/jaeger/internal/metricstest"
3246
"github.com/jaegertracing/jaeger/pkg/metrics"
3347
"github.com/jaegertracing/jaeger/pkg/tenancy"
3448
"github.com/jaegertracing/jaeger/pkg/testutils"
49+
"github.com/jaegertracing/jaeger/storage_v2/tracestore/mocks"
3550
"github.com/jaegertracing/jaeger/storage_v2/v1adapter"
3651
)
3752

@@ -807,3 +822,213 @@ func TestSpanProcessorWithOnDroppedSpanOption(t *testing.T) {
807822
require.EqualError(t, err, processor.ErrBusy.Error())
808823
assert.Equal(t, []string{"op3"}, droppedOperations)
809824
}
825+
826+
func optionsWithPorts(portHttp string, portGrpc string) *cFlags.CollectorOptions {
827+
opts := &cFlags.CollectorOptions{
828+
OTLP: struct {
829+
Enabled bool
830+
GRPC configgrpc.ServerConfig
831+
HTTP confighttp.ServerConfig
832+
}{
833+
Enabled: true,
834+
HTTP: confighttp.ServerConfig{
835+
Endpoint: portHttp,
836+
IncludeMetadata: true,
837+
},
838+
GRPC: configgrpc.ServerConfig{
839+
NetAddr: confignet.AddrConfig{
840+
Endpoint: portGrpc,
841+
Transport: confignet.TransportTypeTCP,
842+
},
843+
},
844+
},
845+
}
846+
return opts
847+
}
848+
849+
func TestOTLPReceiverWithV2Storage(t *testing.T) {
850+
tests := []struct {
851+
name string
852+
requestType string
853+
tenant string
854+
expectedTenant string
855+
expectedError bool
856+
executeRequest func(ctx context.Context, url string, tenant string) error
857+
}{
858+
{
859+
name: "Valid tenant via HTTP",
860+
requestType: "http",
861+
tenant: "test-tenant",
862+
expectedTenant: "test-tenant",
863+
expectedError: false,
864+
executeRequest: sendHTTPRequest,
865+
},
866+
{
867+
name: "Invalid tenant via HTTP",
868+
requestType: "http",
869+
tenant: "invalid-tenant",
870+
expectedTenant: "",
871+
expectedError: true,
872+
executeRequest: sendHTTPRequest,
873+
},
874+
{
875+
name: "Valid tenant via gRPC",
876+
requestType: "grpc",
877+
tenant: "test-tenant",
878+
expectedTenant: "test-tenant",
879+
expectedError: false,
880+
executeRequest: sendGRPCRequest,
881+
},
882+
{
883+
name: "Invalid tenant via gRPC",
884+
requestType: "grpc",
885+
tenant: "invalid-tenant",
886+
expectedTenant: "",
887+
expectedError: true,
888+
executeRequest: sendGRPCRequest,
889+
},
890+
}
891+
892+
for _, tt := range tests {
893+
t.Run(tt.name, func(t *testing.T) {
894+
mockWriter := mocks.NewWriter(t)
895+
896+
spanProcessor, err := NewSpanProcessor(
897+
mockWriter,
898+
nil,
899+
Options.NumWorkers(1),
900+
Options.QueueSize(1),
901+
Options.ReportBusy(true),
902+
)
903+
require.NoError(t, err)
904+
defer spanProcessor.Close()
905+
logger := zaptest.NewLogger(t)
906+
907+
portHttp := "4317"
908+
portGrpc := "4318"
909+
910+
var receivedTraces atomic.Pointer[ptrace.Traces]
911+
var receivedCtx atomic.Pointer[context.Context]
912+
if !tt.expectedError {
913+
mockWriter.On("WriteTraces", mock.Anything, mock.Anything).
914+
Run(func(args mock.Arguments) {
915+
storeContext := args.Get(0).(context.Context)
916+
storeTrace := args.Get(1).(ptrace.Traces)
917+
receivedTraces.Store(&storeTrace)
918+
receivedCtx.Store(&storeContext)
919+
}).Return(nil)
920+
}
921+
922+
tenancyMgr := tenancy.NewManager(&tenancy.Options{
923+
Enabled: true,
924+
Header: "x-tenant",
925+
Tenants: []string{"test-tenant"},
926+
})
927+
928+
rec, err := handler.StartOTLPReceiver(
929+
optionsWithPorts(fmt.Sprintf("localhost:%v", portHttp), fmt.Sprintf("localhost:%v", portGrpc)),
930+
logger,
931+
spanProcessor,
932+
tenancyMgr,
933+
)
934+
require.NoError(t, err)
935+
ctx := context.Background()
936+
defer rec.Shutdown(ctx)
937+
938+
var url string
939+
if tt.requestType == "http" {
940+
url = fmt.Sprintf("http://localhost:%v/v1/traces", portHttp)
941+
} else {
942+
url = fmt.Sprintf("localhost:%v", portGrpc)
943+
}
944+
err = tt.executeRequest(ctx, url, tt.tenant)
945+
if tt.expectedError {
946+
assert.Error(t, err)
947+
return
948+
}
949+
require.NoError(t, err)
950+
951+
assert.Eventually(t, func() bool {
952+
storedTraces := receivedTraces.Load()
953+
storedCtx := receivedCtx.Load()
954+
if storedTraces == nil || storedCtx == nil {
955+
return false
956+
}
957+
receivedSpan := storedTraces.ResourceSpans().At(0).
958+
ScopeSpans().At(0).
959+
Spans().At(0)
960+
receivedTenant := tenancy.GetTenant(*storedCtx)
961+
return receivedSpan.Name() == "test-trace" && receivedTenant == tt.expectedTenant
962+
}, 1*time.Second, 100*time.Millisecond)
963+
964+
mockWriter.AssertExpectations(t)
965+
})
966+
}
967+
}
968+
969+
// Helper function to send HTTP request
970+
func sendHTTPRequest(ctx context.Context, url string, tenant string) error {
971+
traceJSON := `{
972+
"resourceSpans": [{
973+
"scopeSpans": [{
974+
"spans": [{
975+
"name": "test-trace"
976+
}]
977+
}]
978+
}]
979+
}`
980+
981+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, strings.NewReader(traceJSON))
982+
if err != nil {
983+
return err
984+
}
985+
req.Header.Set("Content-Type", "application/json")
986+
req.Header.Set("x-tenant", tenant)
987+
988+
resp, err := http.DefaultClient.Do(req)
989+
if err != nil {
990+
return err
991+
}
992+
defer resp.Body.Close()
993+
if resp.StatusCode != http.StatusOK {
994+
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
995+
}
996+
return nil
997+
}
998+
999+
// Helper function to send gRPC request
1000+
func sendGRPCRequest(ctx context.Context, url string, tenant string) error {
1001+
conn, err := grpc.NewClient(
1002+
url,
1003+
grpc.WithTransportCredentials(insecure.NewCredentials()),
1004+
)
1005+
if err != nil {
1006+
return err
1007+
}
1008+
defer conn.Close()
1009+
1010+
md := metadata.New(map[string]string{
1011+
"x-tenant": tenant,
1012+
})
1013+
ctxWithMD := metadata.NewOutgoingContext(ctx, md)
1014+
1015+
client := otlptrace.NewTraceServiceClient(conn)
1016+
req := &otlptrace.ExportTraceServiceRequest{
1017+
ResourceSpans: []*tracepb.ResourceSpans{
1018+
{
1019+
ScopeSpans: []*tracepb.ScopeSpans{
1020+
{
1021+
Spans: []*tracepb.Span{
1022+
{
1023+
Name: "test-trace",
1024+
},
1025+
},
1026+
},
1027+
},
1028+
},
1029+
},
1030+
}
1031+
1032+
_, err = client.Export(ctxWithMD, req)
1033+
return err
1034+
}

cmd/jaeger/internal/extension/remotesampling/extension.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func (ext *rsExtension) startFileBasedStrategyProvider(_ context.Context) error
172172
}
173173

174174
// contextcheck linter complains about next line that context is not passed.
175-
//nolint
175+
//nolint:contextcheck
176176
provider, err := file.NewProvider(opts, ext.telemetry.Logger)
177177
if err != nil {
178178
return fmt.Errorf("failed to create the local file strategy store: %w", err)

0 commit comments

Comments
 (0)