diff --git a/src/restic/backend/s3/backend_test.go b/src/restic/backend/s3/backend_test.go deleted file mode 100644 index 82eca2631..000000000 --- a/src/restic/backend/s3/backend_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// DO NOT EDIT, AUTOMATICALLY GENERATED -package s3_test - -import ( - "testing" - - "restic/backend/test" -) - -var SkipMessage string - -func TestS3BackendCreate(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestCreate(t) -} - -func TestS3BackendOpen(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestOpen(t) -} - -func TestS3BackendCreateWithConfig(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestCreateWithConfig(t) -} - -func TestS3BackendLocation(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestLocation(t) -} - -func TestS3BackendConfig(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestConfig(t) -} - -func TestS3BackendLoad(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestLoad(t) -} - -func TestS3BackendSave(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestSave(t) -} - -func TestS3BackendSaveFilenames(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestSaveFilenames(t) -} - -func TestS3BackendBackend(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestBackend(t) -} - -func TestS3BackendDelete(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestDelete(t) -} - -func TestS3BackendCleanup(t *testing.T) { - if SkipMessage != "" { - t.Skip(SkipMessage) - } - test.TestCleanup(t) -} diff --git a/src/restic/backend/s3/s3_test.go b/src/restic/backend/s3/s3_test.go index 3bee8c8cd..de95a89c7 100644 --- a/src/restic/backend/s3/s3_test.go +++ b/src/restic/backend/s3/s3_test.go @@ -1,73 +1,174 @@ package s3_test import ( - "fmt" - "net/url" + "context" + "crypto/rand" + "encoding/hex" + "errors" + "io" + "net" "os" + "os/exec" + "path/filepath" "restic" - - "restic/errors" + "testing" + "time" "restic/backend/s3" "restic/backend/test" . "restic/test" ) -//go:generate go run ../test/generate_backend_tests.go - -func init() { - if TestS3Server == "" { - SkipMessage = "s3 test server not available" - return - } - - url, err := url.Parse(TestS3Server) +func mkdir(t testing.TB, dir string) { + err := os.MkdirAll(dir, 0700) if err != nil { - fmt.Fprintf(os.Stderr, "invalid url: %v\n", err) + t.Fatal(err) + } +} + +func runMinio(ctx context.Context, t testing.TB, dir, key, secret string) func() { + mkdir(t, filepath.Join(dir, "config")) + mkdir(t, filepath.Join(dir, "root")) + + cmd := exec.CommandContext(ctx, "minio", + "server", + "--address", "127.0.0.1:9000", + "--config-dir", filepath.Join(dir, "config"), + filepath.Join(dir, "root")) + cmd.Env = append(os.Environ(), + "MINIO_ACCESS_KEY="+key, + "MINIO_SECRET_KEY="+secret, + ) + cmd.Stderr = os.Stderr + + err := cmd.Start() + if err != nil { + t.Fatal(err) + } + + // wait until the TCP port is reachable + var success bool + for i := 0; i < 10; i++ { + c, err := net.Dial("tcp", "localhost:9000") + if err != nil { + time.Sleep(200 * time.Millisecond) + continue + } + + success = true + if err := c.Close(); err != nil { + t.Fatal(err) + } + } + + if !success { + t.Fatal("unable to connect to minio server") + return nil + } + + return func() { + err = cmd.Process.Kill() + if err != nil { + t.Fatal(err) + } + } +} + +func newCredentials(t testing.TB) (key, secret string) { + buf := make([]byte, 10) + _, err := io.ReadFull(rand.Reader, buf) + if err != nil { + t.Fatal(err) + } + key = hex.EncodeToString(buf) + + _, err = io.ReadFull(rand.Reader, buf) + if err != nil { + t.Fatal(err) + } + secret = hex.EncodeToString(buf) + + return key, secret +} + +func TestBackendMinio(t *testing.T) { + // try to find a minio binary + _, err := exec.LookPath("minio") + if err != nil { + t.Skip(err) return } - cfg := s3.Config{ - Endpoint: url.Host, - Bucket: "restictestbucket", - KeyID: os.Getenv("AWS_ACCESS_KEY_ID"), - Secret: os.Getenv("AWS_SECRET_ACCESS_KEY"), + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + type Config struct { + s3.Config + + tempdir string + removeTempdir func() + stopServer func() } - if url.Scheme == "http" { - cfg.UseHTTP = true + suite := test.Suite{ + // NewConfig returns a config for a new temporary backend that will be used in tests. + NewConfig: func() (interface{}, error) { + cfg := Config{} + + cfg.tempdir, cfg.removeTempdir = TempDir(t) + key, secret := newCredentials(t) + cfg.stopServer = runMinio(ctx, t, cfg.tempdir, key, secret) + + cfg.Config = s3.Config{ + Endpoint: "localhost:9000", + Bucket: "restictestbucket", + UseHTTP: true, + KeyID: key, + Secret: secret, + } + return cfg, nil + }, + + // CreateFn is a function that creates a temporary repository for the tests. + Create: func(config interface{}) (restic.Backend, error) { + cfg := config.(Config) + + be, err := s3.Open(cfg.Config) + if err != nil { + return nil, err + } + + exists, err := be.Test(restic.Handle{Type: restic.ConfigFile}) + if err != nil { + return nil, err + } + + if exists { + return nil, errors.New("config already exists") + } + + return be, nil + }, + + // OpenFn is a function that opens a previously created temporary repository. + Open: func(config interface{}) (restic.Backend, error) { + cfg := config.(Config) + return s3.Open(cfg.Config) + }, + + // CleanupFn removes data created during the tests. + Cleanup: func(config interface{}) error { + cfg := config.(Config) + if cfg.stopServer != nil { + cfg.stopServer() + } + if cfg.removeTempdir != nil { + t.Logf("removeTempdir %v", config) + cfg.removeTempdir() + } + return nil + }, } - test.CreateFn = func() (restic.Backend, error) { - be, err := s3.Open(cfg) - if err != nil { - return nil, err - } - - exists, err := be.Test(restic.Handle{Type: restic.ConfigFile}) - if err != nil { - return nil, err - } - - if exists { - return nil, errors.New("config already exists") - } - - return be, nil - } - - test.OpenFn = func() (restic.Backend, error) { - return s3.Open(cfg) - } - - // test.CleanupFn = func() error { - // if tempBackendDir == "" { - // return nil - // } - - // fmt.Printf("removing test backend at %v\n", tempBackendDir) - // err := os.RemoveAll(tempBackendDir) - // tempBackendDir = "" - // return err - // } + suite.RunTests(t) }