backend/pkg/permission/usecase/token_jwt_test.go

330 lines
7.1 KiB
Go
Raw Permalink Normal View History

2025-10-06 08:28:39 +00:00
package usecase
import (
"testing"
"time"
"backend/pkg/permission/domain/entity"
"github.com/golang-jwt/jwt/v4"
"github.com/stretchr/testify/assert"
)
func TestCreateAccessToken(t *testing.T) {
tests := []struct {
name string
token entity.Token
data interface{}
secretKey string
wantErr bool
}{
{
name: "successful token creation",
token: entity.Token{
ID: "test-token-id",
ExpiresIn: int(time.Now().Add(time.Hour).Unix()),
},
data: map[string]string{
"uid": "user123",
"role": "admin",
},
secretKey: "test-secret-key",
wantErr: false,
},
{
name: "empty secret key",
token: entity.Token{
ID: "test-token-id",
ExpiresIn: int(time.Now().Add(time.Hour).Unix()),
},
data: map[string]string{"uid": "user123"},
secretKey: "",
wantErr: false, // JWT library will still create token with empty key
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tokenStr, err := createAccessToken(tt.token, tt.data, tt.secretKey)
if tt.wantErr {
assert.Error(t, err)
assert.Empty(t, tokenStr)
} else {
assert.NoError(t, err)
assert.NotEmpty(t, tokenStr)
// Verify the token can be parsed
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
return []byte(tt.secretKey), nil
})
if tt.secretKey != "" {
assert.NoError(t, err)
assert.True(t, token.Valid)
// Check claims
if claims, ok := token.Claims.(jwt.MapClaims); ok {
assert.Equal(t, tt.token.ID, claims["jti"])
assert.Equal(t, "permission", claims["iss"])
assert.NotNil(t, claims["exp"])
assert.NotNil(t, claims["data"])
}
}
}
})
}
}
func TestCreateRefreshToken(t *testing.T) {
tests := []struct {
name string
accessToken string
want string
}{
{
name: "consistent hash generation",
accessToken: "test-access-token",
want: "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", // SHA256 of "test"
},
{
name: "different token different hash",
accessToken: "different-access-token",
want: "", // We'll check it's different
},
{
name: "empty token",
accessToken: "",
want: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // SHA256 of empty string
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := createRefreshToken(tt.accessToken)
assert.NotEmpty(t, result)
assert.Len(t, result, 64) // SHA256 hex string length
if tt.want != "" {
if tt.name == "consistent hash generation" {
// For "test" input, we know the expected hash
testResult := createRefreshToken("test")
assert.Equal(t, tt.want, testResult)
} else if tt.name == "empty token" {
assert.Equal(t, tt.want, result)
}
}
// Test consistency - same input should produce same output
result2 := createRefreshToken(tt.accessToken)
assert.Equal(t, result, result2)
})
}
}
func TestParseToken(t *testing.T) {
secretKey := "test-secret-key"
// Create a valid token first
token := entity.Token{
ID: "test-id",
ExpiresIn: int(time.Now().Add(time.Hour).Unix()),
}
data := map[string]string{
"uid": "user123",
"role": "admin",
}
validTokenStr, err := createAccessToken(token, data, secretKey)
assert.NoError(t, err)
tests := []struct {
name string
accessToken string
secret string
validate bool
wantErr bool
}{
{
name: "valid token with validation",
accessToken: validTokenStr,
secret: secretKey,
validate: true,
wantErr: false,
},
{
name: "valid token without validation",
accessToken: validTokenStr,
secret: secretKey,
validate: false,
wantErr: false,
},
{
name: "invalid token",
accessToken: "invalid.token.string",
secret: secretKey,
validate: true,
wantErr: true,
},
{
name: "wrong secret",
accessToken: validTokenStr,
secret: "wrong-secret",
validate: true,
wantErr: true,
},
{
name: "empty token",
accessToken: "",
secret: secretKey,
validate: true,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
claims, err := parseToken(tt.accessToken, tt.secret, tt.validate)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, claims)
if tt.accessToken == validTokenStr {
assert.Equal(t, "test-id", claims["jti"])
assert.Equal(t, "permission", claims["iss"])
}
}
})
}
}
func TestParseClaims(t *testing.T) {
secretKey := "test-secret-key"
// Create a valid token with data claims
token := entity.Token{
ID: "test-id",
ExpiresIn: int(time.Now().Add(time.Hour).Unix()),
}
data := map[string]interface{}{
"uid": "user123",
"role": "admin",
"deviceId": "device456",
}
validTokenStr, err := createAccessToken(token, data, secretKey)
assert.NoError(t, err)
tests := []struct {
name string
accessToken string
secret string
validate bool
wantErr bool
expectUID string
expectRole string
}{
{
name: "valid token with data claims",
accessToken: validTokenStr,
secret: secretKey,
validate: false,
wantErr: false,
expectUID: "user123",
expectRole: "admin",
},
{
name: "invalid token",
accessToken: "invalid.token",
secret: secretKey,
validate: false,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
claims, err := parseClaims(tt.accessToken, tt.secret, tt.validate)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, claims)
if tt.expectUID != "" {
uid, exists := claims["uid"]
assert.True(t, exists)
assert.Equal(t, tt.expectUID, uid)
}
if tt.expectRole != "" {
role, exists := claims["role"]
assert.True(t, exists)
assert.Equal(t, tt.expectRole, role)
}
}
})
}
}
func TestConvertMap(t *testing.T) {
tests := []struct {
name string
input map[string]interface{}
expect map[string]string
}{
{
name: "string values",
input: map[string]interface{}{
"key1": "value1",
"key2": "value2",
},
expect: map[string]string{
"key1": "value1",
"key2": "value2",
},
},
{
name: "mixed types",
input: map[string]interface{}{
"string": "value",
"int": 123,
"float": 45.67,
"bool": true,
},
expect: map[string]string{
"string": "value",
"int": "123",
"float": "45.67",
"bool": "true",
},
},
{
name: "empty map",
input: map[string]interface{}{},
expect: map[string]string{},
},
{
name: "nil values",
input: map[string]interface{}{
"nil": nil,
},
expect: map[string]string{
"nil": "<nil>",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := convertMap(tt.input)
assert.Equal(t, tt.expect, result)
})
}
}