// Copyright (C) 2011 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 #include #include #include #include #include using namespace isc::server_common::portconfig; using namespace isc::data; using namespace isc; using namespace std; using namespace asiolink; namespace { /// Testcase for parseAddresses call (struct, nobody cares about private here) struct ParseAddresses : public ::testing::Test { AddressList result_; void empty(ElementPtr config, const string& name) { SCOPED_TRACE(name); EXPECT_NO_THROW(result_ = parseAddresses(config, "test")); EXPECT_TRUE(result_.empty()); } template void invalidTest(const string& json, const string& name) { SCOPED_TRACE(name); ElementPtr config(Element::fromJSON(json)); EXPECT_THROW(parseAddresses(config, "test"), Exception) << "Should throw " << typeid(Exception).name(); } }; // Parse valid IPv4 address TEST_F(ParseAddresses, ipv4) { ElementPtr config(Element::fromJSON("[" " {" " \"address\": \"192.0.2.1\"," " \"port\": 53" " }" "]")); EXPECT_NO_THROW(result_ = parseAddresses(config, "test")); ASSERT_EQ(1, result_.size()); EXPECT_EQ("192.0.2.1", result_[0].first); EXPECT_EQ(53, result_[0].second); } // Parse valid IPv6 address TEST_F(ParseAddresses, ipv6) { ElementPtr config(Element::fromJSON("[" " {" " \"address\": \"2001:db8::1\"," " \"port\": 53" " }" "]")); EXPECT_NO_THROW(result_ = parseAddresses(config, "test")); ASSERT_EQ(1, result_.size()); EXPECT_EQ("2001:db8::1", result_[0].first); EXPECT_EQ(53, result_[0].second); } // Parse multiple addresses at once // (even the ports are different to see they are not mistaken) TEST_F(ParseAddresses, multi) { ElementPtr config(Element::fromJSON("[" " {" " \"address\": \"2001:db8::1\"," " \"port\": 53" " }," " {" " \"address\": \"192.0.2.1\"," " \"port\": 54" " }" "]")); EXPECT_NO_THROW(result_ = parseAddresses(config, "test")); ASSERT_EQ(2, result_.size()); EXPECT_EQ("2001:db8::1", result_[0].first); EXPECT_EQ(53, result_[0].second); EXPECT_EQ("192.0.2.1", result_[1].first); EXPECT_EQ(54, result_[1].second); } // Parse various versions of empty list TEST_F(ParseAddresses, empty) { empty(Element::fromJSON("[]"), "Empty list"); empty(ElementPtr(new NullElement), "Null element"); empty(ElementPtr(), "Null pointer"); } // Reject invalid configs TEST_F(ParseAddresses, invalid) { invalidTest("{}", "Not a list"); invalidTest("[{}]", "Empty element"); invalidTest("[{" " \"port\": 1.5," " \"address\": \"192.0.2.1\"" "}]", "Float port"); invalidTest("[{" " \"port\": -5," " \"address\": \"192.0.2.1\"" "}]", "Negative port"); invalidTest("[{" " \"port\": 1000000," " \"address\": \"192.0.2.1\"" "}]", "Port too big"); invalidTest("[{" " \"port\": 53," " \"address\": \"bad_address\"" "}]", "Bad address"); } // Test fixture for installListenAddresses struct InstallListenAddresses : public ::testing::Test { InstallListenAddresses() : dnss_(ios_, NULL, NULL, NULL) { valid_.push_back(AddressPair("127.0.0.1", 5288)); valid_.push_back(AddressPair("::1", 5288)); invalid_.push_back(AddressPair("192.0.2.2", 1)); } IOService ios_; DNSService dnss_; AddressList store_; // We should be able to bind to these addresses AddressList valid_; // But this shouldn't work AddressList invalid_; // Check that the store_ addresses are the same as expected void checkAddresses(const AddressList& expected, const string& name) { SCOPED_TRACE(name); ASSERT_EQ(expected.size(), store_.size()) << "Different amount of elements, not checking content"; // Run in parallel trough the vectors for (AddressList::const_iterator ei(expected.begin()), si(store_.begin()); ei != expected.end(); ++ei, ++si) { EXPECT_EQ(ei->first, si->first); EXPECT_EQ(ei->second, si->second); } } }; // Try switching valid addresses TEST_F(InstallListenAddresses, valid) { // First, bind to the valid addresses EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_)); checkAddresses(valid_, "Valid addresses"); // TODO Maybe some test to actually connect to them // Try setting it back to nothing EXPECT_NO_THROW(installListenAddresses(AddressList(), store_, dnss_)); checkAddresses(AddressList(), "No addresses"); // Try switching back again EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_)); checkAddresses(valid_, "Valid addresses"); } // Try if rollback works TEST_F(InstallListenAddresses, rollback) { // Set some addresses EXPECT_NO_THROW(installListenAddresses(valid_, store_, dnss_)); checkAddresses(valid_, "Before rollback"); // This should not bind them, but should leave the original addresses EXPECT_NO_THROW(installListenAddresses(invalid_, store_, dnss_)); checkAddresses(valid_, "After rollback"); } }