Files
excalicloud/internal/api/api_test.go
T
claude BotandClaude Opus 5.5 824871bd24 Espaces personnels et favoris : API par utilisateur, /api/me.id, tests
- Chaque route de schémas passe par la vue de l'utilisateur connecté
  (storage.Space) : arborescence commune, .perso et .favoris.
- /api/public résout aussi les liens des espaces personnels.
- /api/me renvoie id (dossier de l'utilisateur : email OIDC, sinon « local »).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0174sFqehj4uGqJHQZvWy1gn
2026-10-08 10:26:31 +02:00

90 lines
2.9 KiB
Go

package api
import (
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/vblogio/excalidraw-go/internal/storage"
)
const doc = `{"type":"excalidraw","version":2,"elements":[]}`
// L'utilisateur vient de l'en-tête X-User (à la place de la session OIDC).
func newServer(t *testing.T) *httptest.Server {
t.Helper()
st, err := storage.New(t.TempDir())
if err != nil {
t.Fatal(err)
}
mux := http.NewServeMux()
(&Handler{
Store: st,
Spaces: storage.NewSpaces(st),
User: func(r *http.Request) string { return storage.UserID(r.Header.Get("X-User")) },
MaxBody: 1 << 20,
}).Register(mux)
srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)
return srv
}
func call(t *testing.T, srv *httptest.Server, user, method, url, body string, out any) int {
t.Helper()
req, _ := http.NewRequest(method, srv.URL+url, strings.NewReader(body))
req.Header.Set("X-User", user)
res, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()
if out != nil {
_ = json.NewDecoder(res.Body).Decode(out)
}
return res.StatusCode
}
func TestFavoritesPerUser(t *testing.T) {
srv := newServer(t)
for _, p := range []string{"a.excalidraw", ".perso/mine.excalidraw"} {
if c := call(t, srv, "alice@x.fr", "PUT", "/api/file?path="+p, doc, nil); c != 200 {
t.Fatalf("écriture %s : %d", p, c)
}
}
if c := call(t, srv, "alice@x.fr", "POST", "/api/meta/favorite", `{"paths":["a.excalidraw",".perso/mine.excalidraw"],"favorite":true}`, nil); c != 204 {
t.Fatalf("favori : %d", c)
}
var favs []storage.Entry
call(t, srv, "alice@x.fr", "GET", "/api/list?path=.favoris", "", &favs)
if len(favs) != 2 || favs[0].Path != "a.excalidraw" || favs[1].Path != ".perso/mine.excalidraw" {
t.Fatalf("favoris d'alice = %+v", favs)
}
call(t, srv, "bob@x.fr", "GET", "/api/list?path=.favoris", "", &favs)
if len(favs) != 0 {
t.Fatalf("favoris de bob = %+v", favs)
}
var root []storage.Entry
call(t, srv, "bob@x.fr", "GET", "/api/list?path=", "", &root)
if len(root) != 3 || root[0].Special != "favoris" || root[2].Favorite {
t.Fatalf("racine de bob = %+v", root)
}
if c := call(t, srv, "bob@x.fr", "GET", "/api/file?path=.perso/mine.excalidraw", "", nil); c != 404 {
t.Fatalf("bob lit l'espace d'alice : %d", c)
}
// Supprimer depuis Favoris ne retire que le lien.
call(t, srv, "alice@x.fr", "DELETE", "/api/entry?path=.favoris/a.excalidraw", "", nil)
if c := call(t, srv, "alice@x.fr", "GET", "/api/file?path=a.excalidraw", "", nil); c != 200 {
t.Fatalf("original supprimé avec le lien : %d", c)
}
call(t, srv, "alice@x.fr", "GET", "/api/list?path=.favoris", "", &favs)
if len(favs) != 1 {
t.Fatalf("favoris après retrait = %+v", favs)
}
// Écrire dans .favoris est refusé.
if c := call(t, srv, "alice@x.fr", "PUT", "/api/file?path=.favoris/x.excalidraw", doc, nil); c != 400 {
t.Fatalf("écriture dans Favoris : %d", c)
}
}