--- /dev/null
+// 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 <config.h>
+
+#include <yang/tests/yang_configs.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <gtest/gtest.h>
+#include <sstream>
+
+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
--- /dev/null
+// 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 <yang/testutils/translator_test.h>
+
+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
--- /dev/null
+// 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 <yang/testutils/translator_test.h>
+#include <boost/lexical_cast.hpp>
+#include <sstream>
+
+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<unsigned>(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<unsigned>(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<unsigned>(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<uint16_t>(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<uint32_t>(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<int>(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<int16_t>(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<int32_t>(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