github.com/decred/dcrlnd@v0.7.6/netann/host_ann_test.go (about) 1 package netann 2 3 import ( 4 "net" 5 "testing" 6 "time" 7 8 "github.com/decred/dcrlnd/ticker" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 // TestHostAnnouncerUpdates tests that the HostAnnouncer will properly announce 14 // a new set of addresses each time a target host changes and will noop if not 15 // change happens during an interval. 16 func TestHostAnnouncerUpdates(t *testing.T) { 17 t.Parallel() 18 19 hosts := []string{"test.com", "example.com"} 20 startingAddrs := []net.Addr{ 21 &net.TCPAddr{ 22 IP: net.ParseIP("1.1.1.1"), 23 }, 24 &net.TCPAddr{ 25 IP: net.ParseIP("8.8.8.8"), 26 }, 27 } 28 29 ticker := ticker.NewForce(time.Hour * 24) 30 31 testTimeout := time.Millisecond * 200 32 33 type annReq struct { 34 newAddrs []net.Addr 35 removedAddrs map[string]struct{} 36 } 37 38 testCases := []struct { 39 preAdvertisedIPs map[string]struct{} 40 startingAddrs []net.Addr 41 42 preTickHosts map[string]net.Addr 43 postTickHosts map[string]net.Addr 44 45 updateTriggered bool 46 47 newAddrs []net.Addr 48 removedAddrs map[string]struct{} 49 }{ 50 // The set of addresses are the same before and after a tick we 51 // expect no change. 52 { 53 preTickHosts: map[string]net.Addr{ 54 "test.com": &net.TCPAddr{ 55 IP: net.ParseIP("1.1.1.1"), 56 }, 57 "example.com": &net.TCPAddr{ 58 IP: net.ParseIP("8.8.8.8"), 59 }, 60 }, 61 startingAddrs: startingAddrs, 62 63 postTickHosts: map[string]net.Addr{ 64 "test.com": &net.TCPAddr{ 65 IP: net.ParseIP("1.1.1.1"), 66 }, 67 "example.com": &net.TCPAddr{ 68 IP: net.ParseIP("8.8.8.8"), 69 }, 70 }, 71 72 updateTriggered: false, 73 }, 74 75 // Half of the addresses are changed out, the new one should be 76 // added with the old one forgotten. 77 { 78 preTickHosts: map[string]net.Addr{ 79 "test.com": &net.TCPAddr{ 80 IP: net.ParseIP("1.1.1.1"), 81 }, 82 "example.com": &net.TCPAddr{ 83 IP: net.ParseIP("8.8.8.8"), 84 }, 85 }, 86 startingAddrs: startingAddrs, 87 88 postTickHosts: map[string]net.Addr{ 89 "test.com": &net.TCPAddr{ 90 IP: net.ParseIP("1.1.1.1"), 91 }, 92 "example.com": &net.TCPAddr{ 93 IP: net.ParseIP("9.9.9.9"), 94 }, 95 }, 96 97 updateTriggered: true, 98 newAddrs: []net.Addr{ 99 &net.TCPAddr{ 100 IP: net.ParseIP("9.9.9.9"), 101 }, 102 }, 103 removedAddrs: map[string]struct{}{ 104 "8.8.8.8:0": {}, 105 }, 106 }, 107 108 // All addresses change, they should all be refreshed. 109 { 110 preTickHosts: map[string]net.Addr{ 111 "test.com": &net.TCPAddr{ 112 IP: net.ParseIP("1.1.1.1"), 113 }, 114 "example.com": &net.TCPAddr{ 115 IP: net.ParseIP("8.8.8.8"), 116 }, 117 }, 118 startingAddrs: startingAddrs, 119 120 postTickHosts: map[string]net.Addr{ 121 "test.com": &net.TCPAddr{ 122 IP: net.ParseIP("2.2.2.2"), 123 }, 124 "example.com": &net.TCPAddr{ 125 IP: net.ParseIP("9.9.9.9"), 126 }, 127 }, 128 129 updateTriggered: true, 130 newAddrs: []net.Addr{ 131 &net.TCPAddr{ 132 IP: net.ParseIP("2.2.2.2"), 133 }, 134 &net.TCPAddr{ 135 IP: net.ParseIP("9.9.9.9"), 136 }, 137 }, 138 removedAddrs: map[string]struct{}{ 139 "8.8.8.8:0": {}, 140 "1.1.1.1:0": {}, 141 }, 142 }, 143 144 // Two addresses, one has already been advertised on start up, 145 // so we only expect one of them to be announced again. After 146 // the tick we don't expect an update trigger since nothing. 147 // changed. 148 { 149 preAdvertisedIPs: map[string]struct{}{ 150 "1.1.1.1:0": {}, 151 }, 152 startingAddrs: []net.Addr{ 153 &net.TCPAddr{ 154 IP: net.ParseIP("8.8.8.8"), 155 }, 156 }, 157 preTickHosts: map[string]net.Addr{ 158 "test.com": &net.TCPAddr{ 159 IP: net.ParseIP("1.1.1.1"), 160 }, 161 "example.com": &net.TCPAddr{ 162 IP: net.ParseIP("8.8.8.8"), 163 }, 164 }, 165 postTickHosts: map[string]net.Addr{ 166 "test.com": &net.TCPAddr{ 167 IP: net.ParseIP("1.1.1.1"), 168 }, 169 "example.com": &net.TCPAddr{ 170 IP: net.ParseIP("8.8.8.8"), 171 }, 172 }, 173 174 updateTriggered: false, 175 }, 176 } 177 for idx, testCase := range testCases { 178 hostResps := make(chan net.Addr) 179 annReqs := make(chan annReq) 180 hostAnncer := NewHostAnnouncer(HostAnnouncerConfig{ 181 Hosts: hosts, 182 AdvertisedIPs: testCase.preAdvertisedIPs, 183 RefreshTicker: ticker, 184 LookupHost: func(str string) (net.Addr, error) { 185 return <-hostResps, nil 186 }, 187 AnnounceNewIPs: func(newAddrs []net.Addr, 188 removeAddrs map[string]struct{}) error { 189 190 annReqs <- annReq{ 191 newAddrs: newAddrs, 192 removedAddrs: removeAddrs, 193 } 194 195 return nil 196 }, 197 }) 198 if err := hostAnncer.Start(); err != nil { 199 t.Fatalf("unable to start announcer: %v", err) 200 } 201 202 // As soon as the announcer starts, it'll try to query for the 203 // state of the hosts. We'll return the preTick state for all 204 // hosts. 205 for i := 0; i < len(hosts); i++ { 206 hostResps <- testCase.preTickHosts[hosts[i]] 207 } 208 209 // Since this is the first time the announcer is starting up, 210 // we expect it to advertise the hosts as they exist before any 211 // updates. 212 select { 213 case addrUpdate := <-annReqs: 214 assert.Equal( 215 t, testCase.startingAddrs, addrUpdate.newAddrs, 216 "addresses should match", 217 ) 218 assert.Empty( 219 t, addrUpdate.removedAddrs, 220 "removed addrs should match", 221 ) 222 223 case <-time.After(testTimeout): 224 t.Fatalf("#%v: no addr update sent", idx) 225 } 226 227 // We'll now force a tick which'll force another query. This 228 // time we'll respond with the set of the hosts as they should 229 // be post-tick. 230 ticker.Force <- time.Time{} 231 232 for i := 0; i < len(hosts); i++ { 233 hostResps <- testCase.postTickHosts[hosts[i]] 234 } 235 236 // If we expect an update, then we'll assert that we received 237 // the proper set of modified addresses. 238 if testCase.updateTriggered { 239 240 select { 241 // The receive update should match exactly what the 242 // test case dictates. 243 case addrUpdate := <-annReqs: 244 require.Equal( 245 t, testCase.newAddrs, addrUpdate.newAddrs, 246 "addresses should match", 247 ) 248 249 require.Equal( 250 t, testCase.removedAddrs, addrUpdate.removedAddrs, 251 "removed addrs should match", 252 ) 253 254 case <-time.After(testTimeout): 255 t.Fatalf("#%v: no addr update set", idx) 256 } 257 258 if err := hostAnncer.Stop(); err != nil { 259 t.Fatalf("unable to stop announcer: %v", err) 260 } 261 continue 262 } 263 264 // Otherwise, no updates should be sent since nothing changed. 265 select { 266 case <-annReqs: 267 t.Fatalf("#%v: expected no call to AnnounceNewIPs", idx) 268 269 case <-time.After(testTimeout): 270 } 271 272 if err := hostAnncer.Stop(); err != nil { 273 t.Fatalf("unable to stop announcer: %v", err) 274 } 275 } 276 }