|
@@ -0,0 +1,199 @@
|
|
|
|
+// Copyright (C) 2015 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.
|
|
|
|
+
|
|
|
|
+#include <config.h>
|
|
|
|
+#include <eval/token.h>
|
|
|
|
+#include <dhcp/pkt4.h>
|
|
|
|
+#include <dhcp/pkt6.h>
|
|
|
|
+#include <dhcp/dhcp4.h>
|
|
|
|
+#include <dhcp/dhcp6.h>
|
|
|
|
+#include <dhcp/option_string.h>
|
|
|
|
+
|
|
|
|
+#include <boost/shared_ptr.hpp>
|
|
|
|
+#include <boost/scoped_ptr.hpp>
|
|
|
|
+#include <gtest/gtest.h>
|
|
|
|
+
|
|
|
|
+using namespace std;
|
|
|
|
+using namespace isc::dhcp;
|
|
|
|
+
|
|
|
|
+namespace {
|
|
|
|
+
|
|
|
|
+/// @brief Test fixture for testing Tokens.
|
|
|
|
+///
|
|
|
|
+/// This class provides several convenience objects to be used during testing
|
|
|
|
+/// of the Token family of classes.
|
|
|
|
+class TokenTest : public ::testing::Test {
|
|
|
|
+public:
|
|
|
|
+
|
|
|
|
+ /// @brief Initializes Pkt4,Pkt6 and options that can be useful for
|
|
|
|
+ /// evaluation tests.
|
|
|
|
+ TokenTest() {
|
|
|
|
+ pkt4_.reset(new Pkt4(DHCPDISCOVER, 12345));
|
|
|
|
+ pkt6_.reset(new Pkt6(DHCPV6_SOLICIT, 12345));
|
|
|
|
+
|
|
|
|
+ // Add options with easily identifiable strings in them
|
|
|
|
+ option_str4_.reset(new OptionString(Option::V4, 100, "hundred4"));
|
|
|
|
+ option_str6_.reset(new OptionString(Option::V6, 100, "hundred6"));
|
|
|
|
+
|
|
|
|
+ pkt4_->addOption(option_str4_);
|
|
|
|
+ pkt6_->addOption(option_str6_);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TokenPtr t_; ///< Just a convenience pointer
|
|
|
|
+
|
|
|
|
+ ValueStack values_; ///< evaluated values will be stored here
|
|
|
|
+
|
|
|
|
+ Pkt4Ptr pkt4_; ///< A stub DHCPv4 packet
|
|
|
|
+ Pkt6Ptr pkt6_; ///< A stub DHCPv6 packet
|
|
|
|
+
|
|
|
|
+ OptionPtr option_str4_; ///< A string option for DHCPv4
|
|
|
|
+ OptionPtr option_str6_; ///< A string option for DHCPv6
|
|
|
|
+
|
|
|
|
+ /// @todo: Add more option types here
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// This simple test checks that a TokenString, representing a constant string,
|
|
|
|
+// can be used in Pkt4 evaluation. (The actual packet is not used)
|
|
|
|
+TEST_F(TokenTest, string4) {
|
|
|
|
+
|
|
|
|
+ // Store constant string "foo" in the TokenString object.
|
|
|
|
+ ASSERT_NO_THROW(t_.reset(new TokenString("foo")));
|
|
|
|
+
|
|
|
|
+ // Make sure that the token can be evaluated without exceptions.
|
|
|
|
+ ASSERT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
|
|
|
+
|
|
|
|
+ // Check that the evaluation put its value on the values stack.
|
|
|
|
+ ASSERT_EQ(1, values_.size());
|
|
|
|
+ EXPECT_EQ("foo", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This simple test checks that a TokenString, representing a constant string,
|
|
|
|
+// can be used in Pkt6 evaluation. (The actual packet is not used)
|
|
|
|
+TEST_F(TokenTest, string6) {
|
|
|
|
+
|
|
|
|
+ // Store constant string "foo" in the TokenString object.
|
|
|
|
+ ASSERT_NO_THROW(t_.reset(new TokenString("foo")));
|
|
|
|
+
|
|
|
|
+ // Make sure that the token can be evaluated without exceptions.
|
|
|
|
+ ASSERT_NO_THROW(t_->evaluate(*pkt6_, values_));
|
|
|
|
+
|
|
|
|
+ // Check that the evaluation put its value on the values stack.
|
|
|
|
+ ASSERT_EQ(1, values_.size());
|
|
|
|
+ EXPECT_EQ("foo", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This test checks if a token representing an option value is able to extract
|
|
|
|
+// the option from an IPv4 packet and properly store the option's value.
|
|
|
|
+TEST_F(TokenTest, optionString4) {
|
|
|
|
+ TokenPtr found;
|
|
|
|
+ TokenPtr not_found;
|
|
|
|
+
|
|
|
|
+ // The packets we use have option 100 with a string in them.
|
|
|
|
+ ASSERT_NO_THROW(found.reset(new TokenOption(100)));
|
|
|
|
+ ASSERT_NO_THROW(not_found.reset(new TokenOption(101)));
|
|
|
|
+
|
|
|
|
+ // This should evaluate to the content of the option 100 (i.e. "hundred4")
|
|
|
|
+ ASSERT_NO_THROW(found->evaluate(*pkt4_, values_));
|
|
|
|
+
|
|
|
|
+ // This should evaluate to "" as there is no option 101.
|
|
|
|
+ ASSERT_NO_THROW(not_found->evaluate(*pkt4_, values_));
|
|
|
|
+
|
|
|
|
+ // There should be 2 values evaluated.
|
|
|
|
+ ASSERT_EQ(2, values_.size());
|
|
|
|
+
|
|
|
|
+ // This is a stack, so the pop order is inversed. We should get the empty
|
|
|
|
+ // string first.
|
|
|
|
+ EXPECT_EQ("", values_.top());
|
|
|
|
+ values_.pop();
|
|
|
|
+
|
|
|
|
+ // Then the content of the option 100.
|
|
|
|
+ EXPECT_EQ("hundred4", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This test checks if a token representing an option value is able to extract
|
|
|
|
+// the option from an IPv6 packet and properly store the option's value.
|
|
|
|
+TEST_F(TokenTest, optionString6) {
|
|
|
|
+ TokenPtr found;
|
|
|
|
+ TokenPtr not_found;
|
|
|
|
+
|
|
|
|
+ // The packets we use have option 100 with a string in them.
|
|
|
|
+ ASSERT_NO_THROW(found.reset(new TokenOption(100)));
|
|
|
|
+ ASSERT_NO_THROW(not_found.reset(new TokenOption(101)));
|
|
|
|
+
|
|
|
|
+ // This should evaluate to the content of the option 100 (i.e. "hundred6")
|
|
|
|
+ ASSERT_NO_THROW(found->evaluate(*pkt6_, values_));
|
|
|
|
+
|
|
|
|
+ // This should evaluate to "" as there is no option 101.
|
|
|
|
+ ASSERT_NO_THROW(not_found->evaluate(*pkt6_, values_));
|
|
|
|
+
|
|
|
|
+ // There should be 2 values evaluated.
|
|
|
|
+ ASSERT_EQ(2, values_.size());
|
|
|
|
+
|
|
|
|
+ // This is a stack, so the pop order is inversed. We should get the empty
|
|
|
|
+ // string first.
|
|
|
|
+ EXPECT_EQ("", values_.top());
|
|
|
|
+ values_.pop();
|
|
|
|
+
|
|
|
|
+ // Then the content of the option 100.
|
|
|
|
+ EXPECT_EQ("hundred6", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This test checks if a token representing an == operator is able to
|
|
|
|
+// compare two values (with incorrectly built stack).
|
|
|
|
+TEST_F(TokenTest, optionEqualInvalid) {
|
|
|
|
+
|
|
|
|
+ ASSERT_NO_THROW(t_.reset(new TokenEqual()));
|
|
|
|
+
|
|
|
|
+ // CASE 1: There's not enough values on the stack. == is an operator that
|
|
|
|
+ // takes two parameters. There are 0 on the stack.
|
|
|
|
+ EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
|
|
|
+
|
|
|
|
+ // CASE 2: One value is still not enough.
|
|
|
|
+ values_.push("foo");
|
|
|
|
+ EXPECT_THROW(t_->evaluate(*pkt4_, values_), EvalBadStack);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This test checks if a token representing an == operator is able to
|
|
|
|
+// compare two different values.
|
|
|
|
+TEST_F(TokenTest, optionEqualFalse) {
|
|
|
|
+
|
|
|
|
+ ASSERT_NO_THROW(t_.reset(new TokenEqual()));
|
|
|
|
+
|
|
|
|
+ values_.push("foo");
|
|
|
|
+ values_.push("bar");
|
|
|
|
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
|
|
|
+
|
|
|
|
+ // After evaluation there should be a single value that represents
|
|
|
|
+ // result of "foo" == "bar" comparision.
|
|
|
|
+ ASSERT_EQ(1, values_.size());
|
|
|
|
+ EXPECT_EQ("false", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// This test checks if a token representing an == operator is able to
|
|
|
|
+// compare two identical values.
|
|
|
|
+TEST_F(TokenTest, optionEqualTrue) {
|
|
|
|
+
|
|
|
|
+ ASSERT_NO_THROW(t_.reset(new TokenEqual()));
|
|
|
|
+
|
|
|
|
+ values_.push("foo");
|
|
|
|
+ values_.push("foo");
|
|
|
|
+ EXPECT_NO_THROW(t_->evaluate(*pkt4_, values_));
|
|
|
|
+
|
|
|
|
+ // After evaluation there should be a single value that represents
|
|
|
|
+ // result of "foo" == "foo" comparision.
|
|
|
|
+ ASSERT_EQ(1, values_.size());
|
|
|
|
+ EXPECT_EQ("true", values_.top());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+};
|