added missing tests for new user profile handlers
This commit is contained in:
@@ -0,0 +1,463 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"bamort/database"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// setupTestEnvironment sets up the test environment
|
||||
func setupTestEnvironment(t *testing.T) {
|
||||
original := os.Getenv("ENVIRONMENT")
|
||||
os.Setenv("ENVIRONMENT", "test")
|
||||
t.Cleanup(func() {
|
||||
if original != "" {
|
||||
os.Setenv("ENVIRONMENT", original)
|
||||
} else {
|
||||
os.Unsetenv("ENVIRONMENT")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// setupHandlerTestEnvironment sets up the test environment for handler tests
|
||||
func setupHandlerTestEnvironment(t *testing.T) {
|
||||
setupTestEnvironment(t)
|
||||
database.SetupTestDB()
|
||||
err := MigrateStructure()
|
||||
require.NoError(t, err, "Should migrate user structure")
|
||||
gin.SetMode(gin.TestMode)
|
||||
}
|
||||
|
||||
// createTestUser creates a test user and returns it
|
||||
func createTestUser(t *testing.T, username, password, email string) *User {
|
||||
user := &User{
|
||||
Username: username,
|
||||
PasswordHash: password,
|
||||
Email: email,
|
||||
}
|
||||
|
||||
hashedPassword := md5.Sum([]byte(password))
|
||||
user.PasswordHash = hex.EncodeToString(hashedPassword[:])
|
||||
|
||||
err := user.Create()
|
||||
require.NoError(t, err, "Should create test user")
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
// TestGetUserProfile tests the GetUserProfile handler
|
||||
func TestGetUserProfile(t *testing.T) {
|
||||
setupHandlerTestEnvironment(t)
|
||||
|
||||
t.Run("Success - Get user profile", func(t *testing.T) {
|
||||
// Create test user
|
||||
testUser := createTestUser(t, "profileuser", "password123", "profile@test.com")
|
||||
|
||||
// Create HTTP request
|
||||
req, _ := http.NewRequest("GET", "/api/user/profile", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
// Set user ID in context (simulating AuthMiddleware)
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
// Call handler
|
||||
GetUserProfile(c)
|
||||
|
||||
// Assertions
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Equal(t, testUser.Username, response["username"])
|
||||
assert.Equal(t, testUser.Email, response["email"])
|
||||
assert.Equal(t, float64(testUser.UserID), response["id"])
|
||||
})
|
||||
|
||||
t.Run("Failure - No user ID in context", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/api/user/profile", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
// Don't set userID in context
|
||||
|
||||
GetUserProfile(c)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Unauthorized", response["error"])
|
||||
})
|
||||
|
||||
t.Run("Failure - User not found", func(t *testing.T) {
|
||||
req, _ := http.NewRequest("GET", "/api/user/profile", nil)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
// Set non-existent user ID
|
||||
c.Set("userID", uint(99999))
|
||||
|
||||
GetUserProfile(c)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "User not found", response["error"])
|
||||
})
|
||||
}
|
||||
|
||||
// TestUpdateEmail tests the UpdateEmail handler
|
||||
func TestUpdateEmail(t *testing.T) {
|
||||
setupHandlerTestEnvironment(t)
|
||||
|
||||
t.Run("Success - Update email", func(t *testing.T) {
|
||||
// Create test user
|
||||
testUser := createTestUser(t, "emailuser", "password123", "old@test.com")
|
||||
|
||||
// Create request body
|
||||
requestData := map[string]interface{}{
|
||||
"email": "new@test.com",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/email", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdateEmail(c)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Email updated successfully", response["message"])
|
||||
assert.Equal(t, "new@test.com", response["email"])
|
||||
|
||||
// Verify email was actually updated in database
|
||||
var updatedUser User
|
||||
err = updatedUser.FirstId(testUser.UserID)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "new@test.com", updatedUser.Email)
|
||||
})
|
||||
|
||||
t.Run("Failure - Email already in use", func(t *testing.T) {
|
||||
// Create two test users
|
||||
testUser1 := createTestUser(t, "emailuser1", "password123", "user1@test.com")
|
||||
createTestUser(t, "emailuser2", "password123", "user2@test.com")
|
||||
|
||||
// Try to change user1's email to user2's email
|
||||
requestData := map[string]interface{}{
|
||||
"email": "user2@test.com",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/email", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser1.UserID)
|
||||
|
||||
UpdateEmail(c)
|
||||
|
||||
assert.Equal(t, http.StatusConflict, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Email already in use", response["error"])
|
||||
})
|
||||
|
||||
t.Run("Failure - Invalid email format", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "emailuser3", "password123", "valid@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"email": "invalid-email",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/email", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdateEmail(c)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Failure - No user ID in context", func(t *testing.T) {
|
||||
requestData := map[string]interface{}{
|
||||
"email": "new@test.com",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/email", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
UpdateEmail(c)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Success - Update to same email (idempotent)", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "emailuser4", "password123", "same@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"email": "same@test.com",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/email", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdateEmail(c)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
})
|
||||
}
|
||||
|
||||
// TestUpdatePassword tests the UpdatePassword handler
|
||||
func TestUpdatePassword(t *testing.T) {
|
||||
setupHandlerTestEnvironment(t)
|
||||
|
||||
t.Run("Success - Update password", func(t *testing.T) {
|
||||
// Create test user
|
||||
testUser := createTestUser(t, "passworduser", "oldpassword123", "password@test.com")
|
||||
|
||||
// Create request body
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "oldpassword123",
|
||||
"new_password": "newpassword456",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Password updated successfully", response["message"])
|
||||
|
||||
// Verify password was actually updated in database
|
||||
var updatedUser User
|
||||
err = updatedUser.FirstId(testUser.UserID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Hash the new password and check it matches
|
||||
hashedNewPassword := md5.Sum([]byte("newpassword456"))
|
||||
expectedHash := hex.EncodeToString(hashedNewPassword[:])
|
||||
assert.Equal(t, expectedHash, updatedUser.PasswordHash)
|
||||
})
|
||||
|
||||
t.Run("Failure - Incorrect current password", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "passworduser2", "correctpassword", "password2@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "wrongpassword",
|
||||
"new_password": "newpassword456",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "Current password is incorrect", response["error"])
|
||||
})
|
||||
|
||||
t.Run("Failure - New password too short", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "passworduser3", "oldpassword", "password3@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "oldpassword",
|
||||
"new_password": "short",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Failure - Missing current password", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "passworduser4", "oldpassword", "password4@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"new_password": "newpassword456",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Failure - Missing new password", func(t *testing.T) {
|
||||
testUser := createTestUser(t, "passworduser5", "oldpassword", "password5@test.com")
|
||||
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "oldpassword",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusBadRequest, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Failure - No user ID in context", func(t *testing.T) {
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "oldpassword",
|
||||
"new_password": "newpassword456",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusUnauthorized, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Failure - User not found", func(t *testing.T) {
|
||||
requestData := map[string]interface{}{
|
||||
"current_password": "oldpassword",
|
||||
"new_password": "newpassword456",
|
||||
}
|
||||
requestBody, _ := json.Marshal(requestData)
|
||||
|
||||
req, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request = req
|
||||
c.Set("userID", uint(99999))
|
||||
|
||||
UpdatePassword(c)
|
||||
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
})
|
||||
|
||||
t.Run("Success - Password can be changed multiple times", func(t *testing.T) {
|
||||
testUser := createTestUser(t, fmt.Sprintf("passworduser6_%d", os.Getpid()), "password1", "password6@test.com")
|
||||
|
||||
// First password change
|
||||
requestData1 := map[string]interface{}{
|
||||
"current_password": "password1",
|
||||
"new_password": "password2",
|
||||
}
|
||||
requestBody1, _ := json.Marshal(requestData1)
|
||||
req1, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody1))
|
||||
req1.Header.Set("Content-Type", "application/json")
|
||||
w1 := httptest.NewRecorder()
|
||||
c1, _ := gin.CreateTestContext(w1)
|
||||
c1.Request = req1
|
||||
c1.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c1)
|
||||
assert.Equal(t, http.StatusOK, w1.Code)
|
||||
|
||||
// Second password change
|
||||
requestData2 := map[string]interface{}{
|
||||
"current_password": "password2",
|
||||
"new_password": "password3",
|
||||
}
|
||||
requestBody2, _ := json.Marshal(requestData2)
|
||||
req2, _ := http.NewRequest("PUT", "/api/user/password", bytes.NewBuffer(requestBody2))
|
||||
req2.Header.Set("Content-Type", "application/json")
|
||||
w2 := httptest.NewRecorder()
|
||||
c2, _ := gin.CreateTestContext(w2)
|
||||
c2.Request = req2
|
||||
c2.Set("userID", testUser.UserID)
|
||||
|
||||
UpdatePassword(c2)
|
||||
assert.Equal(t, http.StatusOK, w2.Code)
|
||||
|
||||
// Verify final password
|
||||
var updatedUser User
|
||||
err := updatedUser.FirstId(testUser.UserID)
|
||||
assert.NoError(t, err)
|
||||
hashedPassword3 := md5.Sum([]byte("password3"))
|
||||
expectedHash := hex.EncodeToString(hashedPassword3[:])
|
||||
assert.Equal(t, expectedHash, updatedUser.PasswordHash)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user