Commit 1b7963c1 authored by Francis Dupont's avatar Francis Dupont

[65-libyang-testutils] Filled files, ready for review

parent b4e30f37
......@@ -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
......
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)
......
......@@ -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
......
// 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
This diff is collapsed.
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
// 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";