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