github.com/annchain/OG@v0.0.9/p2p/onode/nodedb_test.go (about) 1 // Copyright 2015 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 onode 18 19 import ( 20 "bytes" 21 "fmt" 22 "io/ioutil" 23 "net" 24 "os" 25 "path/filepath" 26 "reflect" 27 "testing" 28 "time" 29 ) 30 31 var nodeDBKeyTests = []struct { 32 id ID 33 field string 34 key []byte 35 }{ 36 { 37 id: ID{}, 38 field: "version", 39 key: []byte{0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e}, // field 40 }, 41 { 42 id: HexID("51232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 43 field: ":discover", 44 key: []byte{ 45 0x6e, 0x3a, // prefix 46 0x51, 0x23, 0x2b, 0x8d, 0x78, 0x21, 0x61, 0x7d, // node id 47 0x2b, 0x29, 0xb5, 0x4b, 0x81, 0xcd, 0xef, 0xb9, // 48 0xb3, 0xe9, 0xc3, 0x7d, 0x7f, 0xd5, 0xf6, 0x32, // 49 0x70, 0xbc, 0xc9, 0xe1, 0xa6, 0xf6, 0xa4, 0x39, // 50 0x3a, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, // field 51 }, 52 }, 53 } 54 55 func TestDBKeys(t *testing.T) { 56 for i, tt := range nodeDBKeyTests { 57 if key := makeKey(tt.id, tt.field); !bytes.Equal(key, tt.key) { 58 t.Errorf("make test %d: key mismatch: have 0x%x, want 0x%x", i, key, tt.key) 59 } 60 id, field := splitKey(tt.key) 61 if !bytes.Equal(id[:], tt.id[:]) { 62 t.Errorf("split test %d: id mismatch: have 0x%x, want 0x%x", i, id, tt.id) 63 } 64 if field != tt.field { 65 t.Errorf("split test %d: field mismatch: have 0x%x, want 0x%x", i, field, tt.field) 66 } 67 } 68 } 69 70 var nodeDBInt64Tests = []struct { 71 key []byte 72 value int64 73 }{ 74 {key: []byte{0x01}, value: 1}, 75 {key: []byte{0x02}, value: 2}, 76 {key: []byte{0x03}, value: 3}, 77 } 78 79 func TestDBInt64(t *testing.T) { 80 db, _ := OpenDB("") 81 defer db.Close() 82 83 tests := nodeDBInt64Tests 84 for i := 0; i < len(tests); i++ { 85 // Insert the next value 86 if err := db.storeInt64(tests[i].key, tests[i].value); err != nil { 87 t.Errorf("test %d: failed to store value: %v", i, err) 88 } 89 // Check all existing and non existing values 90 for j := 0; j < len(tests); j++ { 91 num := db.fetchInt64(tests[j].key) 92 switch { 93 case j <= i && num != tests[j].value: 94 t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, tests[j].value) 95 case j > i && num != 0: 96 t.Errorf("test %d, item %d: value mismatch: have %v, want %v", i, j, num, 0) 97 } 98 } 99 } 100 } 101 102 func TestDBFetchStore(t *testing.T) { 103 node := NewV4( 104 hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 105 net.IP{192, 168, 0, 1}, 106 30303, 107 30303, 108 ) 109 inst := time.Now() 110 num := 314 111 112 db, _ := OpenDB("") 113 defer db.Close() 114 115 // Check fetch/store operations on a node ping object 116 if stored := db.LastPingReceived(node.ID()); stored.Unix() != 0 { 117 t.Errorf("ping: non-existing object: %v", stored) 118 } 119 if err := db.UpdateLastPingReceived(node.ID(), inst); err != nil { 120 t.Errorf("ping: failed to update: %v", err) 121 } 122 if stored := db.LastPingReceived(node.ID()); stored.Unix() != inst.Unix() { 123 t.Errorf("ping: value mismatch: have %v, want %v", stored, inst) 124 } 125 // Check fetch/store operations on a node pong object 126 if stored := db.LastPongReceived(node.ID()); stored.Unix() != 0 { 127 t.Errorf("pong: non-existing object: %v", stored) 128 } 129 if err := db.UpdateLastPongReceived(node.ID(), inst); err != nil { 130 t.Errorf("pong: failed to update: %v", err) 131 } 132 if stored := db.LastPongReceived(node.ID()); stored.Unix() != inst.Unix() { 133 t.Errorf("pong: value mismatch: have %v, want %v", stored, inst) 134 } 135 // Check fetch/store operations on a node findnode-failure object 136 if stored := db.FindFails(node.ID()); stored != 0 { 137 t.Errorf("find-node fails: non-existing object: %v", stored) 138 } 139 if err := db.UpdateFindFails(node.ID(), num); err != nil { 140 t.Errorf("find-node fails: failed to update: %v", err) 141 } 142 if stored := db.FindFails(node.ID()); stored != num { 143 t.Errorf("find-node fails: value mismatch: have %v, want %v", stored, num) 144 } 145 // Check fetch/store operations on an actual node object 146 if stored := db.Node(node.ID()); stored != nil { 147 t.Errorf("node: non-existing object: %v", stored) 148 } 149 if err := db.UpdateNode(node); err != nil { 150 t.Errorf("node: failed to update: %v", err) 151 } 152 if stored := db.Node(node.ID()); stored == nil { 153 t.Errorf("node: not found") 154 } else if !reflect.DeepEqual(stored, node) { 155 if ok, _ := node.R.Equal(stored.R); !ok && node.Id != stored.Id { 156 t.Errorf("node: data mismatch: have %v, want %v", stored, node) 157 } 158 } 159 } 160 161 var nodeDBSeedQueryNodes = []struct { 162 node *Node 163 pong time.Time 164 }{ 165 // This one should not be in the result set because its last 166 // pong time is too far in the past. 167 { 168 node: NewV4( 169 hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 170 net.IP{127, 0, 0, 3}, 171 30303, 172 30303, 173 ), 174 pong: time.Now().Add(-3 * time.Hour), 175 }, 176 // This one shouldn't be in the result set because its 177 // nodeID is the local node's ID. 178 { 179 node: NewV4( 180 hexPubkey("ff93ff820abacd4351b0f14e47b324bc82ff014c226f3f66a53535734a3c150e7e38ca03ef0964ba55acddc768f5e99cd59dea95ddd4defbab1339c92fa319b2"), 181 net.IP{127, 0, 0, 3}, 182 30303, 183 30303, 184 ), 185 pong: time.Now().Add(-4 * time.Second), 186 }, 187 188 // These should be in the result set. 189 { 190 node: NewV4( 191 hexPubkey("c2b5eb3f5dde05f815b63777809ee3e7e0cbb20035a6b00ce327191e6eaa8f26a8d461c9112b7ab94698e7361fa19fd647e603e73239002946d76085b6f928d6"), 192 net.IP{127, 0, 0, 1}, 193 30303, 194 30303, 195 ), 196 pong: time.Now().Add(-2 * time.Second), 197 }, 198 { 199 node: NewV4( 200 hexPubkey("6ca1d400c8ddf8acc94bcb0dd254911ad71a57bed5e0ae5aa205beed59b28c2339908e97990c493499613cff8ecf6c3dc7112a8ead220cdcd00d8847ca3db755"), 201 net.IP{127, 0, 0, 2}, 202 30303, 203 30303, 204 ), 205 pong: time.Now().Add(-3 * time.Second), 206 }, 207 { 208 node: NewV4( 209 hexPubkey("234dc63fe4d131212b38236c4c3411288d7bec61cbf7b120ff12c43dc60c96182882f4291d209db66f8a38e986c9c010ff59231a67f9515c7d1668b86b221a47"), 210 net.IP{127, 0, 0, 3}, 211 30303, 212 30303, 213 ), 214 pong: time.Now().Add(-1 * time.Second), 215 }, 216 { 217 node: NewV4( 218 hexPubkey("c013a50b4d1ebce5c377d8af8cb7114fd933ffc9627f96ad56d90fef5b7253ec736fd07ef9a81dc2955a997e54b7bf50afd0aa9f110595e2bec5bb7ce1657004"), 219 net.IP{127, 0, 0, 3}, 220 30303, 221 30303, 222 ), 223 pong: time.Now().Add(-2 * time.Second), 224 }, 225 { 226 node: NewV4( 227 hexPubkey("f141087e3e08af1aeec261ff75f48b5b1637f594ea9ad670e50051646b0416daa3b134c28788cbe98af26992a47652889cd8577ccc108ac02c6a664db2dc1283"), 228 net.IP{127, 0, 0, 3}, 229 30303, 230 30303, 231 ), 232 pong: time.Now().Add(-2 * time.Second), 233 }, 234 } 235 236 func TestDBSeedQuery(t *testing.T) { 237 // Querying seeds uses seeks an might not find all nodes 238 // every time when the database is small. Run the test multiple 239 // times to avoid flakes. 240 const attempts = 15 241 var err error 242 for i := 0; i < attempts; i++ { 243 if err = testSeedQuery(); err == nil { 244 return 245 } 246 } 247 if err != nil { 248 t.Errorf("no successful run in %d attempts: %v", attempts, err) 249 } 250 } 251 252 func testSeedQuery() error { 253 db, _ := OpenDB("") 254 defer db.Close() 255 256 // Insert a batch of nodes for querying 257 for i, seed := range nodeDBSeedQueryNodes { 258 if err := db.UpdateNode(seed.node); err != nil { 259 return fmt.Errorf("node %d: failed to insert: %v", i, err) 260 } 261 if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { 262 return fmt.Errorf("node %d: failed to insert bondTime: %v", i, err) 263 } 264 } 265 266 // Retrieve the entire batch and check for duplicates 267 seeds := db.QuerySeeds(len(nodeDBSeedQueryNodes)*2, time.Hour) 268 have := make(map[ID]struct{}) 269 for _, seed := range seeds { 270 have[seed.ID()] = struct{}{} 271 } 272 want := make(map[ID]struct{}) 273 for _, seed := range nodeDBSeedQueryNodes[1:] { 274 want[seed.node.ID()] = struct{}{} 275 } 276 if len(seeds) != len(want) { 277 return fmt.Errorf("seed count mismatch: have %v, want %v", len(seeds), len(want)) 278 } 279 for id := range have { 280 if _, ok := want[id]; !ok { 281 return fmt.Errorf("extra seed: %v", id) 282 } 283 } 284 for id := range want { 285 if _, ok := have[id]; !ok { 286 return fmt.Errorf("missing seed: %v", id) 287 } 288 } 289 return nil 290 } 291 292 func TestDBPersistency(t *testing.T) { 293 root, err := ioutil.TempDir("", "nodedb-") 294 if err != nil { 295 t.Fatalf("failed to create temporary data folder: %v", err) 296 } 297 defer os.RemoveAll(root) 298 299 var ( 300 testKey = []byte("somekey") 301 testInt = int64(314) 302 ) 303 304 // Create a persistent database and store some values 305 db, err := OpenDB(filepath.Join(root, "database")) 306 if err != nil { 307 t.Fatalf("failed to create persistent database: %v", err) 308 } 309 if err := db.storeInt64(testKey, testInt); err != nil { 310 t.Fatalf("failed to store value: %v.", err) 311 } 312 db.Close() 313 314 // Reopen the database and check the value 315 db, err = OpenDB(filepath.Join(root, "database")) 316 if err != nil { 317 t.Fatalf("failed to open persistent database: %v", err) 318 } 319 if val := db.fetchInt64(testKey); val != testInt { 320 t.Fatalf("value mismatch: have %v, want %v", val, testInt) 321 } 322 db.Close() 323 } 324 325 var nodeDBExpirationNodes = []struct { 326 node *Node 327 pong time.Time 328 exp bool 329 }{ 330 { 331 node: NewV4( 332 hexPubkey("8d110e2ed4b446d9b5fb50f117e5f37fb7597af455e1dab0e6f045a6eeaa786a6781141659020d38bdc5e698ed3d4d2bafa8b5061810dfa63e8ac038db2e9b67"), 333 net.IP{127, 0, 0, 1}, 334 30303, 335 30303, 336 ), 337 pong: time.Now().Add(-dbNodeExpiration + time.Minute), 338 exp: false, 339 }, { 340 node: NewV4( 341 hexPubkey("913a205579c32425b220dfba999d215066e5bdbf900226b11da1907eae5e93eb40616d47412cf819664e9eacbdfcca6b0c6e07e09847a38472d4be46ab0c3672"), 342 net.IP{127, 0, 0, 2}, 343 30303, 344 30303, 345 ), 346 pong: time.Now().Add(-dbNodeExpiration - time.Minute), 347 exp: true, 348 }, 349 } 350 351 func TestDBExpiration(t *testing.T) { 352 db, _ := OpenDB("") 353 defer db.Close() 354 355 // Add all the test nodes and set their last pong time 356 for i, seed := range nodeDBExpirationNodes { 357 if err := db.UpdateNode(seed.node); err != nil { 358 t.Fatalf("node %d: failed to insert: %v", i, err) 359 } 360 if err := db.UpdateLastPongReceived(seed.node.ID(), seed.pong); err != nil { 361 t.Fatalf("node %d: failed to update bondTime: %v", i, err) 362 } 363 } 364 // Expire some of them, and check the rest 365 if err := db.expireNodes(); err != nil { 366 t.Fatalf("failed to expire nodes: %v", err) 367 } 368 for i, seed := range nodeDBExpirationNodes { 369 node := db.Node(seed.node.ID()) 370 if (node == nil && !seed.exp) || (node != nil && seed.exp) { 371 t.Errorf("node %d: expiration mismatch: have %v, want %v", i, node, seed.exp) 372 } 373 } 374 }