Add test_port_shut_down API test

This patch adds test which replaces fullstack test:
neutron.tests.fullstack.test_port_shut_down.PortShutDownTest

It is simple API test which can be done quickly in
neutron-tempest-plugin job. In fullstack instead it requires to prepare
whole environment with neutron-server, fake compute node, agents, etc.
so it takes much more time.

Change-Id: Ica5e72ab6d4c20fdcbd1f0dd38e6adcf627bcefd
diff --git a/neutron_tempest_plugin/api/test_ports.py b/neutron_tempest_plugin/api/test_ports.py
index 8d5772b..ef6d4fa 100644
--- a/neutron_tempest_plugin/api/test_ports.py
+++ b/neutron_tempest_plugin/api/test_ports.py
@@ -20,9 +20,10 @@
 from tempest.lib import decorators
 
 from neutron_tempest_plugin.api import base
+from neutron_tempest_plugin.common import utils as plugin_utils
 
 
-class PortsTestJSON(base.BaseNetworkTest):
+class PortsTestJSON(base.BaseAdminNetworkTest):
 
     @classmethod
     def resource_setup(cls):
@@ -151,6 +152,45 @@
         expected = [s['id'], s['id']]
         self.assertEqual(expected, subnets)
 
+    @decorators.idempotent_id('12a3f5f1-4d9c-4fe1-9e7b-08c75fe77790')
+    def test_port_shut_down(self):
+        # NOTE(slaweq): In some cases (like default ML2/OVN deployment)
+        # extension is enabled but there may not be any DHCP agent available.
+        # In such case those tests should be also skipped.
+        dhcp_agents = self.admin_client.list_agents(
+            agent_type="DHCP Agent")['agents']
+        if not dhcp_agents:
+            msg = ("At least one DHCP agent is required to be running in "
+                   "the environment for this test.")
+            raise self.skipException(msg)
+
+        self.create_subnet(self.network)
+
+        def dhcp_port_created():
+            return self.client.list_ports(
+                network_id=self.network['id'],
+                device_owner=lib_constants.DEVICE_OWNER_DHCP)['ports']
+
+        plugin_utils.wait_until_true(dhcp_port_created)
+
+        dhcp_port = self.client.list_ports(
+            network_id=self.network['id'],
+            device_owner=lib_constants.DEVICE_OWNER_DHCP)['ports'][0]
+
+        def port_active():
+            port = self.client.show_port(dhcp_port['id'])['port']
+            return port['status'] == lib_constants.PORT_STATUS_ACTIVE
+
+        plugin_utils.wait_until_true(port_active)
+
+        self.client.update_port(dhcp_port['id'], admin_state_up=False)
+
+        def port_down():
+            port = self.client.show_port(dhcp_port['id'])['port']
+            return port['status'] == lib_constants.PORT_STATUS_DOWN
+
+        plugin_utils.wait_until_true(port_down)
+
 
 class PortsIpv6TestJSON(base.BaseNetworkTest):