330 lines
7.1 KiB
Go
330 lines
7.1 KiB
Go
|
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)
|
||
|
})
|
||
|
}
|
||
|
}
|