backend: Adjust tests to use the Factory to instantiate the backend
This drastically reduces the amount of duplicated test code.
This commit is contained in:
parent
3d3bb88745
commit
13a8b5822f
13 changed files with 119 additions and 423 deletions
|
@ -12,18 +12,12 @@ import (
|
||||||
"github.com/restic/restic/internal/backend"
|
"github.com/restic/restic/internal/backend"
|
||||||
"github.com/restic/restic/internal/backend/azure"
|
"github.com/restic/restic/internal/backend/azure"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"github.com/restic/restic/internal/options"
|
"github.com/restic/restic/internal/options"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newAzureTestSuite(t testing.TB) *test.Suite[azure.Config] {
|
func newAzureTestSuite(t testing.TB) *test.Suite[azure.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[azure.Config]{
|
return &test.Suite[azure.Config]{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
|
@ -40,42 +34,7 @@ func newAzureTestSuite(t testing.TB) *test.Suite[azure.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: azure.NewFactory(),
|
||||||
Create: func(cfg azure.Config) (restic.Backend, error) {
|
|
||||||
ctx := context.TODO()
|
|
||||||
be, err := azure.Create(ctx, cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
|
||||||
if err != nil && !be.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil, errors.New("config already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
return be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg azure.Config) (restic.Backend, error) {
|
|
||||||
ctx := context.TODO()
|
|
||||||
return azure.Open(ctx, cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg azure.Config) error {
|
|
||||||
ctx := context.TODO()
|
|
||||||
be, err := azure.Open(ctx, cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return be.Delete(context.TODO())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,18 @@
|
||||||
package b2_test
|
package b2_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
|
||||||
"github.com/restic/restic/internal/backend/b2"
|
"github.com/restic/restic/internal/backend/b2"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newB2TestSuite(t testing.TB) *test.Suite[b2.Config] {
|
func newB2TestSuite(t testing.TB) *test.Suite[b2.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[b2.Config]{
|
return &test.Suite[b2.Config]{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
|
@ -40,25 +32,7 @@ func newB2TestSuite(t testing.TB) *test.Suite[b2.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: b2.NewFactory(),
|
||||||
Create: func(cfg b2.Config) (restic.Backend, error) {
|
|
||||||
return b2.Create(context.Background(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg b2.Config) (restic.Backend, error) {
|
|
||||||
return b2.Open(context.Background(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg b2.Config) error {
|
|
||||||
be, err := b2.Open(context.Background(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return be.Delete(context.TODO())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,17 @@
|
||||||
package gs_test
|
package gs_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
|
||||||
"github.com/restic/restic/internal/backend/gs"
|
"github.com/restic/restic/internal/backend/gs"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newGSTestSuite(t testing.TB) *test.Suite[gs.Config] {
|
func newGSTestSuite(t testing.TB) *test.Suite[gs.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[gs.Config]{
|
return &test.Suite[gs.Config]{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
|
@ -37,39 +28,7 @@ func newGSTestSuite(t testing.TB) *test.Suite[gs.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: gs.NewFactory(),
|
||||||
Create: func(cfg gs.Config) (restic.Backend, error) {
|
|
||||||
be, err := gs.Create(context.Background(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
|
||||||
if err != nil && !be.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil, errors.New("config already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
return be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg gs.Config) (restic.Backend, error) {
|
|
||||||
return gs.Open(context.TODO(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg gs.Config) error {
|
|
||||||
be, err := gs.Open(context.TODO(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return be.Delete(context.TODO())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend/local"
|
"github.com/restic/restic/internal/backend/local"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,11 +15,7 @@ func newTestSuite(t testing.TB) *test.Suite[local.Config] {
|
||||||
return &test.Suite[local.Config]{
|
return &test.Suite[local.Config]{
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (*local.Config, error) {
|
NewConfig: func() (*local.Config, error) {
|
||||||
dir, err := os.MkdirTemp(rtest.TestTempDir, "restic-test-local-")
|
dir := rtest.TempDir(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("create new backend at %v", dir)
|
t.Logf("create new backend at %v", dir)
|
||||||
|
|
||||||
cfg := &local.Config{
|
cfg := &local.Config{
|
||||||
|
@ -30,25 +25,7 @@ func newTestSuite(t testing.TB) *test.Suite[local.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: local.NewFactory(),
|
||||||
Create: func(cfg local.Config) (restic.Backend, error) {
|
|
||||||
return local.Create(context.TODO(), cfg)
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg local.Config) (restic.Backend, error) {
|
|
||||||
return local.Open(context.TODO(), cfg)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg local.Config) error {
|
|
||||||
if !rtest.TestCleanupTempDirs {
|
|
||||||
t.Logf("leaving test backend dir at %v", cfg.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
rtest.RemoveAll(t, cfg.Path)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,12 @@ import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"hash"
|
"hash"
|
||||||
"io"
|
"io"
|
||||||
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/cespare/xxhash/v2"
|
"github.com/cespare/xxhash/v2"
|
||||||
"github.com/restic/restic/internal/backend"
|
"github.com/restic/restic/internal/backend"
|
||||||
|
"github.com/restic/restic/internal/backend/location"
|
||||||
"github.com/restic/restic/internal/debug"
|
"github.com/restic/restic/internal/debug"
|
||||||
"github.com/restic/restic/internal/errors"
|
"github.com/restic/restic/internal/errors"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
|
@ -20,6 +22,24 @@ type memMap map[restic.Handle][]byte
|
||||||
// make sure that MemoryBackend implements backend.Backend
|
// make sure that MemoryBackend implements backend.Backend
|
||||||
var _ restic.Backend = &MemoryBackend{}
|
var _ restic.Backend = &MemoryBackend{}
|
||||||
|
|
||||||
|
// NewFactory creates a persistent mem backend
|
||||||
|
func NewFactory() location.Factory {
|
||||||
|
be := New()
|
||||||
|
|
||||||
|
return location.NewHTTPBackendFactory[struct{}, *MemoryBackend](
|
||||||
|
func(s string) (*struct{}, error) {
|
||||||
|
return &struct{}{}, nil
|
||||||
|
},
|
||||||
|
location.NoPassword,
|
||||||
|
func(_ context.Context, _ struct{}, _ http.RoundTripper) (*MemoryBackend, error) {
|
||||||
|
return be, nil
|
||||||
|
},
|
||||||
|
func(_ context.Context, _ struct{}, _ http.RoundTripper) (*MemoryBackend, error) {
|
||||||
|
return be, nil
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
var errNotFound = errors.New("not found")
|
var errNotFound = errors.New("not found")
|
||||||
|
|
||||||
const connectionCount = 2
|
const connectionCount = 2
|
||||||
|
|
|
@ -1,58 +1,20 @@
|
||||||
package mem_test
|
package mem_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend/mem"
|
"github.com/restic/restic/internal/backend/mem"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
type memConfig struct {
|
func newTestSuite() *test.Suite[struct{}] {
|
||||||
be restic.Backend
|
return &test.Suite[struct{}]{
|
||||||
}
|
|
||||||
|
|
||||||
func newTestSuite() *test.Suite[*memConfig] {
|
|
||||||
return &test.Suite[*memConfig]{
|
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (**memConfig, error) {
|
NewConfig: func() (*struct{}, error) {
|
||||||
cfg := &memConfig{}
|
return &struct{}{}, nil
|
||||||
return &cfg, nil
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: mem.NewFactory(),
|
||||||
Create: func(cfg *memConfig) (restic.Backend, error) {
|
|
||||||
if cfg.be != nil {
|
|
||||||
_, err := cfg.be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
|
||||||
if err != nil && !cfg.be.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil, errors.New("config already exists")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.be = mem.New()
|
|
||||||
return cfg.be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg *memConfig) (restic.Backend, error) {
|
|
||||||
if cfg.be == nil {
|
|
||||||
cfg.be = mem.New()
|
|
||||||
}
|
|
||||||
return cfg.be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg *memConfig) error {
|
|
||||||
// no cleanup needed
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
package rclone_test
|
package rclone_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend/rclone"
|
"github.com/restic/restic/internal/backend/rclone"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,23 +21,15 @@ func newTestSuite(t testing.TB) *test.Suite[rclone.Config] {
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: rclone.NewFactory(),
|
||||||
Create: func(cfg rclone.Config) (restic.Backend, error) {
|
}
|
||||||
t.Logf("Create()")
|
}
|
||||||
be, err := rclone.Create(context.TODO(), cfg, nil)
|
|
||||||
var e *exec.Error
|
|
||||||
if errors.As(err, &e) && e.Err == exec.ErrNotFound {
|
|
||||||
t.Skipf("program %q not found", e.Name)
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return be, err
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
func findRclone(t testing.TB) {
|
||||||
Open: func(cfg rclone.Config) (restic.Backend, error) {
|
// try to find a rclone binary
|
||||||
t.Logf("Open()")
|
_, err := exec.LookPath("rclone")
|
||||||
return rclone.Open(context.TODO(), cfg, nil)
|
if err != nil {
|
||||||
},
|
t.Skip(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +40,11 @@ func TestBackendRclone(t *testing.T) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
findRclone(t)
|
||||||
newTestSuite(t).RunTests(t)
|
newTestSuite(t).RunTests(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBackendREST(t *testing.B) {
|
func BenchmarkBackendREST(t *testing.B) {
|
||||||
|
findRclone(t)
|
||||||
newTestSuite(t).RunBenchmarks(t)
|
newTestSuite(t).RunBenchmarks(t)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,8 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
|
||||||
"github.com/restic/restic/internal/backend/rest"
|
"github.com/restic/restic/internal/backend/rest"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -68,11 +66,6 @@ func runRESTServer(ctx context.Context, t testing.TB, dir string) (*url.URL, fun
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestSuite(_ context.Context, t testing.TB, url *url.URL, minimalData bool) *test.Suite[rest.Config] {
|
func newTestSuite(_ context.Context, t testing.TB, url *url.URL, minimalData bool) *test.Suite[rest.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[rest.Config]{
|
return &test.Suite[rest.Config]{
|
||||||
MinimalData: minimalData,
|
MinimalData: minimalData,
|
||||||
|
|
||||||
|
@ -83,20 +76,7 @@ func newTestSuite(_ context.Context, t testing.TB, url *url.URL, minimalData boo
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: rest.NewFactory(),
|
||||||
Create: func(cfg rest.Config) (restic.Backend, error) {
|
|
||||||
return rest.Create(context.TODO(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg rest.Config) (restic.Backend, error) {
|
|
||||||
return rest.Open(context.TODO(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg rest.Config) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,22 +4,18 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
|
||||||
"github.com/restic/restic/internal/backend/s3"
|
"github.com/restic/restic/internal/backend/s3"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/options"
|
"github.com/restic/restic/internal/options"
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,84 +94,34 @@ func newRandomCredentials(t testing.TB) (key, secret string) {
|
||||||
return key, secret
|
return key, secret
|
||||||
}
|
}
|
||||||
|
|
||||||
type MinioTestConfig struct {
|
func newMinioTestSuite(ctx context.Context, t testing.TB, key string, secret string) *test.Suite[s3.Config] {
|
||||||
s3.Config
|
return &test.Suite[s3.Config]{
|
||||||
|
|
||||||
tempdir string
|
|
||||||
stopServer func()
|
|
||||||
}
|
|
||||||
|
|
||||||
func createS3(t testing.TB, cfg MinioTestConfig, tr http.RoundTripper) (be restic.Backend, err error) {
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
be, err = s3.Create(context.TODO(), cfg.Config, tr)
|
|
||||||
if err != nil {
|
|
||||||
t.Logf("s3 open: try %d: error %v", i, err)
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return be, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite[MinioTestConfig] {
|
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[MinioTestConfig]{
|
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (*MinioTestConfig, error) {
|
NewConfig: func() (*s3.Config, error) {
|
||||||
cfg := MinioTestConfig{}
|
cfg := s3.NewConfig()
|
||||||
|
cfg.Endpoint = "localhost:9000"
|
||||||
cfg.tempdir = rtest.TempDir(t)
|
cfg.Bucket = "restictestbucket"
|
||||||
key, secret := newRandomCredentials(t)
|
cfg.Prefix = fmt.Sprintf("test-%d", time.Now().UnixNano())
|
||||||
cfg.stopServer = runMinio(ctx, t, cfg.tempdir, key, secret)
|
cfg.UseHTTP = true
|
||||||
|
cfg.KeyID = key
|
||||||
cfg.Config = s3.NewConfig()
|
cfg.Secret = options.NewSecretString(secret)
|
||||||
cfg.Config.Endpoint = "localhost:9000"
|
|
||||||
cfg.Config.Bucket = "restictestbucket"
|
|
||||||
cfg.Config.Prefix = fmt.Sprintf("test-%d", time.Now().UnixNano())
|
|
||||||
cfg.Config.UseHTTP = true
|
|
||||||
cfg.Config.KeyID = key
|
|
||||||
cfg.Config.Secret = options.NewSecretString(secret)
|
|
||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: s3.NewFactory(),
|
||||||
Create: func(cfg MinioTestConfig) (restic.Backend, error) {
|
}
|
||||||
be, err := createS3(t, cfg, tr)
|
}
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
func createMinioTestSuite(t testing.TB) (*test.Suite[s3.Config], func()) {
|
||||||
if err != nil && !be.IsNotExist(err) {
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
tempdir := rtest.TempDir(t)
|
||||||
return nil, errors.New("config already exists")
|
key, secret := newRandomCredentials(t)
|
||||||
}
|
cleanup := runMinio(ctx, t, tempdir, key, secret)
|
||||||
|
|
||||||
return be, nil
|
return newMinioTestSuite(ctx, t, key, secret), func() {
|
||||||
},
|
defer cancel()
|
||||||
|
defer cleanup()
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg MinioTestConfig) (restic.Backend, error) {
|
|
||||||
return s3.Open(ctx, cfg.Config, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg MinioTestConfig) error {
|
|
||||||
if cfg.stopServer != nil {
|
|
||||||
cfg.stopServer()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,10 +139,10 @@ func TestBackendMinio(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
suite, cleanup := createMinioTestSuite(t)
|
||||||
defer cancel()
|
defer cleanup()
|
||||||
|
|
||||||
newMinioTestSuite(ctx, t).RunTests(t)
|
suite.RunTests(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkBackendMinio(t *testing.B) {
|
func BenchmarkBackendMinio(t *testing.B) {
|
||||||
|
@ -207,18 +153,13 @@ func BenchmarkBackendMinio(t *testing.B) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
suite, cleanup := createMinioTestSuite(t)
|
||||||
defer cancel()
|
defer cleanup()
|
||||||
|
|
||||||
newMinioTestSuite(ctx, t).RunBenchmarks(t)
|
suite.RunBenchmarks(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newS3TestSuite(t testing.TB) *test.Suite[s3.Config] {
|
func newS3TestSuite(t testing.TB) *test.Suite[s3.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[s3.Config]{
|
return &test.Suite[s3.Config]{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
|
@ -236,39 +177,7 @@ func newS3TestSuite(t testing.TB) *test.Suite[s3.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: s3.NewFactory(),
|
||||||
Create: func(cfg s3.Config) (restic.Backend, error) {
|
|
||||||
be, err := s3.Create(context.TODO(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
|
||||||
if err != nil && !be.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil, errors.New("config already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
return be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg s3.Config) (restic.Backend, error) {
|
|
||||||
return s3.Open(context.TODO(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg s3.Config) error {
|
|
||||||
be, err := s3.Open(context.TODO(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return be.Delete(context.TODO())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package sftp_test
|
package sftp_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -11,7 +10,6 @@ import (
|
||||||
"github.com/restic/restic/internal/backend/sftp"
|
"github.com/restic/restic/internal/backend/sftp"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
"github.com/restic/restic/internal/errors"
|
||||||
"github.com/restic/restic/internal/restic"
|
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -33,11 +31,7 @@ func newTestSuite(t testing.TB) *test.Suite[sftp.Config] {
|
||||||
return &test.Suite[sftp.Config]{
|
return &test.Suite[sftp.Config]{
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig: func() (*sftp.Config, error) {
|
NewConfig: func() (*sftp.Config, error) {
|
||||||
dir, err := os.MkdirTemp(rtest.TestTempDir, "restic-test-sftp-")
|
dir := rtest.TempDir(t)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Logf("create new backend at %v", dir)
|
t.Logf("create new backend at %v", dir)
|
||||||
|
|
||||||
cfg := &sftp.Config{
|
cfg := &sftp.Config{
|
||||||
|
@ -48,25 +42,7 @@ func newTestSuite(t testing.TB) *test.Suite[sftp.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: sftp.NewFactory(),
|
||||||
Create: func(cfg sftp.Config) (restic.Backend, error) {
|
|
||||||
return sftp.Create(context.TODO(), cfg)
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg sftp.Config) (restic.Backend, error) {
|
|
||||||
return sftp.Open(context.TODO(), cfg)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg sftp.Config) error {
|
|
||||||
if !rtest.TestCleanupTempDirs {
|
|
||||||
t.Logf("leaving test backend dir at %v", cfg.Path)
|
|
||||||
}
|
|
||||||
|
|
||||||
rtest.RemoveAll(t, cfg.Path)
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,18 @@
|
||||||
package swift_test
|
package swift_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/restic/restic/internal/backend"
|
|
||||||
"github.com/restic/restic/internal/backend/swift"
|
"github.com/restic/restic/internal/backend/swift"
|
||||||
"github.com/restic/restic/internal/backend/test"
|
"github.com/restic/restic/internal/backend/test"
|
||||||
"github.com/restic/restic/internal/errors"
|
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
rtest "github.com/restic/restic/internal/test"
|
rtest "github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newSwiftTestSuite(t testing.TB) *test.Suite[swift.Config] {
|
func newSwiftTestSuite(t testing.TB) *test.Suite[swift.Config] {
|
||||||
tr, err := backend.Transport(backend.TransportOptions{})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("cannot create transport for tests: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &test.Suite[swift.Config]{
|
return &test.Suite[swift.Config]{
|
||||||
// do not use excessive data
|
// do not use excessive data
|
||||||
MinimalData: true,
|
MinimalData: true,
|
||||||
|
@ -54,39 +46,7 @@ func newSwiftTestSuite(t testing.TB) *test.Suite[swift.Config] {
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
},
|
},
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
Factory: swift.NewFactory(),
|
||||||
Create: func(cfg swift.Config) (restic.Backend, error) {
|
|
||||||
be, err := swift.Open(context.TODO(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
|
||||||
if err != nil && !be.IsNotExist(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err == nil {
|
|
||||||
return nil, errors.New("config already exists")
|
|
||||||
}
|
|
||||||
|
|
||||||
return be, nil
|
|
||||||
},
|
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open: func(cfg swift.Config) (restic.Backend, error) {
|
|
||||||
return swift.Open(context.TODO(), cfg, tr)
|
|
||||||
},
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup: func(cfg swift.Config) error {
|
|
||||||
be, err := swift.Open(context.TODO(), cfg, tr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return be.Delete(context.TODO())
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
package test
|
package test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/restic/restic/internal/backend"
|
||||||
|
"github.com/restic/restic/internal/backend/location"
|
||||||
|
"github.com/restic/restic/internal/errors"
|
||||||
"github.com/restic/restic/internal/restic"
|
"github.com/restic/restic/internal/restic"
|
||||||
"github.com/restic/restic/internal/test"
|
"github.com/restic/restic/internal/test"
|
||||||
)
|
)
|
||||||
|
@ -18,14 +23,8 @@ type Suite[C any] struct {
|
||||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||||
NewConfig func() (*C, error)
|
NewConfig func() (*C, error)
|
||||||
|
|
||||||
// CreateFn is a function that creates a temporary repository for the tests.
|
// Factory contains a factory that can be used to create or open a repository for the tests.
|
||||||
Create func(cfg C) (restic.Backend, error)
|
Factory location.Factory
|
||||||
|
|
||||||
// OpenFn is a function that opens a previously created temporary repository.
|
|
||||||
Open func(cfg C) (restic.Backend, error)
|
|
||||||
|
|
||||||
// CleanupFn removes data created during the tests.
|
|
||||||
Cleanup func(cfg C) error
|
|
||||||
|
|
||||||
// MinimalData instructs the tests to not use excessive data.
|
// MinimalData instructs the tests to not use excessive data.
|
||||||
MinimalData bool
|
MinimalData bool
|
||||||
|
@ -60,11 +59,7 @@ func (s *Suite[C]) RunTests(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Cleanup != nil {
|
s.cleanup(t)
|
||||||
if err = s.Cleanup(*s.Config); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type testFunction struct {
|
type testFunction struct {
|
||||||
|
@ -158,13 +153,34 @@ func (s *Suite[C]) RunBenchmarks(b *testing.B) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = s.Cleanup(*s.Config); err != nil {
|
s.cleanup(b)
|
||||||
b.Fatal(err)
|
}
|
||||||
|
|
||||||
|
func (s *Suite[C]) createOrError() (restic.Backend, error) {
|
||||||
|
tr, err := backend.Transport(backend.TransportOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot create transport for tests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
be, err := s.Factory.Create(context.TODO(), s.Config, tr, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = be.Stat(context.TODO(), restic.Handle{Type: restic.ConfigFile})
|
||||||
|
if err != nil && !be.IsNotExist(err) {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return nil, errors.New("config already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
return be, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite[C]) create(t testing.TB) restic.Backend {
|
func (s *Suite[C]) create(t testing.TB) restic.Backend {
|
||||||
be, err := s.Create(*s.Config)
|
be, err := s.createOrError()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -172,13 +188,26 @@ func (s *Suite[C]) create(t testing.TB) restic.Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Suite[C]) open(t testing.TB) restic.Backend {
|
func (s *Suite[C]) open(t testing.TB) restic.Backend {
|
||||||
be, err := s.Open(*s.Config)
|
tr, err := backend.Transport(backend.TransportOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot create transport for tests: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
be, err := s.Factory.Open(context.TODO(), s.Config, tr, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
return be
|
return be
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Suite[C]) cleanup(t testing.TB) {
|
||||||
|
be := s.open(t)
|
||||||
|
if err := be.Delete(context.TODO()); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s.close(t, be)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Suite[C]) close(t testing.TB, be restic.Backend) {
|
func (s *Suite[C]) close(t testing.TB, be restic.Backend) {
|
||||||
err := be.Close()
|
err := be.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -57,7 +57,7 @@ func (s *Suite[C]) TestCreateWithConfig(t *testing.T) {
|
||||||
store(t, b, restic.ConfigFile, []byte("test config"))
|
store(t, b, restic.ConfigFile, []byte("test config"))
|
||||||
|
|
||||||
// now create the backend again, this must fail
|
// now create the backend again, this must fail
|
||||||
_, err = s.Create(*s.Config)
|
_, err = s.createOrError()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected error not found for creating a backend with an existing config file")
|
t.Fatalf("expected error not found for creating a backend with an existing config file")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue