Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
Kea
Commits
6f304d9e
Commit
6f304d9e
authored
Jul 23, 2013
by
Tomek Mrugalski
🛰
Browse files
[2984] DHCPv6 hooks tests moved to a separate file.
parent
61363a11
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
src/bin/dhcp6/tests/Makefile.am
View file @
6f304d9e
...
...
@@ -49,6 +49,8 @@ TESTS += dhcp6_unittests
dhcp6_unittests_SOURCES
=
dhcp6_unittests.cc
dhcp6_unittests_SOURCES
+=
dhcp6_srv_unittest.cc
dhcp6_unittests_SOURCES
+=
hook_unittest.cc
dhcp6_unittests_SOURCES
+=
dhcp6_test_utils.h
dhcp6_unittests_SOURCES
+=
ctrl_dhcp6_srv_unittest.cc
dhcp6_unittests_SOURCES
+=
config_parser_unittest.cc
dhcp6_unittests_SOURCES
+=
../dhcp6_srv.h ../dhcp6_srv.cc
...
...
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
View file @
6f304d9e
This diff is collapsed.
Click to expand it.
src/bin/dhcp6/tests/dhcp6_test_utils.h
0 → 100644
View file @
6f304d9e
// Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
/// @file dhcp6_test_utils.h
///
/// @brief This file contains utility classes used for DHCPv6 server testing
#include
<gtest/gtest.h>
#include
<dhcpsrv/lease_mgr.h>
#include
<dhcpsrv/lease_mgr_factory.h>
#include
<hooks/hooks_manager.h>
#include
<config/ccsession.h>
#include
<dhcp6/dhcp6_srv.h>
#include
<dhcp/pkt6.h>
#include
<dhcp/option6_ia.h>
#include
<dhcp/option6_iaaddr.h>
#include
<dhcp/option_int_array.h>
#include
<list>
using
namespace
isc
::
dhcp
;
using
namespace
isc
::
config
;
using
namespace
isc
::
data
;
using
namespace
isc
::
hooks
;
using
namespace
isc
::
asiolink
;
using
namespace
isc
::
util
;
using
namespace
isc
::
hooks
;
namespace
isc
{
namespace
test
{
/// @brief "naked" Dhcpv6Srv class that exposes internal members
class
NakedDhcpv6Srv
:
public
isc
::
dhcp
::
Dhcpv6Srv
{
public:
NakedDhcpv6Srv
(
uint16_t
port
)
:
Dhcpv6Srv
(
port
)
{
// Open the "memfile" database for leases
std
::
string
memfile
=
"type=memfile"
;
LeaseMgrFactory
::
create
(
memfile
);
}
/// @brief fakes packet reception
/// @param timeout ignored
///
/// The method receives all packets queued in receive
/// queue, one after another. Once the queue is empty,
/// it initiates the shutdown procedure.
///
/// See fake_received_ field for description
virtual
isc
::
dhcp
::
Pkt6Ptr
receivePacket
(
int
/*timeout*/
)
{
// If there is anything prepared as fake incoming
// traffic, use it
if
(
!
fake_received_
.
empty
())
{
Pkt6Ptr
pkt
=
fake_received_
.
front
();
fake_received_
.
pop_front
();
return
(
pkt
);
}
// If not, just trigger shutdown and
// return immediately
shutdown
();
return
(
Pkt6Ptr
());
}
/// @brief fake packet sending
///
/// Pretend to send a packet, but instead just store
/// it in fake_send_ list where test can later inspect
/// server's response.
virtual
void
sendPacket
(
const
Pkt6Ptr
&
pkt
)
{
fake_sent_
.
push_back
(
pkt
);
}
/// @brief adds a packet to fake receive queue
///
/// See fake_received_ field for description
void
fakeReceive
(
const
Pkt6Ptr
&
pkt
)
{
fake_received_
.
push_back
(
pkt
);
}
virtual
~
NakedDhcpv6Srv
()
{
// Close the lease database
LeaseMgrFactory
::
destroy
();
}
using
Dhcpv6Srv
::
processSolicit
;
using
Dhcpv6Srv
::
processRequest
;
using
Dhcpv6Srv
::
processRenew
;
using
Dhcpv6Srv
::
processRelease
;
using
Dhcpv6Srv
::
createStatusCode
;
using
Dhcpv6Srv
::
selectSubnet
;
using
Dhcpv6Srv
::
sanityCheck
;
using
Dhcpv6Srv
::
loadServerID
;
using
Dhcpv6Srv
::
writeServerID
;
/// @brief packets we pretend to receive
///
/// Instead of setting up sockets on interfaces that change between OSes, it
/// is much easier to fake packet reception. This is a list of packets that
/// we pretend to have received. You can schedule new packets to be received
/// using fakeReceive() and NakedDhcpv6Srv::receivePacket() methods.
std
::
list
<
Pkt6Ptr
>
fake_received_
;
std
::
list
<
Pkt6Ptr
>
fake_sent_
;
};
static
const
char
*
DUID_FILE
=
"server-id-test.txt"
;
// test fixture for any tests requiring blank/empty configuration
// serves as base class for additional tests
class
NakedDhcpv6SrvTest
:
public
::
testing
::
Test
{
public:
NakedDhcpv6SrvTest
()
:
rcode_
(
-
1
)
{
// it's ok if that fails. There should not be such a file anyway
unlink
(
DUID_FILE
);
const
IfaceMgr
::
IfaceCollection
&
ifaces
=
IfaceMgr
::
instance
().
getIfaces
();
// There must be some interface detected
if
(
ifaces
.
empty
())
{
// We can't use ASSERT in constructor
ADD_FAILURE
()
<<
"No interfaces detected."
;
}
valid_iface_
=
ifaces
.
begin
()
->
getName
();
}
// Generate IA_NA option with specified parameters
boost
::
shared_ptr
<
Option6IA
>
generateIA
(
uint32_t
iaid
,
uint32_t
t1
,
uint32_t
t2
)
{
boost
::
shared_ptr
<
Option6IA
>
ia
=
boost
::
shared_ptr
<
Option6IA
>
(
new
Option6IA
(
D6O_IA_NA
,
iaid
));
ia
->
setT1
(
t1
);
ia
->
setT2
(
t2
);
return
(
ia
);
}
/// @brief generates interface-id option, based on text
///
/// @param iface_id textual representation of the interface-id content
///
/// @return pointer to the option object
OptionPtr
generateInterfaceId
(
const
std
::
string
&
iface_id
)
{
OptionBuffer
tmp
(
iface_id
.
begin
(),
iface_id
.
end
());
return
OptionPtr
(
new
Option
(
Option
::
V6
,
D6O_INTERFACE_ID
,
tmp
));
}
// Generate client-id option
OptionPtr
generateClientId
(
size_t
duid_size
=
32
)
{
OptionBuffer
clnt_duid
(
duid_size
);
for
(
int
i
=
0
;
i
<
duid_size
;
i
++
)
{
clnt_duid
[
i
]
=
100
+
i
;
}
duid_
=
DuidPtr
(
new
DUID
(
clnt_duid
));
return
(
OptionPtr
(
new
Option
(
Option
::
V6
,
D6O_CLIENTID
,
clnt_duid
.
begin
(),
clnt_duid
.
begin
()
+
duid_size
)));
}
// Checks if server response (ADVERTISE or REPLY) includes proper server-id.
void
checkServerId
(
const
Pkt6Ptr
&
rsp
,
const
OptionPtr
&
expected_srvid
)
{
// check that server included its server-id
OptionPtr
tmp
=
rsp
->
getOption
(
D6O_SERVERID
);
EXPECT_EQ
(
tmp
->
getType
(),
expected_srvid
->
getType
()
);
ASSERT_EQ
(
tmp
->
len
(),
expected_srvid
->
len
()
);
EXPECT_TRUE
(
tmp
->
getData
()
==
expected_srvid
->
getData
());
}
// Checks if server response (ADVERTISE or REPLY) includes proper client-id.
void
checkClientId
(
const
Pkt6Ptr
&
rsp
,
const
OptionPtr
&
expected_clientid
)
{
// check that server included our own client-id
OptionPtr
tmp
=
rsp
->
getOption
(
D6O_CLIENTID
);
ASSERT_TRUE
(
tmp
);
EXPECT_EQ
(
expected_clientid
->
getType
(),
tmp
->
getType
());
ASSERT_EQ
(
expected_clientid
->
len
(),
tmp
->
len
());
// check that returned client-id is valid
EXPECT_TRUE
(
expected_clientid
->
getData
()
==
tmp
->
getData
());
}
// Checks if server response is a NAK
void
checkNakResponse
(
const
Pkt6Ptr
&
rsp
,
uint8_t
expected_message_type
,
uint32_t
expected_transid
,
uint16_t
expected_status_code
)
{
// Check if we get response at all
checkResponse
(
rsp
,
expected_message_type
,
expected_transid
);
// Check that IA_NA was returned
OptionPtr
option_ia_na
=
rsp
->
getOption
(
D6O_IA_NA
);
ASSERT_TRUE
(
option_ia_na
);
// check that the status is no address available
boost
::
shared_ptr
<
Option6IA
>
ia
=
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
option_ia_na
);
ASSERT_TRUE
(
ia
);
checkIA_NAStatusCode
(
ia
,
expected_status_code
);
}
// Checks that server rejected IA_NA, i.e. that it has no addresses and
// that expected status code really appears there. In some limited cases
// (reply to RELEASE) it may be used to verify positive case, where
// IA_NA response is expected to not include address.
//
// Status code indicates type of error encountered (in theory it can also
// indicate success, but servers typically don't send success status
// as this is the default result and it saves bandwidth)
void
checkIA_NAStatusCode
(
const
boost
::
shared_ptr
<
Option6IA
>&
ia
,
uint16_t
expected_status_code
)
{
// Make sure there is no address assigned.
EXPECT_FALSE
(
ia
->
getOption
(
D6O_IAADDR
));
// T1, T2 should be zeroed
EXPECT_EQ
(
0
,
ia
->
getT1
());
EXPECT_EQ
(
0
,
ia
->
getT2
());
OptionCustomPtr
status
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
ia
->
getOption
(
D6O_STATUS_CODE
));
// It is ok to not include status success as this is the default behavior
if
(
expected_status_code
==
STATUS_Success
&&
!
status
)
{
return
;
}
EXPECT_TRUE
(
status
);
if
(
status
)
{
// We don't have dedicated class for status code, so let's just interpret
// first 2 bytes as status. Remainder of the status code option content is
// just a text explanation what went wrong.
EXPECT_EQ
(
static_cast
<
uint16_t
>
(
expected_status_code
),
status
->
readInteger
<
uint16_t
>
(
0
));
}
}
void
checkMsgStatusCode
(
const
Pkt6Ptr
&
msg
,
uint16_t
expected_status
)
{
OptionCustomPtr
status
=
boost
::
dynamic_pointer_cast
<
OptionCustom
>
(
msg
->
getOption
(
D6O_STATUS_CODE
));
// It is ok to not include status success as this is the default behavior
if
(
expected_status
==
STATUS_Success
&&
!
status
)
{
return
;
}
EXPECT_TRUE
(
status
);
if
(
status
)
{
// We don't have dedicated class for status code, so let's just interpret
// first 2 bytes as status. Remainder of the status code option content is
// just a text explanation what went wrong.
EXPECT_EQ
(
static_cast
<
uint16_t
>
(
expected_status
),
status
->
readInteger
<
uint16_t
>
(
0
));
}
}
// Basic checks for generated response (message type and transaction-id).
void
checkResponse
(
const
Pkt6Ptr
&
rsp
,
uint8_t
expected_message_type
,
uint32_t
expected_transid
)
{
ASSERT_TRUE
(
rsp
);
EXPECT_EQ
(
expected_message_type
,
rsp
->
getType
());
EXPECT_EQ
(
expected_transid
,
rsp
->
getTransid
());
}
virtual
~
NakedDhcpv6SrvTest
()
{
// Let's clean up if there is such a file.
unlink
(
DUID_FILE
);
HooksManager
::
preCalloutsLibraryHandle
().
deregisterAllCallouts
(
"pkt6_receive"
);
HooksManager
::
preCalloutsLibraryHandle
().
deregisterAllCallouts
(
"pkt6_send"
);
HooksManager
::
preCalloutsLibraryHandle
().
deregisterAllCallouts
(
"subnet6_select"
);
};
// A DUID used in most tests (typically as client-id)
DuidPtr
duid_
;
int
rcode_
;
ConstElementPtr
comment_
;
// Name of a valid network interface
std
::
string
valid_iface_
;
};
// Provides suport for tests against a preconfigured subnet6
// extends upon NakedDhcp6SrvTest
class
Dhcpv6SrvTest
:
public
NakedDhcpv6SrvTest
{
public:
/// Name of the server-id file (used in server-id tests)
// these are empty for now, but let's keep them around
Dhcpv6SrvTest
()
{
subnet_
=
Subnet6Ptr
(
new
Subnet6
(
IOAddress
(
"2001:db8:1::"
),
48
,
1000
,
2000
,
3000
,
4000
));
pool_
=
Pool6Ptr
(
new
Pool6
(
Pool6
::
TYPE_IA
,
IOAddress
(
"2001:db8:1:1::"
),
64
));
subnet_
->
addPool
(
pool_
);
CfgMgr
::
instance
().
deleteSubnets6
();
CfgMgr
::
instance
().
addSubnet6
(
subnet_
);
}
// Checks that server response (ADVERTISE or REPLY) contains proper IA_NA option
// It returns IAADDR option for each chaining with checkIAAddr method.
boost
::
shared_ptr
<
Option6IAAddr
>
checkIA_NA
(
const
Pkt6Ptr
&
rsp
,
uint32_t
expected_iaid
,
uint32_t
expected_t1
,
uint32_t
expected_t2
)
{
OptionPtr
tmp
=
rsp
->
getOption
(
D6O_IA_NA
);
// Can't use ASSERT_TRUE() in method that returns something
if
(
!
tmp
)
{
ADD_FAILURE
()
<<
"IA_NA option not present in response"
;
return
(
boost
::
shared_ptr
<
Option6IAAddr
>
());
}
boost
::
shared_ptr
<
Option6IA
>
ia
=
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
tmp
);
if
(
!
ia
)
{
ADD_FAILURE
()
<<
"IA_NA cannot convert option ptr to Option6"
;
return
(
boost
::
shared_ptr
<
Option6IAAddr
>
());
}
EXPECT_EQ
(
expected_iaid
,
ia
->
getIAID
());
EXPECT_EQ
(
expected_t1
,
ia
->
getT1
());
EXPECT_EQ
(
expected_t2
,
ia
->
getT2
());
tmp
=
ia
->
getOption
(
D6O_IAADDR
);
boost
::
shared_ptr
<
Option6IAAddr
>
addr
=
boost
::
dynamic_pointer_cast
<
Option6IAAddr
>
(
tmp
);
return
(
addr
);
}
// Check that generated IAADDR option contains expected address
// and lifetime values match the configured subnet
void
checkIAAddr
(
const
boost
::
shared_ptr
<
Option6IAAddr
>&
addr
,
const
IOAddress
&
expected_addr
,
uint32_t
/* expected_preferred */
,
uint32_t
/* expected_valid */
)
{
// Check that the assigned address is indeed from the configured pool.
// Note that when comparing addresses, we compare the textual
// representation. IOAddress does not support being streamed to
// an ostream, which means it can't be used in EXPECT_EQ.
EXPECT_TRUE
(
subnet_
->
inPool
(
addr
->
getAddress
()));
EXPECT_EQ
(
expected_addr
.
toText
(),
addr
->
getAddress
().
toText
());
EXPECT_EQ
(
addr
->
getPreferred
(),
subnet_
->
getPreferred
());
EXPECT_EQ
(
addr
->
getValid
(),
subnet_
->
getValid
());
}
// Checks if the lease sent to client is present in the database
// and is valid when checked agasint the configured subnet
Lease6Ptr
checkLease
(
const
DuidPtr
&
duid
,
const
OptionPtr
&
ia_na
,
boost
::
shared_ptr
<
Option6IAAddr
>
addr
)
{
boost
::
shared_ptr
<
Option6IA
>
ia
=
boost
::
dynamic_pointer_cast
<
Option6IA
>
(
ia_na
);
Lease6Ptr
lease
=
LeaseMgrFactory
::
instance
().
getLease6
(
addr
->
getAddress
());
if
(
!
lease
)
{
std
::
cout
<<
"Lease for "
<<
addr
->
getAddress
().
toText
()
<<
" not found in the database backend."
;
return
(
Lease6Ptr
());
}
EXPECT_EQ
(
addr
->
getAddress
().
toText
(),
lease
->
addr_
.
toText
());
EXPECT_TRUE
(
*
lease
->
duid_
==
*
duid
);
EXPECT_EQ
(
ia
->
getIAID
(),
lease
->
iaid_
);
EXPECT_EQ
(
subnet_
->
getID
(),
lease
->
subnet_id_
);
return
(
lease
);
}
~
Dhcpv6SrvTest
()
{
CfgMgr
::
instance
().
deleteSubnets6
();
};
// A subnet used in most tests
Subnet6Ptr
subnet_
;
// A pool used in most tests
Pool6Ptr
pool_
;
};
};
// end of isc::test namespace
};
// end of isc namespace
src/bin/dhcp6/tests/hook_unittest.cc
0 → 100644
View file @
6f304d9e
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment