test: add comprehensive JWT coverage tests
Added tests for JWT token operations: - TestGenerateAccessToken_Success - TestGenerateRefreshToken_Success - TestGenerateTokenPair_Success - TestGenerateTokenPairWithRemember_Success - TestValidateAccessToken_WrongType - TestValidateRefreshToken_WrongType - TestValidateAccessToken_InvalidToken - TestGetAccessTokenExpire - TestGetRefreshTokenExpire - TestParseToken_Invalid - TestGenerateLongLivedRefreshToken_Success - TestParseRSAPrivateKey_InvalidPEM - TestParseRSAPublicKey_InvalidPEM - TestGenerateAndPersistRSAKeyPair_EmptyPath - TestRefreshAccessToken_Success - TestRefreshAccessToken_InvalidRefreshToken - TestRefreshAccessToken_AccessTokenProvided auth module coverage: 23.8% → 52.5% Key functions now at 100%: ValidateAccessToken, ValidateRefreshToken, RefreshAccessToken, GetAccessTokenExpire, GetRefreshTokenExpire
This commit is contained in:
@@ -124,3 +124,387 @@ func TestNewJWTWithOptions_RS256_RequireExistingKeysAllowsExistingFiles(t *testi
|
||||
t.Fatalf("unexpected algorithm: %s", jwtManager.GetAlgorithm())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateAccessToken_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
token, err := jwtManager.GenerateAccessToken(123, "testuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate access token failed: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Fatal("expected non-empty token")
|
||||
}
|
||||
|
||||
claims, err := jwtManager.ValidateAccessToken(token)
|
||||
if err != nil {
|
||||
t.Fatalf("validate access token failed: %v", err)
|
||||
}
|
||||
if claims.UserID != 123 {
|
||||
t.Errorf("UserID = %d, want 123", claims.UserID)
|
||||
}
|
||||
if claims.Username != "testuser" {
|
||||
t.Errorf("Username = %s, want testuser", claims.Username)
|
||||
}
|
||||
if claims.Type != "access" {
|
||||
t.Errorf("Type = %s, want access", claims.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateRefreshToken_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
token, err := jwtManager.GenerateRefreshToken(456, "refreshuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate refresh token failed: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Fatal("expected non-empty token")
|
||||
}
|
||||
|
||||
claims, err := jwtManager.ValidateRefreshToken(token)
|
||||
if err != nil {
|
||||
t.Fatalf("validate refresh token failed: %v", err)
|
||||
}
|
||||
if claims.UserID != 456 {
|
||||
t.Errorf("UserID = %d, want 456", claims.UserID)
|
||||
}
|
||||
if claims.Type != "refresh" {
|
||||
t.Errorf("Type = %s, want refresh", claims.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateTokenPair_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := jwtManager.GenerateTokenPair(789, "pairuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate token pair failed: %v", err)
|
||||
}
|
||||
if accessToken == "" || refreshToken == "" {
|
||||
t.Fatal("expected non-empty tokens")
|
||||
}
|
||||
|
||||
accessClaims, err := jwtManager.ValidateAccessToken(accessToken)
|
||||
if err != nil {
|
||||
t.Fatalf("validate access token failed: %v", err)
|
||||
}
|
||||
if accessClaims.UserID != 789 {
|
||||
t.Errorf("UserID = %d, want 789", accessClaims.UserID)
|
||||
}
|
||||
|
||||
refreshClaims, err := jwtManager.ValidateRefreshToken(refreshToken)
|
||||
if err != nil {
|
||||
t.Fatalf("validate refresh token failed: %v", err)
|
||||
}
|
||||
if refreshClaims.UserID != 789 {
|
||||
t.Errorf("UserID = %d, want 789", refreshClaims.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateTokenPairWithRemember_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
RememberLoginExpire: 30 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := jwtManager.GenerateTokenPairWithRemember(999, "rememberuser", true)
|
||||
if err != nil {
|
||||
t.Fatalf("generate token pair with remember failed: %v", err)
|
||||
}
|
||||
if accessToken == "" || refreshToken == "" {
|
||||
t.Fatal("expected non-empty tokens")
|
||||
}
|
||||
|
||||
accessClaims, err := jwtManager.ValidateAccessToken(accessToken)
|
||||
if err != nil {
|
||||
t.Fatalf("validate access token failed: %v", err)
|
||||
}
|
||||
if accessClaims.Remember {
|
||||
t.Error("access token should not have Remember flag")
|
||||
}
|
||||
|
||||
refreshClaims, err := jwtManager.ValidateRefreshToken(refreshToken)
|
||||
if err != nil {
|
||||
t.Fatalf("validate refresh token failed: %v", err)
|
||||
}
|
||||
if !refreshClaims.Remember {
|
||||
t.Error("refresh token should have Remember flag set to true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAccessToken_WrongType(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
// Use a refresh token as if it were an access token
|
||||
refreshToken, err := jwtManager.GenerateRefreshToken(123, "testuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate refresh token failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.ValidateAccessToken(refreshToken)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when validating refresh token as access token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRefreshToken_WrongType(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
// Use an access token as if it were a refresh token
|
||||
accessToken, err := jwtManager.GenerateAccessToken(123, "testuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate access token failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.ValidateRefreshToken(accessToken)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when validating access token as refresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateAccessToken_InvalidToken(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.ValidateAccessToken("invalid-token")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAccessTokenExpire(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 30 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
expire := jwtManager.GetAccessTokenExpire()
|
||||
if expire != 30*time.Minute {
|
||||
t.Errorf("GetAccessTokenExpire() = %v, want 30m", expire)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRefreshTokenExpire(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 14 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
expire := jwtManager.GetRefreshTokenExpire()
|
||||
if expire != 14*24*time.Hour {
|
||||
t.Errorf("GetRefreshTokenExpire() = %v, want 14d", expire)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseToken_Invalid(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.ParseToken("not-a-valid-jwt-token")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateLongLivedRefreshToken_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
RememberLoginExpire: 30 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
token, err := jwtManager.GenerateLongLivedRefreshToken(123, "longliveuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate long lived refresh token failed: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Fatal("expected non-empty token")
|
||||
}
|
||||
|
||||
claims, err := jwtManager.ValidateRefreshToken(token)
|
||||
if err != nil {
|
||||
t.Fatalf("validate refresh token failed: %v", err)
|
||||
}
|
||||
if claims.UserID != 123 {
|
||||
t.Errorf("UserID = %d, want 123", claims.UserID)
|
||||
}
|
||||
if !claims.Remember {
|
||||
t.Error("expected Remember flag to be set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSAPrivateKey_InvalidPEM(t *testing.T) {
|
||||
_, err := parseRSAPrivateKey("not-a-valid-pem-block")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid PEM")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSAPublicKey_InvalidPEM(t *testing.T) {
|
||||
_, err := parseRSAPublicKey("not-a-valid-pem-block")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid PEM")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGenerateAndPersistRSAKeyPair_EmptyPath(t *testing.T) {
|
||||
_, _, err := generateAndPersistRSAKeyPair("", "public.pem")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for empty private path")
|
||||
}
|
||||
_, _, err = generateAndPersistRSAKeyPair("private.pem", "")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for empty public path")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshAccessToken_Success(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
// Generate a valid refresh token first
|
||||
refreshToken, err := jwtManager.GenerateRefreshToken(123, "testuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate refresh token failed: %v", err)
|
||||
}
|
||||
|
||||
// Use refresh to get new access token
|
||||
newAccessToken, err := jwtManager.RefreshAccessToken(refreshToken)
|
||||
if err != nil {
|
||||
t.Fatalf("refresh access token failed: %v", err)
|
||||
}
|
||||
if newAccessToken == "" {
|
||||
t.Fatal("expected non-empty access token")
|
||||
}
|
||||
|
||||
claims, err := jwtManager.ValidateAccessToken(newAccessToken)
|
||||
if err != nil {
|
||||
t.Fatalf("validate new access token failed: %v", err)
|
||||
}
|
||||
if claims.UserID != 123 {
|
||||
t.Errorf("UserID = %d, want 123", claims.UserID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshAccessToken_InvalidRefreshToken(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.RefreshAccessToken("invalid-refresh-token")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid refresh token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshAccessToken_AccessTokenProvided(t *testing.T) {
|
||||
jwtManager, err := NewJWTWithOptions(JWTOptions{
|
||||
Algorithm: jwtAlgorithmHS256,
|
||||
HS256Secret: "test-secret-key-for-jwt-at-least-32-chars",
|
||||
AccessTokenExpire: 15 * time.Minute,
|
||||
RefreshTokenExpire: 7 * 24 * time.Hour,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("create jwt manager failed: %v", err)
|
||||
}
|
||||
|
||||
// Generate an access token and try to use it as refresh
|
||||
accessToken, err := jwtManager.GenerateAccessToken(123, "testuser")
|
||||
if err != nil {
|
||||
t.Fatalf("generate access token failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = jwtManager.RefreshAccessToken(accessToken)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when using access token as refresh token")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user