2020-08-25 07:54:55 +03:00
|
|
|
package itest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/lightningnetwork/lnd"
|
|
|
|
"github.com/lightningnetwork/lnd/lnrpc"
|
|
|
|
"github.com/lightningnetwork/lnd/lntest"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
// testNetworkConnectionTimeout checks that the connectiontimeout is taking
|
|
|
|
// effect. It creates a node with a small connection timeout value, and connects
|
|
|
|
// it to a non-routable IP address.
|
|
|
|
func testNetworkConnectionTimeout(net *lntest.NetworkHarness, t *harnessTest) {
|
|
|
|
var (
|
|
|
|
ctxt, _ = context.WithTimeout(
|
|
|
|
context.Background(), defaultTimeout,
|
|
|
|
)
|
|
|
|
// testPub is a random public key for testing only.
|
|
|
|
testPub = "0332bda7da70fefe4b6ab92f53b3c4f4ee7999" +
|
|
|
|
"f312284a8e89c8670bb3f67dbee2"
|
|
|
|
// testHost is a non-routable IP address. It's used to cause a
|
|
|
|
// connection timeout.
|
|
|
|
testHost = "10.255.255.255"
|
|
|
|
)
|
|
|
|
|
|
|
|
// First, test the global timeout settings.
|
|
|
|
// Create Carol with a connection timeout of 1 millisecond.
|
|
|
|
carol, err := net.NewNode("Carol", []string{"--connectiontimeout=1ms"})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create new node carol: %v", err)
|
|
|
|
}
|
|
|
|
defer shutdownAndAssert(net, t, carol)
|
|
|
|
|
|
|
|
// Try to connect Carol to a non-routable IP address, which should give
|
|
|
|
// us a timeout error.
|
|
|
|
req := &lnrpc.ConnectPeerRequest{
|
|
|
|
Addr: &lnrpc.LightningAddress{
|
|
|
|
Pubkey: testPub,
|
|
|
|
Host: testHost,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
assertTimeoutError(ctxt, t, carol, req)
|
|
|
|
|
|
|
|
// Second, test timeout on the connect peer request.
|
|
|
|
// Create Dave with the default timeout setting.
|
|
|
|
dave, err := net.NewNode("Dave", nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to create new node dave: %v", err)
|
|
|
|
}
|
|
|
|
defer shutdownAndAssert(net, t, dave)
|
|
|
|
|
|
|
|
// Try to connect Dave to a non-routable IP address, using a timeout
|
|
|
|
// value of 1ms, which should give us a timeout error immediately.
|
|
|
|
req = &lnrpc.ConnectPeerRequest{
|
|
|
|
Addr: &lnrpc.LightningAddress{
|
|
|
|
Pubkey: testPub,
|
|
|
|
Host: testHost,
|
|
|
|
},
|
|
|
|
Timeout: 1,
|
|
|
|
}
|
|
|
|
assertTimeoutError(ctxt, t, dave, req)
|
|
|
|
}
|
|
|
|
|
|
|
|
// assertTimeoutError asserts that a connection timeout error is raised. A
|
|
|
|
// context with a default timeout is used to make the request. If our customized
|
|
|
|
// connection timeout is less than the default, we won't see the request context
|
|
|
|
// times out, instead a network connection timeout will be returned.
|
|
|
|
func assertTimeoutError(ctxt context.Context, t *harnessTest,
|
|
|
|
node *lntest.HarnessNode, req *lnrpc.ConnectPeerRequest) {
|
|
|
|
|
|
|
|
t.t.Helper()
|
|
|
|
|
|
|
|
// Create a context with a timeout value.
|
|
|
|
ctxt, cancel := context.WithTimeout(ctxt, defaultTimeout)
|
|
|
|
defer cancel()
|
|
|
|
|
2020-01-10 17:27:50 +03:00
|
|
|
err := connect(ctxt, node, req)
|
2020-08-25 07:54:55 +03:00
|
|
|
|
|
|
|
// a DeadlineExceeded error will appear in the context if the above
|
|
|
|
// ctxtTimeout value is reached.
|
|
|
|
require.NoError(t.t, ctxt.Err(), "context time out")
|
|
|
|
|
|
|
|
// Check that the network returns a timeout error.
|
|
|
|
require.Containsf(
|
|
|
|
t.t, err.Error(), "i/o timeout",
|
|
|
|
"expected to get a timeout error, instead got: %v", err,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2020-01-10 17:27:50 +03:00
|
|
|
func connect(ctxt context.Context, node *lntest.HarnessNode,
|
2020-08-25 07:54:55 +03:00
|
|
|
req *lnrpc.ConnectPeerRequest) error {
|
|
|
|
|
|
|
|
syncTimeout := time.After(15 * time.Second)
|
|
|
|
ticker := time.NewTicker(time.Millisecond * 100)
|
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-ticker.C:
|
|
|
|
_, err := node.ConnectPeer(ctxt, req)
|
|
|
|
// If there's no error, return nil
|
|
|
|
if err == nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// If the error is no ErrServerNotActive, return it.
|
|
|
|
// Otherwise, we will retry until timeout.
|
|
|
|
if !strings.Contains(err.Error(),
|
|
|
|
lnd.ErrServerNotActive.Error()) {
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
case <-syncTimeout:
|
|
|
|
return fmt.Errorf("chain backend did not " +
|
|
|
|
"finish syncing")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|