restic/internal/archiver/archiver_duplication_test.go

158 lines
2.6 KiB
Go
Raw Normal View History

2016-08-31 22:39:36 +02:00
package archiver_test
2016-02-01 23:26:57 +01:00
import (
2017-06-05 23:56:59 +02:00
"context"
2016-02-01 23:26:57 +01:00
"crypto/rand"
"io"
mrand "math/rand"
"sync"
"testing"
"time"
2016-09-01 22:17:37 +02:00
"restic/errors"
"restic"
2016-08-31 23:07:50 +02:00
"restic/archiver"
"restic/mock"
"restic/repository"
2016-02-01 23:26:57 +01:00
)
const parallelSaves = 50
const testSaveIndexTime = 100 * time.Millisecond
const testTimeout = 2 * time.Second
2016-02-01 23:26:57 +01:00
2016-08-31 23:07:50 +02:00
var DupID restic.ID
2016-02-01 23:26:57 +01:00
2016-08-31 23:07:50 +02:00
func randomID() restic.ID {
2016-02-01 23:26:57 +01:00
if mrand.Float32() < 0.5 {
return DupID
}
2016-08-31 23:07:50 +02:00
id := restic.ID{}
2016-02-01 23:26:57 +01:00
_, err := io.ReadFull(rand.Reader, id[:])
if err != nil {
panic(err)
}
return id
}
// forgetfulBackend returns a backend that forgets everything.
func forgetfulBackend() restic.Backend {
be := &mock.Backend{}
2016-02-01 23:26:57 +01:00
2017-06-05 23:56:59 +02:00
be.TestFn = func(ctx context.Context, h restic.Handle) (bool, error) {
2016-02-01 23:26:57 +01:00
return false, nil
}
2017-06-05 23:56:59 +02:00
be.LoadFn = func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) {
2017-01-23 17:20:08 +01:00
return nil, errors.New("not found")
2016-02-01 23:26:57 +01:00
}
2017-06-05 23:56:59 +02:00
be.SaveFn = func(ctx context.Context, h restic.Handle, rd io.Reader) error {
2016-02-01 23:26:57 +01:00
return nil
}
2017-06-05 23:56:59 +02:00
be.StatFn = func(ctx context.Context, h restic.Handle) (restic.FileInfo, error) {
2016-08-31 23:07:50 +02:00
return restic.FileInfo{}, errors.New("not found")
2016-02-01 23:26:57 +01:00
}
2017-06-05 23:56:59 +02:00
be.RemoveFn = func(ctx context.Context, h restic.Handle) error {
2016-02-01 23:26:57 +01:00
return nil
}
2017-06-05 23:56:59 +02:00
be.ListFn = func(ctx context.Context, t restic.FileType) <-chan string {
2016-02-01 23:26:57 +01:00
ch := make(chan string)
close(ch)
return ch
}
2017-06-05 23:56:59 +02:00
be.DeleteFn = func(ctx context.Context) error {
2016-02-01 23:26:57 +01:00
return nil
}
return be
}
func testArchiverDuplication(t *testing.T) {
2016-02-01 23:26:57 +01:00
_, err := io.ReadFull(rand.Reader, DupID[:])
if err != nil {
t.Fatal(err)
}
2016-03-06 13:14:06 +01:00
repo := repository.New(forgetfulBackend())
2017-06-05 23:56:59 +02:00
err = repo.Init(context.TODO(), "foo")
2016-02-01 23:26:57 +01:00
if err != nil {
t.Fatal(err)
}
2016-08-31 23:07:50 +02:00
arch := archiver.New(repo)
2016-02-01 23:26:57 +01:00
wg := &sync.WaitGroup{}
done := make(chan struct{})
for i := 0; i < parallelSaves; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case <-done:
return
default:
}
id := randomID()
2016-08-31 22:39:36 +02:00
if repo.Index().Has(id, restic.DataBlob) {
2016-02-01 23:26:57 +01:00
continue
}
buf := make([]byte, 50)
2017-06-05 23:56:59 +02:00
err := arch.Save(context.TODO(), restic.DataBlob, buf, id)
2016-02-01 23:26:57 +01:00
if err != nil {
t.Fatal(err)
}
}
}()
}
saveIndex := func() {
2016-02-01 23:26:57 +01:00
defer wg.Done()
ticker := time.NewTicker(testSaveIndexTime)
2016-02-01 23:26:57 +01:00
defer ticker.Stop()
for {
select {
case <-done:
return
case <-ticker.C:
2017-06-05 23:56:59 +02:00
err := repo.SaveFullIndex(context.TODO())
2016-02-01 23:26:57 +01:00
if err != nil {
t.Fatal(err)
}
}
}
}
wg.Add(1)
go saveIndex()
2016-02-01 23:26:57 +01:00
<-time.After(testTimeout)
close(done)
wg.Wait()
2017-01-23 17:24:34 +01:00
err = repo.Flush()
if err != nil {
t.Fatal(err)
}
2016-02-01 23:26:57 +01:00
}
func TestArchiverDuplication(t *testing.T) {
2016-02-01 23:26:57 +01:00
for i := 0; i < 5; i++ {
testArchiverDuplication(t)
2016-02-01 23:26:57 +01:00
}
}