Merge "tests: Shorten paths to the NETCONF listening socket"
diff --git a/src/datastore_access.hpp b/src/datastore_access.hpp
index 057c96a..b29e152 100644
--- a/src/datastore_access.hpp
+++ b/src/datastore_access.hpp
@@ -50,8 +50,7 @@
virtual void createItem(const std::string& path) = 0;
virtual void deleteItem(const std::string& path) = 0;
virtual void moveItem(const std::string& path, std::variant<yang::move::Absolute, yang::move::Relative> move) = 0;
- virtual Tree executeRpc(const std::string& path, const Tree& input) = 0;
- virtual Tree executeAction(const std::string& path, const Tree& input) = 0;
+ virtual Tree execute(const std::string& path, const Tree& input) = 0;
virtual std::shared_ptr<Schema> schema() = 0;
diff --git a/src/interpreter.cpp b/src/interpreter.cpp
index f1682bf..acb3f0b 100644
--- a/src/interpreter.cpp
+++ b/src/interpreter.cpp
@@ -216,11 +216,7 @@
void Interpreter::operator()(const prepare_& prepare) const
{
- if (std::holds_alternative<rpcNode_>(prepare.m_path.m_nodes.back().m_suffix)) {
- m_datastore.initiateRpc(pathToString(toCanonicalPath(prepare.m_path)));
- } else {
- m_datastore.initiateAction(pathToString(toCanonicalPath(prepare.m_path)));
- }
+ m_datastore.initiate(pathToString(toCanonicalPath(prepare.m_path)));
m_parser.changeNode(prepare.m_path);
}
diff --git a/src/leaf_data.hpp b/src/leaf_data.hpp
index 7bab723..df0f9b3 100644
--- a/src/leaf_data.hpp
+++ b/src/leaf_data.hpp
@@ -162,6 +162,7 @@
parser.add(bit, bit);
parserContext.m_suggestions.insert(Completion{bit});
}
+ parserContext.m_completionIterator = first;
std::vector<std::string> bitsRes;
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index 1e56659..4ed29ae 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -132,7 +132,7 @@
m_session->discard();
}
-DatastoreAccess::Tree NetconfAccess::impl_execute(const std::string& path, const Tree& input)
+DatastoreAccess::Tree NetconfAccess::execute(const std::string& path, const Tree& input)
{
auto root = m_schema->dataNodeFromPath(path);
for (const auto& [k, v] : input) {
@@ -149,16 +149,6 @@
return res;
}
-DatastoreAccess::Tree NetconfAccess::executeRpc(const std::string& path, const Tree& input)
-{
- return impl_execute(path, input);
-}
-
-DatastoreAccess::Tree NetconfAccess::executeAction(const std::string& path, const Tree& input)
-{
- return impl_execute(path, input);
-}
-
NC_DATASTORE toNcDatastore(Datastore datastore)
{
switch (datastore) {
diff --git a/src/netconf_access.hpp b/src/netconf_access.hpp
index 45973a6..c54434d 100644
--- a/src/netconf_access.hpp
+++ b/src/netconf_access.hpp
@@ -47,8 +47,7 @@
void moveItem(const std::string& path, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
void commitChanges() override;
void discardChanges() override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ Tree execute(const std::string& path, const Tree& input) override;
void copyConfig(const Datastore source, const Datastore destination) override;
std::shared_ptr<Schema> schema() override;
@@ -57,14 +56,12 @@
private:
std::vector<ListInstance> listInstances(const std::string& path) override;
- DatastoreAccess::Tree impl_execute(const std::string& path, const Tree& input);
std::string fetchSchema(const std::string_view module, const
std::optional<std::string_view> revision, const
std::optional<std::string_view> submodule, const
std::optional<std::string_view> submoduleRevision);
std::vector<std::string> listImplementedSchemas();
- void datastoreInit();
void doEditFromDataNode(std::shared_ptr<libyang::Data_Node> dataNode);
std::unique_ptr<libnetconf::client::Session> m_session;
diff --git a/src/path_parser.hpp b/src/path_parser.hpp
index fca760d..58d174e 100644
--- a/src/path_parser.hpp
+++ b/src/path_parser.hpp
@@ -76,10 +76,8 @@
{
}
- // GCC complains that `end` isn't used when doing completions only
- // FIXME: GCC 10.1 doesn't emit a warning here. Remove [[maybe_unused]] when GCC 10 is available
template <typename It, typename Ctx, typename RCtx, typename Attr>
- bool parse(It& begin, [[maybe_unused]] It end, Ctx const& ctx, RCtx& rctx, Attr& attr) const
+ bool parse(It& begin, It end, Ctx const& ctx, RCtx& rctx, Attr& attr) const
{
std::string tableName;
if constexpr (std::is_same<attribute_type, schemaNode_>()) {
@@ -165,12 +163,7 @@
if constexpr (PARSER_MODE == NodeParserMode::CompletionsOnly) {
return true;
} else {
- It saveIter;
- // GCC complains that I assign saveIter because I use it only if NodeType is dataNode_
- // FIXME: GCC 10.1 doesn't emit a warning here. Make this unconditional when GCC 10 is available.
- if constexpr (std::is_same<attribute_type, dataNode_>()) {
- saveIter = begin;
- }
+ It saveIter = begin;
auto res = table.parse(begin, end, ctx, rctx, attr);
diff --git a/src/proxy_datastore.cpp b/src/proxy_datastore.cpp
index 113a923..ef3c5db 100644
--- a/src/proxy_datastore.cpp
+++ b/src/proxy_datastore.cpp
@@ -59,34 +59,14 @@
return m_datastore->dump(format);
}
-namespace {
-struct getInputPath {
- template <typename InputType>
- auto operator()(const InputType& input)
- {
- return input.m_path;
- }
-};
-}
-
-void ProxyDatastore::initiateRpc(const std::string& rpcPath)
+void ProxyDatastore::initiate(const std::string& path)
{
if (m_inputDatastore) {
- throw std::runtime_error("RPC/action input already in progress (" + std::visit(getInputPath{}, m_inputPath) + ")");
+ throw std::runtime_error("RPC/action input already in progress (" + m_inputPath + ")");
}
m_inputDatastore = m_createTemporaryDatastore(m_datastore);
- m_inputPath = RpcInput{rpcPath};
- m_inputDatastore->createItem(rpcPath);
-}
-
-void ProxyDatastore::initiateAction(const std::string& actionPath)
-{
- if (m_inputDatastore) {
- throw std::runtime_error("RPC/action input already in progress (" + std::visit(getInputPath{}, m_inputPath) + ")");
- }
- m_inputDatastore = m_createTemporaryDatastore(m_datastore);
- m_inputPath = ActionInput{actionPath};
- m_inputDatastore->createItem(actionPath);
+ m_inputPath = path;
+ m_inputDatastore->createItem(path);
}
DatastoreAccess::Tree ProxyDatastore::execute()
@@ -96,11 +76,7 @@
}
auto inputData = m_inputDatastore->getItems("/");
m_inputDatastore = nullptr;
- if (std::holds_alternative<RpcInput>(m_inputPath)) {
- return m_datastore->executeRpc(std::visit(getInputPath{}, m_inputPath), inputData);
- } else {
- return m_datastore->executeAction(std::visit(getInputPath{}, m_inputPath), inputData);
- }
+ return m_datastore->execute(m_inputPath, inputData);
}
void ProxyDatastore::cancel()
@@ -115,7 +91,7 @@
std::shared_ptr<DatastoreAccess> ProxyDatastore::pickDatastore(const std::string& path) const
{
- if (!m_inputDatastore || !boost::starts_with(path, std::visit(getInputPath{}, m_inputPath))) {
+ if (!m_inputDatastore || !boost::starts_with(path, m_inputPath)) {
return m_datastore;
} else {
return m_inputDatastore;
diff --git a/src/proxy_datastore.hpp b/src/proxy_datastore.hpp
index e7650cd..ab7e3a2 100644
--- a/src/proxy_datastore.hpp
+++ b/src/proxy_datastore.hpp
@@ -29,8 +29,7 @@
void copyConfig(const Datastore source, const Datastore destination);
[[nodiscard]] std::string dump(const DataFormat format) const;
- void initiateRpc(const std::string& rpcPath);
- void initiateAction(const std::string& actionPath);
+ void initiate(const std::string& path);
[[nodiscard]] DatastoreAccess::Tree execute();
void cancel();
@@ -48,14 +47,5 @@
std::function<std::shared_ptr<DatastoreAccess>(const std::shared_ptr<DatastoreAccess>&)> m_createTemporaryDatastore;
std::shared_ptr<DatastoreAccess> m_inputDatastore;
- struct RpcInput {
- std::string m_path;
- };
-
- struct ActionInput {
- std::string m_path;
- };
- // This variant is needed, so that I know whether to call executeRpc or executeAction
- // TODO: get rid of this variant with sysrepo2 because the method for RPC/action is the same there
- std::variant<ActionInput, RpcInput> m_inputPath;
+ std::string m_inputPath;
};
diff --git a/src/python_netconf.cpp b/src/python_netconf.cpp
index 7a0e4d3..c6e3c44 100644
--- a/src/python_netconf.cpp
+++ b/src/python_netconf.cpp
@@ -70,7 +70,7 @@
.def("setLeaf", &NetconfAccess::setLeaf, "xpath"_a, "value"_a)
.def("createItem", &NetconfAccess::createItem, "xpath"_a)
.def("deleteItem", &NetconfAccess::deleteItem, "xpath"_a)
- .def("executeRpc", &NetconfAccess::executeRpc, "rpc"_a, "input"_a=DatastoreAccess::Tree{})
+ .def("execute", &NetconfAccess::execute, "rpc"_a, "input"_a=DatastoreAccess::Tree{})
.def("commitChanges", &NetconfAccess::commitChanges)
;
}
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 7c21cad..21eca7e 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -329,15 +329,7 @@
}
}
-// TODO: merge this with executeAction
-DatastoreAccess::Tree SysrepoAccess::executeRpc(const std::string& path, const Tree& input)
-{
- auto srInput = toSrVals(path, input);
- auto output = m_session->rpc_send(path.c_str(), srInput);
- return toTree(path, output);
-}
-
-DatastoreAccess::Tree SysrepoAccess::executeAction(const std::string& path, const Tree& input)
+DatastoreAccess::Tree SysrepoAccess::execute(const std::string& path, const Tree& input)
{
auto srInput = toSrVals(path, input);
auto output = m_session->rpc_send(path.c_str(), srInput);
diff --git a/src/sysrepo_access.hpp b/src/sysrepo_access.hpp
index d0ad869..55e8ac6 100644
--- a/src/sysrepo_access.hpp
+++ b/src/sysrepo_access.hpp
@@ -33,8 +33,7 @@
void createItem(const std::string& path) override;
void deleteItem(const std::string& path) override;
void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ Tree execute(const std::string& path, const Tree& input) override;
std::shared_ptr<Schema> schema() override;
diff --git a/src/yang_access.cpp b/src/yang_access.cpp
index a460150..7a43507 100644
--- a/src/yang_access.cpp
+++ b/src/yang_access.cpp
@@ -229,7 +229,7 @@
{
}
-[[noreturn]] void YangAccess::impl_execute(const std::string& type, const std::string& path, const Tree& input)
+[[noreturn]] DatastoreAccess::Tree YangAccess::execute(const std::string& path, const Tree& input)
{
auto root = lyWrap(lyd_new_path(nullptr, m_ctx.get(), path.c_str(), nullptr, LYD_ANYDATA_CONSTSTRING, 0));
if (!root) {
@@ -244,17 +244,7 @@
getErrorsAndThrow();
}
}
- throw std::logic_error("in-memory datastore doesn't support executing " + type + "s");
-}
-
-DatastoreAccess::Tree YangAccess::executeRpc(const std::string& path, const Tree& input)
-{
- impl_execute("RPC", path, input);
-}
-
-DatastoreAccess::Tree YangAccess::executeAction(const std::string& path, const Tree& input)
-{
- impl_execute("action", path, input);
+ throw std::logic_error("in-memory datastore doesn't support executing RPC/action");
}
void YangAccess::copyConfig(const Datastore source, const Datastore dest)
diff --git a/src/yang_access.hpp b/src/yang_access.hpp
index 62c43d6..c009420 100644
--- a/src/yang_access.hpp
+++ b/src/yang_access.hpp
@@ -30,8 +30,7 @@
void moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move) override;
void commitChanges() override;
void discardChanges() override;
- Tree executeRpc(const std::string& path, const Tree& input) override;
- Tree executeAction(const std::string& path, const Tree& input) override;
+ [[noreturn]] Tree execute(const std::string& path, const Tree& input) override;
void copyConfig(const Datastore source, const Datastore destination) override;
std::shared_ptr<Schema> schema() override;
diff --git a/tests/datastore_access.cpp b/tests/datastore_access.cpp
index 43d6038..ddfe288 100644
--- a/tests/datastore_access.cpp
+++ b/tests/datastore_access.cpp
@@ -951,7 +951,7 @@
SECTION("noop")
{
rpc = "/example-schema:noop";
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
}
SECTION("small nuke")
@@ -961,7 +961,7 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{333'666}},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{333'666});
// no data are returned
}
@@ -973,7 +973,7 @@
{"description", "dummy"s},
{"payload/kilotons", uint64_t{4}},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:launch-nukes/example-schema:payload/example-schema:kilotons", uint64_t{4});
output = {
@@ -989,7 +989,7 @@
{"payload/kilotons", uint64_t{6}},
{"cities/targets[city='Prague']/city", "Prague"s},
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(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 = {
@@ -1012,17 +1012,17 @@
input = {
{"whom", "Colton"s}
};
- proxyDatastore.initiateRpc(rpc);
+ proxyDatastore.initiate(rpc);
proxyDatastore.setLeaf("/example-schema:fire/example-schema:whom", "Colton"s);
}
- catching<OnExec>([&] { REQUIRE(datastore->executeRpc(rpc, input) == output); });
+ catching<OnExec>([&] { REQUIRE(datastore->execute(rpc, input) == output); });
catching<OnExec>([&] { REQUIRE(proxyDatastore.execute() == output); });
}
SECTION("non-existing RPC")
{
- catching<OnInvalidRpcPath>([&] { datastore->executeRpc("/example-schema:non-existing", DatastoreAccess::Tree{}); });
+ catching<OnInvalidRpcPath>([&] { datastore->execute("/example-schema:non-existing", DatastoreAccess::Tree{}); });
}
}
@@ -1045,7 +1045,7 @@
path = "/example-schema:ports[name='A']/shutdown";
}
- catching<OnExec>([&] { REQUIRE(datastore->executeAction(path, input) == output); });
+ catching<OnExec>([&] { REQUIRE(datastore->execute(path, input) == output); });
}
waitForCompletionAndBitMore(seq1);
diff --git a/tests/datastoreaccess_mock.hpp b/tests/datastoreaccess_mock.hpp
index 751cdad..e708149 100644
--- a/tests/datastoreaccess_mock.hpp
+++ b/tests/datastoreaccess_mock.hpp
@@ -24,8 +24,7 @@
IMPLEMENT_MOCK1(createItem);
IMPLEMENT_MOCK1(deleteItem);
IMPLEMENT_MOCK2(moveItem);
- IMPLEMENT_MOCK2(executeRpc);
- IMPLEMENT_MOCK2(executeAction);
+ IMPLEMENT_MOCK2(execute);
// Can't use IMPLEMENT_MOCK for private methods - IMPLEMENT_MOCK needs full visibility of the method
MAKE_MOCK1(listInstances, std::vector<ListInstance>(const std::string&), override);
diff --git a/tests/interpreter.cpp b/tests/interpreter.cpp
index d57ad64..c6d7c9c 100644
--- a/tests/interpreter.cpp
+++ b/tests/interpreter.cpp
@@ -454,7 +454,7 @@
SECTION("exec")
{
REQUIRE_CALL(*input_datastore, getItems("/")).RETURN(DatastoreAccess::Tree{});
- REQUIRE_CALL(*datastore, executeRpc("/example:launch-nukes", DatastoreAccess::Tree{})).RETURN(DatastoreAccess::Tree{});
+ REQUIRE_CALL(*datastore, execute("/example:launch-nukes", DatastoreAccess::Tree{})).RETURN(DatastoreAccess::Tree{});
boost::apply_visitor(Interpreter(parser, proxyDatastore), command_{exec_{}});
}
diff --git a/tests/prepare.cpp b/tests/prepare.cpp
index 139ef4b..d56a488 100644
--- a/tests/prepare.cpp
+++ b/tests/prepare.cpp
@@ -28,14 +28,14 @@
SECTION("rpc")
{
input = "prepare example:fire";
- expected.m_path.m_nodes.push_back({module_{"example"}, rpcNode_{"fire"}});
+ expected.m_path.m_nodes.emplace_back(module_{"example"}, rpcNode_{"fire"});
}
SECTION("action")
{
input = "prepare example:port[name='eth0']/shutdown";
- expected.m_path.m_nodes.push_back({module_{"example"}, listElement_{"port", {{"name", std::string{"eth0"}}}}});
- expected.m_path.m_nodes.push_back({actionNode_{"shutdown"}});
+ expected.m_path.m_nodes.emplace_back(module_{"example"}, listElement_{"port", {{"name", std::string{"eth0"}}}});
+ expected.m_path.m_nodes.emplace_back(actionNode_{"shutdown"});
}
command_ command = parser.parseCommand(input, errorStream);
diff --git a/tests/set_value_completion.cpp b/tests/set_value_completion.cpp
index dd36e34..f4d8124 100644
--- a/tests/set_value_completion.cpp
+++ b/tests/set_value_completion.cpp
@@ -29,6 +29,7 @@
schema->addIdentity(identityRef_{"mod", "food"}, identityRef_{"mod", "spaghetti"});
schema->addIdentity(identityRef_{"mod", "pizza"}, identityRef_{"pizza-module", "hawaii"});
schema->addLeaf("/", "mod:foodIdentRef", yang::IdentityRef{schema->validIdentities("mod", "food")});
+ schema->addLeaf("/", "mod:flags", yang::Bits{{"parity", "zero", "carry", "sign"}});
auto mockDatastore = std::make_shared<MockDatastoreAccess>();
// The parser will use DataQuery for key value completion, but I'm not testing that here, so I don't return anything.
ALLOW_CALL(*mockDatastore, listInstances("/mod:list"))
@@ -88,5 +89,19 @@
expectedContextLength = 0;
}
+ SECTION("set mod:flags ")
+ {
+ input = "set mod:flags ";
+ expectedCompletions = {"carry", "sign", "parity", "zero"};
+ expectedContextLength = 0;
+ }
+
+ SECTION("set mod:flags ze")
+ {
+ input = "set mod:flags ze";
+ expectedCompletions = {"zero"};
+ expectedContextLength = 2;
+ }
+
REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}