(untested!) added temp backup api scaffoldings before introducing autobackups and rotations

This commit is contained in:
Gani Georgiev
2023-05-08 21:52:40 +03:00
parent 60eee96034
commit d3314e1e23
17 changed files with 914 additions and 40 deletions
+21 -4
View File
@@ -5,10 +5,19 @@ import (
"io"
"io/fs"
"os"
"path/filepath"
"strings"
)
// Create creates a new zip archive from src dir content and saves it in dest path.
func Create(src, dest string) error {
//
// You can specify skipPaths to skip/ignore certain directories and files (relative to src)
// preventing adding them in the final archive.
func Create(src string, dest string, skipPaths ...string) error {
if err := os.MkdirAll(filepath.Dir(dest), os.ModePerm); err != nil {
return err
}
zf, err := os.Create(dest)
if err != nil {
return err
@@ -18,8 +27,8 @@ func Create(src, dest string) error {
zw := zip.NewWriter(zf)
defer zw.Close()
if err := zipAddFS(zw, os.DirFS(src)); err != nil {
// try to cleanup the created zip file
if err := zipAddFS(zw, os.DirFS(src), skipPaths...); err != nil {
// try to cleanup at least the created zip file
os.Remove(dest)
return err
@@ -29,7 +38,7 @@ func Create(src, dest string) error {
}
// note remove after similar method is added in the std lib (https://github.com/golang/go/issues/54898)
func zipAddFS(w *zip.Writer, fsys fs.FS) error {
func zipAddFS(w *zip.Writer, fsys fs.FS, skipPaths ...string) error {
return fs.WalkDir(fsys, ".", func(name string, d fs.DirEntry, err error) error {
if err != nil {
return err
@@ -39,6 +48,14 @@ func zipAddFS(w *zip.Writer, fsys fs.FS) error {
return nil
}
// skip
for _, ignore := range skipPaths {
if ignore == name ||
strings.HasPrefix(name+string(os.PathSeparator), filepath.Clean(ignore)+string(os.PathSeparator)) {
return nil
}
}
info, err := d.Info()
if err != nil {
return err
+47 -11
View File
@@ -34,8 +34,8 @@ func TestCreateSuccess(t *testing.T) {
zipPath := filepath.Join(os.TempDir(), zipName)
defer os.RemoveAll(zipPath)
// zip testDir content
if err := archive.Create(testDir, zipPath); err != nil {
// zip testDir content (excluding test and a/b/c dir)
if err := archive.Create(testDir, zipPath, "a/b/c", "test"); err != nil {
t.Fatalf("Failed to create archive: %v", err)
}
@@ -48,7 +48,7 @@ func TestCreateSuccess(t *testing.T) {
t.Fatalf("Expected zip with name %q, got %q", zipName, name)
}
expectedSize := int64(300)
expectedSize := int64(405)
if size := info.Size(); size != expectedSize {
t.Fatalf("Expected zip with size %d, got %d", expectedSize, size)
}
@@ -68,17 +68,53 @@ func createTestDir(t *testing.T) string {
t.Fatal(err)
}
sub1, err := os.OpenFile(filepath.Join(dir, "a/sub1.txt"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
{
f, err := os.OpenFile(filepath.Join(dir, "test"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
sub1.Close()
sub2, err := os.OpenFile(filepath.Join(dir, "a/b/c/sub2.txt"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
{
f, err := os.OpenFile(filepath.Join(dir, "test2"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
{
f, err := os.OpenFile(filepath.Join(dir, "a/test"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
{
f, err := os.OpenFile(filepath.Join(dir, "a/b/sub1"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
{
f, err := os.OpenFile(filepath.Join(dir, "a/b/c/sub2"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
{
f, err := os.OpenFile(filepath.Join(dir, "a/b/c/sub3"), os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
t.Fatal(err)
}
f.Close()
}
sub2.Close()
return dir
}
+48 -18
View File
@@ -1,6 +1,7 @@
package archive_test
import (
"io/fs"
"os"
"path/filepath"
"testing"
@@ -13,15 +14,15 @@ func TestExtractFailure(t *testing.T) {
defer os.RemoveAll(testDir)
missingZipPath := filepath.Join(os.TempDir(), "pb_missing_test.zip")
extractPath := filepath.Join(os.TempDir(), "pb_zip_extract")
defer os.RemoveAll(extractPath)
extractedPath := filepath.Join(os.TempDir(), "pb_zip_extract")
defer os.RemoveAll(extractedPath)
if err := archive.Extract(missingZipPath, extractPath); err == nil {
if err := archive.Extract(missingZipPath, extractedPath); err == nil {
t.Fatal("Expected Extract to fail due to missing zipPath")
}
if _, err := os.Stat(extractPath); err == nil {
t.Fatalf("Expected %q to not be created", extractPath)
if _, err := os.Stat(extractedPath); err == nil {
t.Fatalf("Expected %q to not be created", extractedPath)
}
}
@@ -32,26 +33,55 @@ func TestExtractSuccess(t *testing.T) {
zipPath := filepath.Join(os.TempDir(), "pb_test.zip")
defer os.RemoveAll(zipPath)
extractPath := filepath.Join(os.TempDir(), "pb_zip_extract")
defer os.RemoveAll(extractPath)
extractedPath := filepath.Join(os.TempDir(), "pb_zip_extract")
defer os.RemoveAll(extractedPath)
// zip testDir content
if err := archive.Create(testDir, zipPath); err != nil {
// zip testDir content (with exclude)
if err := archive.Create(testDir, zipPath, "a/b/c", "test", "sub2"); err != nil {
t.Fatalf("Failed to create archive: %v", err)
}
if err := archive.Extract(zipPath, extractPath); err != nil {
t.Fatalf("Failed to extract %q in %q", zipPath, extractPath)
if err := archive.Extract(zipPath, extractedPath); err != nil {
t.Fatalf("Failed to extract %q in %q", zipPath, extractedPath)
}
pathsToCheck := []string{
filepath.Join(extractPath, "a/sub1.txt"),
filepath.Join(extractPath, "a/b/c/sub2.txt"),
}
availableFiles := []string{}
for _, p := range pathsToCheck {
if _, err := os.Stat(p); err != nil {
t.Fatalf("Failed to retrieve extracted file %q: %v", p, err)
walkErr := filepath.WalkDir(extractedPath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
availableFiles = append(availableFiles, path)
return nil
})
if walkErr != nil {
t.Fatalf("Failed to read the extracted dir: %v", walkErr)
}
expectedFiles := []string{
filepath.Join(extractedPath, "test2"),
filepath.Join(extractedPath, "a/test"),
filepath.Join(extractedPath, "a/b/sub1"),
}
if len(availableFiles) != len(expectedFiles) {
t.Fatalf("Expected \n%v, \ngot \n%v", expectedFiles, availableFiles)
}
ExpectedLoop:
for _, expected := range expectedFiles {
for _, available := range availableFiles {
if available == expected {
continue ExpectedLoop
}
}
t.Fatalf("Missing file %q in \n%v", expected, availableFiles)
}
}