You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
8.3 KiB
334 lines
8.3 KiB
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
"testing"
|
|
|
|
"github.com/cupcakearmy/autorestic/internal/flags"
|
|
"github.com/spf13/viper"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestGenerateRepo(t *testing.T) {
|
|
|
|
t.Run("empty backend", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "empty backend",
|
|
Type: "",
|
|
}
|
|
_, err := b.generateRepo()
|
|
if err == nil {
|
|
t.Errorf("Error expected for empty backend type")
|
|
}
|
|
})
|
|
|
|
t.Run("local backend", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "local backend",
|
|
Type: "local",
|
|
Path: "/foo/bar",
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, "/foo/bar")
|
|
})
|
|
|
|
t.Run("local backend with homedir prefix", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "local backend",
|
|
Type: "local",
|
|
Path: "~/foo/bar",
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, fmt.Sprintf("%s/foo/bar", os.Getenv("HOME")))
|
|
})
|
|
|
|
t.Run("local backend with config file", func(t *testing.T) {
|
|
// config file path should always be present from initConfig
|
|
viper.SetConfigFile("/tmp/.autorestic.yml")
|
|
defer viper.Reset()
|
|
|
|
b := Backend{
|
|
name: "local backend",
|
|
Type: "local",
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, "/tmp")
|
|
})
|
|
|
|
t.Run("rest backend with valid path", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "rest backend",
|
|
Type: "rest",
|
|
Path: "http://localhost:8000/foo",
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, "rest:http://localhost:8000/foo")
|
|
})
|
|
|
|
t.Run("rest backend with user", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "rest backend",
|
|
Type: "rest",
|
|
Path: "http://localhost:8000/foo",
|
|
Rest: BackendRest{
|
|
User: "user",
|
|
Password: "",
|
|
},
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, "rest:http://user@localhost:8000/foo")
|
|
})
|
|
|
|
t.Run("rest backend with user and password", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "rest backend",
|
|
Type: "rest",
|
|
Path: "http://localhost:8000/foo",
|
|
Rest: BackendRest{
|
|
User: "user",
|
|
Password: "pass",
|
|
},
|
|
}
|
|
result, err := b.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result, "rest:http://user:pass@localhost:8000/foo")
|
|
})
|
|
|
|
backendTests := []struct {
|
|
name string
|
|
backend Backend
|
|
want string
|
|
}{
|
|
{name: "b2 backend", backend: Backend{name: "b2", Type: "b2", Path: "foo"}, want: "b2:foo"},
|
|
{name: "azure backend", backend: Backend{name: "azure", Type: "azure", Path: "foo"}, want: "azure:foo"},
|
|
{name: "gs backend", backend: Backend{name: "gs", Type: "gs", Path: "foo"}, want: "gs:foo"},
|
|
{name: "s3 backend", backend: Backend{name: "s3", Type: "s3", Path: "foo"}, want: "s3:foo"},
|
|
{name: "sftp backend", backend: Backend{name: "sftp", Type: "sftp", Path: "foo"}, want: "sftp:foo"},
|
|
{name: "rclone backend", backend: Backend{name: "rclone", Type: "rclone", Path: "foo"}, want: "rclone:foo"},
|
|
}
|
|
|
|
for _, tt := range backendTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := tt.backend.generateRepo()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, got, tt.want)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetEnv(t *testing.T) {
|
|
t.Run("env in key field", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "",
|
|
Type: "local",
|
|
Path: "/foo/bar",
|
|
Key: "secret123",
|
|
}
|
|
result, err := b.getEnv()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result["RESTIC_REPOSITORY"], "/foo/bar")
|
|
assertEqual(t, result["RESTIC_PASSWORD"], "secret123")
|
|
})
|
|
|
|
t.Run("env in config file", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "",
|
|
Type: "local",
|
|
Path: "/foo/bar",
|
|
Env: map[string]string{
|
|
"B2_ACCOUNT_ID": "foo123",
|
|
"B2_ACCOUNT_KEY": "foo456",
|
|
},
|
|
}
|
|
result, err := b.getEnv()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result["RESTIC_REPOSITORY"], "/foo/bar")
|
|
assertEqual(t, result["RESTIC_PASSWORD"], "")
|
|
assertEqual(t, result["B2_ACCOUNT_ID"], "foo123")
|
|
assertEqual(t, result["B2_ACCOUNT_KEY"], "foo456")
|
|
})
|
|
|
|
t.Run("env in Envfile or env vars", func(t *testing.T) {
|
|
// generate env variables
|
|
// TODO better way to teardown
|
|
defer os.Unsetenv("AUTORESTIC_FOO_RESTIC_PASSWORD")
|
|
defer os.Unsetenv("AUTORESTIC_FOO_B2_ACCOUNT_ID")
|
|
defer os.Unsetenv("AUTORESTIC_FOO_B2_ACCOUNT_KEY")
|
|
os.Setenv("AUTORESTIC_FOO_RESTIC_PASSWORD", "secret123")
|
|
os.Setenv("AUTORESTIC_FOO_B2_ACCOUNT_ID", "foo123")
|
|
os.Setenv("AUTORESTIC_FOO_B2_ACCOUNT_KEY", "foo456")
|
|
|
|
b := Backend{
|
|
name: "foo",
|
|
Type: "local",
|
|
Path: "/foo/bar",
|
|
}
|
|
result, err := b.getEnv()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result["RESTIC_REPOSITORY"], "/foo/bar")
|
|
assertEqual(t, result["RESTIC_PASSWORD"], "secret123")
|
|
assertEqual(t, result["B2_ACCOUNT_ID"], "foo123")
|
|
assertEqual(t, result["B2_ACCOUNT_KEY"], "foo456")
|
|
})
|
|
|
|
for _, char := range "@-_:/" {
|
|
t.Run(fmt.Sprintf("env var with special char (%c)", char), func(t *testing.T) {
|
|
// generate env variables
|
|
// TODO better way to teardown
|
|
defer os.Unsetenv("AUTORESTIC_FOO_BAR_RESTIC_PASSWORD")
|
|
defer os.Unsetenv("AUTORESTIC_FOO_BAR_B2_ACCOUNT_ID")
|
|
defer os.Unsetenv("AUTORESTIC_FOO_BAR_B2_ACCOUNT_KEY")
|
|
os.Setenv("AUTORESTIC_FOO_BAR_RESTIC_PASSWORD", "secret123")
|
|
os.Setenv("AUTORESTIC_FOO_BAR_B2_ACCOUNT_ID", "foo123")
|
|
os.Setenv("AUTORESTIC_FOO_BAR_B2_ACCOUNT_KEY", "foo456")
|
|
|
|
b := Backend{
|
|
name: fmt.Sprintf("foo%cbar", char),
|
|
Type: "local",
|
|
Path: "/foo/bar",
|
|
}
|
|
result, err := b.getEnv()
|
|
if err != nil {
|
|
t.Errorf("unexpected error %v", err)
|
|
}
|
|
assertEqual(t, result["RESTIC_REPOSITORY"], "/foo/bar")
|
|
assertEqual(t, result["RESTIC_PASSWORD"], "secret123")
|
|
assertEqual(t, result["B2_ACCOUNT_ID"], "foo123")
|
|
assertEqual(t, result["B2_ACCOUNT_KEY"], "foo456")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValidate(t *testing.T) {
|
|
t.Run("no type given", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "foo",
|
|
Type: "",
|
|
Path: "/foo/bar",
|
|
}
|
|
err := b.validate()
|
|
if err == nil {
|
|
t.Error("expected to get error")
|
|
}
|
|
assertEqual(t, err.Error(), "Backend \"foo\" has no \"type\"")
|
|
})
|
|
|
|
t.Run("no path given", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "foo",
|
|
Type: "local",
|
|
Path: "",
|
|
}
|
|
err := b.validate()
|
|
if err == nil {
|
|
t.Error("expected to get error")
|
|
}
|
|
assertEqual(t, err.Error(), "Backend \"foo\" has no \"path\"")
|
|
})
|
|
|
|
t.Run("require key with no key", func(t *testing.T) {
|
|
b := Backend{
|
|
name: "foo",
|
|
Type: "local",
|
|
Path: "~/foo/bar",
|
|
RequireKey: true,
|
|
}
|
|
err := b.validate()
|
|
fmt.Printf("error: %v\n", err)
|
|
assert.EqualError(t, err, "backend foo requires a key but none was provided")
|
|
})
|
|
}
|
|
|
|
func TestValidateInitsRepo(t *testing.T) {
|
|
// This is normally initialized by the cobra commands but they don't run in
|
|
// this test so we do it ourselves.
|
|
flags.RESTIC_BIN = "restic"
|
|
|
|
workDir := t.TempDir()
|
|
|
|
b := Backend{
|
|
name: "test",
|
|
Type: "local",
|
|
Path: path.Join(workDir, "backend"),
|
|
Key: "supersecret",
|
|
}
|
|
|
|
config = &Config{Backends: map[string]Backend{"test": b}}
|
|
defer func() { config = nil }()
|
|
|
|
// Check should fail because the repo doesn't exist
|
|
err := b.Exec([]string{"check"})
|
|
assert.Error(t, err)
|
|
|
|
err = b.validate()
|
|
assert.NoError(t, err)
|
|
|
|
// Check should pass now
|
|
err = b.Exec([]string{"check"})
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
func TestEnsureInit(t *testing.T) {
|
|
// This is normally initialized by the cobra commands but they don't run in
|
|
// this test so we do it ourselves.
|
|
flags.RESTIC_BIN = "restic"
|
|
|
|
workDir := t.TempDir()
|
|
|
|
b := Backend{
|
|
name: "test",
|
|
Type: "local",
|
|
Path: path.Join(workDir, "backend"),
|
|
Key: "supersecret",
|
|
}
|
|
|
|
config = &Config{Backends: map[string]Backend{"test": b}}
|
|
defer func() { config = nil }()
|
|
|
|
// Check should fail because the repo doesn't exist
|
|
err := b.Exec([]string{"check"})
|
|
assert.Error(t, err)
|
|
|
|
err = b.EnsureInit()
|
|
assert.NoError(t, err)
|
|
|
|
// Check should pass now
|
|
err = b.Exec([]string{"check"})
|
|
assert.NoError(t, err)
|
|
|
|
// Run again to make sure it's idempotent
|
|
err = b.EnsureInit()
|
|
assert.NoError(t, err)
|
|
|
|
// Check should still pass
|
|
err = b.Exec([]string{"check"})
|
|
assert.NoError(t, err)
|
|
}
|