github.com/gochain-io/gochain@v2.2.26+incompatible/swarm/network/syncdb_test.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "bytes" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "path/filepath" 25 "testing" 26 "time" 27 28 "sync" 29 30 "github.com/gochain-io/gochain/crypto" 31 "github.com/gochain-io/gochain/log" 32 "github.com/gochain-io/gochain/swarm/storage" 33 ) 34 35 func init() { 36 log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 37 } 38 39 type testSyncDb struct { 40 *syncDb 41 c int 42 t *testing.T 43 fromDb chan bool 44 sent []int 45 dbdir string 46 at int 47 48 deliveredMu sync.RWMutex 49 delivered [][]byte 50 } 51 52 func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing.T) *testSyncDb { 53 if len(dbdir) == 0 { 54 tmp, err := ioutil.TempDir(os.TempDir(), "syncdb-test") 55 if err != nil { 56 t.Fatalf("unable to create temporary direcory %v: %v", tmp, err) 57 } 58 dbdir = tmp 59 } 60 db, err := storage.NewLDBDatabase(filepath.Join(dbdir, "requestdb")) 61 if err != nil { 62 t.Fatalf("unable to create db: %v", err) 63 } 64 self := &testSyncDb{ 65 fromDb: make(chan bool), 66 dbdir: dbdir, 67 t: t, 68 } 69 h := crypto.Keccak256Hash([]byte{0}) 70 key := storage.Key(h[:]) 71 self.syncDb = newSyncDb(db, key, uint(priority), uint(bufferSize), uint(batchSize), self.deliver) 72 // kick off db iterator right away, if no items on db this will allow 73 // reading from the buffer 74 return self 75 76 } 77 78 func (t *testSyncDb) close() { 79 t.db.Close() 80 os.RemoveAll(t.dbdir) 81 } 82 83 func (t *testSyncDb) push(n int) { 84 for i := 0; i < n; i++ { 85 t.buffer <- storage.Key(crypto.Keccak256([]byte{byte(t.c)})) 86 t.sent = append(t.sent, t.c) 87 t.c++ 88 } 89 log.Debug(fmt.Sprintf("pushed %v requests", n)) 90 } 91 92 func (t *testSyncDb) draindb() { 93 it := t.db.NewIterator() 94 defer it.Release() 95 for { 96 it.Seek(t.start) 97 if !it.Valid() { 98 return 99 } 100 k := it.Key() 101 if len(k) == 0 || k[0] == 1 { 102 return 103 } 104 it.Release() 105 it = t.db.NewIterator() 106 } 107 } 108 109 func (t *testSyncDb) deliver(req interface{}, quit chan bool) bool { 110 _, db := req.(*syncDbEntry) 111 key, _, _, _, err := parseRequest(req) 112 if err != nil { 113 t.t.Fatalf("unexpected error of key %v: %v", key, err) 114 } 115 t.deliveredMu.Lock() 116 t.delivered = append(t.delivered, key) 117 t.deliveredMu.Unlock() 118 select { 119 case t.fromDb <- db: 120 return true 121 case <-quit: 122 return false 123 } 124 } 125 126 func (t *testSyncDb) expect(n int, db bool) { 127 var ok bool 128 // for n items 129 for i := 0; i < n; i++ { 130 ok = <-t.fromDb 131 t.deliveredMu.RLock() 132 l := len(t.delivered) 133 t.deliveredMu.RUnlock() 134 if t.at+1 > l { 135 t.t.Fatalf("expected %v, got %v", t.at+1, l) 136 } 137 t.deliveredMu.RLock() 138 data := t.delivered[t.at] 139 t.deliveredMu.RUnlock() 140 if len(t.sent) > t.at && !bytes.Equal(crypto.Keccak256([]byte{byte(t.sent[t.at])}), data) { 141 t.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, t.at, t.sent[t.at], ok, db) 142 log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, t.at, t.sent[t.at], ok, db)) 143 } 144 if !ok && db { 145 t.t.Fatalf("expected delivery %v/%v/%v from db", i, n, t.at) 146 } 147 if ok && !db { 148 t.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, t.at) 149 } 150 t.at++ 151 } 152 } 153 154 func TestSyncDb(t *testing.T) { 155 t.Skip("fails randomly on all platforms") 156 157 priority := High 158 bufferSize := 5 159 batchSize := 2 * bufferSize 160 s := newTestSyncDb(priority, bufferSize, batchSize, "", t) 161 defer s.close() 162 defer s.stop() 163 s.dbRead(false, 0, s.deliver) 164 s.draindb() 165 166 s.push(4) 167 s.expect(1, false) 168 // 3 in buffer 169 time.Sleep(100 * time.Millisecond) 170 s.push(3) 171 // push over limit 172 s.expect(1, false) 173 // one popped from the buffer, then contention detected 174 s.expect(4, true) 175 s.push(4) 176 s.expect(5, true) 177 // depleted db, switch back to buffer 178 s.draindb() 179 s.push(5) 180 s.expect(4, false) 181 s.push(3) 182 s.expect(4, false) 183 // buffer depleted 184 time.Sleep(100 * time.Millisecond) 185 s.push(6) 186 s.expect(1, false) 187 // push into buffer full, switch to db 188 s.expect(5, true) 189 s.draindb() 190 s.push(1) 191 s.expect(1, false) 192 } 193 194 func TestSaveSyncDb(t *testing.T) { 195 amount := 30 196 priority := High 197 bufferSize := amount 198 batchSize := 10 199 s := newTestSyncDb(priority, bufferSize, batchSize, "", t) 200 go s.dbRead(false, 0, s.deliver) 201 s.push(amount) 202 s.stop() 203 s.db.Close() 204 205 s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) 206 go s.dbRead(false, 0, s.deliver) 207 s.expect(amount, true) 208 s.deliveredMu.RLock() 209 for i, key := range s.delivered { 210 expKey := crypto.Keccak256([]byte{byte(i)}) 211 if !bytes.Equal(key, expKey) { 212 s.deliveredMu.RUnlock() 213 t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) 214 } 215 } 216 s.deliveredMu.RUnlock() 217 s.push(amount) 218 s.expect(amount, false) 219 s.deliveredMu.RLock() 220 for i := amount; i < 2*amount; i++ { 221 key := s.delivered[i] 222 expKey := crypto.Keccak256([]byte{byte(i - amount)}) 223 if !bytes.Equal(key, expKey) { 224 s.deliveredMu.RUnlock() 225 t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) 226 } 227 } 228 s.deliveredMu.RUnlock() 229 s.stop() 230 s.db.Close() 231 232 s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) 233 defer s.close() 234 defer s.stop() 235 236 go s.dbRead(false, 0, s.deliver) 237 s.push(1) 238 s.expect(1, false) 239 240 }