Skip to content

Commit 92049a8

Browse files
committed
Allow parsing standalone notifications in Context::parseOp
Even when the libyang docs is not explicit on that, lyd_parse_op is used for parsing standalone notifications too. For such case, the lyd_node* tree and op are the same, or, they point into the nodes in the same tree. So we should not wrap the pointers separately (this would result in a heap-after-use). Change-Id: Ib94114193a1a9073d9a4c6d15522eb41ba9c425d
1 parent c5ecde0 commit 92049a8

File tree

3 files changed

+128
-42
lines changed

3 files changed

+128
-42
lines changed

src/Context.cpp

+14-6
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ std::optional<DataNode> Context::parseData(
187187
*
188188
* - a NETCONF RPC,
189189
* - a NETCONF notification,
190-
* - a RESTCONF notification.
190+
* - a RESTCONF notification,
191+
* - a YANG notification.
191192
*
192193
* Parsing any of these requires just the schema (which is available through the Context), and the textual payload.
193194
* All the other information are encoded in the textual payload as per the standard.
@@ -211,14 +212,21 @@ ParsedOp Context::parseOp(const std::string& input, const DataFormat format, con
211212
switch (opType) {
212213
case OperationType::RpcNetconf:
213214
case OperationType::NotificationNetconf:
214-
case OperationType::NotificationRestconf: {
215+
case OperationType::NotificationRestconf:
216+
case OperationType::NotificationYang: {
215217
lyd_node* op = nullptr;
216218
lyd_node* tree = nullptr;
217219
auto err = lyd_parse_op(m_ctx.get(), nullptr, in.get(), utils::toLydFormat(format), utils::toOpType(opType), &tree, &op);
218-
ParsedOp res {
219-
.tree = tree ? std::optional{libyang::wrapRawNode(tree)} : std::nullopt,
220-
.op = op ? std::optional{libyang::wrapRawNode(op)} : std::nullopt
221-
};
220+
221+
ParsedOp res;
222+
res.tree = tree ? std::optional{libyang::wrapRawNode(tree)} : std::nullopt;
223+
224+
if (opType == OperationType::NotificationYang) {
225+
res.op = op && tree ? std::optional{DataNode(op, res.tree->m_refs)} : std::nullopt;
226+
} else {
227+
res.op = op ? std::optional{libyang::wrapRawNode(op)} : std::nullopt;
228+
}
229+
222230
throwIfError(err, "Can't parse a standalone rpc/action/notification into operation data tree");
223231
return res;
224232
}

tests/data_node.cpp

+108-36
Original file line numberDiff line numberDiff line change
@@ -2062,48 +2062,117 @@ TEST_CASE("Data Node manipulation")
20622062
ctx.loadModule("ietf-netconf-nmda");
20632063

20642064
DOCTEST_SUBCASE("notifications") {
2065-
std::string payload;
2066-
auto opType = libyang::OperationType::DataYang;
2065+
DOCTEST_SUBCASE("restconf/netconf") {
2066+
std::string payload;
2067+
auto opType = libyang::OperationType::DataYang;
20672068

2068-
DOCTEST_SUBCASE("RESTCONF JSON") {
2069-
payload = R"(
2070-
{
2071-
"ietf-restconf:notification" : {
2072-
"eventTime" : "2013-12-21T00:01:00Z",
2073-
"example-schema:event" : {
2074-
"event-class" : "fault"
2069+
DOCTEST_SUBCASE("RESTCONF JSON") {
2070+
payload = R"(
2071+
{
2072+
"ietf-restconf:notification" : {
2073+
"eventTime" : "2013-12-21T00:01:00Z",
2074+
"example-schema:event" : {
2075+
"event-class" : "fault"
2076+
}
2077+
}
20752078
}
2076-
}
2079+
)";
2080+
opType = libyang::OperationType::NotificationRestconf;
20772081
}
2078-
)";
2079-
opType = libyang::OperationType::NotificationRestconf;
2080-
}
2081-
2082-
DOCTEST_SUBCASE("NETCONF XML") {
2083-
payload = R"(
2084-
<notification
2085-
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
2086-
<eventTime>2013-12-21T00:01:00Z</eventTime>
2087-
<event xmlns="http://example.com/coze">
2088-
<event-class>fault</event-class>
2089-
</event>
2090-
</notification>
2091-
)";
2092-
opType = libyang::OperationType::NotificationNetconf;
2082+
2083+
DOCTEST_SUBCASE("NETCONF XML") {
2084+
payload = R"(
2085+
<notification
2086+
xmlns="urn:ietf:params:xml:ns:netconf:notification:1.0">
2087+
<eventTime>2013-12-21T00:01:00Z</eventTime>
2088+
<event xmlns="http://example.com/coze">
2089+
<event-class>fault</event-class>
2090+
</event>
2091+
</notification>
2092+
)";
2093+
opType = libyang::OperationType::NotificationNetconf;
2094+
}
2095+
2096+
auto notif = ctx.parseOp(payload, dataTypeFor(payload), opType);
2097+
REQUIRE(notif.tree);
2098+
REQUIRE(notif.tree->path() == "/notification");
2099+
auto node = notif.tree->child();
2100+
REQUIRE(node);
2101+
REQUIRE(node->path() == "/notification/eventTime");
2102+
REQUIRE(node->asOpaque().value() == "2013-12-21T00:01:00Z");
2103+
2104+
REQUIRE(notif.op);
2105+
node = notif.op->findPath("/example-schema:event/event-class");
2106+
REQUIRE(!!node);
2107+
REQUIRE(std::visit(libyang::ValuePrinter{}, node->asTerm().value()) == "fault");
20932108
}
20942109

2095-
auto notif = ctx.parseOp(payload, dataTypeFor(payload), opType);
2096-
REQUIRE(notif.tree);
2097-
REQUIRE(notif.tree->path() == "/notification");
2098-
auto node = notif.tree->child();
2099-
REQUIRE(node);
2100-
REQUIRE(node->path() == "/notification/eventTime");
2101-
REQUIRE(node->asOpaque().value() == "2013-12-21T00:01:00Z");
2110+
DOCTEST_SUBCASE("yang")
2111+
{
2112+
std::string payload;
21022113

2103-
REQUIRE(notif.op);
2104-
node = notif.op->findPath("/example-schema:event/event-class");
2105-
REQUIRE(!!node);
2106-
REQUIRE(std::visit(libyang::ValuePrinter{}, node->asTerm().value()) == "fault");
2114+
DOCTEST_SUBCASE("top-level")
2115+
{
2116+
DOCTEST_SUBCASE("json")
2117+
{
2118+
payload = R"({
2119+
"example-schema:event" : {
2120+
"event-class" : "fault"
2121+
}
2122+
})";
2123+
}
2124+
DOCTEST_SUBCASE("xml")
2125+
{
2126+
payload = R"(
2127+
<event xmlns="http://example.com/coze">
2128+
<event-class>fault</event-class>
2129+
</event>
2130+
)";
2131+
}
2132+
auto notif = ctx.parseOp(payload, dataTypeFor(payload), libyang::OperationType::NotificationYang);
2133+
REQUIRE(notif.tree);
2134+
REQUIRE(notif.op);
2135+
REQUIRE(notif.op == notif.tree);
2136+
REQUIRE(notif.tree->path() == "/example-schema:event");
2137+
auto node = notif.op->findPath("/example-schema:event/event-class");
2138+
REQUIRE(!!node);
2139+
REQUIRE(std::visit(libyang::ValuePrinter{}, node->asTerm().value()) == "fault");
2140+
}
2141+
2142+
DOCTEST_SUBCASE("nested")
2143+
{
2144+
DOCTEST_SUBCASE("json")
2145+
{
2146+
payload = R"({
2147+
"example-schema:person" : [{
2148+
"name": "John",
2149+
"event": {
2150+
"description" : "fault"
2151+
}
2152+
}]
2153+
})";
2154+
}
2155+
DOCTEST_SUBCASE("xml")
2156+
{
2157+
payload = R"(
2158+
<person xmlns="http://example.com/coze">
2159+
<name>John</name>
2160+
<event>
2161+
<description>fault</description>
2162+
</event>
2163+
</person>
2164+
)";
2165+
}
2166+
auto notif = ctx.parseOp(payload, dataTypeFor(payload), libyang::OperationType::NotificationYang);
2167+
REQUIRE(notif.tree);
2168+
REQUIRE(notif.op);
2169+
REQUIRE(notif.op != notif.tree);
2170+
REQUIRE(notif.tree->path() == "/example-schema:person[name='John']");
2171+
auto node = notif.op->findPath("/example-schema:person[name='John']/event/description");
2172+
REQUIRE(!!node);
2173+
REQUIRE(std::visit(libyang::ValuePrinter{}, node->asTerm().value()) == "fault");
2174+
}
2175+
}
21072176
}
21082177

21092178
DOCTEST_SUBCASE("invalid notification") {
@@ -2116,6 +2185,9 @@ TEST_CASE("Data Node manipulation")
21162185
REQUIRE_THROWS_WITH_AS(ctx.parseOp("", libyang::DataFormat::XML, libyang::OperationType::NotificationNetconf),
21172186
"Can't parse a standalone rpc/action/notification into operation data tree: LY_ENOT", libyang::Error);
21182187

2188+
REQUIRE_THROWS_WITH_AS(ctx.parseOp("asd", libyang::DataFormat::XML, libyang::OperationType::NotificationYang),
2189+
"Can't parse a standalone rpc/action/notification into operation data tree: LY_EVALID", libyang::Error);
2190+
21192191
/* libyang::setLogOptions(libyang::LogOptions::Log | libyang::LogOptions::Store); */
21202192
REQUIRE_THROWS_WITH_AS(ctx.parseOp(R"(
21212193
{

tests/example_schema.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ module example-schema {
100100
leaf name {
101101
type string;
102102
}
103+
104+
notification event {
105+
leaf description {
106+
type string;
107+
}
108+
}
103109
}
104110
105111
leaf bossPerson {

0 commit comments

Comments
 (0)