Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion router/internal/expr/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (copyCtx Context) Clone() *Context {

query := make(map[string]string, len(copyCtx.Request.URL.Query))
for k, v := range copyCtx.Request.URL.Query {
claims[k] = v
query[k] = v
}
copyCtx.Request.URL.Query = query

Expand Down
154 changes: 153 additions & 1 deletion router/internal/expr/expr_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package expr

import (
"github.com/stretchr/testify/require"
"reflect"
"testing"

"github.com/stretchr/testify/require"
)

func TestExpr(t *testing.T) {
Expand Down Expand Up @@ -55,4 +56,155 @@ func TestExpr(t *testing.T) {
require.False(t, reflect.ValueOf(exprContext.Request.Auth.Scopes).Pointer() == reflect.ValueOf(properClone.Request.Auth.Scopes).Pointer())
require.False(t, reflect.ValueOf(exprContext.Request.URL.Query).Pointer() == reflect.ValueOf(properClone.Request.URL.Query).Pointer())
})

t.Run("clone with query", func(t *testing.T) {
t.Parallel()

exprContext := &Context{
Request: Request{
URL: RequestURL{
Query: map[string]string{
"key": "value",
},
},
},
}

clone := exprContext.Clone()

require.Equal(t, exprContext.Request.URL.Query, clone.Request.URL.Query)

// Verify modifying clone doesn't affect original
clone.Request.URL.Query["new"] = "value2"
require.NotEqual(t, exprContext.Request.URL.Query, clone.Request.URL.Query)
})

t.Run("clone with empty maps and slices", func(t *testing.T) {
t.Parallel()

exprContext := &Context{
Request: Request{
Auth: RequestAuth{
Claims: map[string]any{},
Scopes: []string{},
},
URL: RequestURL{
Query: map[string]string{},
},
},
}

clone := exprContext.Clone()

require.NotNil(t, clone.Request.Auth.Claims)
require.NotNil(t, clone.Request.Auth.Scopes)
require.NotNil(t, clone.Request.URL.Query)
require.Len(t, clone.Request.Auth.Claims, 0)
require.Len(t, clone.Request.Auth.Scopes, 0)
require.Len(t, clone.Request.URL.Query, 0)
})

t.Run("clone with nil maps and slices", func(t *testing.T) {
t.Parallel()

exprContext := &Context{
Request: Request{
Auth: RequestAuth{
Claims: nil,
Scopes: nil,
},
URL: RequestURL{
Query: nil,
},
},
}

clone := exprContext.Clone()

require.NotNil(t, clone.Request.Auth.Claims)
require.NotNil(t, clone.Request.Auth.Scopes)
require.NotNil(t, clone.Request.URL.Query)
require.Len(t, clone.Request.Auth.Claims, 0)
require.Len(t, clone.Request.Auth.Scopes, 0)
require.Len(t, clone.Request.URL.Query, 0)
})

t.Run("verify claims and query values are copied correctly", func(t *testing.T) {
t.Parallel()

exprContext := &Context{
Request: Request{
Auth: RequestAuth{
Claims: map[string]any{
"string": "value",
"number": 42,
"bool": true,
"slice": []string{"a", "b"},
"map": map[string]string{"key": "value"},
},
},
URL: RequestURL{
Query: map[string]string{
"page": "1",
"limit": "10",
"filter": "active",
},
},
},
}

clone := exprContext.Clone()

// Verify claims are copied correctly
require.Equal(t, "value", clone.Request.Auth.Claims["string"])
require.Equal(t, 42, clone.Request.Auth.Claims["number"])
require.Equal(t, true, clone.Request.Auth.Claims["bool"])
require.Equal(t, []string{"a", "b"}, clone.Request.Auth.Claims["slice"])
require.Equal(t, map[string]string{"key": "value"}, clone.Request.Auth.Claims["map"])

// Verify query params are copied correctly
require.Equal(t, "1", clone.Request.URL.Query["page"])
require.Equal(t, "10", clone.Request.URL.Query["limit"])
require.Equal(t, "active", clone.Request.URL.Query["filter"])

// Verify nested structures in claims are also copied by reference (as that's the current behavior)
sliceFromOriginal := exprContext.Request.Auth.Claims["slice"].([]string)
sliceFromClone := clone.Request.Auth.Claims["slice"].([]string)
require.Equal(t, reflect.ValueOf(sliceFromOriginal).Pointer(), reflect.ValueOf(sliceFromClone).Pointer())

mapFromOriginal := exprContext.Request.Auth.Claims["map"].(map[string]string)
mapFromClone := clone.Request.Auth.Claims["map"].(map[string]string)
require.Equal(t, reflect.ValueOf(mapFromOriginal).Pointer(), reflect.ValueOf(mapFromClone).Pointer())
})

t.Run("verify modifying clone doesn't affect original", func(t *testing.T) {
t.Parallel()

exprContext := &Context{
Request: Request{
Auth: RequestAuth{
Claims: map[string]any{"key": "value"},
Scopes: []string{"scope1"},
},
URL: RequestURL{
Query: map[string]string{"param": "value"},
},
},
}

clone := exprContext.Clone()

// Modify clone
clone.Request.Auth.Claims["newKey"] = "newValue"
clone.Request.Auth.Scopes = append(clone.Request.Auth.Scopes, "scope2")
clone.Request.URL.Query["newParam"] = "newValue"

// Verify original is unchanged
require.Len(t, exprContext.Request.Auth.Claims, 1)
require.Equal(t, "value", exprContext.Request.Auth.Claims["key"])
require.Len(t, exprContext.Request.Auth.Scopes, 1)
require.Equal(t, "scope1", exprContext.Request.Auth.Scopes[0])
require.Len(t, exprContext.Request.URL.Query, 1)
require.Equal(t, "value", exprContext.Request.URL.Query["param"])
})
}
Loading