From: Francis Dupont Date: Fri, 8 Mar 2019 01:29:29 +0000 (+0100) Subject: [465-add-subnet4-update-and-subnet6-update-commands-to-subnet-cmds-hook] Added replac... X-Git-Tag: Kea-1.6.0-beta~205 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=9962ca3116dee0dd615a4f6bfeafacd864d9f459;p=thirdparty%2Fkea.git [465-add-subnet4-update-and-subnet6-update-commands-to-subnet-cmds-hook] Added replace unit tests --- diff --git a/src/lib/dhcpsrv/shared_network.cc b/src/lib/dhcpsrv/shared_network.cc index 089fd2015f..0e2b8e0961 100644 --- a/src/lib/dhcpsrv/shared_network.cc +++ b/src/lib/dhcpsrv/shared_network.cc @@ -77,7 +77,6 @@ public: /// /// @tparam SubnetPtrType Type of a pointer to a subnet, i.e. Subnet4Ptr /// or @ref Subnet6Ptr. - /// @tparam SubnetCollectionType Type of a container holding subnets, i.e. /// @ref Subnet4Collection or @ref Subnet6Collection. /// @@ -94,10 +93,13 @@ public: static bool replace(SubnetCollectionType& subnets, const SubnetPtrType& subnet) { - // Subnet must be non-null. - if (!subnet) { - isc_throw(BadValue, "null pointer specified when adding a subnet" - " to a shared network"); + // Check if the subnet is already associated with some network. + NetworkPtr network; + subnet->getSharedNetwork(network); + if (network) { + isc_throw(InvalidOperation, "subnet " << subnet->getID() + << " being replaced in a shared network" + " already belongs to a shared network"); } // Get the subnet with the same ID. @@ -305,6 +307,11 @@ SharedNetwork4::add(const Subnet4Ptr& subnet) { bool SharedNetwork4::replace(const Subnet4Ptr& subnet) { + // Subnet must be non-null. + if (!subnet) { + isc_throw(BadValue, "null pointer specified when adding a subnet" + " to a shared network"); + } const Subnet4Ptr& old = getSubnet(subnet->getID()); bool ret = Impl::replace(subnets_, subnet); if (ret) { @@ -385,6 +392,11 @@ SharedNetwork6::add(const Subnet6Ptr& subnet) { bool SharedNetwork6::replace(const Subnet6Ptr& subnet) { + // Subnet must be non-null. + if (!subnet) { + isc_throw(BadValue, "null pointer specified when adding a subnet" + " to a shared network"); + } const Subnet6Ptr& old = getSubnet(subnet->getID()); bool ret = Impl::replace(subnets_, subnet); if (ret) { diff --git a/src/lib/dhcpsrv/tests/shared_network_unittest.cc b/src/lib/dhcpsrv/tests/shared_network_unittest.cc index 044692b6a5..3e7b9f16de 100644 --- a/src/lib/dhcpsrv/tests/shared_network_unittest.cc +++ b/src/lib/dhcpsrv/tests/shared_network_unittest.cc @@ -120,6 +120,105 @@ TEST(SharedNetwork4Test, addSubnet4) { ASSERT_THROW(network2->add(subnet), InvalidOperation); } +// This test verifies that an IPv4 subnet can be replaced in a shared network. +// It does the same tests than for addSubnet4 (at the exception of conflicts) +// and check the random order is kept. +TEST(SharedNetwork4Test, replaceSubnet4) { + // First, create a network. + SharedNetwork4Ptr network(new SharedNetwork4("frog")); + + // Try to replace null pointer. It should throw. + Subnet4Ptr subnet; + ASSERT_THROW(network->replace(subnet), BadValue); + + // Create some valid subnets. they should now be added successfully. + subnet.reset(new Subnet4(IOAddress("10.0.0.0"), 8, 10, 20, 30, + SubnetID(15))); + ASSERT_NO_THROW(network->add(subnet)); + subnet.reset(new Subnet4(IOAddress("192.168.0.0"), 24, 10, 20, 30, + SubnetID(1))); + ASSERT_NO_THROW(network->add(subnet)); + subnet.reset(new Subnet4(IOAddress("192.168.1.0"), 24, 10, 20, 30, + SubnetID(10))); + ASSERT_NO_THROW(network->add(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + + // Create another subnet with another ID. Replace should return false. + subnet.reset(new Subnet4(IOAddress("192.168.2.0"), 24, 10, 20, 30, + SubnetID(2))); + EXPECT_FALSE(network->replace(subnet)); + + // Subnets did not changed. + ASSERT_EQ(3, network->getAllSubnets()->size()); + Subnet4Ptr returned_subnet = network->getAllSubnets()->at(0); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(15, returned_subnet->getID()); + returned_subnet = network->getAllSubnets()->at(2); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(10, returned_subnet->getID()); + // Finish by the second subnet. + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(1, returned_subnet->getID()); + + // Create another subnet with the same ID than the second subnet. + subnet.reset(new Subnet4(IOAddress("192.168.0.0"), 24, 100, 200, 300, + SubnetID(1))); + EXPECT_TRUE(network->replace(subnet)); + + // Second subnet was updated. + EXPECT_EQ(10, returned_subnet->getT1()); + EXPECT_EQ(20, returned_subnet->getT2()); + EXPECT_EQ(30, returned_subnet->getValid()); + SharedNetwork4Ptr network1; + returned_subnet->getSharedNetwork(network1); + EXPECT_FALSE(network1); + + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ(100, returned_subnet->getT1()); + EXPECT_EQ(200, returned_subnet->getT2()); + EXPECT_EQ(300, returned_subnet->getValid()); + returned_subnet->getSharedNetwork(network1); + EXPECT_TRUE(network1); + EXPECT_TRUE(network == network1); + + // Other subnets did not changed. + returned_subnet = network->getAllSubnets()->at(0); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(15, returned_subnet->getID()); + returned_subnet = network->getAllSubnets()->at(2); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(10, returned_subnet->getID()); + + // Create another network and try to replace a subnet to it. It should fail + // because the subnet is already associated with the first network. + SharedNetwork4Ptr network2(new SharedNetwork4("dog")); + ASSERT_THROW(network2->replace(subnet), InvalidOperation); + + // Try to change the prefix. Not recommended but should work. + subnet.reset(new Subnet4(IOAddress("192.168.10.0"), 24, 100, 200, 300, + SubnetID(1))); + EXPECT_TRUE(network->replace(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ("192.168.10.0/24", returned_subnet->toText()); + + // but not if the prefix already exists for another subnet. + subnet.reset(new Subnet4(IOAddress("192.168.1.0"), 24, 100, 200, 300, + SubnetID(1))); + EXPECT_FALSE(network->replace(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ("192.168.10.0/24", returned_subnet->toText()); +} + // This test verifies that it is possible to remove a specified subnet. TEST(SharedNetwork4Test, delSubnet4) { // Create two subnets and add them to the shared network. @@ -561,6 +660,107 @@ TEST(SharedNetwork6Test, addSubnet6) { ASSERT_THROW(network2->add(subnet), InvalidOperation); } +// This test verifies that an IPv6 subnet can be replaced in a shared network. +// It does the same tests than for addSubnet6 (at the exception of conflicts) +// and check the random order is kept. +TEST(SharedNetwork6Test, replaceSubnet6) { + // First, create a network. + SharedNetwork6Ptr network(new SharedNetwork6("frog")); + + // Try to replace null pointer. It should throw. + Subnet6Ptr subnet; + ASSERT_THROW(network->replace(subnet), BadValue); + + // Create some valid subnets. they should now be added successfully. + subnet.reset(new Subnet6(IOAddress("2001:db8:1::"), 48, 10, 20, 30, 40, + SubnetID(15))); + ASSERT_NO_THROW(network->add(subnet)); + subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 10, 20, 30, 40, + SubnetID(1))); + ASSERT_NO_THROW(network->add(subnet)); + subnet.reset(new Subnet6(IOAddress("2001:db8:3::"), 64, 10, 20, 30, 40, + SubnetID(10))); + ASSERT_NO_THROW(network->add(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + + // Create another subnet with another ID. Replace should return false. + subnet.reset(new Subnet6(IOAddress("2001:db8:4::1"), 64, 10, 20, 30, 40, + SubnetID(2))); + EXPECT_FALSE(network->replace(subnet)); + + // Subnets did not changed. + ASSERT_EQ(3, network->getAllSubnets()->size()); + Subnet6Ptr returned_subnet = network->getAllSubnets()->at(0); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(15, returned_subnet->getID()); + returned_subnet = network->getAllSubnets()->at(2); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(10, returned_subnet->getID()); + // Finish by the second subnet. + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(1, returned_subnet->getID()); + + // Create another subnet with the same ID than the second subnet. + subnet.reset(new Subnet6(IOAddress("2001:db8:2::"), 64, 100, 200, 300, 400, + SubnetID(1))); + EXPECT_TRUE(network->replace(subnet)); + + // Second subnet was updated. + EXPECT_EQ(10, returned_subnet->getT1()); + EXPECT_EQ(20, returned_subnet->getT2()); + EXPECT_EQ(30, returned_subnet->getPreferred()); + EXPECT_EQ(40, returned_subnet->getValid()); + SharedNetwork6Ptr network1; + returned_subnet->getSharedNetwork(network1); + EXPECT_FALSE(network1); + + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ(100, returned_subnet->getT1()); + EXPECT_EQ(200, returned_subnet->getT2()); + EXPECT_EQ(300, returned_subnet->getPreferred()); + EXPECT_EQ(400, returned_subnet->getValid()); + returned_subnet->getSharedNetwork(network1); + EXPECT_TRUE(network1); + EXPECT_TRUE(network == network1); + + // Other subnets did not changed. + returned_subnet = network->getAllSubnets()->at(0); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(15, returned_subnet->getID()); + returned_subnet = network->getAllSubnets()->at(2); + ASSERT_TRUE(returned_subnet); + EXPECT_EQ(10, returned_subnet->getID()); + + // Create another network and try to replace a subnet to it. It should fail + // because the subnet is already associated with the first network. + SharedNetwork6Ptr network2(new SharedNetwork6("dog")); + ASSERT_THROW(network2->replace(subnet), InvalidOperation); + + // Try to change the prefix. Not recommended but should work. + subnet.reset(new Subnet6(IOAddress("2001:db8:10::"), 64, 100, 200, 300, + 400, SubnetID(1))); + EXPECT_TRUE(network->replace(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ("2001:db8:10::/64", returned_subnet->toText()); + + // but not if the prefix already exists for another subnet. + subnet.reset(new Subnet6(IOAddress("2001:db8:3::"), 64, 100, 200, 300, 400, + SubnetID(1))); + EXPECT_FALSE(network->replace(subnet)); + ASSERT_EQ(3, network->getAllSubnets()->size()); + returned_subnet = network->getAllSubnets()->at(1); + ASSERT_TRUE(returned_subnet); + ASSERT_EQ(1, returned_subnet->getID()); + EXPECT_EQ("2001:db8:10::/64", returned_subnet->toText()); +} + // This test verifies that it is possible to remove a specified subnet. TEST(SharedNetwork6Test, delSubnet6) { // Create two subnets and add them to the shared network.