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": "", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := convertMap(tt.input) assert.Equal(t, tt.expect, result) }) } }