diff --git a/tests/plugins/test_libplugin.c b/tests/plugins/test_libplugin.c index 00f0c3196..21722ab0f 100644 --- a/tests/plugins/test_libplugin.c +++ b/tests/plugins/test_libplugin.c @@ -6,11 +6,31 @@ #include #include - -const char *name_option; +static const char *somearg; static bool self_disable = false; static bool dont_shutdown = false; +static struct command_result *get_ds_done(struct command *cmd, + const char *val, + char *arg) +{ + if (!val) + val = "NOT FOUND"; + return command_success(cmd, json_out_obj(cmd, arg, val)); +} + +static struct command_result *get_ds_bin_done(struct command *cmd, + const u8 *val, + char *arg) +{ + plugin_log(cmd->plugin, LOG_INFORM, "get_ds_bin_done: %s", + val ? tal_hex(tmpctx, val) : "NOT FOUND"); + + return jsonrpc_get_datastore_string(cmd->plugin, cmd, + "test_libplugin/name", + get_ds_done, arg); +} + static struct command_result *json_helloworld(struct command *cmd, const char *buf, const jsmntok_t *params) @@ -23,8 +43,12 @@ static struct command_result *json_helloworld(struct command *cmd, return command_param_failed(); plugin_notify_message(cmd, LOG_INFORM, "Notification from %s", "json_helloworld"); + if (!name) - name = name_option ? name_option : tal_strdup(tmpctx, "world"); + return jsonrpc_get_datastore_binary(cmd->plugin, cmd, + "test_libplugin/name", + get_ds_bin_done, + "hello"); return command_success(cmd, json_out_obj(cmd, "hello", name)); } @@ -103,28 +127,37 @@ static struct command_result *json_testrpc(struct command *cmd, return send_outreq(cmd->plugin, req); } -#if DEVELOPER -static void memleak_mark(struct plugin *p, struct htable *memtable) -{ - /* name_option is not a leak! */ - memleak_ptr(memtable, name_option); -} -#endif /* DEVELOPER */ - static const char *init(struct plugin *p, const char *buf UNUSED, const jsmntok_t *config UNUSED) { + const char *name; + const u8 *binname; + plugin_log(p, LOG_DBG, "test_libplugin initialised!"); + if (somearg) + plugin_log(p, LOG_DBG, "somearg = %s", somearg); + somearg = tal_free(somearg); if (self_disable) return "Disabled via selfdisable option"; -#if DEVELOPER - plugin_set_memleak_handler(p, memleak_mark); -#endif + /* Test rpc_scan_datastore funcs */ + if (!rpc_scan_datastore_str(p, "test_libplugin/name", + JSON_SCAN_TAL(tmpctx, json_strdup, + &name))) + name = NULL; + if (!rpc_scan_datastore_hex(p, "test_libplugin/name", + JSON_SCAN_TAL(tmpctx, json_tok_bin_from_hex, + &binname))) + binname = NULL; - return NULL; + plugin_log(p, LOG_INFORM, "String name from datastore: %s", + name ? name : "NOT FOUND"); + plugin_log(p, LOG_INFORM, "Hex name from datastore: %s", + binname ? tal_hex(tmpctx, binname) : "NOT FOUND"); + + return NULL; } static const struct plugin_command commands[] = { { @@ -180,14 +213,14 @@ int main(int argc, char *argv[]) commands, ARRAY_SIZE(commands), notifs, ARRAY_SIZE(notifs), hooks, ARRAY_SIZE(hooks), NULL, 0, /* Notification topics we publish */ - plugin_option("name", + plugin_option("somearg", "string", - "Who to say hello to.", - charp_option, &name_option), - plugin_option_deprecated("name-deprecated", + "Argument to print at init.", + charp_option, &somearg), + plugin_option_deprecated("somearg-deprecated", "string", - "Who to say hello to.", - charp_option, &name_option), + "Deprecated arg for init.", + charp_option, &somearg), plugin_option("selfdisable", "flag", "Whether to disable.", diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 98ddec31b..aeb54cef5 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -1490,12 +1490,22 @@ def test_libplugin(node_factory): plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") l1 = node_factory.get_node(options={"plugin": plugin, 'allow-deprecated-apis': False, - 'log-level': 'io'}) + 'log-level': 'io'}, + allow_broken_log=True) # Test startup assert l1.daemon.is_in_log("test_libplugin initialised!") + assert l1.daemon.is_in_log("String name from datastore: NOT FOUND") + assert l1.daemon.is_in_log("Hex name from datastore: NOT FOUND") + + # This will look on datastore for default, won't find it. + assert l1.rpc.call("helloworld") == {"hello": "NOT FOUND"} + l1.daemon.wait_for_log("get_ds_bin_done: NOT FOUND") + # Test dynamic startup l1.rpc.plugin_stop(plugin) + # Non-string datastore value: + l1.rpc.datastore(["test_libplugin", "name"], hex="00010203") l1.rpc.plugin_start(plugin) l1.rpc.check("helloworld") @@ -1505,14 +1515,24 @@ def test_libplugin(node_factory): # yet whether strings are allowed: l1.daemon.wait_for_log(r"test_libplugin: [0-9]*\[OUT\]") + l1.daemon.wait_for_log("String name from datastore: NOT FOUND") + l1.daemon.wait_for_log("Hex name from datastore: 00010203") + # Test commands - assert l1.rpc.call("helloworld") == {"hello": "world"} + assert l1.rpc.call("helloworld") == {"hello": "NOT FOUND"} + l1.daemon.wait_for_log("get_ds_bin_done: 00010203") + l1.daemon.wait_for_log("BROKEN.* Datastore gave nonstring result.*00010203") assert l1.rpc.call("helloworld", {"name": "test"}) == {"hello": "test"} l1.stop() l1.daemon.opts["plugin"] = plugin - l1.daemon.opts["name"] = "test_opt" + l1.daemon.opts["somearg"] = "test_opt" l1.start() - assert l1.rpc.call("helloworld") == {"hello": "test_opt"} + assert l1.daemon.is_in_log("somearg = test_opt") + l1.rpc.datastore(["test_libplugin", "name"], "foobar", mode="must-replace") + + assert l1.rpc.call("helloworld") == {"hello": "foobar"} + l1.daemon.wait_for_log("get_ds_bin_done: 666f6f626172") + # But param takes over! assert l1.rpc.call("helloworld", {"name": "test"}) == {"hello": "test"} @@ -1536,17 +1556,17 @@ def test_libplugin(node_factory): with pytest.raises(RpcError, match=r"Deprecated command.*testrpc-deprecated"): l1.rpc.help('testrpc-deprecated') - assert 'name-deprecated' not in str(l1.rpc.listconfigs()) + assert 'somearg-deprecated' not in str(l1.rpc.listconfigs()) l1.stop() - l1.daemon.opts["name-deprecated"] = "test_opt" + l1.daemon.opts["somearg-deprecated"] = "test_opt" l1.daemon.start(wait_for_initialized=False, stderr_redir=True) # Will exit with failure code. assert l1.daemon.wait() == 1 - assert l1.daemon.is_in_stderr(r"name-deprecated: deprecated option") + assert l1.daemon.is_in_stderr(r"somearg-deprecated: deprecated option") - del l1.daemon.opts["name-deprecated"] + del l1.daemon.opts["somearg-deprecated"] l1.start() @@ -1554,10 +1574,10 @@ def test_libplugin_deprecated(node_factory): """Sanity checks for plugins made with libplugin using deprecated args""" plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") l1 = node_factory.get_node(options={"plugin": plugin, - 'name-deprecated': 'test_opt depr', + 'somearg-deprecated': 'test_opt depr', 'allow-deprecated-apis': True}) - assert l1.rpc.call("helloworld") == {"hello": "test_opt depr"} + assert l1.daemon.is_in_log("somearg = test_opt depr") l1.rpc.help('testrpc-deprecated') assert l1.rpc.call("testrpc-deprecated") == l1.rpc.getinfo()