mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-17 19:03:42 +01:00
pyln: add support for dependent hooks.
And use that to add simple tests. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
6a55b4367e
commit
e16ed0e207
@ -57,6 +57,8 @@ class Method(object):
|
||||
self.desc = desc
|
||||
self.long_desc = long_desc
|
||||
self.deprecated = deprecated
|
||||
self.before: List[str] = []
|
||||
self.after: List[str] = []
|
||||
|
||||
|
||||
class Request(dict):
|
||||
@ -405,7 +407,9 @@ class Plugin(object):
|
||||
return decorator
|
||||
|
||||
def add_hook(self, name: str, func: Callable[..., JSONType],
|
||||
background: bool = False) -> None:
|
||||
background: bool = False,
|
||||
before: Optional[List[str]] = None,
|
||||
after: Optional[List[str]] = None) -> None:
|
||||
"""Register a hook that is called synchronously by lightningd on events
|
||||
"""
|
||||
if name in self.methods:
|
||||
@ -427,15 +431,23 @@ class Plugin(object):
|
||||
|
||||
method = Method(name, func, MethodType.HOOK)
|
||||
method.background = background
|
||||
method.before = []
|
||||
if before:
|
||||
method.before = before
|
||||
method.after = []
|
||||
if after:
|
||||
method.after = after
|
||||
self.methods[name] = method
|
||||
|
||||
def hook(self, method_name: str) -> JsonDecoratorType:
|
||||
def hook(self, method_name: str,
|
||||
before: List[str] = None,
|
||||
after: List[str] = None) -> JsonDecoratorType:
|
||||
"""Decorator to add a plugin hook to the dispatch table.
|
||||
|
||||
Internally uses add_hook.
|
||||
"""
|
||||
def decorator(f: Callable[..., JSONType]) -> Callable[..., JSONType]:
|
||||
self.add_hook(method_name, f, background=False)
|
||||
self.add_hook(method_name, f, background=False, before=before, after=after)
|
||||
return f
|
||||
return decorator
|
||||
|
||||
@ -689,7 +701,9 @@ class Plugin(object):
|
||||
continue
|
||||
|
||||
if method.mtype == MethodType.HOOK:
|
||||
hooks.append(method.name)
|
||||
hooks.append({'name': method.name,
|
||||
'before': method.before,
|
||||
'after': method.after})
|
||||
continue
|
||||
|
||||
doc = inspect.getdoc(method.func)
|
||||
|
15
tests/plugins/dep_a.py
Executable file
15
tests/plugins/dep_a.py
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
from pyln.client import Plugin
|
||||
|
||||
"""A simple plugin that must come before dep_b.
|
||||
"""
|
||||
plugin = Plugin()
|
||||
|
||||
|
||||
@plugin.hook('htlc_accepted', before=['dep_b.py'])
|
||||
def on_htlc_accepted(htlc, plugin, **kwargs):
|
||||
print("htlc_accepted called")
|
||||
return {'result': 'continue'}
|
||||
|
||||
|
||||
plugin.run()
|
15
tests/plugins/dep_b.py
Executable file
15
tests/plugins/dep_b.py
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
from pyln.client import Plugin
|
||||
|
||||
"""A simple plugin that must come after dep_a, before dep_c.
|
||||
"""
|
||||
plugin = Plugin()
|
||||
|
||||
|
||||
@plugin.hook('htlc_accepted', before=['dep_c.py'], after=['dep_a.py'])
|
||||
def on_htlc_accepted(htlc, plugin, **kwargs):
|
||||
print("htlc_accepted called")
|
||||
return {'result': 'continue'}
|
||||
|
||||
|
||||
plugin.run()
|
15
tests/plugins/dep_c.py
Executable file
15
tests/plugins/dep_c.py
Executable file
@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
from pyln.client import Plugin
|
||||
|
||||
"""A simple plugin that must come before dep_a.
|
||||
"""
|
||||
plugin = Plugin()
|
||||
|
||||
|
||||
@plugin.hook('htlc_accepted', before=['dep_a.py'])
|
||||
def on_htlc_accepted(htlc, plugin, **kwargs):
|
||||
print("htlc_accepted called")
|
||||
return {'result': 'continue'}
|
||||
|
||||
|
||||
plugin.run()
|
@ -2075,3 +2075,26 @@ def test_htlc_accepted_hook_failcodes(node_factory):
|
||||
inv = l2.rpc.invoice(42, 'failcode{}'.format(failcode), '')['bolt11']
|
||||
with pytest.raises(RpcError, match=r'failcodename.: .{}.'.format(expected)):
|
||||
l1.rpc.pay(inv)
|
||||
|
||||
|
||||
def test_hook_dep(node_factory):
|
||||
dep_a = os.path.join(os.path.dirname(__file__), 'plugins/dep_a.py')
|
||||
dep_b = os.path.join(os.path.dirname(__file__), 'plugins/dep_b.py')
|
||||
dep_c = os.path.join(os.path.dirname(__file__), 'plugins/dep_c.py')
|
||||
l1, l2 = node_factory.line_graph(2, opts=[{}, {'plugin': dep_b}])
|
||||
|
||||
# A says it has to be before B.
|
||||
l2.rpc.plugin_start(plugin=dep_a)
|
||||
l2.daemon.wait_for_log(r"started.*dep_a.py")
|
||||
|
||||
l1.pay(l2, 100000)
|
||||
# They must be called in this order!
|
||||
l2.daemon.wait_for_log(r"dep_a.py: htlc_accepted called")
|
||||
l2.daemon.wait_for_log(r"dep_b.py: htlc_accepted called")
|
||||
|
||||
# But depc will not load, due to cyclical dep
|
||||
with pytest.raises(RpcError, match=r'Cannot correctly order hook htlc_accepted'):
|
||||
l2.rpc.plugin_start(plugin=dep_c)
|
||||
|
||||
l1.rpc.plugin_start(plugin=dep_c)
|
||||
l1.daemon.wait_for_log(r"started.*dep_c.py")
|
||||
|
Loading…
Reference in New Issue
Block a user