Commit 63d5e666 authored by Francis Dupont's avatar Francis Dupont Committed by Tomek Mrugalski

[65-libyang-option-data] Filled files, waiting for adaptor merge

parent a388c647
......@@ -8,6 +8,8 @@ lib_LTLIBRARIES = libkea-yang.la
libkea_yang_la_SOURCES = adaptor.cc adaptor.h
libkea_yang_la_SOURCES += sysrepo_error.h
libkea_yang_la_SOURCES += translator.cc translator.h
libkea_yang_la_SOURCES += translator_option_data.cc
libkea_yang_la_SOURCES += translator_option_data.h
libkea_yang_la_LIBADD = $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libkea_yang_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
......
......@@ -19,6 +19,7 @@ if HAVE_GTEST
TESTS += run_unittests
run_unittests_SOURCES = adaptor_unittests.cc
run_unittests_SOURCES += translator_unittests.cc
run_unittests_SOURCES += translator_option_data_unittests.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
......
// 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/translator_option_data.h>
#include <boost/scoped_ptr.hpp>
#include <gtest/gtest.h>
#include <sstream>
using namespace std;
using namespace isc;
using namespace isc::data;
using namespace isc::yang;
namespace {
// Test get empty option data list.
TEST(TranslatorOptionDataListTest, getEmpty) {
// Get a translator option data list object to play with.
S_Connection conn(new Connection("translator option data list unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorOptionDataList> todl_obj;
// Use the ad hoc model.
const string& model = "kea-dhcp4";
EXPECT_NO_THROW(todl_obj.reset(new TranslatorOptionDataList(sess, model)));
// Get the option data list and checks it is empty.
const string& xpath = "/kea-dhcp4:config/option-data-list";
ConstElementPtr options;
EXPECT_NO_THROW(options = todl_obj->getOptionDataList(xpath));
ASSERT_TRUE(options);
ASSERT_EQ(Element::list, options->getType());
EXPECT_EQ(0, options->size());
}
// Test get one option data.
TEST(TranslatorOptionDataListTest, get) {
// Get a translator option data list object to play with.
S_Connection conn(new Connection("translator option data list unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorOptionDataList> todl_obj;
// Use the ad hoc model.
const string& model = "kea-dhcp6";
EXPECT_NO_THROW(todl_obj.reset(new TranslatorOptionDataList(sess, model)));
// Create the option code 100.
const string& xpath = "/kea-dhcp6:config/option-data-list";
const string& xoption = xpath + "/option-data[code='100'][space='dns']";
const string& xformat = xoption + "/csv-format";
const string& xdata = xoption + "/data";
const string& xsend = xoption + "/always-send";
S_Val s_false(new Val(false));
ASSERT_NO_THROW(sess->set_item(xformat.c_str(), s_false));
S_Val s_data(new Val("12121212"));
ASSERT_NO_THROW(sess->set_item(xdata.c_str(), s_data));
ASSERT_NO_THROW(sess->set_item(xsend.c_str(), s_false));
// Get the option data.
ConstElementPtr option;
EXPECT_NO_THROW(option = todl_obj->getOptionData(xoption));
ASSERT_TRUE(option);
EXPECT_EQ("{ \"always-send\": false, \"code\": 100, \"csv-format\": false, \"data\": \"12121212\", \"space\": \"dns\" }",
option->str());
// Get the option data list.
ConstElementPtr options;
EXPECT_NO_THROW(options = todl_obj->getOptionDataList(xpath));
ASSERT_TRUE(options);
ASSERT_EQ(Element::list, options->getType());
EXPECT_EQ(1, options->size());
EXPECT_TRUE(option->equals(*options->get(0)));
}
// Test set empty option data list.
TEST(TranslatorOptionDataListTest, setEmpty) {
// Get a translator option data list object to play with.
S_Connection conn(new Connection("translator option data list unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorOptionDataList> todl_obj;
// Use the ad hoc model.
const string& model = "kea-dhcp4";
EXPECT_NO_THROW(todl_obj.reset(new TranslatorOptionDataList(sess, model)));
// Set empty list.
const string& xpath = "/kea-dhcp4:config/option-data-list";
ConstElementPtr options = Element::createList();
EXPECT_NO_THROW(todl_obj->setOptionDataList(xpath, options));
// Get it back.
options.reset();
EXPECT_NO_THROW(options = todl_obj->getOptionDataList(xpath));
ASSERT_TRUE(options);
EXPECT_EQ(0, options->size());
}
// Test set an option data.
TEST(TranslatorOptionDataListTest, set) {
// Get a translator option data list object to play with.
S_Connection conn(new Connection("translator option data list unittests"));
S_Session sess(new Session(conn, SR_DS_CANDIDATE));
boost::scoped_ptr<TranslatorOptionDataList> todl_obj;
// Use the ad hoc model.
const string& model = "kea-dhcp6";
EXPECT_NO_THROW(todl_obj.reset(new TranslatorOptionDataList(sess, model)));
// Set one option data.
const string& xpath = "/kea-dhcp6:config/option-data-list";
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
option->set("code", Element::create(100));
option->set("space", Element::create(string("dns")));
option->set("csv-format", Element::create(false));
option->set("data", Element::create(string("12121212")));
option->set("always-send", Element::create(false));
options->add(option);
EXPECT_NO_THROW(todl_obj->setOptionDataList(xpath, options));
// Get it back.
ConstElementPtr got;
EXPECT_NO_THROW(got = todl_obj->getOptionDataList(xpath));
ASSERT_TRUE(got);
ASSERT_EQ(1, got->size());
EXPECT_TRUE(option->equals(*got->get(0)));
// Check the tree representation.
S_Tree tree;
EXPECT_NO_THROW(tree = sess->get_subtree("/kea-dhcp6:config"));
ASSERT_TRUE(tree);
string expected =
"kea-dhcp6:config (container)\n"
" |\n"
" -- option-data-list (container)\n"
" |\n"
" -- option-data (list instance)\n"
" |\n"
" -- code = 100\n"
" |\n"
" -- space = dns\n"
" |\n"
" -- data = 12121212\n"
" |\n"
" -- csv-format = false\n"
" |\n"
" -- always-send = false\n";
EXPECT_EQ(expected, tree->to_string(100));
}
}; // end of anonymous namespace
// 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/translator_option_data.h>
#include <yang/adaptor.h>
#include <sstream>
using namespace std;
using namespace isc::data;
namespace isc {
namespace yang {
TranslatorOptionData::TranslatorOptionData(S_Session session,
const string& model)
: TranslatorBasic(session), model_(model) {
}
TranslatorOptionData::~TranslatorOptionData() {
}
ElementPtr
TranslatorOptionData::getOptionData(const string& xpath) {
try {
if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) {
return (getOptionDataKea(xpath));
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting option data at '" << xpath
<< "': " << ex.what());
}
isc_throw(NotImplemented,
"getOptionData not implemented for the model: " << model_);
}
ElementPtr
TranslatorOptionData::getOptionDataKea(const string& xpath) {
ConstElementPtr code = getItem(xpath + "/code");
ConstElementPtr space = getItem(xpath + "/space");
if (!code || !space) {
return (ElementPtr());
}
ElementPtr result = Element::createMap();
result->set("code", code);
result->set("space", space);
ConstElementPtr name = getItem(xpath + "/name");
if (name) {
result->set("name", name);
}
ConstElementPtr data = getItem(xpath + "/data");
if (data) {
result->set("data", data);
}
ConstElementPtr format = getItem(xpath + "/csv-format");
if (format) {
result->set("csv-format", format);
}
ConstElementPtr send = getItem(xpath + "/always-send");
if (send) {
result->set("always-send", send);
}
ConstElementPtr context = getItem(xpath + "/user-context");
if (context) {
result->set("user-context", Element::fromJSON(context->stringValue()));
}
return (result);
}
void
TranslatorOptionData::setOptionData(const string& xpath,
ConstElementPtr elem) {
try {
if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) {
setOptionDataKea(xpath, elem);
} else {
isc_throw(NotImplemented,
"setOptionData not implemented for the model: "
<< model_);
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error setting option data '" << elem->str()
<< "' at '" << xpath << "': " << ex.what());
}
}
void
TranslatorOptionData::setOptionDataKea(const string& xpath,
ConstElementPtr elem) {
ConstElementPtr name = elem->get("name");
if (name) {
setItem(xpath + "/name", name, SR_STRING_T);
}
ConstElementPtr data = elem->get("data");
if (data) {
setItem(xpath + "/data", data, SR_STRING_T);
}
ConstElementPtr format = elem->get("csv-format");
if (format) {
setItem(xpath + "/csv-format", format, SR_BOOL_T);
}
ConstElementPtr send = elem->get("always-send");
if (send) {
setItem(xpath + "/always-send", send, SR_BOOL_T);
}
ConstElementPtr context = Adaptor::getContext(elem);
if (context) {
setItem(xpath + "/user-context", Element::create(context->str()),
SR_STRING_T);
}
}
TranslatorOptionDataList::TranslatorOptionDataList(S_Session session,
const string& model)
: TranslatorBasic(session), TranslatorOptionData(session, model),
model_(model) {
}
TranslatorOptionDataList::~TranslatorOptionDataList() {
}
ConstElementPtr
TranslatorOptionDataList::getOptionDataList(const string& xpath) {
try {
if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) {
return (getOptionDataListKea(xpath));
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error getting option data list at '" << xpath
<< "': " << ex.what());
}
isc_throw(NotImplemented,
"getOptionDataList not implemented for the model: " << model_);
}
ConstElementPtr
TranslatorOptionDataList::getOptionDataListKea(const string& xpath) {
ElementPtr result = Element::createList();
S_Iter_Value iter = getIter(xpath + "/*");
if (!iter) {
return (ConstElementPtr());
}
for (;;) {
const string& option = getNext(iter);
if (option.empty()) {
break;
}
result->add(getOptionData(option));
}
return (result);
}
void
TranslatorOptionDataList::setOptionDataList(const string& xpath,
ConstElementPtr elem) {
try {
if ((model_ == "kea-dhcp4") || (model_ == "kea-dhcp6")) {
setOptionDataListKea(xpath, elem);
} else {
isc_throw(NotImplemented,
"setOptionDataList not implemented for the model: "
<< model_);
}
} catch (const sysrepo_exception& ex) {
isc_throw(SysrepoError,
"sysrepo error setting option data list '" << elem->str()
<< "' at '" << xpath << "': " << ex.what());
}
}
void
TranslatorOptionDataList::setOptionDataListKea(const string& xpath,
ConstElementPtr elem) {
for (size_t i = 0; i < elem->size(); ++i) {
ConstElementPtr option = elem->get(i);
if (!option->contains("code")) {
isc_throw(BadValue, "option data without code: " << option->str());
}
unsigned code = static_cast<unsigned>(option->get("code")->intValue());
if (!option->contains("space")) {
isc_throw(BadValue,"option data without space: " <<option->str());
}
string space = option->get("space")->stringValue();
ostringstream keys;
keys << xpath << "/option-data[code='" << code
<< "'][space='" << space << "']";
setOptionData(keys.str(), option);
}
}
}; // end of namespace isc::yang
}; // end of namespace isc
// 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_OPTION_DATA_H
#define ISC_TRANSLATOR_OPTION_DATA_H 1
#include <yang/translator.h>
#include <list>
namespace isc {
namespace yang {
// @brief Between Yang and JSON translator class for the option data.
class TranslatorOptionData : virtual public TranslatorBasic {
public:
/// @brief Constructor.
///
/// @param session Sysrepo session.
/// @param model Model name.
TranslatorOptionData(S_Session session, const std::string& model);
/// @brief Destructor.
virtual ~TranslatorOptionData();
/// @brief Get and translate an option data from Yang to JSON.
///
/// JSON syntax for Kea DHCP with command channel is:
/// @code
/// {
/// "code": <code>,
/// "name": <name>,
/// "space": <space>,
/// "csv-format": <csv format flag>,
/// "data": <value>,
/// "always-send": <always send flag>,
/// "user-context": { <json map> },
/// "comment": "<comment>"
/// }
/// @endcode
///
/// @param xpath The xpath of the option data.
/// @return JSON representation of the option data.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getOptionData(const std::string& xpath);
/// @brief Translate and set option data from JSON to Yang.
///
/// @param xpath The xpath of the option data.
/// @param elem The JSON element.
void setOptionData(const std::string& xpath,
isc::data::ConstElementPtr elem);
protected:
/// @brief getOptionData JSON for kea-dhcp[46].
///
/// @param xpath The xpath of the option data.
/// @return JSON representation of the option data.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ElementPtr getOptionDataKea(const std::string& xpath);
/// @brief setOptionData for kea-dhcp[46].
///
/// Yang syntax for kea-dhcp[46] with code and space as keys is:
/// @code
/// +--rw name? string
/// +--rw data? string
/// +--rw code uint8 / uint16
/// +--rw space string
/// +--rw csv-format? string
/// +--rw always-send? boolean
/// +--rw user-context? string
/// @endcode
///
/// @param xpath The xpath of the option data.
/// @param elem The JSON element.
void setOptionDataKea(const std::string& xpath,
isc::data::ConstElementPtr elem);
/// @brief The model.
std::string model_;
};
// @brief Between Yang and JSON translator class for option data list.
class TranslatorOptionDataList : virtual public TranslatorOptionData {
public:
/// @brief Constructor.
///
/// @param session Sysrepo session.
/// @param model Model name.
TranslatorOptionDataList(S_Session session, const std::string& model);
/// @brief Destructor.
virtual ~TranslatorOptionDataList();
/// @brief Get and translate option data list from Yang to JSON.
///
/// @param xpath The xpath of the option data list.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ConstElementPtr getOptionDataList(const std::string& xpath);
/// @brief Translate and set option data list from JSON to Yang.
///
/// @param xpath The xpath of the option data list.
/// @param elem The JSON element.
void setOptionDataList(const std::string& xpath,
isc::data::ConstElementPtr elem);
protected:
/// @brief getOptionDataList for kea-dhcp[46].
///
/// @param xpath The xpath of the option data list.
/// @throw SysrepoError when sysrepo raises an error.
isc::data::ConstElementPtr getOptionDataListKea(const std::string& xpath);
/// @brief setOptionDataList for kea-dhcp[46].
///
/// Yang syntax is a option-data list keyed by code and space.
///
/// @param xpath The xpath of the option data list.
/// @param elem The JSON element.
void setOptionDataListKea(const std::string& xpath,
isc::data::ConstElementPtr elem);
/// @brief The model.
std::string model_;
};
}; // end of namespace isc::yang
}; // end of namespace isc
#endif // ISC_TRANSLATOR_OPTION_DATA_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment