2015-04-09 18:11:19 +00:00
|
|
|
package test_helper
|
|
|
|
|
|
|
|
import (
|
2015-08-19 19:00:17 +00:00
|
|
|
"compress/bzip2"
|
|
|
|
"compress/gzip"
|
2015-11-22 21:08:23 +00:00
|
|
|
"crypto/rand"
|
2015-04-09 18:11:19 +00:00
|
|
|
"fmt"
|
2015-08-19 19:00:17 +00:00
|
|
|
"io"
|
2015-07-04 14:51:59 +00:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
2015-04-09 18:11:19 +00:00
|
|
|
"path/filepath"
|
|
|
|
"reflect"
|
|
|
|
"runtime"
|
|
|
|
"testing"
|
|
|
|
|
2015-11-22 21:08:23 +00:00
|
|
|
mrand "math/rand"
|
|
|
|
|
2015-04-09 18:11:19 +00:00
|
|
|
"github.com/restic/restic/backend"
|
2015-07-04 14:51:59 +00:00
|
|
|
"github.com/restic/restic/backend/local"
|
|
|
|
"github.com/restic/restic/repository"
|
2015-04-09 18:11:19 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Assert fails the test if the condition is false.
|
|
|
|
func Assert(tb testing.TB, condition bool, msg string, v ...interface{}) {
|
|
|
|
if !condition {
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
|
|
fmt.Printf("\033[31m%s:%d: "+msg+"\033[39m\n\n", append([]interface{}{filepath.Base(file), line}, v...)...)
|
|
|
|
tb.FailNow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-02 14:22:43 +00:00
|
|
|
// OK fails the test if an err is not nil.
|
2015-04-09 18:11:19 +00:00
|
|
|
func OK(tb testing.TB, err error) {
|
|
|
|
if err != nil {
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
|
|
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
|
|
|
tb.FailNow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-11 14:00:49 +00:00
|
|
|
// OKs fails the test if any error from errs is not nil.
|
|
|
|
func OKs(tb testing.TB, errs []error) {
|
|
|
|
errFound := false
|
|
|
|
for _, err := range errs {
|
|
|
|
if err != nil {
|
|
|
|
errFound = true
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
|
|
fmt.Printf("\033[31m%s:%d: unexpected error: %s\033[39m\n\n", filepath.Base(file), line, err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if errFound {
|
|
|
|
tb.FailNow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-02 14:22:43 +00:00
|
|
|
// Equals fails the test if exp is not equal to act.
|
2015-04-09 18:11:19 +00:00
|
|
|
func Equals(tb testing.TB, exp, act interface{}) {
|
|
|
|
if !reflect.DeepEqual(exp, act) {
|
|
|
|
_, file, line, _ := runtime.Caller(1)
|
|
|
|
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
|
|
|
|
tb.FailNow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-18 19:05:49 +00:00
|
|
|
// ParseID parses s as a backend.ID and panics if that fails.
|
2015-04-26 15:10:31 +00:00
|
|
|
func ParseID(s string) backend.ID {
|
2015-04-09 18:11:19 +00:00
|
|
|
id, err := backend.ParseID(s)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return id
|
|
|
|
}
|
2015-04-12 07:36:14 +00:00
|
|
|
|
|
|
|
// Random returns size bytes of pseudo-random data derived from the seed.
|
|
|
|
func Random(seed, count int) []byte {
|
2016-01-24 16:46:18 +00:00
|
|
|
p := make([]byte, count)
|
2015-04-12 07:36:14 +00:00
|
|
|
|
2015-11-22 21:08:23 +00:00
|
|
|
rnd := mrand.New(mrand.NewSource(int64(seed)))
|
2016-01-24 16:46:18 +00:00
|
|
|
|
|
|
|
for i := 0; i < len(p); i += 8 {
|
|
|
|
val := rnd.Int63()
|
|
|
|
var data = []byte{
|
|
|
|
byte((val >> 0) & 0xff),
|
|
|
|
byte((val >> 8) & 0xff),
|
|
|
|
byte((val >> 16) & 0xff),
|
|
|
|
byte((val >> 24) & 0xff),
|
|
|
|
byte((val >> 32) & 0xff),
|
|
|
|
byte((val >> 40) & 0xff),
|
|
|
|
byte((val >> 48) & 0xff),
|
|
|
|
byte((val >> 56) & 0xff),
|
|
|
|
}
|
|
|
|
|
|
|
|
for j := range data {
|
|
|
|
cur := i + j
|
|
|
|
if len(p) >= cur {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
p[cur] = data[j]
|
|
|
|
}
|
2015-04-12 07:36:14 +00:00
|
|
|
}
|
|
|
|
|
2016-01-24 16:46:18 +00:00
|
|
|
return p
|
2015-04-12 07:36:14 +00:00
|
|
|
}
|
|
|
|
|
2016-01-17 18:46:48 +00:00
|
|
|
type rndReader struct {
|
|
|
|
src *mrand.Rand
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *rndReader) Read(p []byte) (int, error) {
|
2016-01-24 16:46:18 +00:00
|
|
|
for i := 0; i < len(p); i += 8 {
|
|
|
|
val := r.src.Int63()
|
|
|
|
var data = []byte{
|
|
|
|
byte((val >> 0) & 0xff),
|
|
|
|
byte((val >> 8) & 0xff),
|
|
|
|
byte((val >> 16) & 0xff),
|
|
|
|
byte((val >> 24) & 0xff),
|
|
|
|
byte((val >> 32) & 0xff),
|
|
|
|
byte((val >> 40) & 0xff),
|
|
|
|
byte((val >> 48) & 0xff),
|
|
|
|
byte((val >> 56) & 0xff),
|
|
|
|
}
|
|
|
|
|
|
|
|
for j := range data {
|
|
|
|
cur := i + j
|
|
|
|
if len(p) >= cur {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
p[cur] = data[j]
|
|
|
|
}
|
2016-01-17 18:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return len(p), nil
|
|
|
|
}
|
|
|
|
|
2016-01-24 16:46:18 +00:00
|
|
|
// RandomReader returns a reader that returns deterministic pseudo-random data
|
2015-04-12 07:36:14 +00:00
|
|
|
// derived from the seed.
|
2016-01-24 16:46:18 +00:00
|
|
|
func RandomReader(seed int) io.Reader {
|
|
|
|
return &rndReader{src: mrand.New(mrand.NewSource(int64(seed)))}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RandomLimitReader returns a reader that returns size bytes of deterministic
|
|
|
|
// pseudo-random data derived from the seed.
|
|
|
|
func RandomLimitReader(seed, size int) io.Reader {
|
|
|
|
return io.LimitReader(RandomReader(seed), int64(size))
|
2015-04-12 07:36:14 +00:00
|
|
|
}
|
2015-07-04 14:51:59 +00:00
|
|
|
|
2015-11-22 21:08:23 +00:00
|
|
|
// GenRandom returns a []byte filled with up to 1000 random bytes.
|
|
|
|
func GenRandom(t testing.TB) []byte {
|
|
|
|
buf := make([]byte, mrand.Intn(1000))
|
|
|
|
_, err := io.ReadFull(rand.Reader, buf)
|
|
|
|
OK(t, err)
|
|
|
|
return buf
|
|
|
|
}
|
|
|
|
|
2015-07-04 14:51:59 +00:00
|
|
|
// SetupTarTestFixture extracts the tarFile to outputDir.
|
|
|
|
func SetupTarTestFixture(t testing.TB, outputDir, tarFile string) {
|
2015-08-19 19:00:17 +00:00
|
|
|
input, err := os.Open(tarFile)
|
|
|
|
defer input.Close()
|
2015-07-04 14:51:59 +00:00
|
|
|
OK(t, err)
|
|
|
|
|
2015-08-19 19:00:17 +00:00
|
|
|
var rd io.Reader
|
|
|
|
switch filepath.Ext(tarFile) {
|
|
|
|
case ".gz":
|
|
|
|
r, err := gzip.NewReader(input)
|
|
|
|
OK(t, err)
|
|
|
|
|
|
|
|
defer r.Close()
|
|
|
|
rd = r
|
|
|
|
case ".bzip2":
|
|
|
|
rd = bzip2.NewReader(input)
|
|
|
|
default:
|
|
|
|
rd = input
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd := exec.Command("tar", "xf", "-")
|
2015-08-16 21:02:02 +00:00
|
|
|
cmd.Dir = outputDir
|
|
|
|
|
2015-08-19 19:00:17 +00:00
|
|
|
cmd.Stdin = rd
|
2015-07-04 14:51:59 +00:00
|
|
|
cmd.Stdout = os.Stdout
|
|
|
|
cmd.Stderr = os.Stderr
|
|
|
|
|
2015-08-16 21:02:02 +00:00
|
|
|
OK(t, cmd.Run())
|
2015-07-04 14:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// WithTestEnvironment creates a test environment, extracts the repository
|
|
|
|
// fixture and and calls f with the repository dir.
|
|
|
|
func WithTestEnvironment(t testing.TB, repoFixture string, f func(repodir string)) {
|
|
|
|
tempdir, err := ioutil.TempDir(TestTempDir, "restic-test-")
|
|
|
|
OK(t, err)
|
|
|
|
|
|
|
|
fd, err := os.Open(repoFixture)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
OK(t, fd.Close())
|
|
|
|
|
|
|
|
SetupTarTestFixture(t, tempdir, repoFixture)
|
|
|
|
|
|
|
|
f(filepath.Join(tempdir, "repo"))
|
|
|
|
|
2016-01-23 18:12:02 +00:00
|
|
|
if !TestCleanupTempDirs {
|
2015-07-04 14:51:59 +00:00
|
|
|
t.Logf("leaving temporary directory %v used for test", tempdir)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-08-18 19:05:49 +00:00
|
|
|
RemoveAll(t, tempdir)
|
2015-07-04 14:51:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OpenLocalRepo opens the local repository located at dir.
|
|
|
|
func OpenLocalRepo(t testing.TB, dir string) *repository.Repository {
|
|
|
|
be, err := local.Open(dir)
|
|
|
|
OK(t, err)
|
|
|
|
|
|
|
|
repo := repository.New(be)
|
|
|
|
err = repo.SearchKey(TestPassword)
|
|
|
|
OK(t, err)
|
|
|
|
|
|
|
|
return repo
|
|
|
|
}
|
2015-08-18 19:05:49 +00:00
|
|
|
|
|
|
|
func isFile(fi os.FileInfo) bool {
|
|
|
|
return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResetReadOnly recursively resets the read-only flag recursively for dir.
|
|
|
|
// This is mainly used for tests on Windows, which is unable to delete a file
|
|
|
|
// set read-only.
|
|
|
|
func ResetReadOnly(t testing.TB, dir string) {
|
|
|
|
OK(t, filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
|
|
|
|
if fi.IsDir() {
|
|
|
|
return os.Chmod(path, 0777)
|
|
|
|
}
|
|
|
|
|
|
|
|
if isFile(fi) {
|
|
|
|
return os.Chmod(path, 0666)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveAll recursively resets the read-only flag of all files and dirs and
|
|
|
|
// afterwards uses os.RemoveAll() to remove the path.
|
|
|
|
func RemoveAll(t testing.TB, path string) {
|
|
|
|
ResetReadOnly(t, path)
|
|
|
|
OK(t, os.RemoveAll(path))
|
|
|
|
}
|