Files
nekonest-cloud/relay/internal/tenantpurge/purge_test.go
T

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)
}
}