181 lines
6.7 KiB
Go
181 lines
6.7 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/api"
|
|
validator "RenewCMS/api/pkg/validator"
|
|
domainArticle "RenewCMS/internal/domain/article"
|
|
domainImage "RenewCMS/internal/domain/image"
|
|
"RenewCMS/internal/domain/user"
|
|
"RenewCMS/internal/infrastructure/config"
|
|
"RenewCMS/internal/infrastructure/useCases"
|
|
"bytes"
|
|
"encoding/json"
|
|
"log"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/go-chi/jwtauth/v5"
|
|
)
|
|
|
|
const (
|
|
mediaVerifiedUserId uint32 = 1
|
|
mediaSecondUserId uint32 = 2
|
|
mediaUnverifiedUserId uint32 = 3
|
|
mediaStaleUserId uint32 = 4
|
|
)
|
|
|
|
type mediaEnv struct {
|
|
articles *mockArticleRepo
|
|
images *mockImageRepo
|
|
variants *mockVariantFileRepo
|
|
storage *mockImageStorage
|
|
users *mockUserRepo
|
|
purgeSettings *mockPurgeSettingsRepo
|
|
clock time.Time
|
|
logs *bytes.Buffer
|
|
token *jwtauth.JWTAuth
|
|
router http.Handler
|
|
}
|
|
|
|
func newMediaEnv(t *testing.T) *mediaEnv {
|
|
t.Helper()
|
|
validator.InitValidator()
|
|
|
|
env := &mediaEnv{
|
|
articles: newMockArticleRepo(),
|
|
images: newMockImageRepo(),
|
|
variants: newMockVariantFileRepo(),
|
|
storage: newMockImageStorage(),
|
|
users: newMockUserRepo(),
|
|
token: jwtauth.New("HS256", []byte("test-secret"), nil),
|
|
purgeSettings: newMockPurgeSettingsRepo(),
|
|
clock: time.Date(2026, time.October, 5, 9, 0, 0, 0, time.UTC),
|
|
logs: &bytes.Buffer{},
|
|
}
|
|
env.users.users[mediaVerifiedUserId] = user.User{ID: 1, Username: "ines", DisplayName: "Inès Duarte", IsVerified: true}
|
|
env.users.users[mediaSecondUserId] = user.User{ID: 2, Username: "marta", IsVerified: true}
|
|
env.users.users[mediaUnverifiedUserId] = user.User{ID: 3, Username: "pending", IsVerified: false}
|
|
env.users.users[mediaStaleUserId] = user.User{ID: 4, Username: "stale", IsVerified: true, TokenVersion: 1}
|
|
|
|
merge := useCases.NewMergeMediaUseCase(env.images, env.articles, env.storage, newMockVariantFileRepo(), discardRecorder, plainSites(), plainAuthors())
|
|
now := func() time.Time { return env.clock }
|
|
container := &api.UseCases{
|
|
Token: env.token,
|
|
CreateArticleUseCase: useCases.NewCreateArticleUseCase(env.articles, &fakeBodyRenderer{}, discardRecorder, plainSites(), plainAuthors()),
|
|
GetArticleUseCase: useCases.NewGetArticleUseCase(env.articles, &fakeBodyRenderer{}),
|
|
ListArticlesUseCase: useCases.NewListArticlesUseCase(env.articles, &fakeBodyRenderer{}, plainSites()),
|
|
UpdateArticleUseCase: useCases.NewUpdateArticleUseCase(env.articles, &fakeBodyRenderer{}, discardRecorder, plainSites(), plainAuthors()),
|
|
DeleteArticleUseCase: useCases.NewDeleteArticleUseCase(env.articles, discardRecorder),
|
|
GetUserUseCase: useCases.NewGetUserUseCase(env.users),
|
|
GetMyAuthorUseCase: useCases.NewGetMyAuthorUseCase(plainAuthors()),
|
|
CreateImageUseCase: useCases.NewCreateImageUseCase(env.images, env.storage, discardRecorder),
|
|
GenerateVariantsOnUploadUseCase: newInertGenerateOnUploadUseCase(),
|
|
ListMediaUseCase: useCases.NewListMediaUseCase(env.images, env.articles, env.users, env.variants, plainSites(), plainAuthors()),
|
|
RenameMediaUseCase: useCases.NewRenameMediaUseCase(env.images, discardRecorder),
|
|
DeleteMediaUseCase: useCases.NewDeleteMediaUseCase(env.images, env.storage, newMockVariantFileRepo(), discardRecorder, plainSites(), plainAuthors()),
|
|
MergeMediaUseCase: merge,
|
|
GetMediaUsageUseCase: useCases.NewGetMediaUsageUseCase(env.images, env.articles),
|
|
GetPurgeSettingsUseCase: useCases.NewGetPurgeSettingsUseCase(env.purgeSettings),
|
|
UpdatePurgeSettingsUseCase: useCases.NewUpdatePurgeSettingsUseCase(env.purgeSettings, now),
|
|
PreviewPurgeUseCase: useCases.NewPreviewPurgeUseCase(env.images, env.articles, plainSites(), plainAuthors()),
|
|
RunPurgeUseCase: useCases.NewRunPurgeUseCase(env.images, env.articles, merge, env.purgeSettings, now, log.New(env.logs, "", 0), discardRecorder, plainSites(), plainAuthors()),
|
|
}
|
|
router := chi.NewRouter()
|
|
router.Mount("/v1", api.InitBackendRoutes(container, config.Settings{}))
|
|
env.router = router
|
|
return env
|
|
}
|
|
|
|
func (e *mediaEnv) cookie(t *testing.T, userId uint32, tokenVersion uint32) *http.Cookie {
|
|
t.Helper()
|
|
_, tokenString, err := e.token.Encode(map[string]any{"user_id": userId, "token_version": tokenVersion})
|
|
if err != nil {
|
|
t.Fatalf("failed to encode jwt: %v", err)
|
|
}
|
|
return &http.Cookie{Name: "jwt", Value: tokenString}
|
|
}
|
|
|
|
func (e *mediaEnv) serve(t *testing.T, req *http.Request, userId uint32) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
if userId != 0 {
|
|
req.AddCookie(e.cookie(t, userId, 0))
|
|
}
|
|
rec := httptest.NewRecorder()
|
|
e.router.ServeHTTP(rec, req)
|
|
return rec
|
|
}
|
|
|
|
func (e *mediaEnv) send(t *testing.T, method string, path string, body string, userId uint32) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
req := httptest.NewRequest(method, path, strings.NewReader(body))
|
|
if body != "" {
|
|
req.Header.Set("Content-Type", "application/json")
|
|
}
|
|
return e.serve(t, req, userId)
|
|
}
|
|
|
|
func (e *mediaEnv) seedImage(id uint32, filename string, size int64, contentType string, width int, height int, hash string, uploadedBy uint32) {
|
|
extension := map[string]string{"image/jpeg": ".jpeg", "image/svg+xml": ".svg", "image/png": ".png"}[contentType]
|
|
e.images.images[id] = domainImage.Image{
|
|
ID: id,
|
|
Path: "/static/uploadedImages/img-" + strconv.Itoa(int(id)) + "-" + extension,
|
|
Filename: filename,
|
|
Size: size,
|
|
ContentType: contentType,
|
|
Width: width,
|
|
Height: height,
|
|
SHA256: hash,
|
|
UploadedByID: uploadedBy,
|
|
CreatedAt: mockImageEpoch.Add(time.Duration(id) * time.Minute),
|
|
}
|
|
if id > e.images.nextID {
|
|
e.images.nextID = id
|
|
}
|
|
}
|
|
|
|
func (e *mediaEnv) urlOf(id uint32) string {
|
|
return e.images.images[id].Path
|
|
}
|
|
|
|
func (e *mediaEnv) seedArticle(id uint32, title string, online bool, body string) {
|
|
e.articles.articles[id] = domainArticle.Article{ID: id, Title: title, IsOnline: online, Body: body}
|
|
if id > e.articles.nextID {
|
|
e.articles.nextID = id
|
|
}
|
|
}
|
|
|
|
func (e *mediaEnv) bodies() map[uint32]string {
|
|
result := map[uint32]string{}
|
|
for id, a := range e.articles.articles {
|
|
result[id] = a.Body
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (e *mediaEnv) imageIds() []uint32 {
|
|
ids := make([]uint32, 0)
|
|
for _, img := range e.images.sortedImages() {
|
|
ids = append(ids, img.ID)
|
|
}
|
|
return ids
|
|
}
|
|
|
|
func decodeObject(t *testing.T, body string) map[string]any {
|
|
t.Helper()
|
|
var decoded map[string]any
|
|
if err := json.Unmarshal([]byte(body), &decoded); err != nil {
|
|
t.Fatalf("failed to decode %q: %v", body, err)
|
|
}
|
|
return decoded
|
|
}
|
|
|
|
func numberOf(value any) uint32 {
|
|
number, _ := value.(float64)
|
|
return uint32(number)
|
|
}
|