restic: generic implemention of AsBackend

This commit is contained in:
Michael Eischer 2023-06-17 19:23:55 +02:00
parent 11eb88a2ea
commit 51718ec561
4 changed files with 57 additions and 46 deletions

View File

@ -21,26 +21,9 @@ func init() {
// "default" layout. // "default" layout.
type S3Layout struct{} type S3Layout struct{}
func toS3Backend(b restic.Backend) *s3.Backend {
for b != nil {
if be, ok := b.(*s3.Backend); ok {
return be
}
if be, ok := b.(restic.BackendUnwrapper); ok {
b = be.Unwrap()
} else {
// not the backend we're looking for
break
}
}
debug.Log("backend is not s3")
return nil
}
// Check tests whether the migration can be applied. // Check tests whether the migration can be applied.
func (m *S3Layout) Check(_ context.Context, repo restic.Repository) (bool, string, error) { func (m *S3Layout) Check(_ context.Context, repo restic.Repository) (bool, string, error) {
be := toS3Backend(repo.Backend()) be := restic.AsBackend[*s3.Backend](repo.Backend())
if be == nil { if be == nil {
debug.Log("backend is not s3") debug.Log("backend is not s3")
return false, "backend is not s3", nil return false, "backend is not s3", nil
@ -92,7 +75,7 @@ func (m *S3Layout) moveFiles(ctx context.Context, be *s3.Backend, l layout.Layou
// Apply runs the migration. // Apply runs the migration.
func (m *S3Layout) Apply(ctx context.Context, repo restic.Repository) error { func (m *S3Layout) Apply(ctx context.Context, repo restic.Repository) error {
be := toS3Backend(repo.Backend()) be := restic.AsBackend[*s3.Backend](repo.Backend())
if be == nil { if be == nil {
debug.Log("backend is not s3") debug.Log("backend is not s3")
return errors.New("backend is not s3") return errors.New("backend is not s3")

View File

@ -1,27 +0,0 @@
package migrations
import (
"testing"
"github.com/restic/restic/internal/backend/mock"
"github.com/restic/restic/internal/backend/s3"
"github.com/restic/restic/internal/cache"
"github.com/restic/restic/internal/test"
)
func TestS3UnwrapBackend(t *testing.T) {
// toS3Backend(b restic.Backend) *s3.Backend
m := mock.NewBackend()
test.Assert(t, toS3Backend(m) == nil, "mock backend is not an s3 backend")
// uninitialized fake backend for testing
s3 := &s3.Backend{}
test.Assert(t, toS3Backend(s3) == s3, "s3 was not returned")
c := &cache.Backend{Backend: s3}
test.Assert(t, toS3Backend(c) == s3, "failed to unwrap s3 backend")
c.Backend = m
test.Assert(t, toS3Backend(c) == nil, "a wrapped mock backend is not an s3 backend")
}

View File

@ -75,6 +75,23 @@ type BackendUnwrapper interface {
Unwrap() Backend Unwrap() Backend
} }
func AsBackend[B Backend](b Backend) B {
for b != nil {
if be, ok := b.(B); ok {
return be
}
if be, ok := b.(BackendUnwrapper); ok {
b = be.Unwrap()
} else {
// not the backend we're looking for
break
}
}
var be B
return be
}
// FileInfo is contains information about a file in the backend. // FileInfo is contains information about a file in the backend.
type FileInfo struct { type FileInfo struct {
Size int64 Size int64

View File

@ -0,0 +1,38 @@
package restic_test
import (
"testing"
"github.com/restic/restic/internal/restic"
"github.com/restic/restic/internal/test"
)
type testBackend struct {
restic.Backend
}
func (t *testBackend) Unwrap() restic.Backend {
return nil
}
type otherTestBackend struct {
restic.Backend
}
func (t *otherTestBackend) Unwrap() restic.Backend {
return t.Backend
}
func TestAsBackend(t *testing.T) {
other := otherTestBackend{}
test.Assert(t, restic.AsBackend[*testBackend](other) == nil, "otherTestBackend is not a testBackend backend")
testBe := &testBackend{}
test.Assert(t, restic.AsBackend[*testBackend](testBe) == testBe, "testBackend was not returned")
wrapper := &otherTestBackend{Backend: testBe}
test.Assert(t, restic.AsBackend[*testBackend](wrapper) == testBe, "failed to unwrap testBackend backend")
wrapper.Backend = other
test.Assert(t, restic.AsBackend[*testBackend](wrapper) == nil, "a wrapped otherTestBackend is not a testBackend")
}