153 lines
5.0 KiB
Go
153 lines
5.0 KiB
Go
package integration
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"goyco/internal/handlers"
|
|
"goyco/internal/middleware"
|
|
"goyco/internal/server"
|
|
"goyco/internal/services"
|
|
"goyco/internal/testutils"
|
|
)
|
|
|
|
func setupCachingTestContext(t *testing.T) *testContext {
|
|
t.Helper()
|
|
suite := testutils.NewServiceSuite(t)
|
|
|
|
authService, err := services.NewAuthFacadeForTest(testutils.AppTestConfig, suite.UserRepo, suite.PostRepo, suite.DeletionRepo, suite.RefreshTokenRepo, suite.EmailSender)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create auth service: %v", err)
|
|
}
|
|
|
|
voteService := services.NewVoteService(suite.VoteRepo, suite.PostRepo, suite.DB)
|
|
metadataService := services.NewURLMetadataService()
|
|
|
|
authHandler := handlers.NewAuthHandler(authService, suite.UserRepo)
|
|
postHandler := handlers.NewPostHandler(suite.PostRepo, metadataService, voteService)
|
|
voteHandler := handlers.NewVoteHandler(voteService)
|
|
userHandler := handlers.NewUserHandler(suite.UserRepo, authService)
|
|
apiHandler := handlers.NewAPIHandlerWithMonitoring(testutils.AppTestConfig, suite.PostRepo, suite.UserRepo, voteService, suite.DB, middleware.NewInMemoryDBMonitor())
|
|
|
|
staticDir := t.TempDir()
|
|
|
|
router := server.NewRouter(newRouterConfigBuilder().
|
|
withIndividualHandlers(authHandler, postHandler, voteHandler, userHandler, apiHandler, authService).
|
|
withStaticDir(staticDir).
|
|
build())
|
|
|
|
return &testContext{
|
|
Router: router,
|
|
Suite: suite,
|
|
AuthService: authService,
|
|
}
|
|
}
|
|
|
|
func TestIntegration_Caching(t *testing.T) {
|
|
ctx := setupCachingTestContext(t)
|
|
router := ctx.Router
|
|
|
|
t.Run("Cache_Hit_On_Repeated_Requests", func(t *testing.T) {
|
|
req1 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec1 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec1, req1)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
req2 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec2 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec2, req2)
|
|
|
|
if rec1.Code != rec2.Code {
|
|
t.Error("Cached responses should have same status code")
|
|
}
|
|
|
|
if rec1.Body.String() != rec2.Body.String() {
|
|
t.Error("Cached responses should have same body")
|
|
}
|
|
|
|
if rec2.Header().Get("X-Cache") != "HIT" {
|
|
t.Log("Cache may not be enabled for this path or response may not be cacheable")
|
|
}
|
|
})
|
|
|
|
t.Run("Cache_Invalidation_On_POST", func(t *testing.T) {
|
|
ctx.Suite.EmailSender.Reset()
|
|
user := createAuthenticatedUser(t, ctx.AuthService, ctx.Suite.UserRepo, "cache_post_user", "cache_post@example.com")
|
|
|
|
req1 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec1 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec1, req1)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
postBody := map[string]string{
|
|
"title": "Cache Test Post",
|
|
"url": "https://example.com/cache-test",
|
|
"content": "Test content",
|
|
}
|
|
body, _ := json.Marshal(postBody)
|
|
req2 := httptest.NewRequest("POST", "/api/posts", bytes.NewBuffer(body))
|
|
req2.Header.Set("Content-Type", "application/json")
|
|
req2.Header.Set("Authorization", "Bearer "+user.Token)
|
|
req2 = testutils.WithUserContext(req2, middleware.UserIDKey, user.User.ID)
|
|
rec2 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec2, req2)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
req3 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec3 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec3, req3)
|
|
|
|
if rec1.Body.String() == rec3.Body.String() && rec1.Code == http.StatusOK && rec3.Code == http.StatusOK {
|
|
t.Log("Cache invalidation may not be working or cache may not be enabled")
|
|
}
|
|
})
|
|
|
|
t.Run("Cache_Headers_Present", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec := httptest.NewRecorder()
|
|
router.ServeHTTP(rec, req)
|
|
|
|
if rec.Header().Get("Cache-Control") == "" && rec.Header().Get("X-Cache") == "" {
|
|
t.Log("Cache headers may not be present for all responses")
|
|
}
|
|
})
|
|
|
|
t.Run("Cache_Invalidation_On_DELETE", func(t *testing.T) {
|
|
ctx.Suite.EmailSender.Reset()
|
|
user := createAuthenticatedUser(t, ctx.AuthService, ctx.Suite.UserRepo, "cache_delete_user", "cache_delete@example.com")
|
|
|
|
post := testutils.CreatePostWithRepo(t, ctx.Suite.PostRepo, user.User.ID, "Cache Delete Post", "https://example.com/cache-delete")
|
|
|
|
req1 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec1 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec1, req1)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
req2 := httptest.NewRequest("DELETE", "/api/posts/"+fmt.Sprintf("%d", post.ID), nil)
|
|
req2.Header.Set("Authorization", "Bearer "+user.Token)
|
|
req2 = testutils.WithUserContext(req2, middleware.UserIDKey, user.User.ID)
|
|
req2 = testutils.WithURLParams(req2, map[string]string{"id": fmt.Sprintf("%d", post.ID)})
|
|
rec2 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec2, req2)
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
req3 := httptest.NewRequest("GET", "/api/posts", nil)
|
|
rec3 := httptest.NewRecorder()
|
|
router.ServeHTTP(rec3, req3)
|
|
|
|
if rec1.Body.String() == rec3.Body.String() && rec1.Code == http.StatusOK && rec3.Code == http.StatusOK {
|
|
t.Log("Cache invalidation may not be working or cache may not be enabled")
|
|
}
|
|
})
|
|
}
|