78 lines
2.4 KiB
Go
78 lines
2.4 KiB
Go
package tenantpurge
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/klarkxy/nekonest-cloud/relay/internal/tenantfs"
|
|
)
|
|
|
|
const testTenantID = "tenant_0123456789abcdef0123456789abcdef"
|
|
|
|
func TestPurgeDeletesLiveDataAndEveryBackupIdempotently(t *testing.T) {
|
|
dataRoot := t.TempDir()
|
|
backupRoot := t.TempDir()
|
|
paths, err := tenantfs.Resolve(dataRoot, testTenantID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(paths.Database, []byte("sqlite"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
backupTenant := filepath.Join(backupRoot, filepath.Base(paths.Root))
|
|
for _, name := range []string{"g1", "g2"} {
|
|
path := filepath.Join(backupTenant, name)
|
|
if err := os.MkdirAll(path, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(path, "manifest.json"), []byte("{}"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
first, err := Purge(context.Background(), dataRoot, backupRoot, testTenantID, 3)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !first.DataDeleted || !first.BackupsDeleted || len(first.EvidenceSHA256) != 64 {
|
|
t.Fatalf("purge result = %#v", first)
|
|
}
|
|
if _, err := os.Lstat(paths.Root); !os.IsNotExist(err) {
|
|
t.Fatalf("live tenant data survived: %v", err)
|
|
}
|
|
if _, err := os.Lstat(backupTenant); !os.IsNotExist(err) {
|
|
t.Fatalf("tenant backups survived: %v", err)
|
|
}
|
|
second, err := Purge(context.Background(), dataRoot, backupRoot, testTenantID, 3)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if second.DataDeleted || second.BackupsDeleted || second.EvidenceSHA256 != first.EvidenceSHA256 {
|
|
t.Fatalf("idempotent retry = %#v", second)
|
|
}
|
|
}
|
|
|
|
func TestPurgeRefusesSymbolicLinksWithoutTouchingTarget(t *testing.T) {
|
|
dataRoot := t.TempDir()
|
|
backupRoot := t.TempDir()
|
|
outside := t.TempDir()
|
|
outsideFile := filepath.Join(outside, "keep.txt")
|
|
if err := os.WriteFile(outsideFile, []byte("keep"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
paths, err := tenantfs.Resolve(dataRoot, testTenantID)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.Symlink(outsideFile, filepath.Join(paths.Root, "escape")); err != nil {
|
|
t.Skipf("symbolic links unavailable: %v", err)
|
|
}
|
|
if _, err := Purge(context.Background(), dataRoot, backupRoot, testTenantID, 1); err == nil {
|
|
t.Fatal("purge followed or accepted a symbolic link")
|
|
}
|
|
if data, err := os.ReadFile(outsideFile); err != nil || string(data) != "keep" {
|
|
t.Fatalf("outside target changed: data=%q err=%v", data, err)
|
|
}
|
|
}
|