Browse Source

[1955] Added remaining unit tests for PerfPkt4 and cleaned up the code.

Marcin Siodelski 13 years ago
parent
commit
81784141da

+ 16 - 10
tests/tools/perfdhcp/perf_pkt4.cc

@@ -12,8 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <iostream>
-#include <exceptions/exceptions.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/dhcp6.h>
 
@@ -27,22 +25,30 @@ using namespace dhcp;
 namespace isc {
 namespace perfdhcp {
 
-    PerfPkt4::PerfPkt4(const uint8_t* buf, uint32_t len, size_t transid_offset, uint32_t transid) :
+PerfPkt4::PerfPkt4(const uint8_t* buf, size_t len) :
+    Pkt4(buf, len),
+    transid_offset_(1) {
+}
+
+PerfPkt4::PerfPkt4(const uint8_t* buf,
+                   size_t len,
+                   size_t transid_offset,
+                   uint32_t transid) :
     Pkt4(buf, len),
     transid_offset_(transid_offset) {
     transid_ = transid;
 }
 
-PerfPkt4::PerfPkt4(const uint8_t* buf, uint32_t len, size_t transid_offset) :
+PerfPkt4::PerfPkt4(const uint8_t* buf, size_t len, size_t transid_offset) :
     Pkt4(buf, len),
     transid_offset_(transid_offset) {
 }
 
 bool
 PerfPkt4::rawPack() {
-    return (PktTransform::pack(dhcp::Option::V4, 
-                               data_, 
-                               options_, 
+    return (PktTransform::pack(dhcp::Option::V4,
+                               data_,
+                               options_,
                                transid_offset_,
                                transid_,
                                bufferOut_));
@@ -50,9 +56,9 @@ PerfPkt4::rawPack() {
 
 bool
 PerfPkt4::rawUnpack() {
-    return (PktTransform::unpack(dhcp::Option::V4, 
-                                 data_, 
-                                 options_, 
+    return (PktTransform::unpack(dhcp::Option::V4,
+                                 data_,
+                                 options_,
                                  transid_offset_,
                                  transid_));
 }

+ 12 - 2
tests/tools/perfdhcp/perf_pkt4.h

@@ -56,6 +56,16 @@ public:
     /// Localized option pointer type.
     typedef boost::shared_ptr<LocalizedOption> LocalizedOptionPtr;
 
+    /// \brief Constructor, used for outgoing and incoming messages
+    ///
+    /// This constructor initializes transaction id and
+    /// transaction id offset of the packet with default
+    /// values.
+    ///
+    /// \param buf buffer holding contents of the message.
+    /// \param len length of the data in the buffer.
+    PerfPkt4(const uint8_t* buf, size_t len);
+
     /// \brief Constructor, used for outgoing DHCP messages.
     ///
     /// Creates new DHCPv4 message using provided buffer.
@@ -73,7 +83,7 @@ public:
     /// \param transid_offset transaction id offset in outgoing message.
     /// \param transid transaction id to be stored in outgoing message.
     PerfPkt4(const uint8_t* buf,
-             uint32_t len,
+             size_t len,
              size_t transid_offset,
              uint32_t transid);
 
@@ -100,7 +110,7 @@ public:
     /// \param len size of buffer of packet content.
     /// \param transid_offset transaction id offset in a message.
     PerfPkt4(const uint8_t* buf,
-             uint32_t len,
+             size_t len,
              size_t transid_offset);
 
     /// \brief Returns transaction id offset in packet buffer

+ 8 - 9
tests/tools/perfdhcp/pkt_transform.cc

@@ -57,7 +57,7 @@ PktTransform::pack(const Option::Universe universe,
     out_buffer.skip(transid_offset);
 
     try {
-        if (universe == Option::V6) {
+        if (universe == Option::V4) {
             out_buffer.writeUint8(transid >> 24 & 0xFF);
         }
         out_buffer.writeUint8(transid >> 16 & 0xFF);
@@ -111,7 +111,7 @@ PktTransform::unpack(const Option::Universe universe,
     }
 
     try {
-        PktTransform::unpackOptions(universe, in_buffer, options);
+        PktTransform::unpackOptions(in_buffer, options);
     } catch (const isc::BadValue& e) {
         cout << "Packet parsing failed: " << e.what() << endl;
         return (false);
@@ -156,8 +156,7 @@ PktTransform::packOptions(const OptionBuffer& in_buffer,
 }
 
 void
-PktTransform::unpackOptions(const Option::Universe universe,
-                            const OptionBuffer& in_buffer,
+PktTransform::unpackOptions(const OptionBuffer& in_buffer,
                             const Option::OptionCollection& options) {
     for (Option::OptionCollection::const_iterator it = options.begin();
          it != options.end(); ++it) {
@@ -168,7 +167,7 @@ PktTransform::unpackOptions(const Option::Universe universe,
         if (opt_pos == 0) {
             isc_throw(isc::BadValue, "failed to unpack packet from raw buffer "
                       "(Option position not specified)");
-        } else if (opt_pos + 4 > in_buffer.size()) {
+        } else if (opt_pos + option->getHeaderLen() > in_buffer.size()) {
             isc_throw(isc::BadValue,
                       "failed to unpack options from from raw buffer "
                       "(Option position out of bounds)");
@@ -177,7 +176,7 @@ PktTransform::unpackOptions(const Option::Universe universe,
         size_t offset = opt_pos;
         size_t offset_step = 1;
         uint16_t opt_type = 0;
-        if (universe == Option::V6) {
+        if (option->getUniverse() == Option::V6) {
             offset_step = 2;
             // For DHCPv6 option type is in first two octets.
             opt_type = in_buffer[offset] * 256 + in_buffer[offset + 1];
@@ -195,14 +194,14 @@ PktTransform::unpackOptions(const Option::Universe universe,
         // Get option length which is supposed to be after option type.
         offset += offset_step;
         uint16_t opt_len = in_buffer[offset] * 256 + in_buffer[offset + 1];
-        if (universe == Option::V6) {
+        if (option->getUniverse() == Option::V6) {
             opt_len = in_buffer[offset] * 256 + in_buffer[offset + 1];
         } else {
             opt_len = in_buffer[offset];
         }
-        
+
         // Check if packet is not truncated.
-        if (offset + opt_len > in_buffer.size()) {
+        if (offset + option->getHeaderLen() + opt_len > in_buffer.size()) {
             isc_throw(isc::BadValue,
                       "failed to unpack option from raw buffer "
                       "(option truncated)");

+ 21 - 23
tests/tools/perfdhcp/pkt_transform.h

@@ -15,7 +15,6 @@
 #ifndef __PKT_TRANSFORM_H
 #define __PKT_TRANSFORM_H
 
-#include <boost/shared_ptr.hpp>
 #include <dhcp/option.h>
 
 #include "localized_option.h"
@@ -27,20 +26,20 @@ namespace perfdhcp {
 ///
 /// This class provides static functions to read raw
 /// data from packet buffer and write raw data to packet
-/// buffer. When reading data with unpack() method, the 
-/// corresponding options objects are updated. 
-/// When writting to the packet buffer with pack() nethod, 
+/// buffer. When reading data with unpack() method, the
+/// corresponding options objects are updated.
+/// When writting to the packet buffer with pack() nethod,
 /// options objects carry input data to be written.
-/// This class is used both by \ref PerfPkt4 and 
+/// This class is used both by \ref PerfPkt4 and
 /// \ref PerfPkt6 classes in case DHCP packets are created
 /// from template files. In this case, some of the template
-/// packet's options are replaced before sending it to 
+/// packet's options are replaced before sending it to
 /// server. Offset of specific options are provided from
 /// command line by perfdhcp tool user and passed in
 /// options collection.
 /// This class also provide mechanism to read some data
-/// from incoming packet buffer and update options 
-/// in options collection with these data. 
+/// from incoming packet buffer and update options
+/// in options collection with these data.
 /// It is assumed either in case of writting or reading
 /// that all options have to be added to options collection
 /// and their offset have to be specified in buffer
@@ -54,11 +53,11 @@ public:
     /// to output buffer. Input buffer must contain whole
     /// initial packet data. Parts of this data will be
     /// overriden by options data specified in options
-    /// collection. Such options must have their offsets in 
+    /// collection. Such options must have their offsets in
     /// a packet specified (\see LocalizedOption to find out how
     /// to specify options offset).
     ///
-    /// \note Specified options must fit into size of the 
+    /// \note Specified options must fit into size of the
     /// initial packet data. Call to this function will fail
     /// if option's offset + its size is out of bounds.
     ///
@@ -71,7 +70,7 @@ public:
     /// offset
     /// \param transid transaction id value
     /// \param out_buffer output buffer holding "packed" data
-    /// 
+    ///
     /// \retrun false, if pack operation failed.
     static bool pack(const dhcp::Option::Universe universe,
                      const dhcp::OptionBuffer& in_buffer,
@@ -88,8 +87,8 @@ public:
     /// \ref isc::dhcp::Pkt6::addOption to specify which options to parse.
     /// Each option should be of the \ref isc::perfdhcp::LocalizedOption
     /// type with offset value indicated.
-    /// Transaction id offset is specified as separate argument and 
-    /// is used to read transaction id value from buffer. 
+    /// Transaction id offset is specified as separate argument and
+    /// is used to read transaction id value from buffer.
     ///
     /// \param universe universe used, V4 or V6
     /// \param in_buffer input buffer to be parsed
@@ -97,7 +96,7 @@ public:
     /// \param transid_offset offset of transaction id in input buffer
     /// \param transid transaction id value read from input buffer
     /// \return false, if unpack operation failed.
-    static bool unpack(const dhcp::Option::Universe universe, 
+    static bool unpack(const dhcp::Option::Universe universe,
                        const dhcp::OptionBuffer& in_buffer,
                        const dhcp::Option::OptionCollection& options,
                        const size_t transid_offset,
@@ -106,9 +105,9 @@ public:
 private:
     /// \brief Replaces options contents of options in a buffer
     ///
-    /// The method uses localized options collection added to 
-    /// replace parts of initial packet data (e.g. read from 
-    /// template file). 
+    /// The method uses localized options collection added to
+    /// replace parts of initial packet data (e.g. read from
+    /// template file).
     /// This private method is called from \ref PktTransform::pack
     ///
     /// \param in_buffer input buffer holding initial packet data.
@@ -123,24 +122,23 @@ private:
     ///
     /// The method reads options data from the input buffer
     /// and stores read data in options objects. Options
-    /// must have their offsets in a buffer specified 
+    /// must have their offsets in a buffer specified
     /// (\see LocalizedOption to find out how to specify
     /// option offset).
     /// This private method is called by \ref PktTransform::unpack.
     ///
-    /// \note This method iterates through all options in 
+    /// \note This method iterates through all options in
     /// options collection, checks offset of the option
     /// in input buffer and reads data from the buffer to
     /// update option's buffer. If provided options collection
     /// is empty, call to this function will have no effect.
-    /// 
+    ///
     /// \param universe universe used, V4 or V6
     /// \param in_buffer input buffer to be parsed.
-    /// \param options oprions collection with their offsets 
+    /// \param options oprions collection with their offsets
     /// in input buffer specified.
     /// \throw isc::Unexpected if options unpack failed.
-    static void unpackOptions(const dhcp::Option::Universe universe,
-                              const dhcp::OptionBuffer& in_buffer,
+    static void unpackOptions(const dhcp::OptionBuffer& in_buffer,
                               const dhcp::Option::OptionCollection& options);
 };
 

+ 167 - 149
tests/tools/perfdhcp/tests/perf_pkt4_unittest.cc

@@ -35,23 +35,6 @@ typedef PerfPkt4::LocalizedOptionPtr LocalizedOptionPtr;
 
 namespace {
 
-// a sample data
-const uint8_t dummyOp = BOOTREQUEST;
-const uint8_t dummyHtype = 6;
-const uint8_t dummyHlen = 6;
-const uint8_t dummyHops = 13;
-const uint32_t dummyTransid = 0x12345678;
-const uint16_t dummySecs = 42;
-const uint16_t dummyFlags = BOOTP_BROADCAST;
-
-const IOAddress dummyCiaddr("192.0.2.1");
-const IOAddress dummyYiaddr("1.2.3.4");
-const IOAddress dummySiaddr("192.0.2.255");
-const IOAddress dummyGiaddr("255.255.255.255");
-
-// a dummy MAC address
-const uint8_t dummyMacAddr[] = {0, 1, 2, 3, 4, 5};
-
 // a dummy MAC address, padded with 0s
 const uint8_t dummyChaddr[16] = {0, 1, 2, 3, 4, 5, 0, 0,
                                  0, 0, 0, 0, 0, 0, 0, 0 };
@@ -70,16 +53,14 @@ public:
     PerfPkt4Test() {
     }
 
-    /// \brief Returns captured SOLICIT packet.
+    /// \brief Returns buffer with sample DHCPDISCOVER message.
     ///
-    /// Captured SOLICIT packet with transid=0x3d79fb and options: client-id,
-    /// in_na, dns-server, elapsed-time, option-request
-    /// This code was autogenerated
-    /// (see src/bin/dhcp6/tests/iface_mgr_unittest.c),
-    /// but we spent some time to make is less ugly than it used to be.
+    /// This method creates buffer containing on-wire data of
+    /// DHCPDICOSVER message. This buffer is used by tests below
+    /// to create DHCPv4 test packets.
     ///
-    /// \return pointer to Pkt6 that represents received SOLICIT
-    std::vector<uint8_t> capture() {
+    /// \return vector containing on-wire data
+    std::vector<uint8_t>& capture() {
 
         // That is only part of the header. It contains all "short" fields,
         // larger fields are constructed separately.
@@ -97,28 +78,36 @@ public:
             12,  3, 0,   1,  2, // Host name option.
             13,  3, 10, 11, 12, // Boot file size option
             14,  3, 20, 21, 22, // Merit dump file
-            53, 1, 1,           // DHCP message type. 
-            128, 3, 30, 31, 32, 
+            53, 1, 1,           // DHCP message type.
+            128, 3, 30, 31, 32,
             254, 3, 40, 41, 42,
         };
 
         // Initialize the vector with the header fields defined above.
-        vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
-        
-        // Append the large header fields.
-        std::copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN, back_inserter(buf));
-        std::copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN, back_inserter(buf));
-        std::copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN, back_inserter(buf));
-
-        // Append magic cookie.
-        buf.push_back(0x63); 
-        buf.push_back(0x82);
-        buf.push_back(0x53);
-        buf.push_back(0x63);
-
-        // Append options.
-        std::copy(v4Opts, v4Opts + sizeof(v4Opts), back_inserter(buf));
-
+        static std::vector<uint8_t> buf(hdr, hdr + sizeof(hdr));
+
+        // If this is a first call to this function. Initialize
+        // remaining data.
+        if (buf.size() == sizeof(hdr))
+        {
+
+            // Append the large header fields.
+            std::copy(dummyChaddr, dummyChaddr + Pkt4::MAX_CHADDR_LEN,
+                      back_inserter(buf));
+            std::copy(dummySname, dummySname + Pkt4::MAX_SNAME_LEN,
+                      back_inserter(buf));
+            std::copy(dummyFile, dummyFile + Pkt4::MAX_FILE_LEN,
+                      back_inserter(buf));
+
+            // Append magic cookie.
+            buf.push_back(0x63);
+            buf.push_back(0x82);
+            buf.push_back(0x53);
+            buf.push_back(0x63);
+
+            // Append options.
+            std::copy(v4Opts, v4Opts + sizeof(v4Opts), back_inserter(buf));
+        }
         return buf;
     }
 };
@@ -137,28 +126,34 @@ TEST_F(PerfPkt4Test, Constructor) {
 
     // Test constructor to be used for outgoing messages.
     // Use non-zero offset and specify transaction id.
-    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(data, sizeof(data), 10, 0x010203));
+    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(data, sizeof(data),
+                                                  10, 0x010203));
     EXPECT_EQ(0x010203, pkt2->getTransid());
     EXPECT_EQ(10, pkt2->getTransIdOffset());
+
+    // Test default constructor. Transaction id offset is expected to be 1.
+    boost::scoped_ptr<PerfPkt4> pkt3(new PerfPkt4(data, sizeof(data)));
+    EXPECT_EQ(1, pkt3->getTransIdOffset());
 }
 
 TEST_F(PerfPkt4Test, RawPack) {
     // Create new packet.
     std::vector<uint8_t> buf = capture();
-    boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size(), 0x1, 1));
+    boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size()));
 
     // Initialize options data.
     uint8_t buf_hostname[] = { 12, 3, 4, 5, 6 };
     uint8_t buf_boot_filesize[] = { 13,  3, 1, 2, 3 };
     OptionBuffer vec_hostname(buf_hostname + 2, buf_hostname + 5);
-    OptionBuffer vec_boot_filesize(buf_boot_filesize + 2, buf_boot_filesize + 5);
+    OptionBuffer vec_boot_filesize(buf_boot_filesize + 2,
+                                   buf_boot_filesize + 5);
 
     // Create options objects.
-    LocalizedOptionPtr pkt_hostname(new LocalizedOption(Option::V4, 
+    LocalizedOptionPtr pkt_hostname(new LocalizedOption(Option::V4,
                                                         DHO_HOST_NAME,
                                                         vec_hostname,
                                                         240));
-    LocalizedOptionPtr pkt_boot_filesize(new LocalizedOption(Option::V4, 
+    LocalizedOptionPtr pkt_boot_filesize(new LocalizedOption(Option::V4,
                                                              DHO_BOOT_SIZE,
                                                              vec_boot_filesize,
                                                              245));
@@ -167,7 +162,7 @@ TEST_F(PerfPkt4Test, RawPack) {
     ASSERT_NO_THROW(pkt->addOption(pkt_boot_filesize));
     ASSERT_NO_THROW(pkt->addOption(pkt_hostname));
 
-    // We have valid options addedwith valid offsets so 
+    // We have valid options addedwith valid offsets so
     // pack operation should succeed.
     ASSERT_TRUE(pkt->rawPack());
 
@@ -175,7 +170,8 @@ TEST_F(PerfPkt4Test, RawPack) {
     // DHO_BOOT_SIZE options.
     util::OutputBuffer pkt_output = pkt->getBuffer();
     ASSERT_EQ(buf.size(), pkt_output.getLength());
-    const uint8_t* out_buf_data = static_cast<const uint8_t*>(pkt_output.getData());
+    const uint8_t* out_buf_data =
+        static_cast<const uint8_t*>(pkt_output.getData());
 
     // Check if options we read from buffer is valid.
     EXPECT_EQ(0, memcmp(buf_hostname, out_buf_data + 240, 5));
@@ -185,43 +181,47 @@ TEST_F(PerfPkt4Test, RawPack) {
 TEST_F(PerfPkt4Test, RawUnpack) {
     // Create new packet.
     std::vector<uint8_t> buf = capture();
-    boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size(), 0x1, 1));    
+    boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size()));
 
     // Create options (existing in the packet) and specify their offsets.
     LocalizedOptionPtr opt_merit(new LocalizedOption(Option::V4,
                                                      DHO_MERIT_DUMP,
                                                      OptionBuffer(),
                                                      250));
-    
+
     LocalizedOptionPtr opt_msg_type(new LocalizedOption(Option::V4,
                                                         DHO_DHCP_MESSAGE_TYPE,
-                                                        OptionBuffer(), 
+                                                        OptionBuffer(),
                                                         255));
     // Addition should be successful
     ASSERT_NO_THROW(pkt->addOption(opt_merit));
     ASSERT_NO_THROW(pkt->addOption(opt_msg_type));
-    
+
     // Option fit to packet boundaries and offsets are valid,
     // so this should unpack successfully.
     ASSERT_TRUE(pkt->rawUnpack());
 
     // At this point we should have updated options data (read from buffer).
     // Let's try to retrieve them.
-    opt_merit = boost::dynamic_pointer_cast<LocalizedOption>(pkt->getOption(DHO_MERIT_DUMP));
-    opt_msg_type = boost::dynamic_pointer_cast<LocalizedOption>(pkt->getOption(DHO_DHCP_MESSAGE_TYPE));
+    opt_merit = boost::dynamic_pointer_cast<LocalizedOption>
+        (pkt->getOption(DHO_MERIT_DUMP));
+    opt_msg_type = boost::dynamic_pointer_cast<LocalizedOption>
+        (pkt->getOption(DHO_DHCP_MESSAGE_TYPE));
     ASSERT_TRUE(opt_merit);
     ASSERT_TRUE(opt_msg_type);
 
     // Get first option payload.
     OptionBuffer opt_merit_data = opt_merit->getData();
 
-    // Define reference data. 
-    uint8_t buf_merit[] = { 20, 21, 22 }; 
+    // Define reference data.
+    uint8_t buf_merit[] = { 20, 21, 22 };
 
     // Validate first option data.
     ASSERT_EQ(sizeof(buf_merit), opt_merit_data.size());
-    EXPECT_TRUE(std::equal(opt_merit_data.begin(), opt_merit_data.end(), buf_merit));
-    
+    EXPECT_TRUE(std::equal(opt_merit_data.begin(),
+                           opt_merit_data.end(),
+                           buf_merit));
+
     // Get second option payload.
     OptionBuffer opt_msg_type_data = opt_msg_type->getData();
 
@@ -230,115 +230,133 @@ TEST_F(PerfPkt4Test, RawUnpack) {
     EXPECT_EQ(1, opt_msg_type_data[0]);
 }
 
-    /*
 TEST_F(PerfPkt4Test, InvalidOptions) {
-    // Create packet.
-    boost::scoped_ptr<PerfPkt4> pkt1(capture());
-    OptionBuffer vec_server_id;
-    vec_server_id.resize(10);
-    // Testing invalid offset of the option (greater than packet size)
-    LocalizedOptionPtr pkt1_serverid(new LocalizedOption(Option::V6,
-                                                         D6O_SERVERID,
-                                                         vec_server_id,
-                                                         150));
-    pkt1->addOption(pkt1_serverid);
-    // Pack has to fail due to invalid offset.
-    EXPECT_FALSE(pkt1->rawPack());
-
-    // Create packet.
-    boost::scoped_ptr<PerfPkt4> pkt2(capture());
-    // Testing offset of the option (lower than pakcet size but
-    // tail of the option out of bounds).
-    LocalizedOptionPtr pkt2_serverid(new LocalizedOption(Option::V6,
-                                                         D6O_SERVERID,
-                                                         vec_server_id,
-                                                         85));
-    pkt2->addOption(pkt2_serverid);
-    // Pack must fail due to invalid offset.
-    EXPECT_FALSE(pkt2->rawPack());
-}
+    // Create new packet.
+    std::vector<uint8_t> buf = capture();
+    boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&buf[0], buf.size()));
 
+    // Create option with invalid offset.
+    // This option is at offset 250 (not 251).
+    LocalizedOptionPtr opt_merit(new LocalizedOption(Option::V4,
+                                                     DHO_MERIT_DUMP,
+                                                     OptionBuffer(),
+                                                     251));
+    ASSERT_NO_THROW(pkt1->addOption(opt_merit));
 
-TEST_F(PerfPkt4Test, TruncatedPacket) {
-    cout << "Testing parsing options from truncated packet."
-         << "This may produce spurious errors" << endl;
+    cout << "Testing unpack of invalid options. "
+         << "This may produce spurious errors." << endl;
 
-    // Create truncated (in the middle of duid options)
-    boost::scoped_ptr<PerfPkt4> pkt1(captureTruncated());
-    OptionBuffer vec_duid;
-    vec_duid.resize(30);
-    LocalizedOptionPtr pkt1_duid(new LocalizedOption(Option::V6,
-                                                     D6O_CLIENTID,
-                                                     vec_duid,
-                                                     4));
-    pkt1->addOption(pkt1_duid);
-    // Pack/unpack must fail because length of the option read from buffer
-    // will extend over the actual packet length.
-    EXPECT_FALSE(pkt1->rawUnpack());
-    EXPECT_FALSE(pkt1->rawPack());
+    // Unpack is expected to fail because it is supposed to read
+    // option type from buffer and match it with DHO_MERIT_DUMP.
+    // It will not match because option is shifted by on byte.
+    ASSERT_FALSE(pkt1->rawUnpack());
+
+    // Crete another packet.
+    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&buf[0], buf.size()));
+
+    // Create DHO_DHCP_MESSAGE_TYPE option that has wrong offset.
+    // With this offset, option goes beyond packet size (268).
+    LocalizedOptionPtr opt_msg_type(new LocalizedOption(Option::V4,
+                                                        DHO_DHCP_MESSAGE_TYPE,
+                                                        OptionBuffer(1, 2),
+                                                        266));
+    // Adding option is expected to be successful because no
+    // offset validation takes place at this point.
+    ASSERT_NO_THROW(pkt2->addOption(opt_msg_type));
+
+    // This is expected to fail because option is out of bounds.
+    ASSERT_FALSE(pkt2->rawPack());
 }
 
-TEST_F(PerfPkt4Test, PackTransactionId) {
-    uint8_t data[100] = { 0 };
+TEST_F(PerfPkt4Test, TruncatedPacket) {
+    // Get the whole packet and truncate it to 249 bytes.
+    std::vector<uint8_t> buf = capture();
+    buf.resize(249);
+    boost::scoped_ptr<PerfPkt4> pkt(new PerfPkt4(&buf[0], buf.size()));
+
+    // Option DHO_BOOT_SIZE is now truncated because whole packet
+    // is truncated. This option ends at 249 while last index of
+    // truncated packet is now 248.
+    LocalizedOptionPtr opt_boot_filesize(new LocalizedOption(Option::V4,
+                                                             DHO_BOOT_SIZE,
+                                                             OptionBuffer(3, 1),
+                                                             245));
+    ASSERT_NO_THROW(pkt->addOption(opt_boot_filesize));
 
-    // Create dummy packet that is simply filled with zeros.
-    boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(data,
-                                                  sizeof(data),
-                                                  0x010203,
-                                                  PerfPkt4::Offset(50)));
+    cout << "Testing pack and unpack of options in truncated "
+         << "packet. This may produce spurious errors." << endl;
 
-    // Reference data are non zero so we can detect them in dummy packet.
-    uint8_t ref_data[3] = { 1, 2, 3 };
+    // Both pack and unpack are expected to fail because
+    // added option is out of bounds.
+    EXPECT_FALSE(pkt->rawUnpack());
+    EXPECT_FALSE(pkt->rawPack());
+}
 
-    // This will store given transaction id in the packet data at
-    // offset of 50.
+TEST_F(PerfPkt4Test, PackTransactionId) {
+    // Create dummy packet that consists of zeros.
+    std::vector<uint8_t> buf(268, 0);
+    // Initialize transaction id 0x00000102 at offset 10.
+    boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&buf[0], buf.size(),
+                                                  10, 0x0102));
+
+    // Pack will inject transaction id at offset 10 into the
+    // packet buffer.
     ASSERT_TRUE(pkt1->rawPack());
 
-    // Get the output buffer so we can validate it.
+    // Get packet's output buffer and make sure it has valid size.
     util::OutputBuffer out_buf = pkt1->getBuffer();
-    ASSERT_EQ(sizeof(data), out_buf.getLength());
-    const uint8_t *out_buf_data = static_cast<const uint8_t*>
-        (out_buf.getData());
-
-    // Validate transaction id.
-    EXPECT_EQ(0, memcmp(out_buf_data + 50, ref_data, 3));
-
-    // Out of bounds transaction id offset.
-    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(data,
-                                                  sizeof(data),
-                                                  0x010202,
-                                                  PerfPkt4::Offset(100)));
-    cout << "Testing out of bounds offset. "
-        "This may produce spurious errors ..." << endl;
+    ASSERT_EQ(buf.size(), out_buf.getLength());
+    const uint8_t *out_buf_data =
+        static_cast<const uint8_t*>(out_buf.getData());
+
+    // Initialize reference data for transaction id.
+    const uint8_t ref_data[] = { 0, 0, 1, 2 };
+
+    // Expect that reference transaction id matches what we have
+    // read from buffer.
+    EXPECT_EQ(0, memcmp(ref_data, out_buf_data + 10, 4));
+
+    cout << "Testing pack with invalid transaction id offset. "
+         << "This may produce spurious errors" << endl;
+
+    // Create packet with invalid transaction id offset.
+    // Packet length is 268, transaction id is 4 bytes long so last byte of
+    // transaction id is out of bounds.
+    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&buf[0], buf.size(),
+                                                  265, 0x0102));
     EXPECT_FALSE(pkt2->rawPack());
 }
 
 TEST_F(PerfPkt4Test, UnpackTransactionId) {
-    // Initialize data for dummy packet (zeros only).
-    uint8_t data[100] = { 0 };
+    // Initialize packet data, lebgth 268, zeros only.
+    std::vector<uint8_t> in_data(268, 0);
 
-    // Generate transaction id = 0x010203 and inject at offset = 50.
-    for (int i = 50; i <  53; ++i) {
-        data[i] = i - 49;
+    // Assume that transaction id is at offset 100.
+    // Fill 4 bytes at offset 100 with dummy transaction id.
+    for (int i = 100; i < 104; ++i) {
+        in_data[i] = i - 99;
     }
-    // Create packet and point out that transaction id is at offset 50.
-    boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(data,
-                                                  sizeof(data),
-                                                  PerfPkt4::Offset(50)));
 
-    // Get transaction id out of buffer and store in class member.
+    // Create packet from initialized buffer.
+    boost::scoped_ptr<PerfPkt4> pkt1(new PerfPkt4(&in_data[0],
+                                                  in_data.size(),
+                                                  100));
     ASSERT_TRUE(pkt1->rawUnpack());
-    // Test value of transaction id.
-    EXPECT_EQ(0x010203, pkt1->getTransid());
-
-    // Out of bounds transaction id offset.
-    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(data,
-                                                  sizeof(data),
-                                                  PerfPkt4::Offset(300)));
-    cout << "Testing out of bounds offset. "
-        "This may produce spurious errors ..." << endl;
-    EXPECT_FALSE(pkt2->rawUnpack());
 
-    } */
+    // Get unpacked transaction id and compare with reference.
+    EXPECT_EQ(0x01020304, pkt1->getTransid());
+
+    // Create packet with transaction id at invalid offset.
+    boost::scoped_ptr<PerfPkt4> pkt2(new PerfPkt4(&in_data[0],
+                                                  in_data.size(),
+                                                  270));
+
+    cout << "Testing unpack of transaction id at invalid offset."
+         << "This may produce spurious errors." << endl;
+
+    // Unpack is supposed to fail because transaction id is at
+    // out of bounds offset.
+    EXPECT_FALSE(pkt2->rawUnpack());
+}
 
 }