github.com/ethersphere/bee/v2@v2.2.0/pkg/feeds/testing/lookup.go (about) 1 // Copyright 2021 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // package testing provides tests for update and resolution of time-based feeds 6 package testing 7 8 import ( 9 "bytes" 10 "context" 11 "encoding/binary" 12 "errors" 13 "fmt" 14 "math/rand" 15 "testing" 16 "time" 17 18 "github.com/ethersphere/bee/v2/pkg/crypto" 19 "github.com/ethersphere/bee/v2/pkg/feeds" 20 storage "github.com/ethersphere/bee/v2/pkg/storage" 21 "github.com/ethersphere/bee/v2/pkg/storage/inmemchunkstore" 22 "github.com/ethersphere/bee/v2/pkg/swarm" 23 ) 24 25 type Timeout struct { 26 storage.ChunkStore 27 } 28 29 var searchTimeout = 30 * time.Millisecond 30 31 // Get overrides the mock storer and introduces latency 32 func (t *Timeout) Get(ctx context.Context, addr swarm.Address) (swarm.Chunk, error) { 33 ch, err := t.ChunkStore.Get(ctx, addr) 34 if err != nil { 35 if errors.Is(err, storage.ErrNotFound) { 36 time.Sleep(searchTimeout) 37 } 38 return ch, err 39 } 40 time.Sleep(time.Duration(rand.Intn(10)) * time.Millisecond) 41 return ch, nil 42 } 43 44 // nolint:tparallel 45 func TestFinderBasic(t *testing.T, finderf func(storage.Getter, *feeds.Feed) feeds.Lookup, updaterf func(putter storage.Putter, signer crypto.Signer, topic []byte) (feeds.Updater, error)) { 46 t.Parallel() 47 48 storer := &Timeout{inmemchunkstore.New()} 49 topicStr := "testtopic" 50 topic, err := crypto.LegacyKeccak256([]byte(topicStr)) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 pk, _ := crypto.GenerateSecp256k1Key() 56 signer := crypto.NewDefaultSigner(pk) 57 58 updater, err := updaterf(storer, signer, topic) 59 if err != nil { 60 t.Fatal(err) 61 } 62 ctx := context.Background() 63 finder := finderf(storer, updater.Feed()) 64 t.Run("no update", func(t *testing.T) { 65 ch, err := feeds.Latest(ctx, finder, 0) 66 if err != nil { 67 t.Fatal(err) 68 } 69 if ch != nil { 70 t.Fatalf("expected no update, got addr %v", ch.Address()) 71 } 72 }) 73 t.Run("first update", func(t *testing.T) { 74 payload := []byte("payload") 75 at := time.Now().Unix() 76 err = updater.Update(ctx, at, payload) 77 if err != nil { 78 t.Fatal(err) 79 } 80 ch, err := feeds.Latest(ctx, finder, 0) 81 if err != nil { 82 t.Fatal(err) 83 } 84 if ch == nil { 85 t.Fatalf("expected to find update, got none") 86 } 87 exp := payload 88 ts, payload, err := feeds.FromChunk(ch) 89 if err != nil { 90 t.Fatal(err) 91 } 92 if !bytes.Equal(payload, exp) { 93 t.Fatalf("result mismatch. want %8x... got %8x...", exp, payload) 94 } 95 if ts != uint64(at) { 96 t.Fatalf("timestamp mismatch: expected %v, got %v", at, ts) 97 } 98 }) 99 } 100 101 // nolint:tparallel 102 func TestFinderFixIntervals(t *testing.T, nextf func() (bool, int64), finderf func(storage.Getter, *feeds.Feed) feeds.Lookup, updaterf func(putter storage.Putter, signer crypto.Signer, topic []byte) (feeds.Updater, error)) { 103 t.Parallel() 104 105 var stop bool 106 for j := 10; !stop; j += 10 { 107 t.Run(fmt.Sprintf("custom intervals up to %d", j), func(t *testing.T) { 108 var i int64 109 var n int 110 f := func() (bool, int64) { 111 n++ 112 stop, i = nextf() 113 return n == j || stop, i 114 } 115 TestFinderIntervals(t, f, finderf, updaterf) 116 }) 117 } 118 } 119 120 func TestFinderIntervals(t *testing.T, nextf func() (bool, int64), finderf func(storage.Getter, *feeds.Feed) feeds.Lookup, updaterf func(putter storage.Putter, signer crypto.Signer, topic []byte) (feeds.Updater, error)) { 121 122 storer := &Timeout{inmemchunkstore.New()} 123 topicStr := "testtopic" 124 topic, err := crypto.LegacyKeccak256([]byte(topicStr)) 125 if err != nil { 126 t.Fatal(err) 127 } 128 pk, _ := crypto.GenerateSecp256k1Key() 129 signer := crypto.NewDefaultSigner(pk) 130 131 updater, err := updaterf(storer, signer, topic) 132 if err != nil { 133 t.Fatal(err) 134 } 135 finder := finderf(storer, updater.Feed()) 136 137 ctx := context.Background() 138 var ats []int64 139 for stop, at := nextf(); !stop; stop, at = nextf() { 140 ats = append(ats, at) 141 payload := make([]byte, 8) 142 binary.BigEndian.PutUint64(payload, uint64(at)) 143 err = updater.Update(ctx, at, payload) 144 if err != nil { 145 t.Fatal(err) 146 } 147 } 148 for j := 0; j < len(ats)-1; j++ { 149 at := ats[j] 150 diff := ats[j+1] - at 151 for now := at; now < ats[j+1]; now += int64(rand.Intn(int(diff)) + 1) { 152 after := uint64(0) 153 ch, current, next, err := finder.At(ctx, now, after) 154 if err != nil { 155 t.Fatal(err) 156 } 157 if ch == nil { 158 t.Fatalf("expected to find update, got none") 159 } 160 ts, payload, err := feeds.FromChunk(ch) 161 if err != nil { 162 t.Fatal(err) 163 } 164 content := binary.BigEndian.Uint64(payload) 165 if content != uint64(at) { 166 t.Fatalf("payload mismatch: expected %v, got %v", at, content) 167 } 168 169 if ts != uint64(at) { 170 t.Fatalf("timestamp mismatch: expected %v, got %v", at, ts) 171 } 172 173 if current != nil { 174 expectedId := ch.Data()[:32] 175 id, err := feeds.Id(topic, current) 176 if err != nil { 177 t.Fatal(err) 178 } 179 if !bytes.Equal(id, expectedId) { 180 t.Fatalf("current mismatch: expected %x, got %x", expectedId, id) 181 } 182 } 183 if next != nil { 184 expectedNext := current.Next(at, uint64(now)) 185 expectedIdx, err := expectedNext.MarshalBinary() 186 if err != nil { 187 t.Fatal(err) 188 } 189 idx, err := next.MarshalBinary() 190 if err != nil { 191 t.Fatal(err) 192 } 193 if !bytes.Equal(idx, expectedIdx) { 194 t.Fatalf("next mismatch: expected %x, got %x", expectedIdx, idx) 195 } 196 } 197 } 198 } 199 } 200 201 func TestFinderRandomIntervals(t *testing.T, finderf func(storage.Getter, *feeds.Feed) feeds.Lookup, updaterf func(putter storage.Putter, signer crypto.Signer, topic []byte) (feeds.Updater, error)) { 202 t.Parallel() 203 204 for j := 0; j < 3; j++ { 205 j := j 206 t.Run(fmt.Sprintf("random intervals %d", j), func(t *testing.T) { 207 t.Parallel() 208 209 var i int64 210 var n int 211 nextf := func() (bool, int64) { 212 i += int64(rand.Intn(1<<10) + 1) 213 n++ 214 return n == 40, i 215 } 216 TestFinderIntervals(t, nextf, finderf, updaterf) 217 }) 218 } 219 }