Add API Server (Go/PocketBase), Web App (Go BFF + Vue), Fly App (Flutter/DJI MSDK), Adobe Plugin, and Docker/Docker AIO deployment configs. Design assets and build artifacts are gitignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
100 lines
2.9 KiB
Go
100 lines
2.9 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func mountByID(mounts []lsMount, id string) (lsMount, bool) {
|
|
for _, m := range mounts {
|
|
if m.ID == id {
|
|
return m, true
|
|
}
|
|
}
|
|
return lsMount{}, false
|
|
}
|
|
|
|
func TestTenantMountsOrgUser(t *testing.T) {
|
|
who := &callerIdentity{ID: "u1", OrgID: "org9"}
|
|
|
|
// Private off: only the shared org folder.
|
|
off := tenantMounts("/data", who, false)
|
|
if len(off) != 1 {
|
|
t.Fatalf("private off: got %d mounts, want 1", len(off))
|
|
}
|
|
if off[0].ID != "shared" || off[0].Path != "/data/orgs/org9/shared" {
|
|
t.Errorf("shared mount = %+v", off[0])
|
|
}
|
|
|
|
// Private on: shared + a private folder nested inside the org folder.
|
|
on := tenantMounts("/data", who, true)
|
|
if len(on) != 2 {
|
|
t.Fatalf("private on: got %d mounts, want 2", len(on))
|
|
}
|
|
priv, ok := mountByID(on, "private")
|
|
if !ok || priv.Path != "/data/orgs/org9/private/u1" || priv.Kind != "private" {
|
|
t.Errorf("private mount = %+v", priv)
|
|
}
|
|
// The private folder must sit under the org folder but NOT under the shared
|
|
// subtree, so shared-folder members cannot traverse into it.
|
|
shared, _ := mountByID(on, "shared")
|
|
if !strings.HasPrefix(priv.Path, "/data/orgs/org9/") {
|
|
t.Errorf("private folder %q is not inside the org folder", priv.Path)
|
|
}
|
|
if strings.HasPrefix(priv.Path, shared.Path+"/") {
|
|
t.Errorf("private folder %q is reachable from the shared folder %q", priv.Path, shared.Path)
|
|
}
|
|
}
|
|
|
|
func TestTenantMountsOrgLessUser(t *testing.T) {
|
|
m := tenantMounts("/data", &callerIdentity{ID: "solo"}, true)
|
|
if len(m) != 1 || m[0].ID != "personal" || m[0].Path != "/data/users/solo" || m[0].Kind != "private" {
|
|
t.Fatalf("org-less mounts = %+v", m)
|
|
}
|
|
}
|
|
|
|
func TestTenantMountsNoRoot(t *testing.T) {
|
|
if m := tenantMounts("", &callerIdentity{ID: "u1", OrgID: "o"}, true); len(m) != 0 {
|
|
t.Fatalf("no root: got %d mounts, want 0", len(m))
|
|
}
|
|
if m := tenantMounts(" ", &callerIdentity{ID: "u1"}, true); len(m) != 0 {
|
|
t.Fatalf("blank root: got %d mounts, want 0", len(m))
|
|
}
|
|
}
|
|
|
|
// Two members' private folders must never collide (isolation).
|
|
func TestPrivateFolderIsolation(t *testing.T) {
|
|
a := orgPrivateFolder("/data", "org1", "alice")
|
|
b := orgPrivateFolder("/data", "org1", "bob")
|
|
if a == b {
|
|
t.Fatalf("distinct members share a private folder: %q", a)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeReadOnly(t *testing.T) {
|
|
cases := map[string]string{
|
|
"true": "true", "TRUE": "true", " true ": "true",
|
|
"false": "false", "False": "false",
|
|
"": "", "inherit": "", "garbage": "",
|
|
}
|
|
for in, want := range cases {
|
|
if got := normalizeReadOnly(in); got != want {
|
|
t.Errorf("normalizeReadOnly(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestWorseStatus(t *testing.T) {
|
|
cases := []struct{ a, b, want string }{
|
|
{"ok", "ok", "ok"},
|
|
{"ok", "degraded", "degraded"},
|
|
{"degraded", "down", "down"},
|
|
{"down", "ok", "down"},
|
|
}
|
|
for _, c := range cases {
|
|
if got := worseStatus(c.a, c.b); got != c.want {
|
|
t.Errorf("worseStatus(%q,%q) = %q, want %q", c.a, c.b, got, c.want)
|
|
}
|
|
}
|
|
}
|