pytest: Test a plugin crash while handling a hook call
This commit is contained in:
parent
7f6f324590
commit
72757933f0
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from pyln.client import Plugin
|
||||
import sys
|
||||
|
||||
|
||||
plugin = Plugin()
|
||||
|
||||
|
||||
@plugin.hook('htlc_accepted')
|
||||
def on_htlc_accepted(plugin, htlc, onion, **kwargs):
|
||||
"""We die silently, i.e., without returning a response
|
||||
|
||||
`lightningd` should detect that and recover.
|
||||
"""
|
||||
plugin.log("Plugin is about to crash...")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
plugin.run()
|
|
@ -1012,3 +1012,54 @@ def test_bcli(node_factory, bitcoind, chainparams):
|
|||
|
||||
resp = l1.rpc.call("sendrawtransaction", {"tx": "dummy"})
|
||||
assert not resp["success"] and "decode failed" in resp["errmsg"]
|
||||
|
||||
|
||||
@pytest.mark.xfail(strict=True)
|
||||
def test_hook_crash(node_factory, executor, bitcoind):
|
||||
"""Verify that we fail over if a plugin crashes while handling a hook.
|
||||
|
||||
We create a star topology, with l1 opening channels to the other nodes,
|
||||
and then triggering the plugins on those nodes in order to exercise the
|
||||
hook chain. p0 is the interesting plugin because as soon as it get called
|
||||
for the htlc_accepted hook it'll crash on purpose. We should still make it
|
||||
through the chain, the plugins should all be called and the payment should
|
||||
still go through.
|
||||
|
||||
"""
|
||||
p0 = os.path.join(os.path.dirname(__file__), "plugins/hook-crash.py")
|
||||
p1 = os.path.join(os.path.dirname(__file__), "plugins/hook-chain-odd.py")
|
||||
p2 = os.path.join(os.path.dirname(__file__), "plugins/hook-chain-even.py")
|
||||
perm = [
|
||||
(p0, p1, p2), # Crashing plugin is first in chain
|
||||
(p1, p0, p2), # Crashing plugin is in the middle of the chain
|
||||
(p1, p2, p0), # Crashing plugin is last in chain
|
||||
]
|
||||
|
||||
l1 = node_factory.get_node()
|
||||
nodes = [node_factory.get_node() for _ in perm]
|
||||
|
||||
# Start them in any order and we should still always end up with each
|
||||
# plugin being called and ultimately the `pay` call should succeed:
|
||||
for plugins, n in zip(perm, nodes):
|
||||
for p in plugins:
|
||||
n.rpc.plugin_start(p)
|
||||
l1.openchannel(n, 10**6, confirm=False, wait_for_announce=False)
|
||||
|
||||
bitcoind.generate_block(6)
|
||||
|
||||
wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 2 * len(perm))
|
||||
|
||||
futures = []
|
||||
for n in nodes:
|
||||
inv = n.rpc.invoice(123, "lbl", "desc")['bolt11']
|
||||
futures.append(executor.submit(l1.rpc.pay, inv))
|
||||
|
||||
for n in nodes:
|
||||
n.daemon.wait_for_logs([
|
||||
r'Plugin is about to crash.',
|
||||
r'plugin-hook-chain-odd.py: htlc_accepted called for payment_hash',
|
||||
r'plugin-hook-chain-even.py: htlc_accepted called for payment_hash',
|
||||
])
|
||||
|
||||
# Collect the results:
|
||||
[f.result(TIMEOUT) for f in futures]
|
||||
|
|
Loading…
Reference in New Issue