From: Francis Dupont Date: Thu, 13 Sep 2018 14:02:28 +0000 (+0200) Subject: [65-libyang-testutils] Filled files, ready for review X-Git-Tag: 65-libyang-clean-keatext_base~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1b7963c1bcbb1ba6c7a69fed5d2f737a366c286f;p=thirdparty%2Fkea.git [65-libyang-testutils] Filled files, ready for review --- diff --git a/configure.ac b/configure.ac index 46e2fc941c..ba86b3e0ad 100644 --- a/configure.ac +++ b/configure.ac @@ -1621,6 +1621,7 @@ AC_CONFIG_FILES([Makefile src/lib/yang/Makefile src/lib/yang/pretests/Makefile src/lib/yang/tests/Makefile + src/lib/yang/testutils/Makefile src/share/Makefile src/share/database/Makefile src/share/database/scripts/Makefile diff --git a/src/lib/yang/Makefile.am b/src/lib/yang/Makefile.am index 80ba2fc377..27a8fe0adf 100644 --- a/src/lib/yang/Makefile.am +++ b/src/lib/yang/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = . pretests tests +SUBDIRS = . testutils pretests tests AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS) diff --git a/src/lib/yang/tests/Makefile.am b/src/lib/yang/tests/Makefile.am index 9297c9c597..4a8f091ece 100644 --- a/src/lib/yang/tests/Makefile.am +++ b/src/lib/yang/tests/Makefile.am @@ -17,7 +17,8 @@ EXTRA_DIST = keatest-module.yang TESTS = if HAVE_GTEST TESTS += run_unittests -run_unittests_SOURCES = adaptor_unittests.cc +run_unittests_SOURCES = yang_configs.h +run_unittests_SOURCES += adaptor_unittests.cc run_unittests_SOURCES += adaptor_option_unittests.cc run_unittests_SOURCES += adaptor_pool_unittests.cc run_unittests_SOURCES += adaptor_host_unittests.cc @@ -36,11 +37,13 @@ run_unittests_SOURCES += translator_pd_pool_unittests.cc run_unittests_SOURCES += translator_host_unittests.cc run_unittests_SOURCES += translator_subnet_unittests.cc run_unittests_SOURCES += translator_shared_network_unittests.cc +run_unittests_SOURCES += translator_utils_unittests.cc run_unittests_SOURCES += run_unittests.cc run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS) -run_unittests_LDADD = $(top_builddir)/src/lib/yang/libkea-yang.la +run_unittests_LDADD = $(top_builddir)/src/lib/yang/testutils/libyangtest.la +run_unittests_LDADD += $(top_builddir)/src/lib/yang/libkea-yang.la run_unittests_LDADD += $(top_builddir)/src/lib/testutils/libkea-testutils.la run_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la run_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la diff --git a/src/lib/yang/tests/translator_utils_unittests.cc b/src/lib/yang/tests/translator_utils_unittests.cc new file mode 100644 index 0000000000..401951537f --- /dev/null +++ b/src/lib/yang/tests/translator_utils_unittests.cc @@ -0,0 +1,206 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +#include +#include +#include + +using namespace std; +using namespace isc; +using namespace isc::yang; +using namespace isc::yang::test; + +namespace { + +// Test sr_type_t print. +TEST(YangReprTest, type) { + ostringstream os; + + // Verify that string is "string" (vs a number). + sr_type_t t = SR_STRING_T; + os << t; + EXPECT_EQ("string", os.str()); + os.str(""); + + // Compiler does not let to create an invalid value... +} + +// Test YangReprItem basic stuff. +TEST(YangReprTest, item) { + // An item. + YRItem item1("/foo", "bar", SR_STRING_T, true); + EXPECT_EQ("/foo", item1.xpath_); + EXPECT_EQ("bar", item1.value_); + EXPECT_EQ(SR_STRING_T, item1.type_); + EXPECT_TRUE(item1.settable_); + + // Another one. + YRItem item2("/foo", "bar", SR_STRING_T, false); + EXPECT_EQ("/foo", item2.xpath_); + EXPECT_EQ("bar", item2.value_); + EXPECT_EQ(SR_STRING_T, item2.type_); + EXPECT_FALSE(item2.settable_); + + // Equality. + EXPECT_TRUE(item1 == item2); + EXPECT_TRUE(item2 == item1); + EXPECT_FALSE(item1 != item2); + EXPECT_FALSE(item2 != item1); + EXPECT_EQ(item1, item2); + EXPECT_EQ(item2, item1); +} + +// Test get with example module. +TEST(YangReprTest, getExample) { + // Get a translator object to play with. + S_Connection conn(new Connection("utils unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + + // Create a list. + string xpath = "/example-module:container/list"; + S_Val s_val; + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + // Get it. + YangRepr repr(exampleModel); + YRTree tree; + EXPECT_NO_THROW(tree = repr.get(sess)); + + // Verify. + EXPECT_TRUE(repr.verify(exampleTree, sess, cerr)); +} + +// Test get with test module. +TEST(YangReprTest, getTest) { + // Get a translator object to play with. + S_Connection conn(new Connection("utils unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + + // Fill the test module. + string xpath; + S_Val s_val; + + xpath = "/test-module:main/string"; + s_val.reset(new Val("str", SR_STRING_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/boolean"; + s_val.reset(new Val(true, SR_BOOL_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/ui8"; + uint8_t u8(8); + s_val.reset(new Val(u8, SR_UINT8_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/ui16"; + uint16_t u16(16); + s_val.reset(new Val(u16, SR_UINT16_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/ui32"; + uint32_t u32(32); + s_val.reset(new Val(u32, SR_UINT32_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/i8"; + int8_t s8(8); + s_val.reset(new Val(s8, SR_INT8_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/i16"; + int16_t s16(16); + s_val.reset(new Val(s16, SR_INT16_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/i32"; + int32_t s32(32); + s_val.reset(new Val(s32, SR_INT32_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/id_ref"; + s_val.reset(new Val("test-module:id_1", SR_IDENTITYREF_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + xpath = "/test-module:main/enum"; + s_val.reset(new Val("maybe", SR_ENUM_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + // Binary. + xpath = "/test-module:main/raw"; + s_val.reset(new Val("Zm9vYmFy", SR_BINARY_T)); + EXPECT_NO_THROW(sess->set_item(xpath.c_str(), s_val)); + + // Get it. + YangRepr repr(testModel); + YRTree tree; + EXPECT_NO_THROW(tree = repr.get(sess)); + + // Verify. + EXPECT_TRUE(repr.verify(testTree, sess, cerr)); + + // Some error messages will be displayed. + + // Change a path. + YRTree badpath = testTree; + badpath[20].xpath_ = "/test-module:kernel-module"; // removed final 's' + EXPECT_FALSE(repr.verify(badpath, sess, cerr)); + + // Change a value. + YRTree badvalue = testTree; + badvalue[1].value_ = "Str"; // was "str" + EXPECT_FALSE(repr.verify(badvalue, sess, cerr)); + + // Change a type. + YRTree badtype = testTree; + badtype[8].type_ = SR_UINT32_T; // was SR_INT32_T + EXPECT_FALSE(repr.verify(badtype, sess, cerr)); + + // Add a record at the end. + YRTree badmissing = testTree; + const string& xpathpc = "/test-module:presence-container"; + badmissing.push_back(YRItem(xpathpc, "", SR_CONTAINER_PRESENCE_T, false)); + EXPECT_FALSE(repr.verify(badmissing, sess, cerr)); + + // Delete last record. + YRTree badextra = testTree; + badextra.pop_back(); + EXPECT_FALSE(repr.verify(badextra, sess, cerr)); +} + +// Test set with example module. +TEST(YangReprTest, setExample) { + // Get a translator object to play with. + S_Connection conn(new Connection("utils unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + + // Set the module content. + YangRepr repr(exampleModel); + EXPECT_NO_THROW(repr.set(exampleTree, sess)); + + // Verify it. + EXPECT_TRUE(repr.verify(exampleTree, sess, cerr)); +} + +// Test set with test module. +TEST(YangReprTest, setTest) { + // Get a translator object to play with. + S_Connection conn(new Connection("utils unittests")); + S_Session sess(new Session(conn, SR_DS_CANDIDATE)); + + // Set the module content. + YangRepr repr(testModel); + EXPECT_NO_THROW(repr.set(testTree, sess)); + + // Verify it. + EXPECT_TRUE(repr.verify(testTree, sess, cerr)); +} + +}; // end of anonymous namespace diff --git a/src/lib/yang/tests/yang_configs.h b/src/lib/yang/tests/yang_configs.h new file mode 100644 index 0000000000..32b7e23ace --- /dev/null +++ b/src/lib/yang/tests/yang_configs.h @@ -0,0 +1,408 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef ISC_YANG_CONFIGS_H +#define ISC_YANG_CONFIGS_H + +#include + +namespace isc { +namespace yang { +namespace test { + +/// @brief The example module from sysrepo tests. +const std::string exampleModel = "example-module"; +const YRTree exampleTree = { + { "/example-module:container", "", SR_CONTAINER_T, false }, + { "/example-module:container/list", "", SR_LIST_T, true } +}; + +/// @brief The test module from sysrepo tests. +const std::string testModel = "test-module"; +const YRTree testTree = { + { "/test-module:main", "", SR_CONTAINER_T, false }, + { "/test-module:main/string", "str", SR_STRING_T, true }, + { "/test-module:main/boolean", "true", SR_BOOL_T, true }, + { "/test-module:main/ui8", "8", SR_UINT8_T, true }, + { "/test-module:main/ui16", "16", SR_UINT16_T, true }, + { "/test-module:main/ui32", "32", SR_UINT32_T, true }, + { "/test-module:main/i8", "8", SR_INT8_T, true }, + { "/test-module:main/i16", "16", SR_INT16_T, true }, + { "/test-module:main/i32", "32", SR_INT32_T, true }, + { "/test-module:main/id_ref", "test-module:id_1", SR_IDENTITYREF_T, true }, + { "/test-module:main/enum", "maybe", SR_ENUM_T, true }, + { "/test-module:main/raw", "Zm9vYmFy", SR_BINARY_T, true }, + { "/test-module:transfer", "", SR_CONTAINER_T, false }, + { "/test-module:transfer/interval", "30", SR_UINT16_T, false }, + { "/test-module:interface", "", SR_CONTAINER_T, false }, + { "/test-module:top-level-default", "default value", SR_STRING_T, false }, + { "/test-module:university", "", SR_CONTAINER_T, false }, + { "/test-module:university/students", "", SR_CONTAINER_T, false }, + { "/test-module:university/classes", "", SR_CONTAINER_T, false }, + { "/test-module:leafref-chain", "", SR_CONTAINER_T, false }, + { "/test-module:kernel-modules", "", SR_CONTAINER_T, false }, + { "/test-module:tpdfs", "", SR_CONTAINER_T, false }, + { "/test-module:tpdfs/unival", "disabled", SR_STRING_T, false } +}; + +/// @brief A subnet with two pools with ietf-dhcpv6-server model. +const std::string subnetTwoPoolsModelIetf6 = "ietf-dhcpv6-server"; +const YRTree subnetTwoPoolsTreeIetf6 = { + { "/ietf-dhcpv6-server:server", "", SR_CONTAINER_PRESENCE_T, false }, + { "/ietf-dhcpv6-server:server/server-config", "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-range-id", + "111", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-prefix", + "2001:db8::/48", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-id", "0", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-prefix", + "2001:db8::1:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/start-address", + "2001:db8::1:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/end-address", + "2001:db8::1:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/max-address-count", + "disabled", SR_ENUM_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-id", "1", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-prefix", + "2001:db8::2:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/start-address", + "2001:db8::2:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/end-address", + "2001:db8::2:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/max-address-count", + "disabled", SR_ENUM_T, true } +}; + +/// @brief A subnet with timers with ietf-dhcpv6-server model. +const std::string subnetTimersModel = "ietf-dhcpv6-server"; +const YRTree subnetTimersIetf6 = { + { "/ietf-dhcpv6-server:server", "", SR_CONTAINER_PRESENCE_T, false }, + { "/ietf-dhcpv6-server:server/server-config", "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-range-id", + "111", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-prefix", + "2001:db8::/48", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-id", "0", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-prefix", + "2001:db8::1:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/start-address", + "2001:db8::1:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/end-address", + "2001:db8::1:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/renew-time", "1000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/rebind-time", "2000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/max-address-count", + "disabled", SR_ENUM_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-id", "1", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-prefix", + "2001:db8::2:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/start-address", + "2001:db8::2:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/end-address", + "2001:db8::2:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/renew-time", "1000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/rebind-time", "2000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/max-address-count", + "disabled", SR_ENUM_T, true } +}; + +/// @brief A subnet with two pools with ietf-dhcpv6-server model +/// which validates. +const std::string validModelIetf6 = "ietf-dhcpv6-server"; +const YRTree validTreeIetf6 = { + { "/ietf-dhcpv6-server:server", "", SR_CONTAINER_PRESENCE_T, false }, + { "/ietf-dhcpv6-server:server/server-config", "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/serv-attributes", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/serv-attributes/vendor-info", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/serv-attributes" + "/vendor-info/ent-num", "2495", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-range-id", + "111", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-description", + "Subnet#111", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/network-prefix", + "2001:db8::/48", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-id", "0", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/pool-prefix", + "2001:db8::1:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/start-address", + "2001:db8::1:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/end-address", + "2001:db8::1:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/valid-lifetime", "4000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/preferred-lifetime", + "3000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/renew-time", "1000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/rebind-time", "2000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/max-address-count", + "disabled", SR_ENUM_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='0']/option-set-id", "0", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-id", "1", SR_UINT32_T, false }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/pool-prefix", + "2001:db8::2:0/112", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/start-address", + "2001:db8::2:0", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/end-address", + "2001:db8::2:ffff", SR_STRING_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/valid-lifetime", "4000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/preferred-lifetime", + "3000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/renew-time", "1000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/rebind-time", "2000", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/max-address-count", + "disabled", SR_ENUM_T, true }, + { "/ietf-dhcpv6-server:server/server-config/network-ranges/" + "network-range[network-range-id='111']/address-pools/" + "address-pool[pool-id='1']/option-set-id", "0", SR_UINT32_T, true }, + { "/ietf-dhcpv6-server:server/server-config/option-sets", + "", SR_CONTAINER_T, false }, + { "/ietf-dhcpv6-server:server/server-config/option-sets" + "/option-set[option-set-id='0']", "", SR_LIST_T, true }, + { "/ietf-dhcpv6-server:server/server-config/option-sets" + "/option-set[option-set-id='0']/option-set-id", + "0", SR_UINT32_T, false } +}; + +/// @brief A subnet with a pool and option data lists with +/// kea-dhcp4:config model. +const std::string subnetOptionsModelKeaDhcp4 = "kea-dhcp4"; +const YRTree subnetOptionsTreeKeaDhcp4 = { + { "/kea-dhcp4:config", "", SR_CONTAINER_T, false }, + { "/kea-dhcp4:config/subnet4", "", SR_CONTAINER_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']", "", SR_LIST_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/id", + "111", SR_UINT32_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list", + "", SR_CONTAINER_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']", "", SR_LIST_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']/code", + "100", SR_UINT8_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']/space", + "dns", SR_STRING_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']/data", + "12121212", SR_STRING_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']/csv-format", + "false", SR_BOOL_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/option-data-list/" + "option-data[code='100'][space='dns']/always-send", + "false", SR_BOOL_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/pools", + "", SR_CONTAINER_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/pools/" + "pool[start-address='10.0.1.0'][end-address='10.0.1.255']", + "", SR_LIST_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/pools/" + "pool[start-address='10.0.1.0'][end-address='10.0.1.255']/start-address", + "10.0.1.0", SR_STRING_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/pools/" + "pool[start-address='10.0.1.0'][end-address='10.0.1.255']/end-address", + "10.0.1.255", SR_STRING_T, false }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/pools/" + "pool[start-address='10.0.1.0'][end-address='10.0.1.255']/prefix", + "10.0.1.0/24", SR_STRING_T, true }, + { "/kea-dhcp4:config/subnet4/subnet4[id='111']/subnet", + "10.0.0.0/8", SR_STRING_T, true } +}; + +/// @brief A subnet with a pool and option data lists with +/// kea-dhcp6:config model. +const std::string subnetOptionsModelKeaDhcp6 = "kea-dhcp6"; +const YRTree subnetOptionsTreeKeaDhcp6 = { + { "/kea-dhcp6:config", "", SR_CONTAINER_T, false }, + { "/kea-dhcp6:config/subnet6", "", SR_CONTAINER_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']", "", SR_LIST_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/id", + "111", SR_UINT32_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools", + "", SR_CONTAINER_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']", + "", SR_LIST_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "start-address", "2001:db8::1:0", SR_STRING_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "end-address", "2001:db8::1:ffff", SR_STRING_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "prefix", "2001:db8::1:0/112", SR_STRING_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list", "", SR_CONTAINER_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']", + "", SR_LIST_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']/code", + "100", SR_UINT16_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']/space", + "dns", SR_STRING_T, false }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']/data", + "12121212", SR_STRING_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']/csv-format", + "false", SR_BOOL_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/pools/" + "pool[start-address='2001:db8::1:0'][end-address='2001:db8::1:ffff']/" + "option-data-list/option-data[code='100'][space='dns']/always-send", + "false", SR_BOOL_T, true }, + { "/kea-dhcp6:config/subnet6/subnet6[id='111']/subnet", + "2001:db8::/48", SR_STRING_T, true } +}; + +}; // end of namespace isc::yang::test +}; // end of namespace isc::yang +}; // end of namespace isc + +#endif // ISC_YANG_CONFIGS_H diff --git a/src/lib/yang/testutils/Makefile.am b/src/lib/yang/testutils/Makefile.am new file mode 100644 index 0000000000..aa0ac23b22 --- /dev/null +++ b/src/lib/yang/testutils/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = . + +AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib +AM_CPPFLAGS += $(BOOST_INCLUDES) $(SYSREPO_CPPFLAGS) +AM_CXXFLAGS = $(KEA_CXXFLAGS) + +CLEANFILES = *.gcno *.gcda + +if HAVE_GTEST + +noinst_LTLIBRARIES = libyangtest.la + +libyangtest_la_SOURCES = translator_test.cc translator_test.h + +libyangtest_la_CXXFLAGS = $(AM_CXXFLAGS) +libyangtest_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) +libyangtest_la_LDFLAGS = $(AM_LDFLAGS) + +libyangtest_la_LIBADD = $(top_builddir)/src/lib/yang/libkea-yang.la +libyangtest_la_LIBADD += $(top_builddir)/src/lib/log/libkea-log.la + +endif diff --git a/src/lib/yang/testutils/translator_test.cc b/src/lib/yang/testutils/translator_test.cc new file mode 100644 index 0000000000..304554a86e --- /dev/null +++ b/src/lib/yang/testutils/translator_test.cc @@ -0,0 +1,392 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include +#include +#include + +using namespace std; +using namespace isc::data; + +namespace isc { +namespace yang { +namespace test { + +YangRepr::YangReprItem +YangRepr::YangReprItem::get(const string& xpath, S_Session session) { + string val_xpath = xpath; + string value = ""; + sr_type_t type = SR_UNKNOWN_T; + bool settable = true; + try { + S_Val s_val = session->get_item(xpath.c_str()); + if (!s_val) { + isc_throw(BadValue, "YangReprItem failed at '" << xpath << "'"); + } + val_xpath = string(s_val->xpath()); + type = s_val->type(); + ostringstream int_value; + switch (type) { + case SR_CONTAINER_T: + case SR_CONTAINER_PRESENCE_T: + settable = false; + break; + + case SR_LIST_T: + break; + + case SR_STRING_T: + value = s_val->data()->get_string(); + break; + + case SR_BOOL_T: + value = s_val->data()->get_bool() ? "true" : "false"; + break; + + case SR_UINT8_T: + int_value << static_cast(s_val->data()->get_uint8()); + value = int_value.str(); + break; + + case SR_UINT16_T: + int_value << s_val->data()->get_uint16(); + value = int_value.str(); + break; + + case SR_UINT32_T: + int_value << s_val->data()->get_uint32(); + value = int_value.str(); + break; + + case SR_INT8_T: + int_value << static_cast(s_val->data()->get_int8()); + value = int_value.str(); + break; + + case SR_INT16_T: + int_value << s_val->data()->get_int16(); + value = int_value.str(); + break; + + case SR_INT32_T: + int_value << s_val->data()->get_int32(); + value = int_value.str(); + break; + + case SR_IDENTITYREF_T: + value = s_val->data()->get_identityref(); + break; + + case SR_ENUM_T: + value = s_val->data()->get_enum(); + break; + + case SR_BINARY_T: + value = s_val->data()->get_binary(); + break; + + default: + isc_throw(NotImplemented, + "YangReprItem called with unupported type: " << type); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error in YangReprItem: " << ex.what()); + } + return (YangReprItem(val_xpath, value, type, settable)); +} + +YangRepr::Tree +YangRepr::get(S_Session session) const { + Tree result; + try { + const string& xpath0 = "/" + model_ + ":*//."; + TranslatorBasic tb(session); + S_Iter_Value iter = tb.getIter(xpath0); + for (;;) { + const string& xpath = tb.getNext(iter); + if (xpath.empty()) { + break; + } + result.push_back(YangReprItem::get(xpath, session)); + } + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error in YangRepr::getTree: " << ex.what()); + } + return (result); +} + +bool +YangRepr::verify(const Tree& expected, S_Session session, + ostream& errs) const { + const Tree& got = get(session); + for (size_t i = 0; (i < expected.size()) && (i < got.size()); ++i) { + if (expected[i] == got[i]) { + continue; + } + errs << "expected[" << i << "]: " << expected[i] << endl; + errs << "got[" << i << "]: " << got[i] << endl; + return (false); + } + if (expected.size() == got.size()) { + return (true); + } + if (expected.size() > got.size()) { + errs << "missings " << (expected.size() - got.size()); + errs << " beginning by:" << endl << expected[got.size()] << endl; + } else { + errs << "extras " << (got.size() - expected.size()); + errs << " beginning by:" << endl << got[expected.size()] << endl; + } + return (false); +} + +void +YangRepr::set(const Tree& tree, S_Session session) const { + for (auto item : tree) { + if (!item.settable_) { + continue; + } + try { + S_Val s_val; + switch (item.type_) { + case SR_CONTAINER_T: + case SR_CONTAINER_PRESENCE_T: + isc_throw(NotImplemented, + "YangRepr::set called for a container"); + + case SR_LIST_T: + break; + + case SR_STRING_T: + case SR_IDENTITYREF_T: + case SR_ENUM_T: + case SR_BINARY_T: + s_val.reset(new Val(item.value_.c_str(), item.type_)); + break; + + case SR_BOOL_T: + if (item.value_ == "true") { + s_val.reset(new Val(true, SR_BOOL_T)); + } else if (item.value_ == "false") { + s_val.reset(new Val(false, SR_BOOL_T)); + } else { + isc_throw(BadValue, "'" << item.value_ << "' not a bool"); + } + break; + + case SR_UINT8_T: + try { + uint8_t u8 = boost::lexical_cast(item.value_); + s_val.reset(new Val(u8, SR_UINT8_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an uint8"); + } + break; + + case SR_UINT16_T: + try { + uint16_t u16 = boost::lexical_cast(item.value_); + s_val.reset(new Val(u16, SR_UINT16_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an uint16"); + } + break; + + case SR_UINT32_T: + try { + uint32_t u32 = boost::lexical_cast(item.value_); + s_val.reset(new Val(u32, SR_UINT32_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an uint32"); + } + break; + + case SR_INT8_T: + try { + int8_t i8 = boost::lexical_cast(item.value_); + s_val.reset(new Val(i8, SR_INT8_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an int8"); + } + break; + + case SR_INT16_T: + try { + int16_t i16 = boost::lexical_cast(item.value_); + s_val.reset(new Val(i16, SR_INT16_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an int16"); + } + break; + + case SR_INT32_T: + try { + int32_t i32 = boost::lexical_cast(item.value_); + s_val.reset(new Val(i32, SR_INT32_T)); + } catch (const boost::bad_lexical_cast&) { + isc_throw(BadValue, + "'" << item.value_ << "' not an int32"); + } + break; + + default: + isc_throw(NotImplemented, + "YangRepr::set called with unupported type: " + << item.type_); + } + session->set_item(item.xpath_.c_str(), s_val); + } catch (const sysrepo_exception& ex) { + isc_throw(SysrepoError, + "sysrepo error in YangRepr::set for " << item + << ", error: " << ex.what()); + } + } +} + +bool +YangRepr::validate(S_Session session, std::ostream& errs) const { + try { + session->validate(); + return (true); + } catch (const std::exception& ex) { + errs << "validate fails with " << ex.what() << endl; + } + try { + S_Errors s_errors = session->get_last_errors(); + if (!s_errors) { + errs << "no errors" << endl; + return (false); + } + size_t cnt = s_errors->error_cnt(); + errs << "got " << cnt << " errors" << endl; + for (size_t i = 0; i < cnt; ++i) { + S_Error s_error = s_errors->error(i); + if (!s_error) { + continue; + } + const char* xpath = s_error->xpath(); + const char* message = s_error->message(); + if (!xpath || !message) { + continue; + } + // Bug in sysrepo returning message for xpath(). + if (xpath == message) { + errs << message << endl; + } else { + errs << message << endl + << "At " << xpath << endl; + } + } + } catch (const std::exception& ex) { + // Bug in sysrepo rethrowing the last error when trying to get it. + errs << "double error " << ex.what(); + } + return (false); +} + +ostream& +operator<<(ostream& os, sr_type_t type) { + switch (type) { + case SR_CONTAINER_T: + os << "container"; + break; + case SR_CONTAINER_PRESENCE_T: + os << "container presence"; + break; + case SR_LIST_T: + os << "list"; + break; + case SR_STRING_T: + os << "string"; + break; + case SR_BOOL_T: + os << "bool"; + break; + case SR_UINT8_T: + os << "uint8"; + break; + case SR_UINT16_T: + os << "uint16"; + break; + case SR_UINT32_T: + os << "uint32"; + break; + case SR_INT8_T: + os << "int8"; + break; + case SR_INT16_T: + os << "int16"; + break; + case SR_INT32_T: + os << "int32"; + break; + case SR_IDENTITYREF_T: + os << "identity ref"; + break; + case SR_ENUM_T: + os << "enum"; + break; + case SR_BINARY_T: + os << "binary"; + break; + case SR_LEAF_EMPTY_T: + os << "leaf empty"; + break; + case SR_BITS_T: + os << "bits"; + break; + case SR_DECIMAL64_T: + os << "decimal64"; + break; + case SR_INSTANCEID_T: + os << "instance id"; + break; + case SR_INT64_T: + os << "int64"; + break; + case SR_UINT64_T: + os << "uint64"; + break; + case SR_ANYXML_T: + os << "any xml"; + break; + case SR_ANYDATA_T: + os << "any data"; + break; +#ifdef SR_UNION_T + case SR_UNION_T: + os << "union"; + break; +#endif + default: + os << type; + break; + } + return (os); +} + +ostream& operator<<(ostream& os, const YangRepr::YangReprItem& item) { + os << item.xpath_ << " = (" << item.type_ << ") '" << item.value_ << "'"; + return (os); +} + +ostream& operator<<(ostream& os, const YangRepr::Tree& tree) { + for (auto item : tree) { + os << item << endl; + } + return (os); +} + +}; // end of namespace isc::yang::test +}; // end of namespace isc::yang +}; // end of namespace isc diff --git a/src/lib/yang/testutils/translator_test.h b/src/lib/yang/testutils/translator_test.h new file mode 100644 index 0000000000..1036021186 --- /dev/null +++ b/src/lib/yang/testutils/translator_test.h @@ -0,0 +1,127 @@ +// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef ISC_TRANSLATOR_TEST_H +#define ISC_TRANSLATOR_TEST_H 1 + +#include +#include +#include + +namespace isc { +namespace yang { +namespace test { + +/// @brief Yang/sysrepo datastore textual representation class. +class YangRepr { +public: + + /// @brief Constructor. + /// + /// @param model The model name. + YangRepr(const std::string& model) : model_(model) { + } + + /// @brief The item class. + struct YangReprItem { + /// @brief Constructor with content. + /// + /// @param xpath The xpath. + /// @param value The textual value. + /// @param type The type of the value. + /// @param settable The settable flag. + YangReprItem(std::string xpath, std::string value, + sr_type_t type, bool settable) + : xpath_(xpath), value_(value), type_(type), settable_(settable) { + } + + /// @brief Factory from session. + /// + /// @param xpath The xpath. + /// @param session Sysrepo session. + static YangReprItem get(const std::string& xpath, S_Session session); + + /// @brief The xpath. + std::string xpath_; + + /// @brief The textual value. + std::string value_; + + /// @brief The type of the value. + sr_type_t type_; + + /// @brief The settable flag. + bool settable_; + + /// @brief The equal operator ignoring settable. + bool operator==(const YangReprItem& other) const { + return ((xpath_ == other.xpath_) && + (value_ == other.value_) && + (type_ == other.type_)); + } + + /// @brief The unequal operator ignoring settable. + bool operator!=(const YangReprItem& other) const { + return (!(*this == other)); + } + }; + + /// @brief Tree type. + typedef std::vector Tree; + + /// @brief Get tree from session. + /// + /// @param session Sysrepo session. + Tree get(S_Session session) const; + + /// @brief Verify tree. + /// + /// @param expected The expected value. + /// @param session Sysrepo session. + /// @param errs Error stream. + /// @return True if verification succeeds, false with errors displayed + /// on errs if it fails. + bool verify(const Tree& expected, S_Session session, + std::ostream& errs) const; + + /// @brief Set tree to session. + /// + /// @param tree The tree to install. + /// @param session Sysrepo session. + void set(const Tree& tree, S_Session session) const; + + /// @brief Validate. + /// + /// @param session Sysrepo session. + /// @param errs Error stream. + /// @return True if validation succeeds, false with errors displayed + /// on errs if it fails. + bool validate(S_Session session, std::ostream& errs) const; + + /// @brief The model name. + std::string model_; +}; + +/// @brief Alias for Items. +typedef YangRepr::YangReprItem YRItem; + +/// @brief Alias for Trees. +typedef YangRepr::Tree YRTree; + +/// @brief Overrides standard output operator for sr_type_t. +std::ostream& operator<<(std::ostream& os, sr_type_t type); + +/// @brief Overrides standard output operator for @c YangReprItem object. +std::ostream& operator<<(std::ostream& os, const YRItem& item); + +/// @brief Overrides standard output operator for @c Tree object. +std::ostream& operator<<(std::ostream& os, const YRTree& tree); + +}; // end of namespace isc::yang::test +}; // end of namespace isc::yang +}; // end of namespace isc + +#endif // ISC_TRANSLATOR_TEST_H