Browse Source

pytest: fail tests if we get any LOG_BROKEN level messages, unless flagged.

And clean up some dev ones which actually happen (mainly by calling
channel_fail_permanent which logs UNUSUAL, rather than
channel_internal_error which logs BROKEN).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
pull/2938/head
Rusty Russell 6 years ago
parent
commit
54ce4ed1cf
  1. 6
      channeld/full_channel.c
  2. 6
      common/crypto_sync.c
  3. 2
      lightningd/channel.c
  4. 4
      lightningd/peer_control.c
  5. 11
      tests/fixtures.py
  6. 4
      tests/test_closing.py
  7. 2
      tests/test_connection.py
  8. 4
      tests/test_gossip.py
  9. 2
      tests/test_misc.py
  10. 2
      tests/test_plugin.py
  11. 8
      tests/utils.py

6
channeld/full_channel.c

@ -314,10 +314,10 @@ static bool get_room_above_reserve(const struct channel *channel,
for (size_t i = 0; i < tal_count(adding); i++) for (size_t i = 0; i < tal_count(adding); i++)
ok &= balance_add_htlc(balance, adding[i], side); ok &= balance_add_htlc(balance, adding[i], side);
/* Overflow shouldn't happen, but if it does, complain */ /* Can happen if amount completely exceeds capacity */
if (!ok) { if (!ok) {
status_broken("Failed to add %zu remove %zu htlcs", status_trace("Failed to add %zu remove %zu htlcs",
tal_count(adding), tal_count(removing)); tal_count(adding), tal_count(removing));
return false; return false;
} }

6
common/crypto_sync.c

@ -85,9 +85,9 @@ void sync_crypto_write_no_delay(struct per_peer_state *pps,
if (setsockopt(pps->peer_fd, IPPROTO_TCP, opt, &val, sizeof(val)) != 0) { if (setsockopt(pps->peer_fd, IPPROTO_TCP, opt, &val, sizeof(val)) != 0) {
/* This actually happens in testing, where we blackhole the fd */ /* This actually happens in testing, where we blackhole the fd */
if (!complained) { if (!complained) {
status_broken("setsockopt %s=1: %s", status_unusual("setsockopt %s=1: %s",
optname, optname,
strerror(errno)); strerror(errno));
complained = true; complained = true;
} }
} }

2
lightningd/channel.c

@ -441,7 +441,7 @@ void channel_fail_transient(struct channel *channel, const char *fmt, ...)
#if DEVELOPER #if DEVELOPER
if (dev_disconnect_permanent(channel->peer->ld)) { if (dev_disconnect_permanent(channel->peer->ld)) {
channel_internal_error(channel, "dev_disconnect permfail"); channel_fail_permanent(channel, "dev_disconnect permfail");
return; return;
} }
#endif #endif

4
lightningd/peer_control.c

@ -830,7 +830,7 @@ peer_connected_hook_cb(struct peer_connected_hook_payload *payload,
#if DEVELOPER #if DEVELOPER
if (dev_disconnect_permanent(ld)) { if (dev_disconnect_permanent(ld)) {
channel_internal_error(channel, channel_fail_permanent(channel,
"dev_disconnect permfail"); "dev_disconnect permfail");
error = channel->error; error = channel->error;
goto send_error; goto send_error;
@ -1698,7 +1698,7 @@ static struct command_result *json_dev_fail(struct command *cmd,
"Could not find active channel with peer"); "Could not find active channel with peer");
} }
channel_internal_error(channel, "Failing due to dev-fail command"); channel_fail_permanent(channel, "Failing due to dev-fail command");
return command_success(cmd, json_stream_success(cmd)); return command_success(cmd, json_stream_success(cmd));
} }

11
tests/fixtures.py

@ -127,6 +127,10 @@ def node_factory(request, directory, test_name, bitcoind, executor):
err_count += printCrashLog(node) err_count += printCrashLog(node)
check_errors(request, err_count, "{} nodes had crash.log files") check_errors(request, err_count, "{} nodes had crash.log files")
for node in [n for n in nf.nodes if not n.allow_broken_log]:
err_count += checkBroken(node)
check_errors(request, err_count, "{} nodes had BROKEN messages")
for node in nf.nodes: for node in nf.nodes:
err_count += checkReconnect(node) err_count += checkReconnect(node)
check_errors(request, err_count, "{} nodes had unexpected reconnections") check_errors(request, err_count, "{} nodes had unexpected reconnections")
@ -219,6 +223,13 @@ def checkBadGossip(node):
return 0 return 0
def checkBroken(node):
# We can get bad gossip order from inside error msgs.
if node.daemon.is_in_log(r'\*\*BROKEN\*\*'):
return 1
return 0
def checkBadReestablish(node): def checkBadReestablish(node):
if node.daemon.is_in_log('Bad reestablish'): if node.daemon.is_in_log('Bad reestablish'):
return 1 return 1

4
tests/test_closing.py

@ -296,7 +296,7 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor):
"""Test penalty transaction with an incoming HTLC""" """Test penalty transaction with an incoming HTLC"""
# We suppress each one after first commit; HTLC gets added not fulfilled. # We suppress each one after first commit; HTLC gets added not fulfilled.
# Feerates identical so we don't get gratuitous commit to update them # Feerates identical so we don't get gratuitous commit to update them
l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], may_fail=True, feerates=(7500, 7500, 7500)) l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], may_fail=True, feerates=(7500, 7500, 7500), allow_broken_log=True)
l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit']) l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'])
l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
@ -368,7 +368,7 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor):
"""Test penalty transaction with an outgoing HTLC""" """Test penalty transaction with an outgoing HTLC"""
# First we need to get funds to l2, so suppress after second. # First we need to get funds to l2, so suppress after second.
# Feerates identical so we don't get gratuitous commit to update them # Feerates identical so we don't get gratuitous commit to update them
l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'], may_fail=True, feerates=(7500, 7500, 7500)) l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'], may_fail=True, feerates=(7500, 7500, 7500), allow_broken_log=True)
l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit']) l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'])
l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l2.info['id'], 'localhost', l2.port)

2
tests/test_connection.py

@ -1490,7 +1490,7 @@ def test_dataloss_protection(node_factory, bitcoind):
l1 = node_factory.get_node(may_reconnect=True, log_all_io=True, l1 = node_factory.get_node(may_reconnect=True, log_all_io=True,
feerates=(7500, 7500, 7500)) feerates=(7500, 7500, 7500))
l2 = node_factory.get_node(may_reconnect=True, log_all_io=True, l2 = node_factory.get_node(may_reconnect=True, log_all_io=True,
feerates=(7500, 7500, 7500)) feerates=(7500, 7500, 7500), allow_broken_log=True)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
# l1 should send out WIRE_INIT (0010) # l1 should send out WIRE_INIT (0010)

4
tests/test_gossip.py

@ -934,7 +934,7 @@ def test_gossip_store_load_announce_before_update(node_factory):
def test_gossip_store_load_amount_truncated(node_factory): def test_gossip_store_load_amount_truncated(node_factory):
"""Make sure we can read canned gossip store with truncated amount""" """Make sure we can read canned gossip store with truncated amount"""
l1 = node_factory.get_node(start=False) l1 = node_factory.get_node(start=False, allow_broken_log=True)
with open(os.path.join(l1.daemon.lightning_dir, 'gossip_store'), 'wb') as f: with open(os.path.join(l1.daemon.lightning_dir, 'gossip_store'), 'wb') as f:
f.write(bytearray.fromhex("07" # GOSSIP_STORE_VERSION f.write(bytearray.fromhex("07" # GOSSIP_STORE_VERSION
"000001b0" # len "000001b0" # len
@ -1251,7 +1251,7 @@ def test_gossip_store_compact_restart(node_factory, bitcoind):
@unittest.skipIf(not DEVELOPER, "need dev-compact-gossip-store") @unittest.skipIf(not DEVELOPER, "need dev-compact-gossip-store")
def test_gossip_store_load_no_channel_update(node_factory): def test_gossip_store_load_no_channel_update(node_factory):
"""Make sure we can read truncated gossip store with a channel_announcement and no channel_update""" """Make sure we can read truncated gossip store with a channel_announcement and no channel_update"""
l1 = node_factory.get_node(start=False) l1 = node_factory.get_node(start=False, allow_broken_log=True)
# A channel announcement with no channel_update. # A channel announcement with no channel_update.
with open(os.path.join(l1.daemon.lightning_dir, 'gossip_store'), 'wb') as f: with open(os.path.join(l1.daemon.lightning_dir, 'gossip_store'), 'wb') as f:

2
tests/test_misc.py

@ -1044,7 +1044,7 @@ def test_logging(node_factory):
@unittest.skipIf(VALGRIND, @unittest.skipIf(VALGRIND,
"Valgrind sometimes fails assert on injected SEGV") "Valgrind sometimes fails assert on injected SEGV")
def test_crashlog(node_factory): def test_crashlog(node_factory):
l1 = node_factory.get_node(may_fail=True) l1 = node_factory.get_node(may_fail=True, allow_broken_log=True)
def has_crash_log(n): def has_crash_log(n):
files = os.listdir(n.daemon.lightning_dir) files = os.listdir(n.daemon.lightning_dir)

2
tests/test_plugin.py

@ -435,7 +435,7 @@ def test_htlc_accepted_hook_forward_restart(node_factory, executor):
def test_warning_notification(node_factory): def test_warning_notification(node_factory):
""" test 'warning' notifications """ test 'warning' notifications
""" """
l1 = node_factory.get_node(options={'plugin': 'tests/plugins/pretend_badlog.py'}) l1 = node_factory.get_node(options={'plugin': 'tests/plugins/pretend_badlog.py'}, allow_broken_log=True)
# 1. test 'warn' level # 1. test 'warn' level
event = "Test warning notification(for unusual event)" event = "Test warning notification(for unusual event)"

8
tests/utils.py

@ -454,13 +454,14 @@ class LightningD(TailableProc):
class LightningNode(object): class LightningNode(object):
def __init__(self, daemon, rpc, btc, executor, may_fail=False, may_reconnect=False): def __init__(self, daemon, rpc, btc, executor, may_fail=False, may_reconnect=False, allow_broken_log=False):
self.rpc = rpc self.rpc = rpc
self.daemon = daemon self.daemon = daemon
self.bitcoin = btc self.bitcoin = btc
self.executor = executor self.executor = executor
self.may_fail = may_fail self.may_fail = may_fail
self.may_reconnect = may_reconnect self.may_reconnect = may_reconnect
self.allow_broken_log = allow_broken_log
def connect(self, remote_node): def connect(self, remote_node):
self.rpc.connect(remote_node.info['id'], '127.0.0.1', remote_node.daemon.port) self.rpc.connect(remote_node.info['id'], '127.0.0.1', remote_node.daemon.port)
@ -773,6 +774,7 @@ class NodeFactory(object):
node_opt_keys = [ node_opt_keys = [
'disconnect', 'disconnect',
'may_fail', 'may_fail',
'allow_broken_log',
'may_reconnect', 'may_reconnect',
'random_hsm', 'random_hsm',
'log_all_io', 'log_all_io',
@ -819,7 +821,7 @@ class NodeFactory(object):
def get_node(self, disconnect=None, options=None, may_fail=False, def get_node(self, disconnect=None, options=None, may_fail=False,
may_reconnect=False, random_hsm=False, may_reconnect=False, random_hsm=False,
feerates=(15000, 7500, 3750), start=True, log_all_io=False, feerates=(15000, 7500, 3750), start=True, log_all_io=False,
dbfile=None, node_id=None): dbfile=None, node_id=None, allow_broken_log=False):
if not node_id: if not node_id:
node_id = self.get_node_id() node_id = self.get_node_id()
@ -862,7 +864,7 @@ class NodeFactory(object):
rpc = LightningRpc(socket_path, self.executor) rpc = LightningRpc(socket_path, self.executor)
node = LightningNode(daemon, rpc, self.bitcoind, self.executor, may_fail=may_fail, node = LightningNode(daemon, rpc, self.bitcoind, self.executor, may_fail=may_fail,
may_reconnect=may_reconnect) may_reconnect=may_reconnect, allow_broken_log=allow_broken_log)
# Regtest estimatefee are unusable, so override. # Regtest estimatefee are unusable, so override.
node.set_feerates(feerates, False) node.set_feerates(feerates, False)

Loading…
Cancel
Save