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 }