forked from TrueCloudLab/restic
aaac63da8d
For some reason the test fails from time to time. Increase the timeouts to hopefully avoid this issue.
155 lines
3.9 KiB
Go
155 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/restic/restic/internal/repository"
|
|
"github.com/restic/restic/internal/restic"
|
|
rtest "github.com/restic/restic/internal/test"
|
|
)
|
|
|
|
func openTestRepo(t *testing.T, wrapper backendWrapper) (*repository.Repository, func(), *testEnvironment) {
|
|
env, cleanup := withTestEnvironment(t)
|
|
if wrapper != nil {
|
|
env.gopts.backendTestHook = wrapper
|
|
}
|
|
testRunInit(t, env.gopts)
|
|
|
|
repo, err := OpenRepository(context.TODO(), env.gopts)
|
|
rtest.OK(t, err)
|
|
return repo, cleanup, env
|
|
}
|
|
|
|
func checkedLockRepo(ctx context.Context, t *testing.T, repo restic.Repository) (*restic.Lock, context.Context) {
|
|
lock, wrappedCtx, err := lockRepo(ctx, repo)
|
|
rtest.OK(t, err)
|
|
rtest.OK(t, wrappedCtx.Err())
|
|
if lock.Stale() {
|
|
t.Fatal("lock returned stale lock")
|
|
}
|
|
return lock, wrappedCtx
|
|
}
|
|
|
|
func TestLock(t *testing.T) {
|
|
repo, cleanup, _ := openTestRepo(t, nil)
|
|
defer cleanup()
|
|
|
|
lock, wrappedCtx := checkedLockRepo(context.Background(), t, repo)
|
|
unlockRepo(lock)
|
|
if wrappedCtx.Err() == nil {
|
|
t.Fatal("unlock did not cancel context")
|
|
}
|
|
}
|
|
|
|
func TestLockCancel(t *testing.T) {
|
|
repo, cleanup, _ := openTestRepo(t, nil)
|
|
defer cleanup()
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
lock, wrappedCtx := checkedLockRepo(ctx, t, repo)
|
|
cancel()
|
|
if wrappedCtx.Err() == nil {
|
|
t.Fatal("canceled parent context did not cancel context")
|
|
}
|
|
|
|
// unlockRepo should not crash
|
|
unlockRepo(lock)
|
|
}
|
|
|
|
func TestLockUnlockAll(t *testing.T) {
|
|
repo, cleanup, _ := openTestRepo(t, nil)
|
|
defer cleanup()
|
|
|
|
lock, wrappedCtx := checkedLockRepo(context.Background(), t, repo)
|
|
_, err := unlockAll(0)
|
|
rtest.OK(t, err)
|
|
if wrappedCtx.Err() == nil {
|
|
t.Fatal("canceled parent context did not cancel context")
|
|
}
|
|
|
|
// unlockRepo should not crash
|
|
unlockRepo(lock)
|
|
}
|
|
|
|
func TestLockConflict(t *testing.T) {
|
|
repo, cleanup, env := openTestRepo(t, nil)
|
|
defer cleanup()
|
|
repo2, err := OpenRepository(context.TODO(), env.gopts)
|
|
rtest.OK(t, err)
|
|
|
|
lock, _, err := lockRepoExclusive(context.Background(), repo)
|
|
rtest.OK(t, err)
|
|
defer unlockRepo(lock)
|
|
_, _, err = lockRepo(context.Background(), repo2)
|
|
if err == nil {
|
|
t.Fatal("second lock should have failed")
|
|
}
|
|
}
|
|
|
|
type writeOnceBackend struct {
|
|
restic.Backend
|
|
written bool
|
|
}
|
|
|
|
func (b *writeOnceBackend) Save(ctx context.Context, h restic.Handle, rd restic.RewindReader) error {
|
|
if b.written {
|
|
return fmt.Errorf("fail after first write")
|
|
}
|
|
b.written = true
|
|
return b.Backend.Save(ctx, h, rd)
|
|
}
|
|
|
|
func TestLockFailedRefresh(t *testing.T) {
|
|
repo, cleanup, _ := openTestRepo(t, func(r restic.Backend) (restic.Backend, error) {
|
|
return &writeOnceBackend{Backend: r}, nil
|
|
})
|
|
defer cleanup()
|
|
|
|
// reduce locking intervals to be suitable for testing
|
|
ri, rt := refreshInterval, refreshabilityTimeout
|
|
refreshInterval = 20 * time.Millisecond
|
|
refreshabilityTimeout = 100 * time.Millisecond
|
|
defer func() {
|
|
refreshInterval, refreshabilityTimeout = ri, rt
|
|
}()
|
|
|
|
lock, wrappedCtx := checkedLockRepo(context.Background(), t, repo)
|
|
|
|
select {
|
|
case <-wrappedCtx.Done():
|
|
// expected lock refresh failure
|
|
case <-time.After(time.Second):
|
|
t.Fatal("failed lock refresh did not cause context cancellation")
|
|
}
|
|
// unlockRepo should not crash
|
|
unlockRepo(lock)
|
|
}
|
|
|
|
func TestLockSuccessfulRefresh(t *testing.T) {
|
|
repo, cleanup, _ := openTestRepo(t, nil)
|
|
defer cleanup()
|
|
|
|
t.Log("test for successful lock refresh")
|
|
// reduce locking intervals to be suitable for testing
|
|
ri, rt := refreshInterval, refreshabilityTimeout
|
|
refreshInterval = 40 * time.Millisecond
|
|
refreshabilityTimeout = 200 * time.Millisecond
|
|
defer func() {
|
|
refreshInterval, refreshabilityTimeout = ri, rt
|
|
}()
|
|
|
|
lock, wrappedCtx := checkedLockRepo(context.Background(), t, repo)
|
|
|
|
select {
|
|
case <-wrappedCtx.Done():
|
|
t.Fatal("lock refresh failed")
|
|
case <-time.After(2 * refreshabilityTimeout):
|
|
// expected lock refresh to work
|
|
}
|
|
// unlockRepo should not crash
|
|
unlockRepo(lock)
|
|
}
|