Merge "tests: Move testtools to 3rd party libraries section"
diff --git a/neutron/tests/tempest/api/test_allowed_address_pair.py b/neutron/tests/tempest/api/test_allowed_address_pair.py
index e4c499c..5313785 100644
--- a/neutron/tests/tempest/api/test_allowed_address_pair.py
+++ b/neutron/tests/tempest/api/test_allowed_address_pair.py
@@ -83,7 +83,7 @@
         body = self.client.update_port(
             port_id, allowed_address_pairs=allowed_address_pairs)
         allowed_address_pair = body['port']['allowed_address_pairs']
-        self.assertEqual(allowed_address_pair, allowed_address_pairs)
+        self.assertItemsEqual(allowed_address_pair, allowed_address_pairs)
 
     @test.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
     def test_update_port_with_address_pair(self):
diff --git a/neutron/tests/tempest/api/test_revisions.py b/neutron/tests/tempest/api/test_revisions.py
index 10438b7..a70b995 100644
--- a/neutron/tests/tempest/api/test_revisions.py
+++ b/neutron/tests/tempest/api/test_revisions.py
@@ -10,6 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
+
 from tempest import test
 
 from neutron.tests.tempest.api import base
@@ -90,12 +92,7 @@
         self.client.update_port(
             port['id'], security_groups=[sg['security_group']['id']])
         updated = self.client.show_port(port['id'])
-        self.client.update_port(port['id'], security_groups=[])
-        # TODO(kevinbenton): these extra shows after after the update are
-        # to work around the fact that ML2 creates the result dict before
-        # commit happens if the port is unbound. The update response should
-        # be usable directly once that is fixed.
-        updated2 = self.client.show_port(port['id'])
+        updated2 = self.client.update_port(port['id'], security_groups=[])
         self.assertGreater(updated['port']['revision_number'],
                            port['revision_number'])
         self.assertGreater(updated2['port']['revision_number'],
@@ -118,6 +115,116 @@
         self.assertGreater(updated2['security_group']['revision_number'],
                            updated['security_group']['revision_number'])
 
+    @test.idempotent_id('db70c285-0365-4fac-9f55-2a0ad8cf55a8')
+    @test.requires_ext(extension="allowed-address-pairs", service="network")
+    def test_update_allowed_address_pairs_bumps_revision(self):
+        net = self.create_network()
+        port = self.create_port(net)
+        updated = self.client.update_port(
+            port['id'], allowed_address_pairs=[{'ip_address': '1.1.1.1/32'}])
+        self.assertGreater(updated['port']['revision_number'],
+                           port['revision_number'])
+        updated2 = self.client.update_port(
+            port['id'], allowed_address_pairs=[])
+        self.assertGreater(updated2['port']['revision_number'],
+                           updated['port']['revision_number'])
+
+    @test.idempotent_id('a21ec3b4-3569-4b77-bf29-4177edaa2df5')
+    @test.requires_ext(extension="extra_dhcp_opt", service="network")
+    def test_update_extra_dhcp_opt_bumps_revision(self):
+        net = self.create_network()
+        port = self.create_port(net)
+        opts = [{'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'}]
+        updated = self.client.update_port(port['id'], extra_dhcp_opts=opts)
+        self.assertGreater(updated['port']['revision_number'],
+                           port['revision_number'])
+        opts[0]['opt_value'] = 'pxelinux.77'
+        updated2 = self.client.update_port(
+            port['id'], extra_dhcp_opts=opts)
+        self.assertGreater(updated2['port']['revision_number'],
+                           updated['port']['revision_number'])
+
+    @test.idempotent_id('40ba648f-f374-4c29-a5b7-489dd5a38a4e')
+    @test.requires_ext(extension="dns-integration", service="network")
+    def test_update_dns_domain_bumps_revision(self):
+        net = self.create_network(dns_domain='example.test.')
+        updated = self.client.update_network(net['id'], dns_domain='exa.test.')
+        self.assertGreater(updated['network']['revision_number'],
+                           net['revision_number'])
+        port = self.create_port(net)
+        updated = self.client.update_port(port['id'], dns_name='port1')
+        if not updated['port']['dns_name']:
+            self.skipTest("Server does not have DNS domain configured.")
+        self.assertGreater(updated['port']['revision_number'],
+                           port['revision_number'])
+        updated2 = self.client.update_port(port['id'], dns_name='')
+        self.assertGreater(updated2['port']['revision_number'],
+                           updated['port']['revision_number'])
+
+    @test.idempotent_id('8482324f-cf59-4d73-b98e-d37119255300')
+    @test.requires_ext(extension="router", service="network")
+    @test.requires_ext(extension="extraroute", service="network")
+    def test_update_router_extra_routes_bumps_revision(self):
+        subnet = self.create_subnet(self.create_network())
+        subgateway = netaddr.IPAddress(subnet['gateway_ip'])
+        router = self.create_router(router_name='test')
+        self.create_router_interface(router['id'], subnet['id'])
+        router = self.client.show_router(router['id'])['router']
+        updated = self.client.update_router(
+            router['id'], routes=[{'destination': '2.0.0.0/24',
+                                   'nexthop': str(subgateway + 1)}])
+        self.assertGreater(updated['router']['revision_number'],
+                           router['revision_number'])
+        updated2 = self.client.update_router(router['id'], routes=[])
+        self.assertGreater(updated2['router']['revision_number'],
+                           updated['router']['revision_number'])
+
+    @test.idempotent_id('6bd18702-e25a-4b4b-8c0c-680113533511')
+    @test.requires_ext(extension="subnet-service-types", service="network")
+    def test_update_subnet_service_types_bumps_revisions(self):
+        subnet = self.create_subnet(self.create_network())
+        updated = self.client.update_subnet(
+            subnet['id'], service_types=['compute:'])
+        self.assertGreater(updated['subnet']['revision_number'],
+                           subnet['revision_number'])
+        updated2 = self.client.update_subnet(
+            subnet['id'], service_types=[])
+        self.assertGreater(updated2['subnet']['revision_number'],
+                           updated['subnet']['revision_number'])
+
+    @test.idempotent_id('9c83105c-9973-45ff-9ca2-e66d64700abe')
+    @test.requires_ext(extension="port-security", service="network")
+    def test_update_port_security_bumps_revisions(self):
+        net = self.create_network(port_security_enabled=False)
+        updated = self.client.update_network(net['id'],
+                                             port_security_enabled=True)
+        self.assertGreater(updated['network']['revision_number'],
+                           net['revision_number'])
+        updated2 = self.client.update_network(net['id'],
+                                              port_security_enabled=False)
+        self.assertGreater(updated2['network']['revision_number'],
+                           updated['network']['revision_number'])
+        port = self.create_port(net, port_security_enabled=False)
+        updated = self.client.update_port(port['id'],
+                                          port_security_enabled=True)
+        self.assertGreater(updated['port']['revision_number'],
+                           port['revision_number'])
+        updated2 = self.client.update_port(port['id'],
+                                           port_security_enabled=False)
+        self.assertGreater(updated2['port']['revision_number'],
+                           updated['port']['revision_number'])
+
+    @test.idempotent_id('68d5ac3a-11a1-4847-8e2e-5843c043d89b')
+    @test.requires_ext(extension="binding", service="network")
+    def test_portbinding_bumps_revision(self):
+        port = self.create_port(self.create_network())
+        port = self.admin_client.update_port(
+            port['id'], **{'binding:host_id': 'badhost1'})['port']
+        updated = self.admin_client.update_port(
+            port['id'], **{'binding:host_id': 'badhost2'})['port']
+        self.assertGreater(updated['revision_number'],
+                           port['revision_number'])
+
     @test.idempotent_id('4a37bde9-1975-47e0-9b8c-2c9ca36415b0')
     @test.requires_ext(extension="router", service="network")
     def test_update_router_bumps_revision(self):
diff --git a/neutron/tests/tempest/api/test_trunk_details.py b/neutron/tests/tempest/api/test_trunk_details.py
index 4b7ec28..0c91c45 100644
--- a/neutron/tests/tempest/api/test_trunk_details.py
+++ b/neutron/tests/tempest/api/test_trunk_details.py
@@ -35,15 +35,16 @@
     @test.idempotent_id('544bcaf2-86fb-4930-93ab-ece1c3cc33df')
     def test_port_resource_trunk_details_with_subport(self):
         subport_network = self.create_network()
-        parent_port = self.create_port(subport_network)
-        subport_data = {'port_id': parent_port['id'],
+        subport = self.create_port(subport_network)
+        subport_data = {'port_id': subport['id'],
                         'segmentation_type': 'vlan',
                         'segmentation_id': 2}
         trunk = self._create_trunk_with_network_and_parent([subport_data])
-        port = self.client.show_port(trunk['trunk']['port_id'])
+        subport_data['mac_address'] = subport['mac_address']
+        parent_port = self.client.show_port(trunk['trunk']['port_id'])
         expected_trunk_details = {'sub_ports': [subport_data],
                                   'trunk_id': trunk['trunk']['id']}
-        observed_trunk_details = port['port'].get('trunk_details')
+        observed_trunk_details = parent_port['port'].get('trunk_details')
         self.assertIsNotNone(observed_trunk_details)
         self.assertEqual(expected_trunk_details,
                          observed_trunk_details)