tests: make test_libplugin use the datastore.

It's a bit convoluted, but it exercises all our datastore fetch APIs.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2022-12-12 14:44:15 +10:30
committed by Christian Decker
parent 7b24ea60e3
commit d1b5943e90
2 changed files with 84 additions and 31 deletions

View File

@@ -6,11 +6,31 @@
#include <common/memleak.h> #include <common/memleak.h>
#include <plugins/libplugin.h> #include <plugins/libplugin.h>
static const char *somearg;
const char *name_option;
static bool self_disable = false; static bool self_disable = false;
static bool dont_shutdown = 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, static struct command_result *json_helloworld(struct command *cmd,
const char *buf, const char *buf,
const jsmntok_t *params) const jsmntok_t *params)
@@ -23,8 +43,12 @@ static struct command_result *json_helloworld(struct command *cmd,
return command_param_failed(); return command_param_failed();
plugin_notify_message(cmd, LOG_INFORM, "Notification from %s", "json_helloworld"); plugin_notify_message(cmd, LOG_INFORM, "Notification from %s", "json_helloworld");
if (!name) 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)); return command_success(cmd, json_out_obj(cmd, "hello", name));
} }
@@ -103,26 +127,35 @@ static struct command_result *json_testrpc(struct command *cmd,
return send_outreq(cmd->plugin, req); 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, static const char *init(struct plugin *p,
const char *buf UNUSED, const char *buf UNUSED,
const jsmntok_t *config UNUSED) const jsmntok_t *config UNUSED)
{ {
const char *name;
const u8 *binname;
plugin_log(p, LOG_DBG, "test_libplugin initialised!"); 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) if (self_disable)
return "Disabled via selfdisable option"; return "Disabled via selfdisable option";
#if DEVELOPER /* Test rpc_scan_datastore funcs */
plugin_set_memleak_handler(p, memleak_mark); if (!rpc_scan_datastore_str(p, "test_libplugin/name",
#endif 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;
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; return NULL;
} }
@@ -180,14 +213,14 @@ int main(int argc, char *argv[])
commands, ARRAY_SIZE(commands), commands, ARRAY_SIZE(commands),
notifs, ARRAY_SIZE(notifs), hooks, ARRAY_SIZE(hooks), notifs, ARRAY_SIZE(notifs), hooks, ARRAY_SIZE(hooks),
NULL, 0, /* Notification topics we publish */ NULL, 0, /* Notification topics we publish */
plugin_option("name", plugin_option("somearg",
"string", "string",
"Who to say hello to.", "Argument to print at init.",
charp_option, &name_option), charp_option, &somearg),
plugin_option_deprecated("name-deprecated", plugin_option_deprecated("somearg-deprecated",
"string", "string",
"Who to say hello to.", "Deprecated arg for init.",
charp_option, &name_option), charp_option, &somearg),
plugin_option("selfdisable", plugin_option("selfdisable",
"flag", "flag",
"Whether to disable.", "Whether to disable.",

View File

@@ -1490,12 +1490,22 @@ def test_libplugin(node_factory):
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
l1 = node_factory.get_node(options={"plugin": plugin, l1 = node_factory.get_node(options={"plugin": plugin,
'allow-deprecated-apis': False, 'allow-deprecated-apis': False,
'log-level': 'io'}) 'log-level': 'io'},
allow_broken_log=True)
# Test startup # Test startup
assert l1.daemon.is_in_log("test_libplugin initialised!") 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 # Test dynamic startup
l1.rpc.plugin_stop(plugin) l1.rpc.plugin_stop(plugin)
# Non-string datastore value:
l1.rpc.datastore(["test_libplugin", "name"], hex="00010203")
l1.rpc.plugin_start(plugin) l1.rpc.plugin_start(plugin)
l1.rpc.check("helloworld") l1.rpc.check("helloworld")
@@ -1505,14 +1515,24 @@ def test_libplugin(node_factory):
# yet whether strings are allowed: # yet whether strings are allowed:
l1.daemon.wait_for_log(r"test_libplugin: [0-9]*\[OUT\]") 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 # 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"} assert l1.rpc.call("helloworld", {"name": "test"}) == {"hello": "test"}
l1.stop() l1.stop()
l1.daemon.opts["plugin"] = plugin l1.daemon.opts["plugin"] = plugin
l1.daemon.opts["name"] = "test_opt" l1.daemon.opts["somearg"] = "test_opt"
l1.start() 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! # But param takes over!
assert l1.rpc.call("helloworld", {"name": "test"}) == {"hello": "test"} 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"): with pytest.raises(RpcError, match=r"Deprecated command.*testrpc-deprecated"):
l1.rpc.help('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.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) l1.daemon.start(wait_for_initialized=False, stderr_redir=True)
# Will exit with failure code. # Will exit with failure code.
assert l1.daemon.wait() == 1 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() l1.start()
@@ -1554,10 +1574,10 @@ def test_libplugin_deprecated(node_factory):
"""Sanity checks for plugins made with libplugin using deprecated args""" """Sanity checks for plugins made with libplugin using deprecated args"""
plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") plugin = os.path.join(os.getcwd(), "tests/plugins/test_libplugin")
l1 = node_factory.get_node(options={"plugin": plugin, l1 = node_factory.get_node(options={"plugin": plugin,
'name-deprecated': 'test_opt depr', 'somearg-deprecated': 'test_opt depr',
'allow-deprecated-apis': True}) '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') l1.rpc.help('testrpc-deprecated')
assert l1.rpc.call("testrpc-deprecated") == l1.rpc.getinfo() assert l1.rpc.call("testrpc-deprecated") == l1.rpc.getinfo()