github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/renter/hostdb/scan_test.go (about) 1 package hostdb 2 3 import ( 4 "net" 5 "testing" 6 "time" 7 8 "github.com/NebulousLabs/Sia/crypto" 9 "github.com/NebulousLabs/Sia/encoding" 10 "github.com/NebulousLabs/Sia/modules" 11 "github.com/NebulousLabs/Sia/types" 12 ) 13 14 // TestDecrementReliability tests the decrementReliability method. 15 func TestDecrementReliability(t *testing.T) { 16 hdb := bareHostDB() 17 18 // Decrementing a non-existent host should be a no-op. 19 // NOTE: can't check any post-conditions here; only indication of correct 20 // behavior is that the test doesn't panic. 21 hdb.decrementReliability("foo", types.NewCurrency64(0)) 22 23 // Add a host to allHosts and activeHosts. Decrementing it should remove it 24 // from activeHosts. 25 h := new(hostEntry) 26 h.NetAddress = "foo" 27 h.Reliability = types.NewCurrency64(1) 28 hdb.allHosts[h.NetAddress] = h 29 hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h} 30 hdb.decrementReliability(h.NetAddress, types.NewCurrency64(0)) 31 if len(hdb.ActiveHosts()) != 0 { 32 t.Error("decrementing did not remove host from activeHosts") 33 } 34 35 // Decrement reliability to 0. This should remove the host from allHosts. 36 hdb.decrementReliability(h.NetAddress, h.Reliability) 37 if len(hdb.AllHosts()) != 0 { 38 t.Error("decrementing did not remove host from allHosts") 39 } 40 } 41 42 // probeDialer is used to test the threadedProbeHosts method. A simple type 43 // alias is used so that it can easily be redefined during testing, allowing 44 // multiple behaviors to be tested. 45 type probeDialer func(modules.NetAddress, time.Duration) (net.Conn, error) 46 47 func (dial probeDialer) DialTimeout(addr modules.NetAddress, timeout time.Duration) (net.Conn, error) { 48 return dial(addr, timeout) 49 } 50 51 // TestThreadedProbeHosts tests the threadedProbeHosts method. 52 func TestThreadedProbeHosts(t *testing.T) { 53 hdb := bareHostDB() 54 hdb.persist = &memPersist{} 55 56 // create a host to send to threadedProbeHosts 57 sk, pk, err := crypto.GenerateKeyPair() 58 if err != nil { 59 t.Fatal(err) 60 } 61 h := new(hostEntry) 62 h.NetAddress = "foo" 63 h.PublicKey = types.SiaPublicKey{ 64 Algorithm: types.SignatureEd25519, 65 Key: pk[:], 66 } 67 h.Reliability = baseWeight // enough to withstand a few failures 68 69 // define a helper function for running threadedProbeHosts. We send the 70 // hostEntry, close the channel, and then call threadedProbeHosts. 71 // threadedProbeHosts will receive the host, loop once, and return after 72 // seeing the channel has closed. 73 // 74 // NOTE: since threadedProbeHosts decrements hdb.threadGroup, we Add(100) 75 // to prevent it from going negative. This is acceptable because we don't 76 // call hdb.Close in this test. 77 hdb.threadGroup.Add(100) 78 runProbe := func(h *hostEntry) { 79 hdb.scanPool <- h 80 close(hdb.scanPool) 81 hdb.threadedProbeHosts() 82 // reset hdb.scanPool 83 hdb.scanPool = make(chan *hostEntry, 1) 84 } 85 86 // make the dial fail 87 hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) { 88 return nil, net.UnknownNetworkError("fail") 89 }) 90 runProbe(h) 91 if len(hdb.ActiveHosts()) != 0 { 92 t.Error("unresponsive host was added") 93 } 94 95 // make the RPC fail 96 hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) { 97 ourPipe, theirPipe := net.Pipe() 98 ourPipe.Close() 99 return theirPipe, nil 100 }) 101 runProbe(h) 102 if len(hdb.ActiveHosts()) != 0 { 103 t.Error("unresponsive host was added") 104 } 105 106 // normal host 107 hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) { 108 // create an in-memory conn and spawn a goroutine to handle our half 109 ourConn, theirConn := net.Pipe() 110 go func() { 111 // read the RPC 112 encoding.ReadObject(ourConn, new(types.Specifier), types.SpecifierLen) 113 // write host settings 114 crypto.WriteSignedObject(ourConn, modules.HostExternalSettings{ 115 NetAddress: "probed", 116 }, sk) 117 ourConn.Close() 118 }() 119 return theirConn, nil 120 }) 121 runProbe(h) 122 if len(hdb.ActiveHosts()) != 1 { 123 t.Error("host was not added") 124 } 125 } 126 127 // TestThreadedScan tests the threadedScan method. 128 func TestThreadedScan(t *testing.T) { 129 hdb := bareHostDB() 130 hdb.persist = &memPersist{} 131 132 // use a real sleeper; this will prevent threadedScan from looping too 133 // quickly. 134 hdb.sleeper = stdSleeper{} 135 // use a dummy dialer that always fails 136 hdb.dialer = probeDialer(func(modules.NetAddress, time.Duration) (net.Conn, error) { 137 return nil, net.UnknownNetworkError("fail") 138 }) 139 140 // create a host to be scanned 141 h := new(hostEntry) 142 h.NetAddress = "foo" 143 h.Reliability = types.NewCurrency64(1) 144 hdb.activeHosts[h.NetAddress] = &hostNode{hostEntry: h} 145 146 // perform one scan 147 go hdb.threadedScan() 148 149 // host should be sent down scanPool 150 select { 151 case <-hdb.scanPool: 152 case <-time.After(time.Second): 153 t.Error("host was not scanned") 154 } 155 156 // remove the host from activeHosts and add it to allHosts 157 hdb.mu.Lock() 158 delete(hdb.activeHosts, h.NetAddress) 159 hdb.allHosts[h.NetAddress] = h 160 hdb.mu.Unlock() 161 162 // perform one scan 163 go hdb.threadedScan() 164 165 // host should be sent down scanPool 166 select { 167 case <-hdb.scanPool: 168 case <-time.After(time.Second): 169 t.Error("host was not scanned") 170 } 171 }