github.com/decred/dcrlnd@v0.7.6/lntest/itest/dcrlnd_misc_test.go (about) 1 package itest 2 3 import ( 4 "context" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/decred/dcrlnd/lnrpc" 10 "github.com/decred/dcrlnd/lntest" 11 ) 12 13 // testConcurrentNodeConnection tests whether we can repeatedly connect and 14 // disconnect two nodes and that trying to connect "at the same time" will not 15 // cause problems. 16 // 17 // "At the same time" is used in scare quotes, since at the level of abstraction 18 // used in these tests it's not possible to really enforce that the connection 19 // attempts are sent in any specific order or parallelism. So we resort to doing 20 // a number of repeated number of trial runs, with as much concurrency as 21 // possible. 22 func testConcurrentNodeConnection(net *lntest.NetworkHarness, t *harnessTest) { 23 ctxb := context.Background() 24 25 aliceToBobReq := &lnrpc.ConnectPeerRequest{ 26 Addr: &lnrpc.LightningAddress{ 27 Pubkey: net.Bob.PubKeyStr, 28 Host: net.Bob.P2PAddr(), 29 }, 30 Perm: false, 31 } 32 33 bobToAliceReq := &lnrpc.ConnectPeerRequest{ 34 Addr: &lnrpc.LightningAddress{ 35 Pubkey: net.Alice.PubKeyStr, 36 Host: net.Alice.P2PAddr(), 37 }, 38 Perm: false, 39 } 40 41 connect := func(node *lntest.HarnessNode, req *lnrpc.ConnectPeerRequest, wg *sync.WaitGroup) error { 42 _, err := node.ConnectPeer(ctxb, req) 43 wg.Done() 44 return err 45 } 46 47 // Initially disconnect Alice and Bob. Several connection attempts will 48 // be performed later on. Ignore errors if they are not connected and 49 // give some time for the disconnection to clear all resources. 50 net.DisconnectNodes(net.Alice, net.Bob) 51 time.Sleep(50 * time.Millisecond) 52 53 // Perform a number of trial runs in sequence, so we have some reasonable 54 // chance actually performing connections "at the same time". 55 nbAttempts := 10 56 for i := 0; i < nbAttempts; i++ { 57 // Sanity check that neither node has a connection. 58 assertNotConnected(t, net.Alice, net.Bob) 59 60 logLine := fmt.Sprintf("=== %s: Starting connection iteration %d\n", 61 time.Now(), i) 62 net.Alice.AddToLog(logLine) 63 net.Bob.AddToLog(logLine) 64 65 var aliceReply, bobReply error 66 wg := new(sync.WaitGroup) 67 68 // Start two go routines which will try to connect "at the same 69 // time". 70 wg.Add(2) 71 go func() { aliceReply = connect(net.Alice, aliceToBobReq, wg) }() 72 go func() { bobReply = connect(net.Bob, bobToAliceReq, wg) }() 73 74 wgWaitChan := make(chan struct{}) 75 go func() { 76 wg.Wait() 77 close(wgWaitChan) 78 }() 79 80 select { 81 case <-wgWaitChan: 82 if aliceReply != nil && bobReply != nil { 83 // Depending on exact timings, one of the replies might fail 84 // due to the nodes already being connected, but not both. 85 t.Fatalf("Both replies should not error out") 86 } 87 case <-time.After(15 * time.Second): 88 t.Fatalf("Timeout while waiting for connection reply") 89 } 90 91 // Give the nodes time to settle their connections and background 92 // processes. 93 time.Sleep(50 * time.Millisecond) 94 95 logLine = fmt.Sprintf("=== %s: Connections requests sent. Will check on status\n", 96 time.Now()) 97 net.Alice.AddToLog(logLine) 98 net.Bob.AddToLog(logLine) 99 100 // Sanity check connection number. 101 assertConnected(t, net.Alice, net.Bob) 102 103 // Check whether the connection was made alice -> bob or bob -> 104 // alice. The assert above ensures we can safely access 105 // alicePeers[0]. 106 alicePeers, err := net.Alice.ListPeers(ctxb, &lnrpc.ListPeersRequest{}) 107 if err != nil { 108 t.Fatalf("unable to fetch carol's peers %v", err) 109 } 110 if !alicePeers.Peers[0].Inbound { 111 // Connection was made in the alice -> bob direction. 112 net.DisconnectNodes(net.Alice, net.Bob) 113 } else { 114 // Connection was made in the alice <- bob direction. 115 net.DisconnectNodes(net.Alice, net.Bob) 116 } 117 } 118 logLine := fmt.Sprintf("=== %s: Reconnection tests successful\n", 119 time.Now()) 120 net.Alice.AddToLog(logLine) 121 net.Bob.AddToLog(logLine) 122 123 // Wait for the final disconnection to release all resources, then 124 // ensure both nodes are connected again. 125 assertNotConnected(t, net.Alice, net.Bob) 126 net.EnsureConnected(t.t, net.Alice, net.Bob) 127 }