Add support for executing RPCs
Creating a temporary YangAccess for RPC input means I need to somehow
give the right libyang schemas. For that reason I supply a callable
which is able to fetch the schema and create a YangAccess instance for
ProxyDatastore.
The ProxyDatastore class now has a simple mechanism for deciding whether
to use the normal datastore and the temporary based on a path prefix.
Change-Id: Ib455f53237598bc2620161a44fb89c48ddfeb6e3
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index b45f027..fb44018 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -8,6 +8,8 @@
#include "trompeloeil_doctest.hpp"
#include <sysrepo-cpp/Session.hpp>
+#include "yang_schema.hpp"
+#include "proxy_datastore.hpp"
#ifdef sysrepo_BACKEND
#include "sysrepo_access.hpp"
@@ -831,9 +833,11 @@
int rpc(const char *xpath, const ::sysrepo::S_Vals input, ::sysrepo::S_Vals_Holder output, void *) override
{
const auto nukes = "/example-schema:launch-nukes"s;
- if (xpath == "/example-schema:noop"s) {
+ if (xpath == "/example-schema:noop"s || xpath == "/example-schema:fire"s) {
return SR_ERR_OK;
- } else if (xpath == nukes) {
+ }
+
+ if (xpath == nukes) {
uint64_t kilotons = 0;
bool hasCities = false;
for (size_t i = 0; i < input->val_cnt(); ++i) {
@@ -879,21 +883,32 @@
auto srSubscription = std::make_shared<sysrepo::Subscribe>(srSession);
auto cb = std::make_shared<RpcCb>();
sysrepo::Logs{}.set_stderr(SR_LL_INF);
+ auto doNothingCb = std::make_shared<sysrepo::Callback>();
+ srSubscription->module_change_subscribe("example-schema", doNothingCb, nullptr, SR_SUBSCR_CTX_REUSE);
+ // careful here, sysrepo insists on module_change CBs being registered before RPC CBs, otherwise there's a memleak
srSubscription->rpc_subscribe("/example-schema:noop", cb, nullptr, SR_SUBSCR_CTX_REUSE);
srSubscription->rpc_subscribe("/example-schema:launch-nukes", cb, nullptr, SR_SUBSCR_CTX_REUSE);
+ srSubscription->rpc_subscribe("/example-schema:fire", cb, nullptr, SR_SUBSCR_CTX_REUSE);
#ifdef sysrepo_BACKEND
- SysrepoAccess datastore("netconf-cli-test", Datastore::Running);
+ auto datastore = std::make_shared<SysrepoAccess>("netconf-cli-test", Datastore::Running);
#elif defined(netconf_BACKEND)
- NetconfAccess datastore(NETOPEER_SOCKET_PATH);
+ auto datastore = std::make_shared<NetconfAccess>(NETOPEER_SOCKET_PATH);
#elif defined(yang_BACKEND)
- YangAccess datastore;
- datastore.addSchemaDir(schemaDir);
- datastore.addSchemaFile(exampleSchemaFile);
+ auto datastore = std::make_shared<YangAccess>();
+ datastore->addSchemaDir(schemaDir);
+ datastore->addSchemaFile(exampleSchemaFile);
#else
#error "Unknown backend"
#endif
+ auto createTemporaryDatastore = [](const std::shared_ptr<DatastoreAccess>& datastore) {
+ return std::make_shared<YangAccess>(std::static_pointer_cast<YangSchema>(datastore->schema()));
+ };
+
+ ProxyDatastore proxyDatastore(datastore, createTemporaryDatastore);
+
+ // ProxyDatastore cannot easily read DatastoreAccess::Tree, so we need to set the input via create/setLeaf/etc.
SECTION("valid")
{
std::string rpc;
@@ -901,6 +916,7 @@
SECTION("noop") {
rpc = "/example-schema:noop";
+ proxyDatastore.initiateRpc(rpc);
}
SECTION("small nuke") {
@@ -909,6 +925,8 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{333'666}},
};
+ proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{333'666});
// no data are returned
}
@@ -918,6 +936,9 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{4}},
};
+ proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{4});
+
output = {
{"blast-radius", uint32_t{33'666}},
{"actual-yield", uint64_t{5}},
@@ -930,6 +951,9 @@
{"payload/kilotons", uint64_t{6}},
{"cities/targets[city='Prague']/city", "Prague"s},
};
+ proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{6});
+ proxyDatastore.createItem("/example-schema:launch-nukes/example-schema:cities/example-schema:targets[city='Prague']");
output = {
{"blast-radius", uint32_t{33'666}},
{"actual-yield", uint64_t{7}},
@@ -941,12 +965,25 @@
};
}
- catching<OnRPC>([&] {REQUIRE(datastore.executeRpc(rpc, input) == output);});
+ SECTION("with leafref") {
+ datastore->createItem("/example-schema:person[name='Colton']");
+ datastore->commitChanges();
+
+ rpc = "/example-schema:fire";
+ input = {
+ {"whom", "Colton"s}
+ };
+ proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.setLeaf("/example-schema:fire/example-schema:whom", "Colton"s);
+ }
+
+ catching<OnRPC>([&] {REQUIRE(datastore->executeRpc(rpc, input) == output);});
+ catching<OnRPC>([&] {REQUIRE(proxyDatastore.executeRpc() == output);});
}
SECTION("non-existing RPC")
{
- catching<OnInvalidRpcPath>([&] {datastore.executeRpc("/example-schema:non-existing", DatastoreAccess::Tree{});});
+ catching<OnInvalidRpcPath>([&] {datastore->executeRpc("/example-schema:non-existing", DatastoreAccess::Tree{});});
}
waitForCompletionAndBitMore(seq1);