2018-05-12 19:40:31 +00:00
|
|
|
package archiver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"runtime"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/restic/restic/internal/errors"
|
|
|
|
"github.com/restic/restic/internal/restic"
|
2022-08-20 09:56:00 +00:00
|
|
|
"github.com/restic/restic/internal/test"
|
2022-05-27 17:08:50 +00:00
|
|
|
"golang.org/x/sync/errgroup"
|
2018-05-12 19:40:31 +00:00
|
|
|
)
|
|
|
|
|
2023-05-18 17:18:09 +00:00
|
|
|
func treeSaveHelper(_ context.Context, t restic.BlobType, buf *Buffer, cb func(res SaveBlobResponse)) {
|
2022-10-07 18:23:38 +00:00
|
|
|
cb(SaveBlobResponse{
|
2022-08-19 21:08:13 +00:00
|
|
|
id: restic.NewRandomID(),
|
|
|
|
known: false,
|
2022-10-08 19:29:32 +00:00
|
|
|
length: len(buf.Data),
|
|
|
|
sizeInRepo: len(buf.Data),
|
2022-10-07 18:23:38 +00:00
|
|
|
})
|
2022-08-19 21:08:13 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 19:29:32 +00:00
|
|
|
func setupTreeSaver() (context.Context, context.CancelFunc, *TreeSaver, func() error) {
|
2018-05-12 19:40:31 +00:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
2022-05-27 17:08:50 +00:00
|
|
|
wg, ctx := errgroup.WithContext(ctx)
|
2018-05-12 19:40:31 +00:00
|
|
|
|
2022-05-20 22:31:26 +00:00
|
|
|
errFn := func(snPath string, err error) error {
|
2022-08-19 21:08:13 +00:00
|
|
|
return err
|
2018-05-12 19:40:31 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 19:29:32 +00:00
|
|
|
b := NewTreeSaver(ctx, wg, uint(runtime.NumCPU()), treeSaveHelper, errFn)
|
|
|
|
|
|
|
|
shutdown := func() error {
|
|
|
|
b.TriggerShutdown()
|
|
|
|
return wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
return ctx, cancel, b, shutdown
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeSaver(t *testing.T) {
|
|
|
|
ctx, cancel, b, shutdown := setupTreeSaver()
|
|
|
|
defer cancel()
|
2018-05-12 19:40:31 +00:00
|
|
|
|
2022-05-29 09:57:10 +00:00
|
|
|
var results []FutureNode
|
2018-05-12 19:40:31 +00:00
|
|
|
|
|
|
|
for i := 0; i < 20; i++ {
|
|
|
|
node := &restic.Node{
|
|
|
|
Name: fmt.Sprintf("file-%d", i),
|
|
|
|
}
|
|
|
|
|
2022-08-19 21:08:13 +00:00
|
|
|
fb := b.Save(ctx, join("/", node.Name), node.Name, node, nil, nil)
|
2018-05-12 19:40:31 +00:00
|
|
|
results = append(results, fb)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tree := range results {
|
2022-05-29 09:57:10 +00:00
|
|
|
tree.take(ctx)
|
2018-05-12 19:40:31 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 19:29:32 +00:00
|
|
|
err := shutdown()
|
2018-05-12 19:40:31 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestTreeSaverError(t *testing.T) {
|
|
|
|
var tests = []struct {
|
|
|
|
trees int
|
2022-08-19 21:08:13 +00:00
|
|
|
failAt int
|
2018-05-12 19:40:31 +00:00
|
|
|
}{
|
|
|
|
{1, 1},
|
|
|
|
{20, 2},
|
|
|
|
{20, 5},
|
|
|
|
{20, 15},
|
|
|
|
{200, 150},
|
|
|
|
}
|
|
|
|
|
|
|
|
errTest := errors.New("test error")
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
t.Run("", func(t *testing.T) {
|
2022-10-08 19:29:32 +00:00
|
|
|
ctx, cancel, b, shutdown := setupTreeSaver()
|
2018-05-12 19:40:31 +00:00
|
|
|
defer cancel()
|
|
|
|
|
2022-05-29 09:57:10 +00:00
|
|
|
var results []FutureNode
|
2018-05-12 19:40:31 +00:00
|
|
|
|
|
|
|
for i := 0; i < test.trees; i++ {
|
|
|
|
node := &restic.Node{
|
|
|
|
Name: fmt.Sprintf("file-%d", i),
|
|
|
|
}
|
2022-08-19 21:08:13 +00:00
|
|
|
nodes := []FutureNode{
|
|
|
|
newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
|
|
|
|
Name: fmt.Sprintf("child-%d", i),
|
|
|
|
}}),
|
|
|
|
}
|
|
|
|
if (i + 1) == test.failAt {
|
|
|
|
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{
|
|
|
|
err: errTest,
|
|
|
|
}))
|
|
|
|
}
|
2018-05-12 19:40:31 +00:00
|
|
|
|
2022-08-19 21:08:13 +00:00
|
|
|
fb := b.Save(ctx, join("/", node.Name), node.Name, node, nodes, nil)
|
2018-05-12 19:40:31 +00:00
|
|
|
results = append(results, fb)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tree := range results {
|
2022-05-29 09:57:10 +00:00
|
|
|
tree.take(ctx)
|
2018-05-12 19:40:31 +00:00
|
|
|
}
|
|
|
|
|
2022-10-08 19:29:32 +00:00
|
|
|
err := shutdown()
|
2018-05-12 19:40:31 +00:00
|
|
|
if err == nil {
|
|
|
|
t.Errorf("expected error not found")
|
|
|
|
}
|
|
|
|
if err != errTest {
|
|
|
|
t.Fatalf("unexpected error found: %v", err)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2022-08-20 09:56:00 +00:00
|
|
|
|
|
|
|
func TestTreeSaverDuplicates(t *testing.T) {
|
|
|
|
for _, identicalNodes := range []bool{true, false} {
|
|
|
|
t.Run("", func(t *testing.T) {
|
|
|
|
ctx, cancel, b, shutdown := setupTreeSaver()
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
node := &restic.Node{
|
|
|
|
Name: "file",
|
|
|
|
}
|
|
|
|
nodes := []FutureNode{
|
|
|
|
newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
|
|
|
|
Name: "child",
|
|
|
|
}}),
|
|
|
|
}
|
|
|
|
if identicalNodes {
|
|
|
|
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
|
|
|
|
Name: "child",
|
|
|
|
}}))
|
|
|
|
} else {
|
|
|
|
nodes = append(nodes, newFutureNodeWithResult(futureNodeResult{node: &restic.Node{
|
|
|
|
Name: "child",
|
|
|
|
Size: 42,
|
|
|
|
}}))
|
|
|
|
}
|
|
|
|
|
|
|
|
fb := b.Save(ctx, join("/", node.Name), node.Name, node, nodes, nil)
|
|
|
|
fb.take(ctx)
|
|
|
|
|
|
|
|
err := shutdown()
|
|
|
|
if identicalNodes {
|
|
|
|
test.Assert(t, err == nil, "unexpected error found: %v", err)
|
|
|
|
} else {
|
|
|
|
test.Assert(t, err != nil, "expected error not found")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|