| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | package core_test | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io/fs" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/core" | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/tests" | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/tools/archive" | 
					
						
							|  |  |  | 	"github.com/pocketbase/pocketbase/tools/list" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestCreateBackup(t *testing.T) { | 
					
						
							|  |  |  | 	app, _ := tests.NewTestApp() | 
					
						
							|  |  |  | 	defer app.Cleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-29 01:34:44 +08:00
										 |  |  | 	// set some long app name with spaces and special characters
 | 
					
						
							|  |  |  | 	app.Settings().Meta.AppName = "test @! " + strings.Repeat("a", 100) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	expectedAppNamePrefix := "test_" + strings.Repeat("a", 45) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 	// test pending error
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	app.Store().Set(core.StoreKeyActiveBackup, "") | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 	if err := app.CreateBackup(context.Background(), "test.zip"); err == nil { | 
					
						
							|  |  |  | 		t.Fatal("Expected pending error, got nil") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	app.Store().Remove(core.StoreKeyActiveBackup) | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// create with auto generated name
 | 
					
						
							|  |  |  | 	if err := app.CreateBackup(context.Background(), ""); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to create a backup with autogenerated name") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// create with custom name
 | 
					
						
							|  |  |  | 	if err := app.CreateBackup(context.Background(), "custom"); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to create a backup with custom name") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// create new with the same name (aka. replace)
 | 
					
						
							|  |  |  | 	if err := app.CreateBackup(context.Background(), "custom"); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to create and replace a backup with the same name") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	backupsDir := filepath.Join(app.DataDir(), core.LocalBackupsDirName) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	entries, err := os.ReadDir(backupsDir) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		t.Fatal(err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	expectedFiles := []string{ | 
					
						
							| 
									
										
										
										
											2023-08-29 01:34:44 +08:00
										 |  |  | 		`^pb_backup_` + expectedAppNamePrefix + `_\w+\.zip$`, | 
					
						
							|  |  |  | 		`^pb_backup_` + expectedAppNamePrefix + `_\w+\.zip.attrs$`, | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 		"custom", | 
					
						
							|  |  |  | 		"custom.attrs", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(entries) != len(expectedFiles) { | 
					
						
							|  |  |  | 		names := getEntryNames(entries) | 
					
						
							|  |  |  | 		t.Fatalf("Expected %d backup files, got %d: \n%v", len(expectedFiles), len(entries), names) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, entry := range entries { | 
					
						
							|  |  |  | 		if !list.ExistInSliceWithRegex(entry.Name(), expectedFiles) { | 
					
						
							|  |  |  | 			t.Fatalf("[%d] Missing backup file %q", i, entry.Name()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if strings.HasSuffix(entry.Name(), ".attrs") { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		path := filepath.Join(backupsDir, entry.Name()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := verifyBackupContent(app, path); err != nil { | 
					
						
							|  |  |  | 			t.Fatalf("[%d] Failed to verify backup content: %v", i, err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRestoreBackup(t *testing.T) { | 
					
						
							|  |  |  | 	app, _ := tests.NewTestApp() | 
					
						
							|  |  |  | 	defer app.Cleanup() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-23 21:47:58 +08:00
										 |  |  | 	// create a initial test backup to ensure that there are at least 1
 | 
					
						
							|  |  |  | 	// backup file and that the generated zip doesn't contain the backups dir
 | 
					
						
							|  |  |  | 	if err := app.CreateBackup(context.Background(), "initial"); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to create test initial backup") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 	// create test backup
 | 
					
						
							|  |  |  | 	if err := app.CreateBackup(context.Background(), "test"); err != nil { | 
					
						
							|  |  |  | 		t.Fatal("Failed to create test backup") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// test pending error
 | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	app.Store().Set(core.StoreKeyActiveBackup, "") | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 	if err := app.RestoreBackup(context.Background(), "test"); err == nil { | 
					
						
							|  |  |  | 		t.Fatal("Expected pending error, got nil") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-11-26 19:33:17 +08:00
										 |  |  | 	app.Store().Remove(core.StoreKeyActiveBackup) | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// missing backup
 | 
					
						
							|  |  |  | 	if err := app.RestoreBackup(context.Background(), "missing"); err == nil { | 
					
						
							|  |  |  | 		t.Fatal("Expected missing error, got nil") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // -------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func verifyBackupContent(app core.App, path string) error { | 
					
						
							|  |  |  | 	dir, err := os.MkdirTemp("", "backup_test") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer os.RemoveAll(dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if err := archive.Extract(path, dir); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	expectedRootEntries := []string{ | 
					
						
							|  |  |  | 		"storage", | 
					
						
							|  |  |  | 		"data.db", | 
					
						
							|  |  |  | 		"data.db-shm", | 
					
						
							|  |  |  | 		"data.db-wal", | 
					
						
							| 
									
										
										
										
											2024-10-06 21:41:05 +08:00
										 |  |  | 		"auxiliary.db", | 
					
						
							|  |  |  | 		"auxiliary.db-shm", | 
					
						
							|  |  |  | 		"auxiliary.db-wal", | 
					
						
							| 
									
										
										
										
											2023-05-14 03:10:14 +08:00
										 |  |  | 		".gitignore", | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	entries, err := os.ReadDir(dir) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if len(entries) != len(expectedRootEntries) { | 
					
						
							|  |  |  | 		names := getEntryNames(entries) | 
					
						
							|  |  |  | 		return fmt.Errorf("Expected %d backup files, got %d: \n%v", len(expectedRootEntries), len(entries), names) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, entry := range entries { | 
					
						
							|  |  |  | 		if !list.ExistInSliceWithRegex(entry.Name(), expectedRootEntries) { | 
					
						
							|  |  |  | 			return fmt.Errorf("Didn't expect %q entry", entry.Name()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getEntryNames(entries []fs.DirEntry) []string { | 
					
						
							|  |  |  | 	names := make([]string, len(entries)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i, entry := range entries { | 
					
						
							|  |  |  | 		names[i] = entry.Name() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return names | 
					
						
							|  |  |  | } |