github.com/decred/dcrlnd@v0.7.6/lntest/test_common.go (about) 1 package lntest 2 3 import ( 4 "errors" 5 "flag" 6 "fmt" 7 "io" 8 "net" 9 "os" 10 "sync/atomic" 11 12 "github.com/decred/dcrd/wire" 13 "github.com/decred/dcrlnd/lnrpc" 14 ) 15 16 const ( 17 // defaultNodePort is the start of the range for listening ports of 18 // harness nodes. Ports are monotonically increasing starting from this 19 // number and are determined by the results of nextAvailablePort(). 20 defaultNodePort = 5555 21 22 // ListenerFormat is the format string that is used to generate local 23 // listener addresses. 24 ListenerFormat = "127.0.0.1:%d" 25 26 // NeutrinoBackendName is the name of the neutrino backend. 27 NeutrinoBackendName = "neutrino" 28 ) 29 30 type DatabaseBackend int 31 32 const ( 33 BackendBbolt DatabaseBackend = iota 34 BackendEtcd 35 BackendPostgres 36 ) 37 38 var ( 39 // lastPort is the last port determined to be free for use by a new 40 // node. It should be used atomically. 41 lastPort uint32 = defaultNodePort 42 43 // logOutput is a flag that can be set to append the output from the 44 // seed nodes to log files. 45 logOutput = flag.Bool("logoutput", false, 46 "log output from node n to file output-n.log") 47 48 // logSubDir is the default directory where the logs are written to if 49 // logOutput is true. 50 logSubDir = flag.String("logdir", ".", "default dir to write logs to") 51 52 // goroutineDump is a flag that can be set to dump the active 53 // goroutines of test nodes on failure. 54 goroutineDump = flag.Bool("goroutinedump", false, 55 "write goroutine dump from node n to file pprof-n.log") 56 ) 57 58 // NextAvailablePort returns the first port that is available for listening by 59 // a new node. It panics if no port is found and the maximum available TCP port 60 // is reached. 61 func NextAvailablePort() int { 62 port := atomic.AddUint32(&lastPort, 1) 63 for port < 65535 { 64 // If there are no errors while attempting to listen on this 65 // port, close the socket and return it as available. While it 66 // could be the case that some other process picks up this port 67 // between the time the socket is closed and it's reopened in 68 // the harness node, in practice in CI servers this seems much 69 // less likely than simply some other process already being 70 // bound at the start of the tests. 71 addr := fmt.Sprintf(ListenerFormat, port) 72 l, err := net.Listen("tcp4", addr) 73 if err == nil { 74 err := l.Close() 75 if err == nil { 76 return int(port) 77 } 78 } 79 port = atomic.AddUint32(&lastPort, 1) 80 } 81 82 // No ports available? Must be a mistake. 83 panic("no ports available for listening") 84 } 85 86 // ApplyPortOffset adds the given offset to the lastPort variable, making it 87 // possible to run the tests in parallel without colliding on the same ports. 88 func ApplyPortOffset(offset uint32) { 89 _ = atomic.AddUint32(&lastPort, offset) 90 } 91 92 // GetLogDir returns the passed --logdir flag or the default value if it wasn't 93 // set. 94 func GetLogDir() string { 95 if logSubDir != nil && *logSubDir != "" { 96 return *logSubDir 97 } 98 return "." 99 } 100 101 // MakeOutpoint returns the outpoint of the channel's funding transaction. 102 func MakeOutpoint(chanPoint *lnrpc.ChannelPoint) (wire.OutPoint, error) { 103 fundingTxID, err := lnrpc.GetChanPointFundingTxid(chanPoint) 104 if err != nil { 105 return wire.OutPoint{}, err 106 } 107 108 return wire.OutPoint{ 109 Hash: *fundingTxID, 110 Index: chanPoint.OutputIndex, 111 }, nil 112 } 113 114 // CheckChannelPolicy checks that the policy matches the expected one. 115 func CheckChannelPolicy(policy, expectedPolicy *lnrpc.RoutingPolicy) error { 116 if policy.FeeBaseMAtoms != expectedPolicy.FeeBaseMAtoms { 117 return fmt.Errorf("expected base fee %v, got %v", 118 expectedPolicy.FeeBaseMAtoms, policy.FeeBaseMAtoms) 119 } 120 if policy.FeeRateMilliMAtoms != expectedPolicy.FeeRateMilliMAtoms { 121 return fmt.Errorf("expected fee rate %v, got %v", 122 expectedPolicy.FeeRateMilliMAtoms, 123 policy.FeeRateMilliMAtoms) 124 } 125 if policy.TimeLockDelta != expectedPolicy.TimeLockDelta { 126 return fmt.Errorf("expected time lock delta %v, got %v", 127 expectedPolicy.TimeLockDelta, 128 policy.TimeLockDelta) 129 } 130 if policy.MinHtlc != expectedPolicy.MinHtlc { 131 return fmt.Errorf("expected min htlc %v, got %v", 132 expectedPolicy.MinHtlc, policy.MinHtlc) 133 } 134 if policy.MaxHtlcMAtoms != expectedPolicy.MaxHtlcMAtoms { 135 return fmt.Errorf("expected max htlc %v, got %v", 136 expectedPolicy.MaxHtlcMAtoms, policy.MaxHtlcMAtoms) 137 } 138 if policy.Disabled != expectedPolicy.Disabled { 139 return errors.New("edge should be disabled but isn't") 140 } 141 142 return nil 143 } 144 145 // CopyFile copies the file src to dest. 146 func CopyFile(dest, src string) error { 147 s, err := os.Open(src) 148 if err != nil { 149 return err 150 } 151 defer s.Close() 152 153 d, err := os.Create(dest) 154 if err != nil { 155 return err 156 } 157 158 if _, err := io.Copy(d, s); err != nil { 159 d.Close() 160 return err 161 } 162 163 return d.Close() 164 }