github.com/decred/dcrlnd@v0.7.6/lntest/itest/lnd_test.go (about)

     1  package itest
     2  
     3  import (
     4  	"context"
     5  	"flag"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/decred/dcrlnd/lntest"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  const (
    17  	// defaultSplitTranches is the default number of tranches we split the
    18  	// test cases into.
    19  	defaultSplitTranches uint = 1
    20  
    21  	// defaultRunTranche is the default index of the test cases tranche that
    22  	// we run.
    23  	defaultRunTranche uint = 0
    24  )
    25  
    26  var (
    27  	// testCasesSplitParts is the number of tranches the test cases should
    28  	// be split into. By default this is set to 1, so no splitting happens.
    29  	// If this value is increased, then the -runtranche flag must be
    30  	// specified as well to indicate which part should be run in the current
    31  	// invocation.
    32  	testCasesSplitTranches = flag.Uint(
    33  		"splittranches", defaultSplitTranches, "split the test cases "+
    34  			"in this many tranches and run the tranche at "+
    35  			"0-based index specified by the -runtranche flag",
    36  	)
    37  
    38  	// testCasesRunTranche is the 0-based index of the split test cases
    39  	// tranche to run in the current invocation.
    40  	testCasesRunTranche = flag.Uint(
    41  		"runtranche", defaultRunTranche, "run the tranche of the "+
    42  			"split test cases with the given (0-based) index",
    43  	)
    44  
    45  	// dbBackendFlag specifies the backend to use
    46  	dbBackendFlag = flag.String("dbbackend", "bbolt", "Database backend "+
    47  		"(bbolt, etcd, postgres)")
    48  )
    49  
    50  // getTestCaseSplitTranche returns the sub slice of the test cases that should
    51  // be run as the current split tranche as well as the index and slice offset of
    52  // the tranche.
    53  func getTestCaseSplitTranche() ([]*testCase, uint, uint) {
    54  	numTranches := defaultSplitTranches
    55  	if testCasesSplitTranches != nil {
    56  		numTranches = *testCasesSplitTranches
    57  	}
    58  	runTranche := defaultRunTranche
    59  	if testCasesRunTranche != nil {
    60  		runTranche = *testCasesRunTranche
    61  	}
    62  
    63  	// There's a special flake-hunt mode where we run the same test multiple
    64  	// times in parallel. In that case the tranche index is equal to the
    65  	// thread ID, but we need to actually run all tests for the regex
    66  	// selection to work.
    67  	threadID := runTranche
    68  	if numTranches == 1 {
    69  		runTranche = 0
    70  	}
    71  
    72  	numCases := uint(len(allTestCases))
    73  	testsPerTranche := numCases / numTranches
    74  	trancheOffset := runTranche * testsPerTranche
    75  	trancheEnd := trancheOffset + testsPerTranche
    76  	if trancheEnd > numCases || runTranche == numTranches-1 {
    77  		trancheEnd = numCases
    78  	}
    79  
    80  	return allTestCases[trancheOffset:trancheEnd], threadID, trancheOffset
    81  }
    82  
    83  // TestLightningNetworkDaemon performs a series of integration tests amongst a
    84  // programmatically driven network of lnd nodes.
    85  func TestLightningNetworkDaemon(t *testing.T) {
    86  	// If no tests are registered, then we can exit early.
    87  	if len(allTestCases) == 0 {
    88  		t.Skip("integration tests not selected with flag 'rpctest'")
    89  	}
    90  
    91  	// Parse testing flags that influence our test execution.
    92  	logDir := lntest.GetLogDir()
    93  	require.NoError(t, os.MkdirAll(logDir, 0700))
    94  	testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
    95  	lntest.ApplyPortOffset(uint32(trancheIndex) * 1000)
    96  
    97  	ht := newHarnessTest(t, nil)
    98  
    99  	// Declare the network harness here to gain access to its
   100  	// 'OnTxAccepted' call back.
   101  	var lndHarness *lntest.NetworkHarness
   102  
   103  	// Create an instance of dcrd's rpctest.Harness that will act as the
   104  	// miner for all tests. This will be used to fund the wallets of the
   105  	// nodes within the test network and to drive blockchain related events
   106  	// within the network. Revert the default setting of accepting
   107  	// non-standard transactions on simnet to reject them. Transactions on
   108  	// the lightning network should always be standard to get better
   109  	// guarantees of getting included in to blocks.
   110  	//
   111  	// We will also connect it to our chain backend.
   112  	miner, err := lntest.NewMiner()
   113  	require.NoError(t, err, "failed to create new miner")
   114  	defer func() {
   115  		require.NoError(t, miner.Stop(), "failed to stop miner")
   116  	}()
   117  
   118  	// Setup the initial chain. This is a dcrlnd-only operation, needed to
   119  	// setup the initial chain + the voting wallet.
   120  	err = miner.SetUpChain()
   121  	require.NoError(t, err)
   122  
   123  	if err := miner.Node.NotifyNewTransactions(context.Background(), false); err != nil {
   124  		ht.Fatalf("unable to request transaction notifications: %v", err)
   125  	}
   126  
   127  	// Start a chain backend.
   128  	chainBackend, cleanUp, err := lntest.NewBackend(t, miner.Harness)
   129  	if err != nil {
   130  		ht.Fatalf("unable to start dcrd: %v", err)
   131  	}
   132  	defer func() {
   133  		require.NoError(
   134  			t, cleanUp(), "failed to clean up chain backend",
   135  		)
   136  	}()
   137  
   138  	// Connect chainbackend to miner.
   139  	require.NoError(
   140  		t, chainBackend.ConnectMiner(), "failed to connect to miner",
   141  	)
   142  
   143  	// Parse database backend
   144  	var dbBackend lntest.DatabaseBackend
   145  	switch *dbBackendFlag {
   146  	case "bbolt":
   147  		dbBackend = lntest.BackendBbolt
   148  
   149  	case "etcd":
   150  		dbBackend = lntest.BackendEtcd
   151  
   152  	case "postgres":
   153  		dbBackend = lntest.BackendPostgres
   154  
   155  	default:
   156  		require.Fail(t, "unknown db backend")
   157  	}
   158  
   159  	// Now we can set up our test harness (LND instance), with the chain
   160  	// backend we just created.
   161  	binary := ht.getLndBinary()
   162  	lndHarness, err = lntest.NewNetworkHarness(
   163  		miner, chainBackend, binary, dbBackend,
   164  	)
   165  	if err != nil {
   166  		ht.Fatalf("unable to create lightning network harness: %v", err)
   167  	}
   168  	defer lndHarness.Stop()
   169  
   170  	// Spawn a new goroutine to watch for any fatal errors that any of the
   171  	// running lnd processes encounter. If an error occurs, then the test
   172  	// case should naturally as a result and we log the server error here to
   173  	// help debug.
   174  	go func() {
   175  		errChan := lndHarness.ProcessErrors()
   176  		for err := range errChan {
   177  			ht.Logf("lnd finished with error (stderr):\n%v",
   178  				err)
   179  
   180  		}
   181  	}()
   182  
   183  	// With the dcrd harness created, we can now complete the
   184  	// initialization of the network. args - list of lnd arguments,
   185  	// example: "--debuglevel=debug"
   186  	// TODO(roasbeef): create master balanced channel with all the monies?
   187  	aliceBobArgs := []string{
   188  		"--default-remote-max-htlcs=150",
   189  		"--dust-threshold=5000000",
   190  	}
   191  
   192  	err = lndHarness.SetUp(t, "", aliceBobArgs)
   193  	require.NoError(t,
   194  		err, "unable to set up test lightning network",
   195  	)
   196  	defer func() {
   197  		require.NoError(t, lndHarness.TearDown())
   198  	}()
   199  
   200  	// Run the subset of the test cases selected in this tranche.
   201  	t.Logf("Running %v integration tests", len(testCases))
   202  	for idx, testCase := range testCases {
   203  		testCase := testCase
   204  		name := fmt.Sprintf("tranche%02d/%02d-of-%d/%s/%s",
   205  			trancheIndex, trancheOffset+uint(idx)+1,
   206  			len(allTestCases), chainBackend.Name(), testCase.name)
   207  
   208  		success := t.Run(name, func(t1 *testing.T) {
   209  			cleanTestCaseName := strings.ReplaceAll(
   210  				testCase.name, " ", "_",
   211  			)
   212  
   213  			lndHarness.ModifyTestCaseName(cleanTestCaseName)
   214  
   215  			logLine := fmt.Sprintf(
   216  				"STARTING ============ %v ============\n",
   217  				testCase.name,
   218  			)
   219  
   220  			lndHarness.Alice.AddToLog(logLine)
   221  			lndHarness.Bob.AddToLog(logLine)
   222  
   223  			// Start every test with the default static fee estimate.
   224  			lndHarness.SetFeeEstimate(10000)
   225  
   226  			// Create a separate harness test for the testcase to
   227  			// avoid overwriting the external harness test that is
   228  			// tied to the parent test.
   229  			ht := newHarnessTest(t1, lndHarness)
   230  			ht.RunTestCase(testCase)
   231  			assertCleanState(ht, lndHarness)
   232  		})
   233  
   234  		// Stop at the first failure. Mimic behavior of original test
   235  		// framework.
   236  		if !success {
   237  			// Log failure time to help relate the lnd logs to the
   238  			// failure.
   239  			t.Logf("Failure time: %v", time.Now().Format(
   240  				"2006-01-02 15:04:05.000",
   241  			))
   242  			break
   243  		}
   244  	}
   245  }