Commit 3a1cec32 authored by Francis Dupont's avatar Francis Dupont

[219-allow-an-option-value-to-be-set-from-an-expression] Added new tests and an example

parent 85ff0365
......@@ -1216,14 +1216,15 @@ take a string value representing an expression.
::
"Dhcp6": {
"Dhcp4": {
"hook_libraries": [
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
"parameters": {
"options": [
{
"code": 100,
"add": "concat(relay6[0].option[37].hex, 'abc')"
"code": 67,
"add":
"ifelse(option[host-name].exists,concat(option[host-name].text,'.boot'),'')"
}
]
}
......@@ -1232,8 +1233,14 @@ take a string value representing an expression.
]
}
If (and only if) the query includes a host-name option (code 12),
a boot-file-name option (code 67) is added to the response with the host
name followed by .boot for content.
The flexible option library supports both DHCPv4 and DHCPv6.
.. _host-cmds:
host_cmds: Host Commands
......
......@@ -63,7 +63,7 @@ To configure it for kea-dhcp6, the commands are simply as shown below:
{ "library": "/usr/local/lib/libdhcp_flex_option.so",
"parameters": {
"options": [
{
{
"code": 100,
"add": "concat(relay6[0].option[37].hex, 'abc')"
}
......
......@@ -17,6 +17,8 @@
#include <hooks/hooks_manager.h>
#include <hooks/callout_manager.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt6.h>
#include <dhcpsrv/cfgmgr.h>
#include <gtest/gtest.h>
#include <errno.h>
......@@ -114,7 +116,7 @@ TEST_F(CalloutTest, pkt4Send) {
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt4_send_,
*handle));
EXPECT_EQ(0, handle->getStatus());
// Check the result.
OptionPtr opt = response->getOption(DHO_HOST_NAME);
ASSERT_TRUE(opt);
......@@ -124,4 +126,49 @@ TEST_F(CalloutTest, pkt4Send) {
EXPECT_EQ(0, memcmp(&buffer[0], "abc", 3));
}
// Simple test which exercises the pkt6_send callout.
TEST_F(CalloutTest, pkt6Send) {
// Move to DHCPv6.
CfgMgr::instance().setFamily(AF_INET6);
// Prepare load() parameters.
ElementPtr params = Element::createMap();
ElementPtr options = Element::createList();
params->set("options", options);
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(D6O_BOOTFILE_URL);
option->set("code", code);
ElementPtr supersede = Element::create(string("'abc'"));
option->set("supersede", supersede);
// Load the library.
addLib(FLEX_OPTION_LIB_SO, params);
loadLibs();
// Prepare packets.
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 12345));
Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, 12345));
EXPECT_FALSE(response->getOption(D6O_BOOTFILE_URL));
// Get and setup the callout handle.
EXPECT_TRUE(HooksManager::calloutsPresent(testHooks.hook_index_pkt6_send_));
CalloutHandlePtr handle = HooksManager::createCalloutHandle();
handle->setArgument("query6", query);
handle->setArgument("response6", response);
// Execute the callout.
EXPECT_NO_THROW(HooksManager::callCallouts(testHooks.hook_index_pkt6_send_,
*handle));
EXPECT_EQ(0, handle->getStatus());
// Check the result.
OptionPtr opt = response->getOption(D6O_BOOTFILE_URL);
ASSERT_TRUE(opt);
EXPECT_EQ(D6O_BOOTFILE_URL, opt->getType());
const OptionBuffer& buffer = opt->getData();
ASSERT_EQ(3, buffer.size());
EXPECT_EQ(0, memcmp(&buffer[0], "abc", 3));
}
} // end of anonymous namespace
......@@ -778,6 +778,8 @@ TEST_F(FlexOptionTest, processAdd) {
// Verify that ADD action does not add an already existing option.
TEST_F(FlexOptionTest, processAddExisting) {
CfgMgr::instance().setFamily(AF_INET6);
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
options->add(option);
......@@ -852,6 +854,8 @@ TEST_F(FlexOptionTest, processSupersede) {
// Verify that SUPERSEDE action supersedes an already existing option.
TEST_F(FlexOptionTest, processSupersedeExisting) {
CfgMgr::instance().setFamily(AF_INET6);
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
options->add(option);
......@@ -916,6 +920,8 @@ TEST_F(FlexOptionTest, processSupersedeEmpty) {
// Verify that REMOVE action removes an already existing option.
TEST_F(FlexOptionTest, processRemove) {
CfgMgr::instance().setFamily(AF_INET6);
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
options->add(option);
......@@ -961,6 +967,8 @@ TEST_F(FlexOptionTest, processRemoveNoOption) {
// Verify that REMOVE action does nothing when the expression evaluates to false.
TEST_F(FlexOptionTest, processRemoveFalse) {
CfgMgr::instance().setFamily(AF_INET6);
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
options->add(option);
......@@ -971,16 +979,46 @@ TEST_F(FlexOptionTest, processRemoveFalse) {
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 12345));
Pkt4Ptr response(new Pkt4(DHCPOFFER, 12345));
Pkt6Ptr query(new Pkt6(DHCPV6_SOLICIT, 12345));
Pkt6Ptr response(new Pkt6(DHCPV6_ADVERTISE, 12345));
OptionStringPtr str(new OptionString(Option::V6, D6O_BOOTFILE_URL, "http"));
response->addOption(str);
string response_txt = response->toText();
EXPECT_NO_THROW(impl_->process<Pkt4Ptr>(Option::V6, query, response));
EXPECT_NO_THROW(impl_->process<Pkt6Ptr>(Option::V6, query, response));
EXPECT_EQ(response_txt, response->toText());
EXPECT_TRUE(response->getOption(D6O_BOOTFILE_URL));
}
// A more complex check...
TEST_F(FlexOptionTest, processFullTest) {
ElementPtr options = Element::createList();
ElementPtr option = Element::createMap();
options->add(option);
ElementPtr code = Element::create(DHO_BOOT_FILE_NAME);
option->set("code", code);
string expr = "ifelse(option[host-name].exists,";
expr += "concat(option[host-name].text,'.boot'),'')";
ElementPtr add = Element::create(expr);
option->set("add", add);
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty());
Pkt4Ptr query(new Pkt4(DHCPDISCOVER, 12345));
Pkt4Ptr response(new Pkt4(DHCPOFFER, 12345));
OptionStringPtr str(new OptionString(Option::V4, DHO_HOST_NAME, "foo"));
query->addOption(str);
EXPECT_FALSE(response->getOption(DHO_BOOT_FILE_NAME));
EXPECT_NO_THROW(impl_->process<Pkt4Ptr>(Option::V4, query, response));
OptionPtr opt = response->getOption(DHO_BOOT_FILE_NAME);
ASSERT_TRUE(opt);
EXPECT_EQ(DHO_BOOT_FILE_NAME, opt->getType());
const OptionBuffer& buffer = opt->getData();
ASSERT_EQ(8, buffer.size());
EXPECT_EQ(0, memcmp(&buffer[0], "foo.boot", 8));
}
} // end of anonymous namespace
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