Add a lot more testing
This commit is contained in:
parent
512d924f0c
commit
57afeab4ca
76
job.go
76
job.go
@ -14,10 +14,11 @@ import (
|
|||||||
const WorkDirPerms = 0o666
|
const WorkDirPerms = 0o666
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrNoJobsFound = errors.New("no jobs found and at least one job is required")
|
ErrNoJobsFound = errors.New("no jobs found and at least one job is required")
|
||||||
ErrMissingField = errors.New("missing config field")
|
ErrMissingField = errors.New("missing config field")
|
||||||
ErrMissingBlock = errors.New("missing config block")
|
ErrMissingBlock = errors.New("missing config block")
|
||||||
ErrMutuallyExclusive = errors.New("mutually exclusive values not valid")
|
ErrMutuallyExclusive = errors.New("mutually exclusive values not valid")
|
||||||
|
ErrInvalidConfigValue = errors.New("invalid config value")
|
||||||
)
|
)
|
||||||
|
|
||||||
type TaskConfig struct {
|
type TaskConfig struct {
|
||||||
@ -128,11 +129,20 @@ func (t JobTaskMySQL) Filename() string {
|
|||||||
|
|
||||||
func (t JobTaskMySQL) Validate() error {
|
func (t JobTaskMySQL) Validate() error {
|
||||||
if invalidChars := "'\";"; strings.ContainsAny(t.Name, invalidChars) {
|
if invalidChars := "'\";"; strings.ContainsAny(t.Name, invalidChars) {
|
||||||
return fmt.Errorf("mysql task %s has an invalid name. The name may not contain %s", t.Name, invalidChars)
|
return fmt.Errorf(
|
||||||
|
"mysql task %s has an invalid name. The name may not contain %s: %w",
|
||||||
|
t.Name,
|
||||||
|
invalidChars,
|
||||||
|
ErrInvalidConfigValue,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(t.Tables) > 0 && t.Database == "" {
|
if len(t.Tables) > 0 && t.Database == "" {
|
||||||
return fmt.Errorf("mysql task %s is invalid. Must specify a database to use tables: %w", t.Name, ErrMissingField)
|
return fmt.Errorf(
|
||||||
|
"mysql task %s is invalid. Must specify a database to use tables: %w",
|
||||||
|
t.Name,
|
||||||
|
ErrMissingField,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -206,7 +216,12 @@ func (t JobTaskSqlite) Filename() string {
|
|||||||
|
|
||||||
func (t JobTaskSqlite) Validate() error {
|
func (t JobTaskSqlite) Validate() error {
|
||||||
if invalidChars := "'\";"; strings.ContainsAny(t.Name, invalidChars) {
|
if invalidChars := "'\";"; strings.ContainsAny(t.Name, invalidChars) {
|
||||||
return fmt.Errorf("sqlite task %s has an invalid name. The name may not contain %s", t.Name, invalidChars)
|
return fmt.Errorf(
|
||||||
|
"sqlite task %s has an invalid name. The name may not contain %s: %w",
|
||||||
|
t.Name,
|
||||||
|
invalidChars,
|
||||||
|
ErrInvalidConfigValue,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -217,7 +232,7 @@ func (t JobTaskSqlite) GetPreTask() ExecutableTask {
|
|||||||
name: t.Name,
|
name: t.Name,
|
||||||
env: nil,
|
env: nil,
|
||||||
OnBackup: fmt.Sprintf(
|
OnBackup: fmt.Sprintf(
|
||||||
"sqlite3 %s '.backup $RESTIC_JOB_DIR/%s'",
|
"sqlite3 '%s' '.backup $RESTIC_JOB_DIR/%s'",
|
||||||
t.Path, t.Filename(),
|
t.Path, t.Filename(),
|
||||||
),
|
),
|
||||||
OnRestore: "",
|
OnRestore: "",
|
||||||
@ -429,17 +444,6 @@ func (j Job) JobDir() string {
|
|||||||
return cwd
|
return cwd
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* func NewTaskConfig(jobDir string, jobLogger *log.Logger, restic *ResticCmd, taskName string) TaskConfig {
|
|
||||||
* return TaskConfig{
|
|
||||||
* JobDir: jobDir,
|
|
||||||
* Logger: GetChildLogger(jobLogger, taskName),
|
|
||||||
* Restic: restic,
|
|
||||||
* Env: nil,
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (j Job) RunBackup() error {
|
func (j Job) RunBackup() error {
|
||||||
logger := GetLogger(j.Name)
|
logger := GetLogger(j.Name)
|
||||||
restic := j.NewRestic()
|
restic := j.NewRestic()
|
||||||
@ -524,37 +528,3 @@ func (c Config) Validate() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
|
|
||||||
job "My App" {
|
|
||||||
schedule = "* * * * *"
|
|
||||||
config {
|
|
||||||
repo = "s3://..."
|
|
||||||
passphrase = "foo"
|
|
||||||
}
|
|
||||||
|
|
||||||
task "Dump mysql" {
|
|
||||||
mysql {
|
|
||||||
hostname = "foo"
|
|
||||||
username = "bar"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "Create biz file" {
|
|
||||||
on_backup {
|
|
||||||
body = <<EOF
|
|
||||||
echo foo > /biz.txt
|
|
||||||
EOF
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task "Backup data files" {
|
|
||||||
files = [
|
|
||||||
"/foo/bar",
|
|
||||||
"/biz.txt",
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
***/
|
|
||||||
|
122
job_test.go
122
job_test.go
@ -173,3 +173,125 @@ func TestJobTaskScript(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJobTaskMySQL(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type TaskGenerator interface {
|
||||||
|
Validate() error
|
||||||
|
GetPreTask() main.ExecutableTask
|
||||||
|
GetPostTask() main.ExecutableTask
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
task TaskGenerator
|
||||||
|
validationErr error
|
||||||
|
preBackup string
|
||||||
|
postBackup string
|
||||||
|
preRestore string
|
||||||
|
postRestore string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "mysql simple",
|
||||||
|
// nolint:exhaustivestruct
|
||||||
|
task: main.JobTaskMySQL{Name: "simple"},
|
||||||
|
validationErr: nil,
|
||||||
|
preBackup: "mysqldump --result-file './simple.sql'",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "mysql < './simple.sql'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mysql invalid name",
|
||||||
|
// nolint:exhaustivestruct
|
||||||
|
task: main.JobTaskMySQL{Name: "it's invalid;"},
|
||||||
|
validationErr: main.ErrInvalidConfigValue,
|
||||||
|
preBackup: "",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mysql tables no database",
|
||||||
|
// nolint:exhaustivestruct
|
||||||
|
task: main.JobTaskMySQL{
|
||||||
|
Name: "name",
|
||||||
|
Tables: []string{"table1", "table2"},
|
||||||
|
},
|
||||||
|
validationErr: main.ErrMissingField,
|
||||||
|
preBackup: "",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mysql all options",
|
||||||
|
task: main.JobTaskMySQL{
|
||||||
|
Name: "simple",
|
||||||
|
Hostname: "host",
|
||||||
|
Username: "user",
|
||||||
|
Password: "pass",
|
||||||
|
Database: "db",
|
||||||
|
Tables: []string{"table1", "table2"},
|
||||||
|
},
|
||||||
|
validationErr: nil,
|
||||||
|
preBackup: "mysqldump --result-file './simple.sql' --host host --user user --password pass db table1 table2",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "mysql --host host --user user --password pass < './simple.sql'",
|
||||||
|
},
|
||||||
|
// Sqlite
|
||||||
|
{
|
||||||
|
name: "sqlite simple",
|
||||||
|
|
||||||
|
task: main.JobTaskSqlite{Name: "simple", Path: "database.db"},
|
||||||
|
validationErr: nil,
|
||||||
|
preBackup: "sqlite3 'database.db' '.backup $RESTIC_JOB_DIR/simple.db.bak'",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "cp '$RESTIC_JOB_DIR/simple.db.bak' 'database.db'",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sqlite invalid name",
|
||||||
|
|
||||||
|
task: main.JobTaskSqlite{Name: "it's invalid;", Path: "database.db"},
|
||||||
|
validationErr: main.ErrInvalidConfigValue,
|
||||||
|
preBackup: "",
|
||||||
|
postBackup: "",
|
||||||
|
preRestore: "",
|
||||||
|
postRestore: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
testCase := c
|
||||||
|
|
||||||
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
validateErr := testCase.task.Validate()
|
||||||
|
if !errors.Is(validateErr, testCase.validationErr) {
|
||||||
|
t.Errorf("unexpected validation result. expected: %v, actual: %v", testCase.validationErr, validateErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if validateErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if preTask, ok := testCase.task.GetPreTask().(main.JobTaskScript); ok {
|
||||||
|
AssertEqual(t, "incorrect pre-backup", testCase.preBackup, preTask.OnBackup)
|
||||||
|
AssertEqual(t, "incorrect pre-restore", testCase.preRestore, preTask.OnRestore)
|
||||||
|
} else {
|
||||||
|
t.Error("pre task was not a JobTaskScript")
|
||||||
|
}
|
||||||
|
|
||||||
|
if postTask, ok := testCase.task.GetPostTask().(main.JobTaskScript); ok {
|
||||||
|
AssertEqual(t, "incorrect post-backup", testCase.postBackup, postTask.OnBackup)
|
||||||
|
AssertEqual(t, "incorrect post-restore", testCase.postRestore, postTask.OnRestore)
|
||||||
|
} else {
|
||||||
|
t.Error("post task was not a JobTaskScript")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -7,6 +7,16 @@ import (
|
|||||||
"github.com/go-test/deep"
|
"github.com/go-test/deep"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func AssertEqual(t *testing.T, message string, expected, actual interface{}) bool {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
t.Errorf("%s. expected: %v, actual: %v", message, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func TestMergeEnvMap(t *testing.T) {
|
func TestMergeEnvMap(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user