2022-02-23 16:05:24 +00:00
|
|
|
package main_test
|
|
|
|
|
|
|
|
import (
|
2022-03-24 21:59:40 +00:00
|
|
|
"errors"
|
|
|
|
"log"
|
2022-02-23 16:05:24 +00:00
|
|
|
"os"
|
2022-03-24 21:59:40 +00:00
|
|
|
"path/filepath"
|
2022-02-23 16:05:24 +00:00
|
|
|
"testing"
|
2022-02-23 22:13:00 +00:00
|
|
|
"time"
|
2022-02-23 16:05:24 +00:00
|
|
|
|
|
|
|
main "git.iamthefij.com/iamthefij/restic-scheduler"
|
|
|
|
)
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
func TestNoOpts(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.NoOpts{}.ToArgs()
|
|
|
|
expected := []string{}
|
|
|
|
|
|
|
|
AssertEqual(t, "no opts returned some opts", expected, args)
|
|
|
|
}
|
|
|
|
|
2022-02-23 16:05:24 +00:00
|
|
|
func TestGlobalOptions(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.ResticGlobalOpts{
|
|
|
|
CaCertFile: "file",
|
|
|
|
CacheDir: "directory",
|
|
|
|
PasswordFile: "file",
|
|
|
|
TLSClientCertFile: "file",
|
|
|
|
LimitDownload: 1,
|
|
|
|
LimitUpload: 1,
|
|
|
|
VerboseLevel: 1,
|
|
|
|
CleanupCache: true,
|
2023-11-06 23:02:07 +00:00
|
|
|
InsecureTLS: true,
|
2022-02-23 16:05:24 +00:00
|
|
|
NoCache: true,
|
|
|
|
NoLock: true,
|
2022-11-03 22:34:17 +00:00
|
|
|
Options: map[string]string{
|
|
|
|
"key": "a long value",
|
|
|
|
},
|
2022-02-23 16:05:24 +00:00
|
|
|
}.ToArgs()
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"--cacert", "file",
|
|
|
|
"--cache-dir", "directory",
|
|
|
|
"--password-file", "file",
|
|
|
|
"--tls-client-cert", "file",
|
|
|
|
"--limit-download", "1",
|
|
|
|
"--limit-upload", "1",
|
|
|
|
"--verbose", "1",
|
|
|
|
"--cleanup-cache",
|
2023-11-06 23:02:07 +00:00
|
|
|
"--insecure-tls",
|
2022-02-23 16:05:24 +00:00
|
|
|
"--no-cache",
|
|
|
|
"--no-lock",
|
2022-11-03 23:43:17 +00:00
|
|
|
"--option", "key='a long value'",
|
2022-02-23 16:05:24 +00:00
|
|
|
}
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
AssertEqual(t, "args didn't match", expected, args)
|
2022-02-23 16:05:24 +00:00
|
|
|
}
|
|
|
|
|
2022-02-23 22:13:00 +00:00
|
|
|
func TestBackupOpts(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.BackupOpts{
|
|
|
|
Exclude: []string{"file1", "file2"},
|
|
|
|
Include: []string{"directory"},
|
|
|
|
Tags: []string{"thing"},
|
|
|
|
Host: "steve",
|
|
|
|
}.ToArgs()
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"--exclude", "file1",
|
|
|
|
"--exclude", "file2",
|
|
|
|
"--include", "directory",
|
|
|
|
"--tag", "thing",
|
|
|
|
"--host", "steve",
|
|
|
|
}
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
AssertEqual(t, "args didn't match", expected, args)
|
2022-02-23 22:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestRestoreOpts(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.RestoreOpts{
|
|
|
|
Exclude: []string{"file1", "file2"},
|
|
|
|
Include: []string{"directory"},
|
|
|
|
Host: []string{"steve"},
|
|
|
|
Tags: []string{"thing"},
|
|
|
|
Path: "directory",
|
|
|
|
Target: "directory",
|
|
|
|
Verify: true,
|
|
|
|
}.ToArgs()
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"--exclude", "file1",
|
|
|
|
"--exclude", "file2",
|
|
|
|
"--include", "directory",
|
|
|
|
"--host", "steve",
|
|
|
|
"--tag", "thing",
|
|
|
|
"--path", "directory",
|
|
|
|
"--target", "directory",
|
|
|
|
"--verify",
|
|
|
|
}
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
AssertEqual(t, "args didn't match", expected, args)
|
2022-02-23 22:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestForgetOpts(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.ForgetOpts{
|
|
|
|
KeepLast: 1,
|
|
|
|
KeepHourly: 1,
|
|
|
|
KeepDaily: 1,
|
|
|
|
KeepWeekly: 1,
|
|
|
|
KeepMonthly: 1,
|
|
|
|
KeepYearly: 1,
|
|
|
|
KeepWithin: 1 * time.Second,
|
|
|
|
KeepWithinHourly: 1 * time.Second,
|
|
|
|
KeepWithinDaily: 1 * time.Second,
|
|
|
|
KeepWithinWeekly: 1 * time.Second,
|
|
|
|
KeepWithinMonthly: 1 * time.Second,
|
|
|
|
KeepWithinYearly: 1 * time.Second,
|
|
|
|
Tags: []main.TagList{
|
|
|
|
{"thing1", "thing2"},
|
|
|
|
{"otherthing"},
|
|
|
|
},
|
|
|
|
KeepTags: []main.TagList{{"thing"}},
|
|
|
|
Prune: true,
|
|
|
|
}.ToArgs()
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"--keep-last", "1",
|
|
|
|
"--keep-hourly", "1",
|
|
|
|
"--keep-daily", "1",
|
|
|
|
"--keep-weekly", "1",
|
|
|
|
"--keep-monthly", "1",
|
|
|
|
"--keep-yearly", "1",
|
|
|
|
"--keep-within", "1s",
|
|
|
|
"--keep-within-hourly", "1s",
|
|
|
|
"--keep-within-daily", "1s",
|
|
|
|
"--keep-within-weekly", "1s",
|
|
|
|
"--keep-within-monthly", "1s",
|
|
|
|
"--keep-within-yearly", "1s",
|
|
|
|
"--tag", "thing1,thing2",
|
|
|
|
"--tag", "otherthing",
|
|
|
|
"--keep-tag", "thing",
|
|
|
|
"--prune",
|
|
|
|
}
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
AssertEqual(t, "args didn't match", expected, args)
|
2022-02-23 22:13:00 +00:00
|
|
|
}
|
|
|
|
|
2024-01-06 22:29:14 +00:00
|
|
|
func TestUnlockOpts(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
args := main.UnlockOpts{
|
|
|
|
RemoveAll: true,
|
|
|
|
}.ToArgs()
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"--remove-all",
|
|
|
|
}
|
|
|
|
|
|
|
|
AssertEqual(t, "args didn't match", expected, args)
|
|
|
|
}
|
|
|
|
|
2022-02-23 16:05:24 +00:00
|
|
|
func TestBuildEnv(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
cases := []struct {
|
|
|
|
name string
|
2022-02-24 06:53:18 +00:00
|
|
|
cmd main.Restic
|
2022-02-23 16:05:24 +00:00
|
|
|
expected []string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "No Env",
|
2022-11-10 21:30:30 +00:00
|
|
|
cmd: main.Restic{}, //nolint:exhaustruct
|
2022-02-23 16:05:24 +00:00
|
|
|
expected: os.Environ(),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "SetEnv",
|
2022-11-10 21:30:30 +00:00
|
|
|
cmd: main.Restic{ //nolint:exhaustruct
|
2022-02-23 16:05:24 +00:00
|
|
|
Env: map[string]string{"TestKey": "Value"},
|
|
|
|
},
|
|
|
|
expected: append(os.Environ(), "TestKey=Value"),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "SetEnv",
|
2022-11-10 21:30:30 +00:00
|
|
|
cmd: main.Restic{ //nolint:exhaustruct
|
2022-02-23 16:05:24 +00:00
|
|
|
Passphrase: "Shhhhhhhh!!",
|
|
|
|
},
|
|
|
|
expected: append(os.Environ(), "RESTIC_PASSWORD=Shhhhhhhh!!"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
c := c
|
|
|
|
|
|
|
|
t.Run(c.name, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2022-03-24 17:09:33 +00:00
|
|
|
AssertEqual(t, "args didn't match", c.expected, c.cmd.BuildEnv())
|
2022-02-23 16:05:24 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-03-24 21:59:40 +00:00
|
|
|
|
|
|
|
func TestResticInterface(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2022-03-29 05:01:18 +00:00
|
|
|
if testing.Short() {
|
|
|
|
t.Skip("Skip integration test when running short tests")
|
|
|
|
}
|
|
|
|
|
2022-03-24 21:59:40 +00:00
|
|
|
dataDir := t.TempDir()
|
|
|
|
repoDir := t.TempDir()
|
|
|
|
cacheDir := t.TempDir()
|
|
|
|
restoreTarget := t.TempDir()
|
|
|
|
|
|
|
|
dataFile := filepath.Join(dataDir, "test.txt")
|
|
|
|
restoredDataFile := filepath.Join(restoreTarget, dataFile)
|
|
|
|
|
|
|
|
restic := main.Restic{
|
|
|
|
Logger: log.New(os.Stderr, t.Name()+":", log.Lmsgprefix),
|
|
|
|
Repo: repoDir,
|
|
|
|
Env: map[string]string{},
|
|
|
|
Passphrase: "Correct.Horse.Battery.Staple",
|
2022-11-10 21:30:30 +00:00
|
|
|
//nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
GlobalOpts: &main.ResticGlobalOpts{
|
|
|
|
CacheDir: cacheDir,
|
2022-11-03 23:43:17 +00:00
|
|
|
Options: map[string]string{
|
|
|
|
"s3.storage-class": "REDUCED_REDUNDANCY",
|
|
|
|
},
|
2022-03-24 21:59:40 +00:00
|
|
|
},
|
|
|
|
Cwd: dataDir,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write test file to the data dir
|
2024-01-06 23:10:29 +00:00
|
|
|
err := os.WriteFile(dataFile, []byte("testing"), 0o644)
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error writing to test file", nil, err)
|
|
|
|
|
|
|
|
// Make sure no existing repo is found
|
|
|
|
_, err = restic.ReadSnapshots()
|
|
|
|
if err == nil || !errors.Is(err, main.ErrRepoNotFound) {
|
2022-11-03 22:16:37 +00:00
|
|
|
AssertEqualFail(t, "didn't get expected error for backup", main.ErrRepoNotFound.Error(), err.Error())
|
2022-03-24 21:59:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Try to backup when repo is not initialized
|
2022-11-10 21:30:30 +00:00
|
|
|
err = restic.Backup([]string{dataDir}, main.BackupOpts{}) //nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
if !errors.Is(err, main.ErrRepoNotFound) {
|
|
|
|
AssertEqualFail(t, "unexpected error creating making backup", nil, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Init repo
|
|
|
|
err = restic.EnsureInit()
|
|
|
|
AssertEqualFail(t, "unexpected error initializing repo", nil, err)
|
|
|
|
|
|
|
|
// Verify it can be reinitialized with no issues
|
|
|
|
err = restic.EnsureInit()
|
|
|
|
AssertEqualFail(t, "unexpected error reinitializing repo", nil, err)
|
|
|
|
|
|
|
|
// Backup for real this time
|
2022-11-10 21:30:30 +00:00
|
|
|
err = restic.Backup([]string{dataDir}, main.BackupOpts{Tags: []string{"test"}}) //nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error creating making backup", nil, err)
|
|
|
|
|
|
|
|
// Check snapshots
|
|
|
|
expectedHostname, _ := os.Hostname()
|
|
|
|
snapshots, err := restic.ReadSnapshots()
|
|
|
|
AssertEqualFail(t, "unexpected error reading snapshots", nil, err)
|
|
|
|
AssertEqual(t, "unexpected number of snapshots", 1, len(snapshots))
|
|
|
|
|
|
|
|
AssertEqual(t, "unexpected snapshot value: hostname", expectedHostname, snapshots[0].Hostname)
|
|
|
|
AssertEqual(t, "unexpected snapshot value: paths", []string{dataDir}, snapshots[0].Paths)
|
|
|
|
AssertEqual(t, "unexpected snapshot value: tags", []string{"test"}, snapshots[0].Tags)
|
|
|
|
|
|
|
|
// Backup again
|
2022-11-10 21:30:30 +00:00
|
|
|
err = restic.Backup([]string{dataDir}, main.BackupOpts{}) //nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error creating making second backup", nil, err)
|
|
|
|
|
|
|
|
// Check for second backup
|
|
|
|
snapshots, err = restic.ReadSnapshots()
|
|
|
|
AssertEqualFail(t, "unexpected error reading second snapshots", nil, err)
|
|
|
|
AssertEqual(t, "unexpected number of snapshots", 2, len(snapshots))
|
|
|
|
|
|
|
|
// Forget one backup
|
2022-11-10 21:30:30 +00:00
|
|
|
err = restic.Forget(main.ForgetOpts{KeepLast: 1, Prune: true}) //nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error forgetting snapshot", nil, err)
|
|
|
|
|
|
|
|
// Check forgotten snapshot
|
|
|
|
snapshots, err = restic.ReadSnapshots()
|
|
|
|
AssertEqualFail(t, "unexpected error reading post forget snapshots", nil, err)
|
|
|
|
AssertEqual(t, "unexpected number of snapshots", 1, len(snapshots))
|
|
|
|
|
|
|
|
// Check restic repo
|
|
|
|
err = restic.Check()
|
|
|
|
AssertEqualFail(t, "unexpected error checking repo", nil, err)
|
|
|
|
|
|
|
|
// Change the data file
|
2024-01-06 23:10:29 +00:00
|
|
|
err = os.WriteFile(dataFile, []byte("unexpected"), 0o644)
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error writing to test file", nil, err)
|
|
|
|
|
|
|
|
// Check that data wrote
|
|
|
|
value, err := os.ReadFile(dataFile)
|
|
|
|
AssertEqualFail(t, "unexpected error reading from test file", nil, err)
|
|
|
|
AssertEqualFail(t, "incorrect value in test file (we expect the unexpected!)", "unexpected", string(value))
|
|
|
|
|
|
|
|
// Restore files
|
2022-11-10 21:30:30 +00:00
|
|
|
err = restic.Restore("latest", main.RestoreOpts{Target: restoreTarget}) //nolint:exhaustruct
|
2022-03-24 21:59:40 +00:00
|
|
|
AssertEqualFail(t, "unexpected error restoring latest snapshot", nil, err)
|
|
|
|
|
|
|
|
// Check restored values
|
|
|
|
value, err = os.ReadFile(restoredDataFile)
|
|
|
|
AssertEqualFail(t, "unexpected error reading from test file", nil, err)
|
|
|
|
AssertEqualFail(t, "incorrect value in test file", "testing", string(value))
|
2024-01-06 22:29:14 +00:00
|
|
|
|
|
|
|
// Try to unlock the repo (repo shouldn't really be locked, but this should still run without error
|
|
|
|
err = restic.Unlock(main.UnlockOpts{}) //nolint:exhaustruct
|
|
|
|
AssertEqualFail(t, "unexpected error unlocking repo", nil, err)
|
2022-03-24 21:59:40 +00:00
|
|
|
}
|