Skip to content

pyln-testing: don't let wait_for_log match its own forwarded announcement#9344

Open
ksedgwic wants to merge 1 commit into
ElementsProject:masterfrom
ksedgwic:fix-inline-plugin-log-selfmatch
Open

pyln-testing: don't let wait_for_log match its own forwarded announcement#9344
ksedgwic wants to merge 1 commit into
ElementsProject:masterfrom
ksedgwic:fix-inline-plugin-log-selfmatch

Conversation

@ksedgwic

Copy link
Copy Markdown
Collaborator

Fixes #9343.

An inline plugin's Plugin() lives in the test process, and Plugin() installs a PluginLogHandler on the root logger so a plugin author's logging calls reach lightningd. In the test process that handler also forwards pyln's own machinery logs into the node's log whenever the test-side logger emits at DEBUG. wait_for_logs() announces Waiting for [pattern] with the pattern embedded verbatim, so the announcement lands in the very log being scanned and matches itself - the wait silently becomes a no-op. That is what let test_sendpay_notifications_nowaiter race its channel close against the first payment (assert 0 == 1); any literal-pattern wait_for_log on an inline-plugin node is similarly voided under DEBUG logging, which can mask races in tests that currently pass.

The fix attaches a filter to the inline plugin's log handler that only forwards records originating outside the pyln packages: author logging still reaches the node log, pyln internals never do.

The new test proves both directions and reproduces the bug deterministically: before the fix it fails with DID NOT RAISE TimeoutError (the sentinel wait matched its own announcement); after it, an author-logged marker is still found while the never-logged sentinel genuinely times out.

@ksedgwic
ksedgwic requested a review from cdecker as a code owner July 21, 2026 22:41
@ksedgwic
ksedgwic requested a review from daywalker90 July 22, 2026 15:51
@daywalker90

Copy link
Copy Markdown
Collaborator
=================================== FAILURES ===================================
_________________ test_inline_plugin_wait_for_log_no_selfmatch _________________
[gw0] linux -- Python 3.10.20 /home/runner/work/lightning/lightning/.venv/bin/python

node_factory = <pyln.testing.utils.NodeFactory object at 0x7f8fe41b0fa0>

    def test_inline_plugin_wait_for_log_no_selfmatch(node_factory):
        """On inline-plugin nodes the test process's logging is forwarded into
        the node's log.  wait_for_log()'s own 'Waiting for [pattern]'
        announcement embeds the pattern, so with test logging at DEBUG it used
        to land in the scanned log and match itself, reducing the wait to a
        no-op (#9343).  A pattern that never appears must genuinely time out.
        """
        def setup(plugin):
            @plugin.method('inline_ping')
            def inline_ping(plugin):
                logging.info("AUTHOR_LOG_MARKER_9343")
                return {'pong': True}
    
>       l1 = node_factory.get_node(inline_plugin=setup)

tests/test_plugin.py:1817: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
contrib/pyln-testing/pyln/testing/utils.py:1898: in get_node
    _inline_plugin(node, inline_plugin)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

node = <fixtures.LightningNode object at 0x7f8ffe6e3fd0>
setup_fn = <function test_inline_plugin_wait_for_log_no_selfmatch.<locals>.setup at 0x7f8fff4ca560>

    def _inline_plugin(node, setup_fn):
        """Set up an inline plugin serve thread for a not-yet-started node.
    
        Normally called via get_node(inline_plugin=setup_fn).  The plugin's cwd
        (set by lightningd) is node.daemon.lightning_dir/TEST_NETWORK/, which is
        where the shim looks for inline-plugin.sock.
    
        Example::
    
            def setup(plugin):
                @plugin.method('greet')
                def greet(name, plugin):
                    return {'message': f'hello {name}'}
    
            l1 = node_factory.get_node(inline_plugin=setup)
            assert l1.rpc.greet('world') == {'message': 'hello world'}
        """
        sock_path = os.path.join(node.daemon.lightning_dir, TEST_NETWORK, 'inline-plugin.sock')
        srv = socket.socket(socket.AF_UNIX)
>       srv.bind(sock_path)
E       OSError: AF_UNIX path too long

contrib/pyln-testing/pyln/testing/utils.py:2055: OSError
----------------------------- Captured stdout call -----------------------------
{'run_id': 338097548104253440, 'github_repository': 'ElementsProject/lightning', 'github_sha': '751601e833243e0791cdaee4ca3cf428123d3f8b', 'github_ref': 'refs/pull/9344/merge', 'github_ref_name': 'HEAD', 'github_run_id': 29874630952, 'github_head_ref': 'fix-inline-plugin-log-selfmatch', 'github_run_number': 17275, 'github_base_ref': 'master', 'github_run_attempt': '1', 'testname': 'test_inline_plugin_wait_for_log_no_selfmatch', 'start_time': 1784678189, 'end_time': 1784678189, 'outcome': 'fail'}
----- generated xml file: /home/runner/work/lightning/lightning/report.xml -----
============================= slowest 10 durations =============================
475.22s call     test_connection.py::test_networkevents
241.39s call     test_plugin.py::test_plugin_startdir_lol
240.74s call     test_gossip.py::test_gossip_pruning
204.50s call     test_gossip.py::test_gossip_force_broadcast_channel_msgs
149.41s call     test_gossip.py::test_gossip_query_channel_range
129.42s call     test_connection.py::test_last_stable_connection
129.14s call     test_currencyrate.py::test_bkpr_currencyrate_warns_for_old_events
122.48s call     test_plugin.py::test_plugin_command
120.75s call     test_plugin.py::test_plugin_slowinit
120.28s call     test_plugin.py::test_failing_plugins
=========================== short test summary info ============================
FAILED tests/test_plugin.py::test_inline_plugin_wait_for_log_no_selfmatch - OSError: AF_UNIX path too long

AF_UNIX path too long :/

…ment

An inline plugin's Plugin() object lives in the test process, and
Plugin() installs a PluginLogHandler on the root logger so that a
plugin author's `logging` calls reach lightningd.  In the test process
that handler also forwards pyln's own machinery logs into the node's
log whenever the test-side logger emits at DEBUG.  In particular
wait_for_logs() announces 'Waiting for [pattern]' with the pattern
embedded verbatim, so the announcement lands in the very log being
scanned and matches itself, silently reducing the wait to a no-op.
That let test_sendpay_notifications_nowaiter race its channel close
against the first payment (both payments then fail and the success
assertion sees an empty list); any literal-pattern wait_for_log on an
inline-plugin node is similarly voided under DEBUG logging.

Attach a filter to the inline plugin's log handler that only forwards
records originating outside the pyln packages, so author logging still
reaches the node log but pyln internals never do.

The new test covers both directions: an author log line is found by
wait_for_log, and a never-logged sentinel genuinely times out (it
matched instantly via the forwarded announcement before this fix).

The node directory embeds the test name, and this test's long name
pushed the inline-plugin.sock path past Linux's 108-byte AF_UNIX
limit on the liquid-regtest CI run.  Teach _inline_plugin() to fall
back to binding through a directory fd alias under /proc/self/fd, the
bind-side analogue of UnixSocket.connect's existing workaround; the
socket file still lands where the shim's cwd-relative connect expects
it.

Fixes: ElementsProject#9343
Changelog-None
@ksedgwic
ksedgwic force-pushed the fix-inline-plugin-log-selfmatch branch from 2a59c49 to c23ecc1 Compare July 23, 2026 18:28
@ksedgwic

Copy link
Copy Markdown
Collaborator Author

Force-pushed: rebased on current master and fixed the liquid CI failure above.

The test's long name pushed the inline-plugin.sock path past Linux's 108-byte AF_UNIX limit (the node directory embeds the test name, and liquid-regtest is 7 chars longer than regtest, which fit at 106). _inline_plugin() now falls back to binding through a directory fd alias under /proc/self/fd when the direct bind fails, the bind-side analogue of UnixSocket.connect's existing long-path workaround. Verified locally with the default short path and with TEST_DIR padded past the limit to force the fallback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flaky test_sendpay_notifications_nowaiter: wait_for_log self-matches its own forwarded announcement on inline-plugin nodes

2 participants