feat: docker compose backup
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestApplyRetentionByCount(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
projDir := filepath.Join(dir, "testapp")
|
||||
os.MkdirAll(projDir, 0755)
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
name := "testapp-20250101-00000" + string(rune('1'+i)) + ".tar.gz"
|
||||
f, err := os.Create(filepath.Join(projDir, name))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
mt := time.Now().Add(-time.Duration(5-i) * time.Hour)
|
||||
os.Chtimes(f.Name(), mt, mt)
|
||||
}
|
||||
|
||||
removed, err := ApplyRetention(dir, "testapp", RetentionPolicy{Count: 3})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if removed != 2 {
|
||||
t.Errorf("expected 2 removed, got %d", removed)
|
||||
}
|
||||
|
||||
entries, _ := os.ReadDir(projDir)
|
||||
if len(entries) != 3 {
|
||||
t.Errorf("expected 3 remaining, got %d", len(entries))
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRetentionByDays(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
projDir := filepath.Join(dir, "testapp")
|
||||
os.MkdirAll(projDir, 0755)
|
||||
|
||||
oldTime := time.Now().AddDate(0, 0, -10)
|
||||
recentTime := time.Now().Add(-1 * time.Hour)
|
||||
|
||||
f1, _ := os.Create(filepath.Join(projDir, "testapp-old.tar.gz"))
|
||||
f1.Close()
|
||||
os.Chtimes(f1.Name(), oldTime, oldTime)
|
||||
|
||||
f2, _ := os.Create(filepath.Join(projDir, "testapp-recent.tar.gz"))
|
||||
f2.Close()
|
||||
os.Chtimes(f2.Name(), recentTime, recentTime)
|
||||
|
||||
removed, err := ApplyRetention(dir, "testapp", RetentionPolicy{Count: 0, Days: 7})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if removed != 1 {
|
||||
t.Errorf("expected 1 removed, got %d", removed)
|
||||
}
|
||||
|
||||
entries, _ := os.ReadDir(projDir)
|
||||
if len(entries) != 1 {
|
||||
t.Errorf("expected 1 remaining, got %d", len(entries))
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRetentionIgnoresNonBackupFiles(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
projDir := filepath.Join(dir, "testapp")
|
||||
os.MkdirAll(projDir, 0755)
|
||||
|
||||
keepNames := []string{"README.txt", "otherapp-20250101.tar.gz", "testapp-note.txt"}
|
||||
for _, name := range keepNames {
|
||||
f, err := os.Create(filepath.Join(projDir, name))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
name := "testapp-20250101-00000" + string(rune('1'+i)) + ".tar.gz"
|
||||
f, err := os.Create(filepath.Join(projDir, name))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
f.Close()
|
||||
mt := time.Now().Add(-time.Duration(3-i) * time.Hour)
|
||||
os.Chtimes(f.Name(), mt, mt)
|
||||
}
|
||||
|
||||
removed, err := ApplyRetention(dir, "testapp", RetentionPolicy{Count: 1})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if removed != 2 {
|
||||
t.Errorf("expected 2 removed, got %d", removed)
|
||||
}
|
||||
|
||||
for _, name := range keepNames {
|
||||
if _, err := os.Stat(filepath.Join(projDir, name)); err != nil {
|
||||
t.Fatalf("non-backup file %s should remain: %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRetentionEmptyDir(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
removed, err := ApplyRetention(dir, "nonexistent", RetentionPolicy{Count: 7})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if removed != 0 {
|
||||
t.Errorf("expected 0 removed, got %d", removed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyRetentionSortOrder(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
projDir := filepath.Join(dir, "testapp")
|
||||
os.MkdirAll(projDir, 0755)
|
||||
|
||||
times := []time.Time{
|
||||
time.Now().Add(-5 * time.Hour),
|
||||
time.Now().Add(-1 * time.Hour),
|
||||
time.Now().Add(-3 * time.Hour),
|
||||
}
|
||||
|
||||
for i, mt := range times {
|
||||
name := "testapp-2025010" + string(rune('1'+i)) + "-000001.tar.gz"
|
||||
f, _ := os.Create(filepath.Join(projDir, name))
|
||||
f.Close()
|
||||
os.Chtimes(f.Name(), mt, mt)
|
||||
}
|
||||
|
||||
removed, err := ApplyRetention(dir, "testapp", RetentionPolicy{Count: 2})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if removed != 1 {
|
||||
t.Fatalf("expected 1 removed, got %d", removed)
|
||||
}
|
||||
|
||||
entries, _ := os.ReadDir(projDir)
|
||||
names := make([]string, len(entries))
|
||||
for i, e := range entries {
|
||||
names[i] = e.Name()
|
||||
}
|
||||
sort.Strings(names)
|
||||
|
||||
expected := []string{"testapp-20250102-000001.tar.gz", "testapp-20250103-000001.tar.gz"}
|
||||
if len(names) != len(expected) {
|
||||
t.Fatalf("expected %v, got %v", expected, names)
|
||||
}
|
||||
for i := range expected {
|
||||
if expected[i] != names[i] {
|
||||
t.Errorf("expected[%d]=%s, got %s", i, expected[i], names[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user