From c03bf9905c065b125ff827dc71e3159c38e3fff4 Mon Sep 17 00:00:00 2001 From: Shivanshu Raj Shrivastava Date: Tue, 29 Apr 2025 17:13:11 +0530 Subject: [PATCH] test: add more tests to utils Signed-off-by: Shivanshu Raj Shrivastava --- pkg/modules/tracefunnel/utils_test.go | 322 ++++++++++++++++++++++++++ 1 file changed, 322 insertions(+) diff --git a/pkg/modules/tracefunnel/utils_test.go b/pkg/modules/tracefunnel/utils_test.go index d9f8f87872..2f7ed891b1 100644 --- a/pkg/modules/tracefunnel/utils_test.go +++ b/pkg/modules/tracefunnel/utils_test.go @@ -1,9 +1,13 @@ package tracefunnel import ( + "net/http" + "net/http/httptest" "testing" "time" + "github.com/SigNoz/signoz/pkg/types" + "github.com/SigNoz/signoz/pkg/types/authtypes" tracefunnel "github.com/SigNoz/signoz/pkg/types/tracefunnel" "github.com/SigNoz/signoz/pkg/valuer" "github.com/stretchr/testify/assert" @@ -333,3 +337,321 @@ func TestNormalizeFunnelSteps(t *testing.T) { }) } } + +func TestGetClaims(t *testing.T) { + tests := []struct { + name string + setup func(*http.Request) + expectError bool + }{ + { + name: "valid claims", + setup: func(r *http.Request) { + claims := authtypes.Claims{ + UserID: "user-123", + OrgID: "org-123", + Email: "test@example.com", + } + *r = *r.WithContext(authtypes.NewContextWithClaims(r.Context(), claims)) + }, + expectError: false, + }, + { + name: "no claims in context", + setup: func(r *http.Request) {}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest("GET", "/", nil) + tt.setup(req) + + claims, err := GetClaims(req) + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, claims) + } else { + assert.NoError(t, err) + assert.NotNil(t, claims) + assert.Equal(t, "user-123", claims.UserID) + assert.Equal(t, "org-123", claims.OrgID) + assert.Equal(t, "test@example.com", claims.Email) + } + }) + } +} + +func TestValidateAndConvertTimestamp(t *testing.T) { + tests := []struct { + name string + timestamp int64 + expectError bool + }{ + { + name: "valid timestamp", + timestamp: time.Now().UnixMilli(), + expectError: false, + }, + { + name: "zero timestamp", + timestamp: 0, + expectError: true, + }, + { + name: "negative timestamp", + timestamp: -1, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ValidateAndConvertTimestamp(tt.timestamp) + if tt.expectError { + assert.Error(t, err) + assert.True(t, result.IsZero()) + } else { + assert.NoError(t, err) + assert.False(t, result.IsZero()) + // Verify the conversion from milliseconds to nanoseconds + assert.Equal(t, tt.timestamp*1000000, result.UnixNano()) + } + }) + } +} + +func TestConstructFunnelResponse(t *testing.T) { + now := time.Now() + funnelID := valuer.GenerateUUID() + orgID := valuer.GenerateUUID() + + tests := []struct { + name string + funnel *tracefunnel.Funnel + claims *authtypes.Claims + expected tracefunnel.FunnelResponse + }{ + { + name: "with user email from funnel", + funnel: &tracefunnel.Funnel{ + BaseMetadata: tracefunnel.BaseMetadata{ + Identifiable: types.Identifiable{ + ID: funnelID, + }, + Name: "test-funnel", + OrgID: orgID, + TimeAuditable: types.TimeAuditable{ + CreatedAt: now, + UpdatedAt: now, + }, + UserAuditable: types.UserAuditable{ + CreatedBy: "user-123", + UpdatedBy: "user-123", + }, + }, + CreatedByUser: &types.User{ + ID: "user-123", + Email: "funnel@example.com", + }, + Steps: []tracefunnel.FunnelStep{ + { + Id: valuer.GenerateUUID(), + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: 1, + }, + }, + }, + claims: &authtypes.Claims{ + UserID: "user-123", + OrgID: orgID.String(), + Email: "claims@example.com", + }, + expected: tracefunnel.FunnelResponse{ + FunnelName: "test-funnel", + FunnelID: funnelID.String(), + Steps: []tracefunnel.FunnelStep{ + { + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: 1, + }, + }, + CreatedAt: now.UnixNano() / 1000000, + CreatedBy: "user-123", + UpdatedAt: now.UnixNano() / 1000000, + UpdatedBy: "user-123", + OrgID: orgID.String(), + UserEmail: "funnel@example.com", + }, + }, + { + name: "with user email from claims", + funnel: &tracefunnel.Funnel{ + BaseMetadata: tracefunnel.BaseMetadata{ + Identifiable: types.Identifiable{ + ID: funnelID, + }, + Name: "test-funnel", + OrgID: orgID, + TimeAuditable: types.TimeAuditable{ + CreatedAt: now, + UpdatedAt: now, + }, + UserAuditable: types.UserAuditable{ + CreatedBy: "user-123", + UpdatedBy: "user-123", + }, + }, + Steps: []tracefunnel.FunnelStep{ + { + Id: valuer.GenerateUUID(), + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: 1, + }, + }, + }, + claims: &authtypes.Claims{ + UserID: "user-123", + OrgID: orgID.String(), + Email: "claims@example.com", + }, + expected: tracefunnel.FunnelResponse{ + FunnelName: "test-funnel", + FunnelID: funnelID.String(), + Steps: []tracefunnel.FunnelStep{ + { + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: 1, + }, + }, + CreatedAt: now.UnixNano() / 1000000, + CreatedBy: "user-123", + UpdatedAt: now.UnixNano() / 1000000, + UpdatedBy: "user-123", + OrgID: orgID.String(), + UserEmail: "claims@example.com", + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := ConstructFunnelResponse(tt.funnel, tt.claims) + + // Compare top-level fields + assert.Equal(t, tt.expected.FunnelName, result.FunnelName) + assert.Equal(t, tt.expected.FunnelID, result.FunnelID) + assert.Equal(t, tt.expected.CreatedAt, result.CreatedAt) + assert.Equal(t, tt.expected.CreatedBy, result.CreatedBy) + assert.Equal(t, tt.expected.UpdatedAt, result.UpdatedAt) + assert.Equal(t, tt.expected.UpdatedBy, result.UpdatedBy) + assert.Equal(t, tt.expected.OrgID, result.OrgID) + assert.Equal(t, tt.expected.UserEmail, result.UserEmail) + + // Compare steps + assert.Len(t, result.Steps, len(tt.expected.Steps)) + for i, step := range result.Steps { + expectedStep := tt.expected.Steps[i] + assert.Equal(t, expectedStep.Name, step.Name) + assert.Equal(t, expectedStep.ServiceName, step.ServiceName) + assert.Equal(t, expectedStep.SpanName, step.SpanName) + assert.Equal(t, expectedStep.Order, step.Order) + } + }) + } +} + +func TestProcessFunnelSteps(t *testing.T) { + tests := []struct { + name string + steps []tracefunnel.FunnelStep + expectError bool + }{ + { + name: "valid steps with missing IDs", + steps: []tracefunnel.FunnelStep{ + { + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: 0, // Will be normalized to 1 + }, + { + Name: "Step 2", + ServiceName: "test-service", + SpanName: "test-span-2", + Order: 0, // Will be normalized to 2 + }, + }, + expectError: false, + }, + { + name: "invalid steps - missing service name", + steps: []tracefunnel.FunnelStep{ + { + Name: "Step 1", + SpanName: "test-span", + Order: 1, + }, + { + Name: "Step 2", + ServiceName: "test-service", + SpanName: "test-span-2", + Order: 2, + }, + }, + expectError: true, + }, + { + name: "invalid steps - negative order", + steps: []tracefunnel.FunnelStep{ + { + Name: "Step 1", + ServiceName: "test-service", + SpanName: "test-span", + Order: -1, + }, + { + Name: "Step 2", + ServiceName: "test-service", + SpanName: "test-span-2", + Order: 2, + }, + }, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := ProcessFunnelSteps(tt.steps) + if tt.expectError { + assert.Error(t, err) + assert.Nil(t, result) + } else { + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Len(t, result, len(tt.steps)) + + // Verify IDs are generated + for _, step := range result { + assert.False(t, step.Id.IsZero()) + } + + // Verify orders are normalized + for i, step := range result { + assert.Equal(t, int64(i+1), step.Order) + } + } + }) + } +}