mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-23 14:40:30 +01:00
Previous splitting logic simply put all the remainder in the last tranche, which could make the last tranche run significantly more test cases. We now change it so the remainder is evened out across tranches.
278 lines
8.3 KiB
Go
278 lines
8.3 KiB
Go
package itest
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
"github.com/btcsuite/btcd/integration/rpctest"
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
"github.com/lightningnetwork/lnd/lntest/node"
|
|
"github.com/lightningnetwork/lnd/lntest/port"
|
|
"github.com/lightningnetwork/lnd/lntest/wait"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/exp/rand"
|
|
"google.golang.org/grpc/grpclog"
|
|
)
|
|
|
|
const (
|
|
// defaultSplitTranches is the default number of tranches we split the
|
|
// test cases into.
|
|
defaultSplitTranches uint = 1
|
|
|
|
// defaultRunTranche is the default index of the test cases tranche that
|
|
// we run.
|
|
defaultRunTranche uint = 0
|
|
|
|
defaultTimeout = wait.DefaultTimeout
|
|
itestLndBinary = "../lnd-itest"
|
|
|
|
// TODO(yy): remove the following defined constants and put them in the
|
|
// specific tests where they are used?
|
|
testFeeBase = 1e+6
|
|
anchorSize = 330
|
|
defaultCSV = node.DefaultCSV
|
|
noFeeLimitMsat = math.MaxInt64
|
|
|
|
AddrTypeWitnessPubkeyHash = lnrpc.AddressType_WITNESS_PUBKEY_HASH
|
|
AddrTypeNestedPubkeyHash = lnrpc.AddressType_NESTED_PUBKEY_HASH
|
|
AddrTypeTaprootPubkey = lnrpc.AddressType_TAPROOT_PUBKEY
|
|
)
|
|
|
|
var (
|
|
harnessNetParams = &chaincfg.RegressionNetParams
|
|
|
|
// testCasesSplitParts is the number of tranches the test cases should
|
|
// be split into. By default this is set to 1, so no splitting happens.
|
|
// If this value is increased, then the -runtranche flag must be
|
|
// specified as well to indicate which part should be run in the current
|
|
// invocation.
|
|
testCasesSplitTranches = flag.Uint(
|
|
"splittranches", defaultSplitTranches, "split the test cases "+
|
|
"in this many tranches and run the tranche at "+
|
|
"0-based index specified by the -runtranche flag",
|
|
)
|
|
|
|
// shuffleSeedFlag is the source of randomness used to shuffle the test
|
|
// cases. If not specified, the test cases won't be shuffled.
|
|
shuffleSeedFlag = flag.Uint64(
|
|
"shuffleseed", 0, "if set, shuffles the test cases using this "+
|
|
"as the source of randomness",
|
|
)
|
|
|
|
// testCasesRunTranche is the 0-based index of the split test cases
|
|
// tranche to run in the current invocation.
|
|
testCasesRunTranche = flag.Uint(
|
|
"runtranche", defaultRunTranche, "run the tranche of the "+
|
|
"split test cases with the given (0-based) index",
|
|
)
|
|
|
|
// dbBackendFlag specifies the backend to use.
|
|
dbBackendFlag = flag.String("dbbackend", "bbolt", "Database backend "+
|
|
"(bbolt, etcd, postgres)")
|
|
|
|
nativeSQLFlag = flag.Bool("nativesql", false, "Database backend to "+
|
|
"use native SQL when applicable (only for sqlite and postgres")
|
|
|
|
// lndExecutable is the full path to the lnd binary.
|
|
lndExecutable = flag.String(
|
|
"lndexec", itestLndBinary, "full path to lnd binary",
|
|
)
|
|
)
|
|
|
|
// TestLightningNetworkDaemon performs a series of integration tests amongst a
|
|
// programmatically driven network of lnd nodes.
|
|
func TestLightningNetworkDaemon(t *testing.T) {
|
|
// If no tests are registered, then we can exit early.
|
|
if len(allTestCases) == 0 {
|
|
t.Skip("integration tests not selected with flag 'integration'")
|
|
}
|
|
|
|
// Get the test cases to be run in this tranche.
|
|
testCases, trancheIndex, trancheOffset := getTestCaseSplitTranche()
|
|
|
|
// Create a simple fee service.
|
|
feeService := lntest.NewFeeService(t)
|
|
|
|
// Get the binary path and setup the harness test.
|
|
binary := getLndBinary(t)
|
|
harnessTest := lntest.SetupHarness(
|
|
t, binary, *dbBackendFlag, *nativeSQLFlag, feeService,
|
|
)
|
|
defer harnessTest.Stop()
|
|
|
|
// Get the current block height.
|
|
height := harnessTest.CurrentHeight()
|
|
|
|
// Run the subset of the test cases selected in this tranche.
|
|
for idx, testCase := range testCases {
|
|
testCase := testCase
|
|
name := fmt.Sprintf("tranche%02d/%02d-of-%d/%s/%s",
|
|
trancheIndex, trancheOffset+uint(idx)+1,
|
|
len(allTestCases), harnessTest.ChainBackendName(),
|
|
testCase.Name)
|
|
|
|
success := t.Run(name, func(t1 *testing.T) {
|
|
// Create a separate harness test for the testcase to
|
|
// avoid overwriting the external harness test that is
|
|
// tied to the parent test.
|
|
ht := harnessTest.Subtest(t1)
|
|
ht.SetTestName(testCase.Name)
|
|
|
|
ht.RunTestCase(testCase)
|
|
})
|
|
|
|
// Stop at the first failure. Mimic behavior of original test
|
|
// framework.
|
|
if !success {
|
|
// Log failure time to help relate the lnd logs to the
|
|
// failure.
|
|
t.Logf("Failure time: %v", time.Now().Format(
|
|
"2006-01-02 15:04:05.000",
|
|
))
|
|
break
|
|
}
|
|
}
|
|
|
|
//nolint:forbidigo
|
|
fmt.Printf("=========> tranche %v finished, tested %d cases, mined "+
|
|
"blocks: %d\n", trancheIndex, len(testCases),
|
|
harnessTest.CurrentHeight()-height)
|
|
}
|
|
|
|
// maybeShuffleTestCases shuffles the test cases if the flag `shuffleseed` is
|
|
// set and not 0. In parallel tests we want to shuffle the test cases so they
|
|
// are executed in a random order. This is done to even out the blocks mined in
|
|
// each test tranche so they can run faster.
|
|
//
|
|
// NOTE: Because the parallel tests are initialized with the same seed (job
|
|
// ID), they will always have the same order.
|
|
func maybeShuffleTestCases() {
|
|
// Exit if not set.
|
|
if shuffleSeedFlag == nil {
|
|
return
|
|
}
|
|
|
|
// Exit if set to 0.
|
|
if *shuffleSeedFlag == 0 {
|
|
return
|
|
}
|
|
|
|
// Init the seed and shuffle the test cases.
|
|
rand.Seed(*shuffleSeedFlag)
|
|
rand.Shuffle(len(allTestCases), func(i, j int) {
|
|
allTestCases[i], allTestCases[j] =
|
|
allTestCases[j], allTestCases[i]
|
|
})
|
|
}
|
|
|
|
// createIndices divides the number of test cases into pairs of indices that
|
|
// specify the start and end of a tranche.
|
|
func createIndices(numCases, numTranches uint) [][2]uint {
|
|
// Calculate base value and remainder.
|
|
base := numCases / numTranches
|
|
remainder := numCases % numTranches
|
|
|
|
// Generate indices.
|
|
indices := make([][2]uint, numTranches)
|
|
start := uint(0)
|
|
|
|
for i := uint(0); i < numTranches; i++ {
|
|
end := start + base
|
|
if i < remainder {
|
|
// Add one for the remainder.
|
|
end++
|
|
}
|
|
indices[i] = [2]uint{start, end}
|
|
start = end
|
|
}
|
|
|
|
return indices
|
|
}
|
|
|
|
// getTestCaseSplitTranche returns the sub slice of the test cases that should
|
|
// be run as the current split tranche as well as the index and slice offset of
|
|
// the tranche.
|
|
func getTestCaseSplitTranche() ([]*lntest.TestCase, uint, uint) {
|
|
numTranches := defaultSplitTranches
|
|
if testCasesSplitTranches != nil {
|
|
numTranches = *testCasesSplitTranches
|
|
}
|
|
runTranche := defaultRunTranche
|
|
if testCasesRunTranche != nil {
|
|
runTranche = *testCasesRunTranche
|
|
}
|
|
|
|
// There's a special flake-hunt mode where we run the same test multiple
|
|
// times in parallel. In that case the tranche index is equal to the
|
|
// thread ID, but we need to actually run all tests for the regex
|
|
// selection to work.
|
|
threadID := runTranche
|
|
if numTranches == 1 {
|
|
runTranche = 0
|
|
}
|
|
|
|
// Shuffle the test cases if the `shuffleseed` flag is set.
|
|
maybeShuffleTestCases()
|
|
|
|
numCases := uint(len(allTestCases))
|
|
indices := createIndices(numCases, numTranches)
|
|
index := indices[runTranche]
|
|
trancheOffset, trancheEnd := index[0], index[1]
|
|
|
|
return allTestCases[trancheOffset:trancheEnd], threadID,
|
|
trancheOffset
|
|
}
|
|
|
|
func getLndBinary(t *testing.T) string {
|
|
binary := itestLndBinary
|
|
lndExec := ""
|
|
if lndExecutable != nil && *lndExecutable != "" {
|
|
lndExec = *lndExecutable
|
|
}
|
|
if lndExec == "" && runtime.GOOS == "windows" {
|
|
// Windows (even in a bash like environment like git bash as on
|
|
// Travis) doesn't seem to like relative paths to exe files...
|
|
currentDir, err := os.Getwd()
|
|
require.NoError(t, err, "unable to get working directory")
|
|
|
|
targetPath := filepath.Join(currentDir, "../../lnd-itest.exe")
|
|
binary, err = filepath.Abs(targetPath)
|
|
require.NoError(t, err, "unable to get absolute path")
|
|
} else if lndExec != "" {
|
|
binary = lndExec
|
|
}
|
|
|
|
return binary
|
|
}
|
|
|
|
// isDarwin returns true if the test is running on a macOS.
|
|
func isDarwin() bool {
|
|
return runtime.GOOS == "darwin"
|
|
}
|
|
|
|
// isWindowsOS returns true if the test is running on a Windows OS.
|
|
func isWindowsOS() bool {
|
|
return runtime.GOOS == "windows"
|
|
}
|
|
|
|
func init() {
|
|
// Before we start any node, we need to make sure that any btcd node
|
|
// that is started through the RPC harness uses a unique port as well
|
|
// to avoid any port collisions.
|
|
rpctest.ListenAddressGenerator =
|
|
port.GenerateSystemUniqueListenerAddresses
|
|
|
|
// Swap out grpc's default logger with our fake logger which drops the
|
|
// statements on the floor.
|
|
fakeLogger := grpclog.NewLoggerV2(io.Discard, io.Discard, io.Discard)
|
|
grpclog.SetLoggerV2(fakeLogger)
|
|
}
|