package restic_test import ( "crypto/rand" "encoding/json" "flag" "io" mrand "math/rand" "sync" "testing" "time" "github.com/restic/restic" "github.com/restic/restic/backend" "github.com/restic/restic/server" . "github.com/restic/restic/test" ) var maxWorkers = flag.Uint("workers", 20, "number of workers to test Map concurrent access against") func randomID() []byte { buf := make([]byte, backend.IDSize) _, err := io.ReadFull(rand.Reader, buf) if err != nil { panic(err) } return buf } func newBlob() server.Blob { return server.Blob{ ID: randomID(), Size: uint64(mrand.Uint32()), Storage: randomID(), StorageSize: uint64(mrand.Uint32()), } } // Test basic functionality func TestMap(t *testing.T) { bl := restic.NewMap() b := newBlob() bl.Insert(b) for i := 0; i < 1000; i++ { bl.Insert(newBlob()) } b2, err := bl.Find(server.Blob{ID: b.ID, Size: b.Size}) OK(t, err) Assert(t, b2.Compare(b) == 0, "items are not equal: want %v, got %v", b, b2) b2, err = bl.FindID(b.ID) OK(t, err) Assert(t, b2.Compare(b) == 0, "items are not equal: want %v, got %v", b, b2) bl2 := restic.NewMap() for i := 0; i < 1000; i++ { bl.Insert(newBlob()) } b2, err = bl2.Find(b) Assert(t, err != nil, "found ID in restic that was never inserted: %v", b2) bl2.Merge(bl) b2, err = bl2.Find(b) if err != nil { t.Fatal(err) } if b.Compare(b2) != 0 { t.Fatalf("items are not equal: want %v, got %v", b, b2) } } // Test JSON encode/decode func TestMapJSON(t *testing.T) { bl := restic.NewMap() b := server.Blob{ID: randomID()} bl.Insert(b) b2, err := bl.Find(b) OK(t, err) Assert(t, b2.Compare(b) == 0, "items are not equal: want %v, got %v", b, b2) buf, err := json.Marshal(bl) OK(t, err) bl2 := restic.Map{} json.Unmarshal(buf, &bl2) b2, err = bl2.Find(b) OK(t, err) Assert(t, b2.Compare(b) == 0, "items are not equal: want %v, got %v", b, b2) buf, err = json.Marshal(bl2) OK(t, err) } // random insert/find access by several goroutines func TestMapRandom(t *testing.T) { var wg sync.WaitGroup worker := func(bl *restic.Map) { defer wg.Done() b := newBlob() bl.Insert(b) for i := 0; i < 200; i++ { bl.Insert(newBlob()) } d := time.Duration(mrand.Intn(10)*100) * time.Millisecond time.Sleep(d) for i := 0; i < 100; i++ { b2, err := bl.Find(b) if err != nil { t.Fatal(err) } if b.Compare(b2) != 0 { t.Fatalf("items are not equal: want %v, got %v", b, b2) } } bl2 := restic.NewMap() for i := 0; i < 200; i++ { bl2.Insert(newBlob()) } bl2.Merge(bl) } bl := restic.NewMap() for i := 0; uint(i) < *maxWorkers; i++ { wg.Add(1) go worker(bl) } wg.Wait() }