Browse Source

[4483] Generic unit-tests for evaluating expressions written

Tomek Mrugalski 8 years ago
parent
commit
2dd4214ba5

+ 3 - 0
src/lib/dhcp/pkt4.cc

@@ -444,6 +444,9 @@ Pkt4::setHWAddrMember(const uint8_t htype, const uint8_t hlen,
         isc_throw(OutOfRange, "Invalid HW Address specified");
     }
 
+    /// @todo: what if mac_addr.size() doesn't match hlen?
+    /// We would happily copy over hardware address that is possibly
+    /// too long or doesn't match hlen value.
     hw_addr.reset(new HWAddr(mac_addr, htype));
 }
 

+ 2 - 2
src/lib/eval/tests/context_unittest.cc

@@ -1011,12 +1011,12 @@ TEST_F(EvalContextTest, pkt4FieldSiaddr) {
 
 // Tests whether message type field in DHCPv6 can be accessed.
 TEST_F(EvalContextTest, pkt6FieldMsgtype) {
-    testPkt6Field("pkt6.msgtype == '1'", TokenPkt6::MSGTYPE, 3);
+    testPkt6Field("pkt6.msgtype == 1", TokenPkt6::MSGTYPE, 3);
 }
 
 // Tests whether transaction id field in DHCPv6 can be accessed.
 TEST_F(EvalContextTest, pkt6FieldTransid) {
-    testPkt6Field("pkt6.transid == '1'", TokenPkt6::TRANSID, 3);
+    testPkt6Field("pkt6.transid == 1", TokenPkt6::TRANSID, 3);
 }
 
 // Tests if the linkaddr field in a Relay6 encapsulation can be accessed.

+ 120 - 0
src/lib/eval/tests/evaluate_unittest.cc

@@ -6,6 +6,7 @@
 
 #include <config.h>
 #include <eval/evaluate.h>
+#include <eval/eval_context.h>
 #include <eval/token.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt6.h>
@@ -282,4 +283,123 @@ TEST_F(EvaluateTest, complex) {
     EXPECT_TRUE(result_);
 }
 
+/// @brief Generic class for parsing expressions and evaluating them.
+///
+/// The main purpose of this class is to provide a generic interface to the
+/// eval library, so everything (expression parsing and then its evaluation for
+/// given packets) can be done in one simple call.
+///
+/// Those tests may be somewhat redundant to other more specialized tests, but
+/// the idea here is to mass produce tests that are trivial to write.
+class ExpressionsTest : public EvaluateTest {
+public:
+
+    /// @brief Checks if expression can be parsed and evaluated
+    ///
+    /// There are skeleton packets created in pkt4_ and pkt6_. Make sure you
+    /// tweak them as needed before calling this method.
+    ///
+    /// Note that contrary to the usual interface, this method calls
+    /// @ref isc::dhcp::evaluateString, rather than @ref isc::dhcp::evaluate.
+    /// The main benefit of this is the ability to test partial expressions that
+    /// not necessarily evaluate to bool.
+    ///
+    /// @param u universe (V4 or V6)
+    /// @param expr expression to be parsed
+    /// @param exp_result expected result (true or false)
+    void testExpression(const Option::Universe& u, const std::string& expr,
+                        const bool exp_result) {
+
+        EvalContext eval(u);
+        bool result;
+        bool parsed;
+
+        EXPECT_NO_THROW(parsed = eval.parseString(expr));
+        EXPECT_TRUE(parsed) << " for expression " << expr;
+
+        switch (u) {
+        case Option::V4:
+            ASSERT_NO_THROW(result = evaluate(eval.expression, *pkt4_))
+                << " for expression " << expr;
+            break;
+        case Option::V6:
+            ASSERT_NO_THROW(result = evaluate(eval.expression, *pkt6_))
+                << " for expression " << expr;
+            break;
+        }
+
+        EXPECT_EQ(exp_result, result) << " for expression " << expr;
+    }
+};
+
+// This is a quick way to check if certain expressions are valid or not and
+// whether the whole expression makes sense. This particular test checks if
+// integers can be used properly in expressions. There are many places where
+// integers are used. This particular test checks if pkt6.msgtype returns
+// something that can be compared with integers.
+//
+// For basic things we can take advantage of the skeleton packets created in
+// EvaluateTest constructors: The packet type is DISCOVER in DHCPv4 and
+// SOLICIT in DHCPv6. There is one option added with code 100 and content
+// being either "hundred4" or "hundred6" depending on the universe.
+
+// Tests if pkt6.msgtype returns something that can be compared with integers.
+TEST_F(ExpressionsTest, expressionsInteger1) {
+    testExpression(Option::V6, "pkt6.msgtype == 1", true);
+    testExpression(Option::V6, "pkt6.msgtype == 2", false);
+
+    testExpression(Option::V6, "pkt6.msgtype == 0x00000001", true);
+    testExpression(Option::V6, "pkt6.msgtype == 0x00000002", false);
+}
+
+// Tests if pkt6.transid returns something that can be compared with integers.
+TEST_F(ExpressionsTest, expressionsInteger2) {
+    testExpression(Option::V6, "pkt6.transid == 0", false);
+    testExpression(Option::V6, "pkt6.transid == 12345", true);
+    testExpression(Option::V6, "pkt6.transid == 12346", false);
+}
+
+// Tests if pkt4.transid returns something that can be compared with integers.
+TEST_F(ExpressionsTest, expressionsInteger3) {
+    testExpression(Option::V4, "pkt4.transid == 0", false);
+    testExpression(Option::V4, "pkt4.transid == 12345", true);
+    testExpression(Option::V4, "pkt4.transid == 12346", false);
+}
+
+// Tests if integers can be compared with integers.
+TEST_F(ExpressionsTest, expressionsInteger4) {
+    testExpression(Option::V6, "0 == 0", true);
+    testExpression(Option::V6, "2 == 3", false);
+}
+
+// Tests if pkt4.hlen and pkt4.htype return values that can be compared with integers.
+TEST_F(ExpressionsTest, expressionsPkt4Hlen) {
+
+    // By default there's no hardware set up. The default Pkt4 constructor
+    // creates HWAddr(), which has hlen=0 and htype set to HTYPE_ETHER.
+    testExpression(Option::V4, "pkt4.hlen == 0", true);
+    testExpression(Option::V4, "pkt4.htype == 1", true);
+
+    // Ok, let's initialized the hardware address to something plausible.
+    const size_t hwaddr_len = 6;
+    const uint16_t expected_htype = 123;
+    std::vector<uint8_t> hw(hwaddr_len,0);
+    for (int i = 0; i < hwaddr_len; i++) {
+        hw[i] = i + 1;
+    }
+    pkt4_->setHWAddr(expected_htype, hwaddr_len, hw);
+
+    testExpression(Option::V4, "pkt4.hlen == 0", false);
+    testExpression(Option::V4, "pkt4.hlen == 5", false);
+    testExpression(Option::V4, "pkt4.hlen == 6", true);
+    testExpression(Option::V4, "pkt4.hlen == 7", false);
+
+    testExpression(Option::V4, "pkt4.htype == 0", false);
+    testExpression(Option::V4, "pkt4.htype == 122", false);
+    testExpression(Option::V4, "pkt4.htype == 123", true);
+    testExpression(Option::V4, "pkt4.htype == 124", false);
+
+    testExpression(Option::V4, "pkt4.mac == 0x010203040506", true);
+}
+
 };