|
@@ -0,0 +1,273 @@
|
|
|
|
|
+// Copyright 2019 The go-ethereum Authors
|
|
|
|
|
+// This file is part of the go-ethereum library.
|
|
|
|
|
+//
|
|
|
|
|
+// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
|
|
|
+// it under the terms of the GNU Lesser General Public License as published by
|
|
|
|
|
+// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
+// (at your option) any later version.
|
|
|
|
|
+//
|
|
|
|
|
+// The go-ethereum library is distributed in the hope that it will be useful,
|
|
|
|
|
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
+// GNU Lesser General Public License for more details.
|
|
|
|
|
+//
|
|
|
|
|
+// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
|
+// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
+
|
|
|
|
|
+package chunk
|
|
|
|
|
+
|
|
|
|
|
+import (
|
|
|
|
|
+ "bytes"
|
|
|
|
|
+ "sync"
|
|
|
|
|
+ "testing"
|
|
|
|
|
+ "time"
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+var (
|
|
|
|
|
+ allStates = []State{SPLIT, STORED, SEEN, SENT, SYNCED}
|
|
|
|
|
+)
|
|
|
|
|
+
|
|
|
|
|
+// TestTagSingleIncrements tests if Inc increments the tag state value
|
|
|
|
|
+func TestTagSingleIncrements(t *testing.T) {
|
|
|
|
|
+ tg := &Tag{total: 10}
|
|
|
|
|
+
|
|
|
|
|
+ tc := []struct {
|
|
|
|
|
+ state uint32
|
|
|
|
|
+ inc int
|
|
|
|
|
+ expcount int
|
|
|
|
|
+ exptotal int
|
|
|
|
|
+ }{
|
|
|
|
|
+ {state: SPLIT, inc: 10, expcount: 10, exptotal: 10},
|
|
|
|
|
+ {state: STORED, inc: 9, expcount: 9, exptotal: 9},
|
|
|
|
|
+ {state: SEEN, inc: 1, expcount: 1, exptotal: 10},
|
|
|
|
|
+ {state: SENT, inc: 9, expcount: 9, exptotal: 9},
|
|
|
|
|
+ {state: SYNCED, inc: 9, expcount: 9, exptotal: 9},
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, tc := range tc {
|
|
|
|
|
+ for i := 0; i < tc.inc; i++ {
|
|
|
|
|
+ tg.Inc(tc.state)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, tc := range tc {
|
|
|
|
|
+ if tg.Get(tc.state) != tc.expcount {
|
|
|
|
|
+ t.Fatalf("not incremented")
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestTagStatus is a unit test to cover Tag.Status method functionality
|
|
|
|
|
+func TestTagStatus(t *testing.T) {
|
|
|
|
|
+ tg := &Tag{total: 10}
|
|
|
|
|
+ tg.Inc(SEEN)
|
|
|
|
|
+ tg.Inc(SENT)
|
|
|
|
|
+ tg.Inc(SYNCED)
|
|
|
|
|
+
|
|
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
|
|
+ tg.Inc(SPLIT)
|
|
|
|
|
+ tg.Inc(STORED)
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, v := range []struct {
|
|
|
|
|
+ state State
|
|
|
|
|
+ expVal int
|
|
|
|
|
+ expTotal int
|
|
|
|
|
+ }{
|
|
|
|
|
+ {state: STORED, expVal: 10, expTotal: 10},
|
|
|
|
|
+ {state: SPLIT, expVal: 10, expTotal: 10},
|
|
|
|
|
+ {state: SEEN, expVal: 1, expTotal: 10},
|
|
|
|
|
+ {state: SENT, expVal: 1, expTotal: 9},
|
|
|
|
|
+ {state: SYNCED, expVal: 1, expTotal: 9},
|
|
|
|
|
+ } {
|
|
|
|
|
+ val, total, err := tg.Status(v.state)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+ if val != v.expVal {
|
|
|
|
|
+ t.Fatalf("should be %d, got %d", v.expVal, val)
|
|
|
|
|
+ }
|
|
|
|
|
+ if total != v.expTotal {
|
|
|
|
|
+ t.Fatalf("expected total to be %d, got %d", v.expTotal, total)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// tests ETA is precise
|
|
|
|
|
+func TestTagETA(t *testing.T) {
|
|
|
|
|
+ now := time.Now()
|
|
|
|
|
+ maxDiff := 100000 // 100 microsecond
|
|
|
|
|
+ tg := &Tag{total: 10, startedAt: now}
|
|
|
|
|
+ time.Sleep(100 * time.Millisecond)
|
|
|
|
|
+ tg.Inc(SPLIT)
|
|
|
|
|
+ eta, err := tg.ETA(SPLIT)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+ diff := time.Until(eta) - 9*time.Since(now)
|
|
|
|
|
+ if int(diff) > maxDiff {
|
|
|
|
|
+ t.Fatalf("ETA is not precise, got diff %v > .1ms", diff)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestTagConcurrentIncrements tests Inc calls concurrently
|
|
|
|
|
+func TestTagConcurrentIncrements(t *testing.T) {
|
|
|
|
|
+ tg := &Tag{}
|
|
|
|
|
+ n := 1000
|
|
|
|
|
+ wg := sync.WaitGroup{}
|
|
|
|
|
+ wg.Add(5 * n)
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ go func(f State) {
|
|
|
|
|
+ for j := 0; j < n; j++ {
|
|
|
|
|
+ go func() {
|
|
|
|
|
+ tg.Inc(f)
|
|
|
|
|
+ wg.Done()
|
|
|
|
|
+ }()
|
|
|
|
|
+ }
|
|
|
|
|
+ }(f)
|
|
|
|
|
+ }
|
|
|
|
|
+ wg.Wait()
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ v := tg.Get(f)
|
|
|
|
|
+ if v != n {
|
|
|
|
|
+ t.Fatalf("expected state %v to be %v, got %v", f, n, v)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestTagsMultipleConcurrentIncrements tests Inc calls concurrently
|
|
|
|
|
+func TestTagsMultipleConcurrentIncrementsSyncMap(t *testing.T) {
|
|
|
|
|
+ ts := NewTags()
|
|
|
|
|
+ n := 100
|
|
|
|
|
+ wg := sync.WaitGroup{}
|
|
|
|
|
+ wg.Add(10 * 5 * n)
|
|
|
|
|
+ for i := 0; i < 10; i++ {
|
|
|
|
|
+ s := string([]byte{uint8(i)})
|
|
|
|
|
+ tag, err := ts.New(s, n)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ go func(tag *Tag, f State) {
|
|
|
|
|
+ for j := 0; j < n; j++ {
|
|
|
|
|
+ go func() {
|
|
|
|
|
+ tag.Inc(f)
|
|
|
|
|
+ wg.Done()
|
|
|
|
|
+ }()
|
|
|
|
|
+ }
|
|
|
|
|
+ }(tag, f)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ wg.Wait()
|
|
|
|
|
+ i := 0
|
|
|
|
|
+ ts.Range(func(k, v interface{}) bool {
|
|
|
|
|
+ i++
|
|
|
|
|
+ uid := k.(uint32)
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ tag, err := ts.Get(uid)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+ stateVal := tag.Get(f)
|
|
|
|
|
+ if stateVal != n {
|
|
|
|
|
+ t.Fatalf("expected tag %v state %v to be %v, got %v", uid, f, n, v)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return true
|
|
|
|
|
+
|
|
|
|
|
+ })
|
|
|
|
|
+ if i != 10 {
|
|
|
|
|
+ t.Fatal("not enough tagz")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestMarshallingWithAddr tests that marshalling and unmarshalling is done correctly when the
|
|
|
|
|
+// tag Address (byte slice) contains some arbitrary value
|
|
|
|
|
+func TestMarshallingWithAddr(t *testing.T) {
|
|
|
|
|
+ tg := NewTag(111, "test/tag", 10)
|
|
|
|
|
+ tg.Address = []byte{0, 1, 2, 3, 4, 5, 6}
|
|
|
|
|
+
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ tg.Inc(f)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ b, err := tg.MarshalBinary()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ unmarshalledTag := &Tag{}
|
|
|
|
|
+ err = unmarshalledTag.UnmarshalBinary(b)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Uid != tg.Uid {
|
|
|
|
|
+ t.Fatalf("tag uids not equal. want %d got %d", tg.Uid, unmarshalledTag.Uid)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Name != tg.Name {
|
|
|
|
|
+ t.Fatalf("tag names not equal. want %s got %s", tg.Name, unmarshalledTag.Name)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, state := range allStates {
|
|
|
|
|
+ uv, tv := unmarshalledTag.Get(state), tg.Get(state)
|
|
|
|
|
+ if uv != tv {
|
|
|
|
|
+ t.Fatalf("state %d inconsistent. expected %d to equal %d", state, uv, tv)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Total() != tg.Total() {
|
|
|
|
|
+ t.Fatalf("tag names not equal. want %d got %d", tg.Total(), unmarshalledTag.Total())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(unmarshalledTag.Address) != len(tg.Address) {
|
|
|
|
|
+ t.Fatalf("tag addresses length mismatch, want %d, got %d", len(tg.Address), len(unmarshalledTag.Address))
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if !bytes.Equal(unmarshalledTag.Address, tg.Address) {
|
|
|
|
|
+ t.Fatalf("expected tag address to be %v got %v", unmarshalledTag.Address, tg.Address)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// TestMarshallingNoAddress tests that marshalling and unmarshalling is done correctly
|
|
|
|
|
+// when the tag Address (byte slice) is empty in this case
|
|
|
|
|
+func TestMarshallingNoAddr(t *testing.T) {
|
|
|
|
|
+ tg := NewTag(111, "test/tag", 10)
|
|
|
|
|
+ for _, f := range allStates {
|
|
|
|
|
+ tg.Inc(f)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ b, err := tg.MarshalBinary()
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ unmarshalledTag := &Tag{}
|
|
|
|
|
+ err = unmarshalledTag.UnmarshalBinary(b)
|
|
|
|
|
+ if err != nil {
|
|
|
|
|
+ t.Fatal(err)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Uid != tg.Uid {
|
|
|
|
|
+ t.Fatalf("tag uids not equal. want %d got %d", tg.Uid, unmarshalledTag.Uid)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Name != tg.Name {
|
|
|
|
|
+ t.Fatalf("tag names not equal. want %s got %s", tg.Name, unmarshalledTag.Name)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for _, state := range allStates {
|
|
|
|
|
+ uv, tv := unmarshalledTag.Get(state), tg.Get(state)
|
|
|
|
|
+ if uv != tv {
|
|
|
|
|
+ t.Fatalf("state %d inconsistent. expected %d to equal %d", state, uv, tv)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if unmarshalledTag.Total() != tg.Total() {
|
|
|
|
|
+ t.Fatalf("tag names not equal. want %d got %d", tg.Total(), unmarshalledTag.Total())
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if len(unmarshalledTag.Address) != len(tg.Address) {
|
|
|
|
|
+ t.Fatalf("expected tag addresses to be equal length")
|
|
|
|
|
+ }
|
|
|
|
|
+}
|