github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/discover/database_test.go (about) 1 package discover 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "net" 7 "os" 8 "path/filepath" 9 "reflect" 10 "testing" 11 "time" 12 ) 13 14 var nodeDBKeyTests = []struct { 15 id NodeID 16 field string 17 key []byte 18 }{ 19 { 20 id: NodeID{}, 21 field: "version", 22 key: []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e}, // field 23 }, 24 { 25 id: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 26 field: ":discover", 27 key: []byte{0x6e, 0x3a, // prefix 28 0x1d, 0xd9, 0xd6, 0x5c, 0x45, 0x52, 0xb5, 0xeb, // node id 29 0x43, 0xd5, 0xad, 0x55, 0xa2, 0xee, 0x3f, 0x56, // 30 0xc6, 0xcb, 0xc1, 0xc6, 0x4a, 0x5c, 0x8d, 0x65, // 31 0x9f, 0x51, 0xfc, 0xd5, 0x1b, 0xac, 0xe2, 0x43, // 32 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // 33 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, // 34 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, // 35 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, // 36 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, // field 37 }, 38 }, 39 } 40 41 func TestNodeDBKeys(t *testing.T) { 42 for i, tt := range nodeDBKeyTests { 43 if key := makeKey(tt.id, tt.field); !bytes.Equal(key, tt.key) { 44 t.Errorf("make test %d: key mismatch: have 0x%x, want 0x%x", i, key, tt.key) 45 } 46 id, field := splitKey(tt.key) 47 if !bytes.Equal(id[:], tt.id[:]) { 48 t.Errorf("split test %d: id mismatch: have 0x%x, want 0x%x", i, id, tt.id) 49 } 50 if field != tt.field { 51 t.Errorf("split test %d: field mismatch: have 0x%x, want 0x%x", i, field, tt.field) 52 } 53 } 54 } 55 56 var nodeDBInt64Tests = []struct { 57 key []byte 58 value int64 59 }{ 60 {key: []byte{0x01}, value: 1}, 61 {key: []byte{0x02}, value: 2}, 62 {key: []byte{0x03}, value: 3}, 63 } 64 65 func TestNodeDBInt64(t *testing.T) { 66 db, _ := newNodeDB("", Version, NodeID{}) 67 defer db.close() 68 69 tests := nodeDBInt64Tests 70 for i := 0; i < len(tests); i++ { 71 // Insert the next value 72 if err := db.storeInt64(tests[i].key, tests[i].value); err != nil { 73 t.Errorf("test %d: failed to store value: %v", i, err) 74 } 75 // Check all existing and non existing values 76 for j := 0; j < len(tests); j++ { 77 num := db.fetchInt64(tests[j].key) 78 switch { 79 case j <= i && num != tests[j].value: 80 t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, tests[j].value) 81 case j > i && num != 0: 82 t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, 0) 83 } 84 } 85 } 86 } 87 88 func TestNodeDBFetchStore(t *testing.T) { 89 node := NewNode( 90 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 91 net.IP{192, 168, 0, 1}, 92 36663, 93 36663, 94 ) 95 inst := time.Now() 96 num := 314 97 98 db, _ := newNodeDB("", Version, NodeID{}) 99 defer db.close() 100 101 // Check fetch/store operations on a node ping object 102 if stored := db.lastPing(node.ID); stored.Unix() != 0 { 103 t.Errorf("ping: non-existing object: %v", stored) 104 } 105 if err := db.updateLastPing(node.ID, inst); err != nil { 106 t.Errorf("ping: failed to update: %v", err) 107 } 108 if stored := db.lastPing(node.ID); stored.Unix() != inst.Unix() { 109 t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) 110 } 111 // Check fetch/store operations on a node pong object 112 if stored := db.bondTime(node.ID); stored.Unix() != 0 { 113 t.Errorf("pong: non-existing object: %v", stored) 114 } 115 if err := db.updateBondTime(node.ID, inst); err != nil { 116 t.Errorf("pong: failed to update: %v", err) 117 } 118 if stored := db.bondTime(node.ID); stored.Unix() != inst.Unix() { 119 t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) 120 } 121 // Check fetch/store operations on a node findnode-failure object 122 if stored := db.findFails(node.ID); stored != 0 { 123 t.Errorf("find-node fails: non-existing object: %v", stored) 124 } 125 if err := db.updateFindFails(node.ID, num); err != nil { 126 t.Errorf("find-node fails: failed to update: %v", err) 127 } 128 if stored := db.findFails(node.ID); stored != num { 129 t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) 130 } 131 // Check fetch/store operations on an actual node object 132 if stored := db.node(node.ID); stored != nil { 133 t.Errorf("node: non-existing object: %v", stored) 134 } 135 if err := db.updateNode(node); err != nil { 136 t.Errorf("node: failed to update: %v", err) 137 } 138 if stored := db.node(node.ID); stored == nil { 139 t.Errorf("node: not found") 140 } else if !reflect.DeepEqual(stored, node) { 141 t.Errorf("node: data mismatch: have %v, want %v", stored, node) 142 } 143 } 144 145 var nodeDBSeedQueryNodes = []struct { 146 node *Node 147 pong time.Time 148 }{ 149 // This one should not be in the result set because its last 150 // pong time is too far in the past. 151 { 152 node: NewNode( 153 MustHexID("0x84d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 154 net.IP{127, 0, 0, 3}, 155 36663, 156 36663, 157 ), 158 pong: time.Now().Add(-3 * time.Hour), 159 }, 160 // This one shouldn't be in in the result set because its 161 // nodeID is the local node's ID. 162 { 163 node: NewNode( 164 MustHexID("0x57d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 165 net.IP{127, 0, 0, 3}, 166 36663, 167 36663, 168 ), 169 pong: time.Now().Add(-4 * time.Second), 170 }, 171 172 // These should be in the result set. 173 { 174 node: NewNode( 175 MustHexID("0x22d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 176 net.IP{127, 0, 0, 1}, 177 36663, 178 36663, 179 ), 180 pong: time.Now().Add(-2 * time.Second), 181 }, 182 { 183 node: NewNode( 184 MustHexID("0x44d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 185 net.IP{127, 0, 0, 2}, 186 36663, 187 36663, 188 ), 189 pong: time.Now().Add(-3 * time.Second), 190 }, 191 { 192 node: NewNode( 193 MustHexID("0xe2d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 194 net.IP{127, 0, 0, 3}, 195 36663, 196 36663, 197 ), 198 pong: time.Now().Add(-1 * time.Second), 199 }, 200 } 201 202 func TestNodeDBSeedQuery(t *testing.T) { 203 db, _ := newNodeDB("", Version, nodeDBSeedQueryNodes[1].node.ID) 204 defer db.close() 205 206 // Insert a batch of nodes for querying 207 for i, seed := range nodeDBSeedQueryNodes { 208 if err := db.updateNode(seed.node); err != nil { 209 t.Fatalf("node %d: failed to insert: %v", i, err) 210 } 211 if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil { 212 t.Fatalf("node %d: failed to insert bondTime: %v", i, err) 213 } 214 } 215 216 // Retrieve the entire batch and check for duplicates 217 seeds := db.querySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) 218 have := make(map[NodeID]struct{}) 219 for _, seed := range seeds { 220 have[seed.ID] = struct{}{} 221 } 222 want := make(map[NodeID]struct{}) 223 for _, seed := range nodeDBSeedQueryNodes[2:] { 224 want[seed.node.ID] = struct{}{} 225 } 226 if len(seeds) != len(want) { 227 t.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) 228 } 229 for id := range have { 230 if _, ok := want[id]; !ok { 231 t.Errorf("extra seed: %v", id) 232 } 233 } 234 for id := range want { 235 if _, ok := have[id]; !ok { 236 t.Errorf("missing seed: %v", id) 237 } 238 } 239 } 240 241 func TestNodeDBPersistency(t *testing.T) { 242 root, err := ioutil.TempDir("", "nodedb-") 243 if err != nil { 244 t.Fatalf("failed to create temporary data folder: %v", err) 245 } 246 defer os.RemoveAll(root) 247 248 var ( 249 testKey = []byte("somekey") 250 testInt = int64(314) 251 ) 252 253 // Create a persistent database and store some values 254 db, err := newNodeDB(filepath.Join(root, "database"), Version, NodeID{}) 255 if err != nil { 256 t.Fatalf("failed to create persistent database: %v", err) 257 } 258 if err := db.storeInt64(testKey, testInt); err != nil { 259 t.Fatalf("failed to store value: %v.", err) 260 } 261 db.close() 262 263 // Reopen the database and check the value 264 db, err = newNodeDB(filepath.Join(root, "database"), Version, NodeID{}) 265 if err != nil { 266 t.Fatalf("failed to open persistent database: %v", err) 267 } 268 if val := db.fetchInt64(testKey); val != testInt { 269 t.Fatalf("value mismatch: have %v, want %v", val, testInt) 270 } 271 db.close() 272 273 // Change the database version and check flush 274 db, err = newNodeDB(filepath.Join(root, "database"), Version+1, NodeID{}) 275 if err != nil { 276 t.Fatalf("failed to open persistent database: %v", err) 277 } 278 if val := db.fetchInt64(testKey); val != 0 { 279 t.Fatalf("value mismatch: have %v, want %v", val, 0) 280 } 281 db.close() 282 } 283 284 var nodeDBExpirationNodes = []struct { 285 node *Node 286 pong time.Time 287 exp bool 288 }{ 289 { 290 node: NewNode( 291 MustHexID("0x01d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 292 net.IP{127, 0, 0, 1}, 293 36663, 294 36663, 295 ), 296 pong: time.Now().Add(-nodeDBNodeExpiration + time.Minute), 297 exp: false, 298 }, { 299 node: NewNode( 300 MustHexID("0x02d9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 301 net.IP{127, 0, 0, 2}, 302 36663, 303 36663, 304 ), 305 pong: time.Now().Add(-nodeDBNodeExpiration - time.Minute), 306 exp: true, 307 }, 308 } 309 310 func TestNodeDBExpiration(t *testing.T) { 311 db, _ := newNodeDB("", Version, NodeID{}) 312 defer db.close() 313 314 // Add all the test nodes and set their last pong time 315 for i, seed := range nodeDBExpirationNodes { 316 if err := db.updateNode(seed.node); err != nil { 317 t.Fatalf("node %d: failed to insert: %v", i, err) 318 } 319 if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil { 320 t.Fatalf("node %d: failed to update bondTime: %v", i, err) 321 } 322 } 323 // Expire some of them, and check the rest 324 if err := db.expireNodes(); err != nil { 325 t.Fatalf("failed to expire nodes: %v", err) 326 } 327 for i, seed := range nodeDBExpirationNodes { 328 node := db.node(seed.node.ID) 329 if (node == nil && !seed.exp) || (node != nil && seed.exp) { 330 t.Errorf("node %d: expiration mismatch: have %v, want %v", i, node, seed.exp) 331 } 332 } 333 } 334 335 func TestNodeDBSelfExpiration(t *testing.T) { 336 // Find a node in the tests that shouldn't expire, and assign it as self 337 var self NodeID 338 for _, node := range nodeDBExpirationNodes { 339 if !node.exp { 340 self = node.node.ID 341 break 342 } 343 } 344 db, _ := newNodeDB("", Version, self) 345 defer db.close() 346 347 // Add all the test nodes and set their last pong time 348 for i, seed := range nodeDBExpirationNodes { 349 if err := db.updateNode(seed.node); err != nil { 350 t.Fatalf("node %d: failed to insert: %v", i, err) 351 } 352 if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil { 353 t.Fatalf("node %d: failed to update bondTime: %v", i, err) 354 } 355 } 356 // Expire the nodes and make sure self has been evacuated too 357 if err := db.expireNodes(); err != nil { 358 t.Fatalf("failed to expire nodes: %v", err) 359 } 360 node := db.node(self) 361 if node != nil { 362 t.Errorf("self not evacuated") 363 } 364 }