2015-06-24 16:17:01 +00:00
|
|
|
package restic_test
|
|
|
|
|
|
|
|
import (
|
2017-06-05 21:56:59 +00:00
|
|
|
"context"
|
2021-11-20 15:48:22 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
2015-06-24 16:17:01 +00:00
|
|
|
"os"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2023-10-01 09:40:12 +00:00
|
|
|
"github.com/restic/restic/internal/backend"
|
2021-11-20 15:48:22 +00:00
|
|
|
"github.com/restic/restic/internal/backend/mem"
|
2017-07-23 12:21:03 +00:00
|
|
|
"github.com/restic/restic/internal/repository"
|
2017-07-24 15:42:25 +00:00
|
|
|
"github.com/restic/restic/internal/restic"
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest "github.com/restic/restic/internal/test"
|
2015-06-24 16:17:01 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestLock(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestDoubleUnlock(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
err = lock.Unlock(context.TODO())
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, err != nil,
|
2015-06-24 16:17:01 +00:00
|
|
|
"double unlock didn't return an error, got %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMultipleLock(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock1, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock2, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock1.Unlock(context.TODO()))
|
|
|
|
rtest.OK(t, lock2.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
2021-11-20 15:48:22 +00:00
|
|
|
type failLockLoadingBackend struct {
|
2023-10-01 09:40:12 +00:00
|
|
|
backend.Backend
|
2021-11-20 15:48:22 +00:00
|
|
|
}
|
|
|
|
|
2023-10-01 09:40:12 +00:00
|
|
|
func (be *failLockLoadingBackend) Load(ctx context.Context, h backend.Handle, length int, offset int64, fn func(rd io.Reader) error) error {
|
2021-11-20 15:48:22 +00:00
|
|
|
if h.Type == restic.LockFile {
|
|
|
|
return fmt.Errorf("error loading lock")
|
|
|
|
}
|
|
|
|
return be.Backend.Load(ctx, h, length, offset, fn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMultipleLockFailure(t *testing.T) {
|
|
|
|
be := &failLockLoadingBackend{Backend: mem.New()}
|
2024-05-10 14:59:09 +00:00
|
|
|
repo, _ := repository.TestRepositoryWithBackend(t, be, 0, repository.Options{})
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2021-11-20 15:48:22 +00:00
|
|
|
|
|
|
|
lock1, err := restic.NewLock(context.TODO(), repo)
|
|
|
|
rtest.OK(t, err)
|
|
|
|
|
|
|
|
_, err = restic.NewLock(context.TODO(), repo)
|
|
|
|
rtest.Assert(t, err != nil, "unreadable lock file did not result in an error")
|
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock1.Unlock(context.TODO()))
|
2021-11-20 15:48:22 +00:00
|
|
|
}
|
|
|
|
|
2015-06-24 16:17:01 +00:00
|
|
|
func TestLockExclusive(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
elock, err := restic.NewExclusiveLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, elock.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockOnExclusiveLockedRepo(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
elock, err := restic.NewExclusiveLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, err != nil,
|
2015-06-24 16:17:01 +00:00
|
|
|
"create normal lock with exclusively locked repo didn't return an error")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, restic.IsAlreadyLocked(err),
|
2015-06-27 13:50:36 +00:00
|
|
|
"create normal lock with exclusively locked repo didn't return the correct error")
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock.Unlock(context.TODO()))
|
|
|
|
rtest.OK(t, elock.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestExclusiveLockOnLockedRepo(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2023-07-09 13:35:11 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
elock, err := restic.NewLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-06-05 21:56:59 +00:00
|
|
|
lock, err := restic.NewExclusiveLock(context.TODO(), repo)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, err != nil,
|
2015-06-27 13:50:36 +00:00
|
|
|
"create normal lock with exclusively locked repo didn't return an error")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, restic.IsAlreadyLocked(err),
|
2015-06-27 13:50:36 +00:00
|
|
|
"create normal lock with exclusively locked repo didn't return the correct error")
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock.Unlock(context.TODO()))
|
|
|
|
rtest.OK(t, elock.Unlock(context.TODO()))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
2024-01-19 21:44:50 +00:00
|
|
|
func createFakeLock(repo restic.SaverUnpacked, t time.Time, pid int) (restic.ID, error) {
|
2015-08-16 14:24:04 +00:00
|
|
|
hostname, err := os.Hostname()
|
|
|
|
if err != nil {
|
2016-08-31 18:29:54 +00:00
|
|
|
return restic.ID{}, err
|
2015-08-16 14:24:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
newLock := &restic.Lock{Time: t, PID: pid, Hostname: hostname}
|
2022-06-12 12:38:19 +00:00
|
|
|
return restic.SaveJSONUnpacked(context.TODO(), repo, restic.LockFile, &newLock)
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
2024-05-10 16:19:14 +00:00
|
|
|
func removeLock(repo restic.RemoverUnpacked, id restic.ID) error {
|
2024-05-09 23:16:23 +00:00
|
|
|
return repo.RemoveUnpacked(context.TODO(), restic.LockFile, id)
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var staleLockTests = []struct {
|
2015-08-16 14:24:04 +00:00
|
|
|
timestamp time.Time
|
|
|
|
stale bool
|
|
|
|
staleOnOtherHost bool
|
|
|
|
pid int
|
2015-06-24 16:17:01 +00:00
|
|
|
}{
|
|
|
|
{
|
2015-08-16 14:24:04 +00:00
|
|
|
timestamp: time.Now(),
|
|
|
|
stale: false,
|
|
|
|
staleOnOtherHost: false,
|
|
|
|
pid: os.Getpid(),
|
2015-06-24 16:17:01 +00:00
|
|
|
},
|
|
|
|
{
|
2015-08-16 14:24:04 +00:00
|
|
|
timestamp: time.Now().Add(-time.Hour),
|
|
|
|
stale: true,
|
|
|
|
staleOnOtherHost: true,
|
|
|
|
pid: os.Getpid(),
|
2015-06-24 16:17:01 +00:00
|
|
|
},
|
|
|
|
{
|
2015-08-16 14:24:04 +00:00
|
|
|
timestamp: time.Now().Add(3 * time.Minute),
|
|
|
|
stale: false,
|
|
|
|
staleOnOtherHost: false,
|
|
|
|
pid: os.Getpid(),
|
2015-06-24 16:17:01 +00:00
|
|
|
},
|
|
|
|
{
|
2015-08-16 14:24:04 +00:00
|
|
|
timestamp: time.Now(),
|
|
|
|
stale: true,
|
|
|
|
staleOnOtherHost: false,
|
2015-08-19 18:25:59 +00:00
|
|
|
pid: os.Getpid() + 500000,
|
2015-06-24 16:17:01 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockStale(t *testing.T) {
|
2015-08-16 14:24:04 +00:00
|
|
|
hostname, err := os.Hostname()
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-08-16 14:24:04 +00:00
|
|
|
|
|
|
|
otherHostname := "other-" + hostname
|
|
|
|
|
2015-06-24 16:17:01 +00:00
|
|
|
for i, test := range staleLockTests {
|
|
|
|
lock := restic.Lock{
|
2015-08-16 14:24:04 +00:00
|
|
|
Time: test.timestamp,
|
|
|
|
PID: test.pid,
|
|
|
|
Hostname: hostname,
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lock.Stale() == test.stale,
|
2015-06-24 16:17:01 +00:00
|
|
|
"TestStaleLock: test %d failed: expected stale: %v, got %v",
|
|
|
|
i, test.stale, !test.stale)
|
2015-08-16 14:24:04 +00:00
|
|
|
|
|
|
|
lock.Hostname = otherHostname
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lock.Stale() == test.staleOnOtherHost,
|
2015-08-16 14:24:04 +00:00
|
|
|
"TestStaleLock: test %d failed: expected staleOnOtherHost: %v, got %v",
|
|
|
|
i, test.staleOnOtherHost, !test.staleOnOtherHost)
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-10 16:19:14 +00:00
|
|
|
func lockExists(repo restic.Lister, t testing.TB, lockID restic.ID) bool {
|
2024-05-10 14:08:22 +00:00
|
|
|
var exists bool
|
|
|
|
rtest.OK(t, repo.List(context.TODO(), restic.LockFile, func(id restic.ID, size int64) error {
|
|
|
|
if id == lockID {
|
|
|
|
exists = true
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
|
|
|
return exists
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockWithStaleLock(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
|
|
|
id1, err := createFakeLock(repo, time.Now().Add(-time.Hour), os.Getpid())
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
|
|
|
id2, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid())
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2015-08-14 13:19:45 +00:00
|
|
|
id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2022-09-18 10:40:19 +00:00
|
|
|
processed, err := restic.RemoveStaleLocks(context.TODO(), repo)
|
|
|
|
rtest.OK(t, err)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id1) == false,
|
2015-06-24 16:17:01 +00:00
|
|
|
"stale lock still exists after RemoveStaleLocks was called")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id2) == true,
|
2015-06-24 16:17:01 +00:00
|
|
|
"non-stale lock was removed by RemoveStaleLocks")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id3) == false,
|
2015-06-24 16:17:01 +00:00
|
|
|
"stale lock still exists after RemoveStaleLocks was called")
|
2022-09-18 10:40:19 +00:00
|
|
|
rtest.Assert(t, processed == 2,
|
|
|
|
"number of locks removed does not match: expected %d, got %d",
|
|
|
|
2, processed)
|
2015-06-24 16:17:01 +00:00
|
|
|
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, removeLock(repo, id2))
|
2015-06-24 16:17:01 +00:00
|
|
|
}
|
2015-06-27 12:26:33 +00:00
|
|
|
|
2015-06-27 13:50:36 +00:00
|
|
|
func TestRemoveAllLocks(t *testing.T) {
|
2022-12-11 09:41:22 +00:00
|
|
|
repo := repository.TestRepository(t)
|
2015-06-27 13:50:36 +00:00
|
|
|
|
|
|
|
id1, err := createFakeLock(repo, time.Now().Add(-time.Hour), os.Getpid())
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-27 13:50:36 +00:00
|
|
|
|
|
|
|
id2, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid())
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-27 13:50:36 +00:00
|
|
|
|
2015-08-19 18:25:59 +00:00
|
|
|
id3, err := createFakeLock(repo, time.Now().Add(-time.Minute), os.Getpid()+500000)
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.OK(t, err)
|
2015-06-27 13:50:36 +00:00
|
|
|
|
2022-09-18 10:40:19 +00:00
|
|
|
processed, err := restic.RemoveAllLocks(context.TODO(), repo)
|
|
|
|
rtest.OK(t, err)
|
2015-06-27 13:50:36 +00:00
|
|
|
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id1) == false,
|
2015-06-27 13:50:36 +00:00
|
|
|
"lock still exists after RemoveAllLocks was called")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id2) == false,
|
2015-06-27 13:50:36 +00:00
|
|
|
"lock still exists after RemoveAllLocks was called")
|
2017-10-02 13:06:39 +00:00
|
|
|
rtest.Assert(t, lockExists(repo, t, id3) == false,
|
2015-06-27 13:50:36 +00:00
|
|
|
"lock still exists after RemoveAllLocks was called")
|
2022-09-18 10:40:19 +00:00
|
|
|
rtest.Assert(t, processed == 3,
|
|
|
|
"number of locks removed does not match: expected %d, got %d",
|
|
|
|
3, processed)
|
2015-06-27 13:50:36 +00:00
|
|
|
}
|
2015-07-12 19:02:00 +00:00
|
|
|
|
2024-01-19 21:44:50 +00:00
|
|
|
func checkSingleLock(t *testing.T, repo restic.Lister) restic.ID {
|
2023-07-09 13:35:37 +00:00
|
|
|
t.Helper()
|
2016-08-31 18:29:54 +00:00
|
|
|
var lockID *restic.ID
|
2023-07-09 13:35:37 +00:00
|
|
|
err := repo.List(context.TODO(), restic.LockFile, func(id restic.ID, size int64) error {
|
2015-07-12 19:02:00 +00:00
|
|
|
if lockID != nil {
|
|
|
|
t.Error("more than one lock found")
|
|
|
|
}
|
2015-07-25 15:05:45 +00:00
|
|
|
lockID = &id
|
2018-01-21 16:25:36 +00:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
2015-07-12 19:02:00 +00:00
|
|
|
}
|
2023-07-09 13:35:37 +00:00
|
|
|
if lockID == nil {
|
|
|
|
t.Fatal("no lock found")
|
|
|
|
}
|
|
|
|
return *lockID
|
|
|
|
}
|
|
|
|
|
2023-07-09 13:41:44 +00:00
|
|
|
func testLockRefresh(t *testing.T, refresh func(lock *restic.Lock) error) {
|
2023-07-09 13:35:37 +00:00
|
|
|
repo := repository.TestRepository(t)
|
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
|
|
|
|
|
|
|
lock, err := restic.NewLock(context.TODO(), repo)
|
|
|
|
rtest.OK(t, err)
|
|
|
|
time0 := lock.Time
|
|
|
|
|
|
|
|
lockID := checkSingleLock(t, repo)
|
2015-07-12 19:02:00 +00:00
|
|
|
|
2019-09-04 18:38:35 +00:00
|
|
|
time.Sleep(time.Millisecond)
|
2023-07-09 13:41:44 +00:00
|
|
|
rtest.OK(t, refresh(lock))
|
2015-07-12 19:02:00 +00:00
|
|
|
|
2023-07-09 13:35:37 +00:00
|
|
|
lockID2 := checkSingleLock(t, repo)
|
2015-07-12 19:02:00 +00:00
|
|
|
|
2023-07-09 13:35:37 +00:00
|
|
|
rtest.Assert(t, !lockID.Equal(lockID2),
|
2015-07-12 19:02:00 +00:00
|
|
|
"expected a new ID after lock refresh, got the same")
|
2023-07-09 13:35:37 +00:00
|
|
|
lock2, err := restic.LoadLock(context.TODO(), repo, lockID2)
|
2019-09-04 18:38:35 +00:00
|
|
|
rtest.OK(t, err)
|
|
|
|
rtest.Assert(t, lock2.Time.After(time0),
|
|
|
|
"expected a later timestamp after lock refresh")
|
2024-04-29 19:43:28 +00:00
|
|
|
rtest.OK(t, lock.Unlock(context.TODO()))
|
2015-07-12 19:02:00 +00:00
|
|
|
}
|
2023-07-09 13:41:44 +00:00
|
|
|
|
|
|
|
func TestLockRefresh(t *testing.T) {
|
|
|
|
testLockRefresh(t, func(lock *restic.Lock) error {
|
|
|
|
return lock.Refresh(context.TODO())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockRefreshStale(t *testing.T) {
|
|
|
|
testLockRefresh(t, func(lock *restic.Lock) error {
|
|
|
|
return lock.RefreshStaleLock(context.TODO())
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestLockRefreshStaleMissing(t *testing.T) {
|
2024-05-10 15:11:08 +00:00
|
|
|
repo, be := repository.TestRepositoryWithVersion(t, 0)
|
2023-07-09 13:41:44 +00:00
|
|
|
restic.TestSetLockTimeout(t, 5*time.Millisecond)
|
|
|
|
|
|
|
|
lock, err := restic.NewLock(context.TODO(), repo)
|
|
|
|
rtest.OK(t, err)
|
|
|
|
lockID := checkSingleLock(t, repo)
|
|
|
|
|
|
|
|
// refresh must fail if lock was removed
|
2024-05-10 15:11:08 +00:00
|
|
|
rtest.OK(t, be.Remove(context.TODO(), backend.Handle{Type: restic.LockFile, Name: lockID.String()}))
|
2023-07-09 13:41:44 +00:00
|
|
|
time.Sleep(time.Millisecond)
|
|
|
|
err = lock.RefreshStaleLock(context.TODO())
|
|
|
|
rtest.Assert(t, err == restic.ErrRemovedLock, "unexpected error, expected %v, got %v", restic.ErrRemovedLock, err)
|
|
|
|
}
|