github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/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 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/log" 30 "github.com/ethereum/go-ethereum/swarm/storage" 31 ) 32 33 func init() { 34 log.Root().SetHandler(log.LvlFilterHandler(log.LvlCrit, log.StreamHandler(os.Stderr, log.TerminalFormat(false)))) 35 } 36 37 type testSyncDb struct { 38 *syncDb 39 c int 40 t *testing.T 41 fromDb chan bool 42 delivered [][]byte 43 sent []int 44 dbdir string 45 at int 46 } 47 48 func newTestSyncDb(priority, bufferSize, batchSize int, dbdir string, t *testing.T) *testSyncDb { 49 if len(dbdir) == 0 { 50 tmp, err := ioutil.TempDir(os.TempDir(), "syncdb-test") 51 if err != nil { 52 t.Fatalf("unable to create temporary direcory %v: %v", tmp, err) 53 } 54 dbdir = tmp 55 } 56 db, err := storage.NewLDBDatabase(filepath.Join(dbdir, "requestdb")) 57 if err != nil { 58 t.Fatalf("unable to create db: %v", err) 59 } 60 self := &testSyncDb{ 61 fromDb: make(chan bool), 62 dbdir: dbdir, 63 t: t, 64 } 65 h := crypto.Keccak256Hash([]byte{0}) 66 key := storage.Key(h[:]) 67 self.syncDb = newSyncDb(db, key, uint(priority), uint(bufferSize), uint(batchSize), self.deliver) 68 // kick off db iterator right away, if no items on db this will allow 69 // reading from the buffer 70 return self 71 72 } 73 74 func (self *testSyncDb) close() { 75 self.db.Close() 76 os.RemoveAll(self.dbdir) 77 } 78 79 func (self *testSyncDb) push(n int) { 80 for i := 0; i < n; i++ { 81 self.buffer <- storage.Key(crypto.Keccak256([]byte{byte(self.c)})) 82 self.sent = append(self.sent, self.c) 83 self.c++ 84 } 85 log.Debug(fmt.Sprintf("pushed %v requests", n)) 86 } 87 88 func (self *testSyncDb) draindb() { 89 it := self.db.NewIterator() 90 defer it.Release() 91 for { 92 it.Seek(self.start) 93 if !it.Valid() { 94 return 95 } 96 k := it.Key() 97 if len(k) == 0 || k[0] == 1 { 98 return 99 } 100 it.Release() 101 it = self.db.NewIterator() 102 } 103 } 104 105 func (self *testSyncDb) deliver(req interface{}, quit chan bool) bool { 106 _, db := req.(*syncDbEntry) 107 key, _, _, _, err := parseRequest(req) 108 if err != nil { 109 self.t.Fatalf("unexpected error of key %v: %v", key, err) 110 } 111 self.delivered = append(self.delivered, key) 112 select { 113 case self.fromDb <- db: 114 return true 115 case <-quit: 116 return false 117 } 118 } 119 120 func (self *testSyncDb) expect(n int, db bool) { 121 var ok bool 122 // for n items 123 for i := 0; i < n; i++ { 124 ok = <-self.fromDb 125 if self.at+1 > len(self.delivered) { 126 self.t.Fatalf("expected %v, got %v", self.at+1, len(self.delivered)) 127 } 128 if len(self.sent) > self.at && !bytes.Equal(crypto.Keccak256([]byte{byte(self.sent[self.at])}), self.delivered[self.at]) { 129 self.t.Fatalf("expected delivery %v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db) 130 log.Debug(fmt.Sprintf("%v/%v/%v to be hash of %v, from db: %v = %v", i, n, self.at, self.sent[self.at], ok, db)) 131 } 132 if !ok && db { 133 self.t.Fatalf("expected delivery %v/%v/%v from db", i, n, self.at) 134 } 135 if ok && !db { 136 self.t.Fatalf("expected delivery %v/%v/%v from cache", i, n, self.at) 137 } 138 self.at++ 139 } 140 } 141 142 func TestSyncDb(t *testing.T) { 143 t.Skip("fails randomly on all platforms") 144 145 priority := High 146 bufferSize := 5 147 batchSize := 2 * bufferSize 148 s := newTestSyncDb(priority, bufferSize, batchSize, "", t) 149 defer s.close() 150 defer s.stop() 151 s.dbRead(false, 0, s.deliver) 152 s.draindb() 153 154 s.push(4) 155 s.expect(1, false) 156 // 3 in buffer 157 time.Sleep(100 * time.Millisecond) 158 s.push(3) 159 // push over limit 160 s.expect(1, false) 161 // one popped from the buffer, then contention detected 162 s.expect(4, true) 163 s.push(4) 164 s.expect(5, true) 165 // depleted db, switch back to buffer 166 s.draindb() 167 s.push(5) 168 s.expect(4, false) 169 s.push(3) 170 s.expect(4, false) 171 // buffer depleted 172 time.Sleep(100 * time.Millisecond) 173 s.push(6) 174 s.expect(1, false) 175 // push into buffer full, switch to db 176 s.expect(5, true) 177 s.draindb() 178 s.push(1) 179 s.expect(1, false) 180 } 181 182 func TestSaveSyncDb(t *testing.T) { 183 amount := 30 184 priority := High 185 bufferSize := amount 186 batchSize := 10 187 s := newTestSyncDb(priority, bufferSize, batchSize, "", t) 188 go s.dbRead(false, 0, s.deliver) 189 s.push(amount) 190 s.stop() 191 s.db.Close() 192 193 s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) 194 go s.dbRead(false, 0, s.deliver) 195 s.expect(amount, true) 196 for i, key := range s.delivered { 197 expKey := crypto.Keccak256([]byte{byte(i)}) 198 if !bytes.Equal(key, expKey) { 199 t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) 200 } 201 } 202 s.push(amount) 203 s.expect(amount, false) 204 for i := amount; i < 2*amount; i++ { 205 key := s.delivered[i] 206 expKey := crypto.Keccak256([]byte{byte(i - amount)}) 207 if !bytes.Equal(key, expKey) { 208 t.Fatalf("delivery %v expected to be key %x, got %x", i, expKey, key) 209 } 210 } 211 s.stop() 212 s.db.Close() 213 214 s = newTestSyncDb(priority, bufferSize, batchSize, s.dbdir, t) 215 defer s.close() 216 defer s.stop() 217 218 go s.dbRead(false, 0, s.deliver) 219 s.push(1) 220 s.expect(1, false) 221 222 }