wishli-api/tests/integration/api_test.go
2025-03-23 20:05:51 +03:00

399 lines
12 KiB
Go

package integration
import (
"bytes"
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"wish-list-api/api/handlers"
"wish-list-api/api/middleware"
"wish-list-api/pkg/auth"
"wish-list-api/pkg/entities"
"wish-list-api/pkg/user"
wishlist "wish-list-api/pkg/wish-list"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
"github.com/stretchr/testify/assert"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
var (
app *fiber.App
testDB *mongo.Database
client *mongo.Client
authSvc auth.Service
)
func TestMain(m *testing.M) {
setup()
exitCode := m.Run()
teardown()
os.Exit(exitCode)
}
func setup() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
var err error
mongoURI := os.Getenv("MONGODB_URI")
if mongoURI == "" {
mongoURI = "mongodb://mongo_user:mongo_password@localhost:27017/admin"
}
client, err = mongo.Connect(ctx, options.Client().ApplyURI(mongoURI))
if err != nil {
log.Fatalf("Error connecting to MongoDB: %v", err)
}
err = client.Ping(ctx, nil)
if err != nil {
log.Fatalf("Could not connect to MongoDB: %v", err)
}
dbName := fmt.Sprintf("wishlist_test_%d", time.Now().UnixNano())
testDB = client.Database(dbName)
userCollection := testDB.Collection("users")
wishlistCollection := testDB.Collection("wishlists")
wishlistItemCollection := testDB.Collection("wishlist_items")
userRepo := user.NewMongoRepository(userCollection)
wishlistRepo := wishlist.NewMongoRepository(wishlistCollection, wishlistItemCollection)
userService := user.NewService(userRepo)
authSvc = auth.NewService(auth.ServiceConfig{
UserService: userService,
})
wishlistSvc := wishlist.NewService(wishlistRepo)
app = fiber.New()
api := app.Group("/api")
api.Post("/auth/register", handlers.Register(authSvc))
api.Post("/auth/login", handlers.Login(authSvc))
api.Post("/auth/refresh", handlers.RefreshToken(authSvc))
wishListHandler := handlers.NewWishListHandler(wishlistSvc, authSvc)
wishList := api.Group("/wishlist")
wishList.Get("/:id", wishListHandler.GetWishList)
wishList.Get("/user/:userId", wishListHandler.GetUserWishLists)
wishList.Get("/:wishlistId/items", wishListHandler.GetWishListItems)
wishList.Get("/item/:id", wishListHandler.GetWishListItem)
wishList.Post("/", middleware.Protected(authSvc), wishListHandler.CreateWishList)
wishList.Put("/:id", middleware.Protected(authSvc), wishListHandler.UpdateWishList)
wishList.Delete("/:id", middleware.Protected(authSvc), wishListHandler.DeleteWishList)
wishList.Post("/item", middleware.Protected(authSvc), wishListHandler.CreateWishListItem)
wishList.Put("/item/:id", middleware.Protected(authSvc), wishListHandler.UpdateWishListItem)
wishList.Delete("/item/:id", middleware.Protected(authSvc), wishListHandler.DeleteWishListItem)
}
func teardown() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := testDB.Drop(ctx); err != nil {
log.Printf("Error dropping test database: %v", err)
}
if err := client.Disconnect(ctx); err != nil {
log.Printf("Error disconnecting from MongoDB: %v", err)
}
}
func registerTestUser(t *testing.T) (string, primitive.ObjectID) {
userData := entities.RegisterRequest{
Email: fmt.Sprintf("test%d@example.com", time.Now().UnixNano()),
Password: "password123",
}
jsonBody, _ := json.Marshal(userData)
req := httptest.NewRequest("POST", "/api/auth/register", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
var response struct {
Status bool `json:"status"`
Data entities.TokenPair `json:"data"`
Error *string `json:"error"`
}
err = json.NewDecoder(resp.Body).Decode(&response)
assert.NoError(t, err)
claims, err := authSvc.ValidateToken(response.Data.AccessToken)
assert.NoError(t, err)
mapClaims := claims.Claims.(jwt.MapClaims)
userIDStr := mapClaims["user_id"].(string)
userID, err := primitive.ObjectIDFromHex(userIDStr)
assert.NoError(t, err)
return response.Data.AccessToken, userID
}
func TestRegister(t *testing.T) {
userData := entities.RegisterRequest{
Email: fmt.Sprintf("test%d@example.com", time.Now().UnixNano()),
Password: "password123",
}
jsonBody, _ := json.Marshal(userData)
req := httptest.NewRequest("POST", "/api/auth/register", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("POST", "/api/auth/register", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusConflict, resp.StatusCode)
}
func TestLogin(t *testing.T) {
email := fmt.Sprintf("test%d@example.com", time.Now().UnixNano())
userData := entities.RegisterRequest{
Email: email,
Password: "password123",
}
jsonBody, _ := json.Marshal(userData)
req := httptest.NewRequest("POST", "/api/auth/register", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
loginData := entities.LoginRequest{
Email: email,
Password: "password123",
}
jsonBody, _ = json.Marshal(loginData)
req = httptest.NewRequest("POST", "/api/auth/login", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
loginData.Password = "wrongpassword"
jsonBody, _ = json.Marshal(loginData)
req = httptest.NewRequest("POST", "/api/auth/login", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
}
func TestWishListCRUD(t *testing.T) {
token, userID := registerTestUser(t)
wishlistData := entities.WishList{
Title: "Test Wishlist",
Description: "Integration test wishlist",
IsPublic: true,
}
jsonBody, _ := json.Marshal(wishlistData)
req := httptest.NewRequest("POST", "/api/wishlist", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
var createResponse struct {
Status bool `json:"status"`
Data entities.WishList `json:"data"`
Error *string `json:"error"`
}
err = json.NewDecoder(resp.Body).Decode(&createResponse)
assert.NoError(t, err)
wishlistID := createResponse.Data.ID
req = httptest.NewRequest("GET", "/api/wishlist/"+wishlistID, nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
updatedData := entities.WishList{
Title: "Updated Title",
Description: "Updated description",
IsPublic: false,
}
jsonBody, _ = json.Marshal(updatedData)
req = httptest.NewRequest("PUT", "/api/wishlist/"+wishlistID, bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/"+wishlistID, nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusUnauthorized, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/"+wishlistID, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/user/"+userID.Hex(), nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("DELETE", "/api/wishlist/"+wishlistID, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/"+wishlistID, nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
}
func TestWishListItemsCRUD(t *testing.T) {
token, _ := registerTestUser(t)
wishlistData := entities.WishList{
Title: "Test Wishlist for Items",
Description: "Testing wishlist items",
IsPublic: true,
}
jsonBody, _ := json.Marshal(wishlistData)
req := httptest.NewRequest("POST", "/api/wishlist", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
var createResponse struct {
Status bool `json:"status"`
Data entities.WishList `json:"data"`
Error *string `json:"error"`
}
err = json.NewDecoder(resp.Body).Decode(&createResponse)
assert.NoError(t, err)
wishlistID := createResponse.Data.ID
itemData := entities.WishListItem{
Title: "Test Item",
Description: "Test item description",
URL: "https://example.com",
Cost: 99.99,
WishListID: wishlistID,
}
jsonBody, _ = json.Marshal(itemData)
req = httptest.NewRequest("POST", "/api/wishlist/item", bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusCreated, resp.StatusCode)
var itemResponse struct {
Status bool `json:"status"`
Data entities.WishListItem `json:"data"`
Error *string `json:"error"`
}
err = json.NewDecoder(resp.Body).Decode(&itemResponse)
assert.NoError(t, err)
itemID := itemResponse.Data.ID
req = httptest.NewRequest("GET", "/api/wishlist/item/"+itemID, nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
updatedItemData := entities.WishListItem{
Title: "Updated Item Title",
Description: "Updated item description",
URL: "https://example.com",
Cost: 149.99,
}
jsonBody, _ = json.Marshal(updatedItemData)
req = httptest.NewRequest("PUT", "/api/wishlist/item/"+itemID, bytes.NewReader(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/"+wishlistID+"/items", nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
var itemsResponse struct {
Status bool `json:"status"`
Data []entities.WishListItem `json:"data"`
Error *string `json:"error"`
}
err = json.NewDecoder(resp.Body).Decode(&itemsResponse)
assert.NoError(t, err)
assert.Equal(t, 1, len(itemsResponse.Data))
req = httptest.NewRequest("DELETE", "/api/wishlist/item/"+itemID, nil)
req.Header.Set("Authorization", "Bearer "+token)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
req = httptest.NewRequest("GET", "/api/wishlist/item/"+itemID, nil)
resp, err = app.Test(req, -1)
assert.NoError(t, err)
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
}