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  }