280 lines
10 KiB
Go
280 lines
10 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"log/slog"
|
|
"net/http"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
archivalDomain "git.nakama.town/fmartingr/hako/internal/archival/domain"
|
|
authDomain "git.nakama.town/fmartingr/hako/internal/auth/domain"
|
|
"git.nakama.town/fmartingr/hako/internal/model"
|
|
"git.nakama.town/fmartingr/hako/internal/server/middleware"
|
|
"git.nakama.town/fmartingr/hako/internal/testutil"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestHandleCreateLink_Success(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user and get token
|
|
_, token, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Create logger for tests
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
|
|
// Create link handler
|
|
linkHandler := NewLinkHandler(deps.Dependencies, logger)
|
|
|
|
// Create handlers with auth middleware
|
|
globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuthMiddleware := middleware.RequireAuthMiddleware()
|
|
handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(linkHandler.HandleCreateLink)))
|
|
|
|
// Test request
|
|
requestBody := `{"url": "https://example.com"}`
|
|
w := testutil.PerformRequestWithHandler(handler, http.MethodPost, "/api/v1/links",
|
|
testutil.WithAuthToken(token),
|
|
testutil.WithBody(requestBody),
|
|
)
|
|
|
|
// Assert response
|
|
resp := testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusCreated)
|
|
|
|
// Check response structure
|
|
var linkResp model.LinkListItem
|
|
err = json.Unmarshal(resp.GetBody(), &linkResp)
|
|
require.NoError(t, err)
|
|
|
|
require.NotEmpty(t, linkResp.ID)
|
|
require.Equal(t, "https://example.com", linkResp.URL)
|
|
}
|
|
|
|
func TestHandleCreateLink_MissingURL(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user and get token
|
|
_, token, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Create logger for tests
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
|
|
// Create link handler
|
|
linkHandler := NewLinkHandler(deps.Dependencies, logger)
|
|
|
|
// Create handlers with auth middleware
|
|
globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuthMiddleware := middleware.RequireAuthMiddleware()
|
|
handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(linkHandler.HandleCreateLink)))
|
|
|
|
// Test request with empty URL
|
|
requestBody := `{"url": ""}`
|
|
w := testutil.PerformRequestWithHandler(handler, http.MethodPost, "/api/v1/links",
|
|
testutil.WithAuthToken(token),
|
|
testutil.WithBody(requestBody),
|
|
)
|
|
|
|
// Assert response
|
|
resp := testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusBadRequest)
|
|
}
|
|
|
|
func TestHandleCreateLink_Unauthorized(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Create logger for tests
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
|
|
// Create link handler
|
|
linkHandler := NewLinkHandler(deps.Dependencies, logger)
|
|
|
|
// Create handlers with auth middleware
|
|
globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuthMiddleware := middleware.RequireAuthMiddleware()
|
|
handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(linkHandler.HandleCreateLink)))
|
|
|
|
// Test request without token
|
|
requestBody := `{"url": "https://example.com"}`
|
|
w := testutil.PerformRequestWithHandler(handler, http.MethodPost, "/api/v1/links",
|
|
testutil.WithBody(requestBody),
|
|
)
|
|
|
|
// Assert response
|
|
resp := testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusUnauthorized)
|
|
}
|
|
|
|
func TestHandleListLinks_Success(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user and get token
|
|
_, token, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Create logger for tests
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
|
|
// Create link handler
|
|
linkHandler := NewLinkHandler(deps.Dependencies, logger)
|
|
|
|
// Create handlers with auth middleware
|
|
globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuthMiddleware := middleware.RequireAuthMiddleware()
|
|
handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(linkHandler.HandleListLinks)))
|
|
|
|
// Test request
|
|
w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
|
|
// Assert response
|
|
resp := testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
|
|
// Check response structure
|
|
var listResp ListLinksResponse
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, listResp.Items)
|
|
require.GreaterOrEqual(t, listResp.Total, 0)
|
|
}
|
|
|
|
func TestHandleListLinks_WithSearch(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user and get token
|
|
user, token, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Create logger for tests
|
|
logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
|
|
|
|
// Create link handler
|
|
linkHandler := NewLinkHandler(deps.Dependencies, logger)
|
|
|
|
// Create handlers with auth middleware
|
|
globalAuthMiddleware := middleware.AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuthMiddleware := middleware.RequireAuthMiddleware()
|
|
handler := globalAuthMiddleware(requireAuthMiddleware(http.HandlerFunc(linkHandler.HandleListLinks)))
|
|
|
|
// Create a link with a searchable URL
|
|
linkDomain := deps.Dependencies.Domains().Links()
|
|
link, err := linkDomain.CreateLink(ctx, "https://example.com/searchable", user.ID.String())
|
|
require.NoError(t, err)
|
|
|
|
// Create an archive with a searchable title
|
|
now := time.Now()
|
|
archive := &model.Archive{
|
|
ID: uuid.New().String(),
|
|
LinkID: link.ID,
|
|
UserID: user.ID.String(),
|
|
Status: model.ArchiveStatusCompleted,
|
|
Title: "Searchable Title Content",
|
|
CreatedAt: now,
|
|
}
|
|
err = deps.Dependencies.ArchiveStore.Create(ctx, archive)
|
|
require.NoError(t, err)
|
|
|
|
// Create an archive file with searchable content
|
|
archiveFile := &model.ArchiveFile{
|
|
ID: uuid.New().String(),
|
|
ArchiveID: archive.ID,
|
|
ArchiverKey: "test",
|
|
Filename: "test.txt",
|
|
MimeType: "text/plain",
|
|
Content: "This is searchable content text",
|
|
CreatedAt: now,
|
|
}
|
|
err = deps.Dependencies.ArchiveFileStore.Create(ctx, archiveFile)
|
|
require.NoError(t, err)
|
|
|
|
// Test search by URL
|
|
w := testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links?q=searchable",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
resp := testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
var listResp ListLinksResponse
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(listResp.Items), 1, "Should find link by URL search")
|
|
require.Equal(t, link.ID, listResp.Items[0].ID)
|
|
|
|
// Test search by title
|
|
w = testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links?q=Title",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
resp = testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(listResp.Items), 1, "Should find link by title search")
|
|
|
|
// Test that search queries with less than 3 characters are ignored
|
|
w = testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links?q=ab",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
resp = testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
// Should return all links (no search filter applied)
|
|
require.GreaterOrEqual(t, len(listResp.Items), 1, "Should return all links when query is too short")
|
|
|
|
// Test search by content
|
|
w = testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links?q=content",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
resp = testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
require.GreaterOrEqual(t, len(listResp.Items), 1, "Should find link by content search")
|
|
|
|
// Test search with no results
|
|
w = testutil.PerformRequestWithHandler(handler, http.MethodGet, "/api/v1/links?q=nonexistentterm12345",
|
|
testutil.WithAuthToken(token),
|
|
)
|
|
resp = testutil.NewTestResponse(w)
|
|
resp.AssertStatus(t, http.StatusOK)
|
|
err = json.Unmarshal(resp.GetBody(), &listResp)
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(listResp.Items), "Should return no results for nonexistent term")
|
|
}
|