Merge "Test security group creation with insufficient rules quota"
diff --git a/.zuul.yaml b/.zuul.yaml
index 3a6b925..ff55295 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -1213,7 +1213,6 @@
       - openstack/tempest
     vars:
       tempest_test_regex: ^neutron_tempest_plugin\.sfc
-      tox_envlist: all-plugin
       devstack_plugins:
         networking-sfc: https://opendev.org/openstack/networking-sfc
         neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin
@@ -1276,7 +1275,6 @@
       - openstack/tempest
     vars:
       tempest_test_regex: ^neutron_tempest_plugin\.fwaas
-      tox_envlist: all-plugin
       devstack_plugins:
         neutron-fwaas: https://opendev.org/openstack/neutron-fwaas.git
         neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
@@ -1335,7 +1333,6 @@
       - openstack/tempest
     vars:
       tempest_test_regex: ^neutron_tempest_plugin\.vpnaas
-      tox_envlist: all-plugin
       devstack_plugins:
         neutron-vpnaas: https://opendev.org/openstack/neutron-vpnaas.git
         neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index 25cfba6..7a46014 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -12,8 +12,10 @@
 if [[ "$1" == "stack" ]]; then
     case "$2" in
         install)
-            echo_summary "Installing neutron-tempest-plugin"
-            install_neutron_tempest_plugin
+            if [[ "$INSTALL_TEMPEST" == "True" ]]; then
+                echo_summary "Installing neutron-tempest-plugin"
+                install_neutron_tempest_plugin
+            fi
             ;;
         test-config)
             echo_summary "Configuring neutron-tempest-plugin tempest options"
diff --git a/neutron_tempest_plugin/api/admin/test_external_network_extension.py b/neutron_tempest_plugin/api/admin/test_external_network_extension.py
index a713492..cf6c44d 100644
--- a/neutron_tempest_plugin/api/admin/test_external_network_extension.py
+++ b/neutron_tempest_plugin/api/admin/test_external_network_extension.py
@@ -35,9 +35,18 @@
             post_body['router:external'] = external
         body = self.admin_client.create_network(**post_body)
         network = body['network']
-        self.addCleanup(self.admin_client.delete_network, network['id'])
+        self.addCleanup(self._delete_network, network['id'])
         return network
 
+    def _delete_network(self, net_id):
+        try:
+            self.admin_client.delete_network(net_id)
+        except lib_exc.Conflict:
+            ports = self.admin_client.list_ports(network_id=net_id)['ports']
+            for port in ports:
+                self.admin_client.delete_port(port['id'])
+            self.admin_client.delete_network(net_id)
+
     @decorators.idempotent_id('afd8f1b7-a81e-4629-bca8-a367b3a144bb')
     def test_regular_client_shares_with_another(self):
         net = self.create_network()
diff --git a/neutron_tempest_plugin/api/test_security_groups.py b/neutron_tempest_plugin/api/test_security_groups.py
index 3c611eb..dd1597c 100644
--- a/neutron_tempest_plugin/api/test_security_groups.py
+++ b/neutron_tempest_plugin/api/test_security_groups.py
@@ -307,6 +307,20 @@
             self._set_sg_rules_quota(value)
             self.assertEqual(value, self._get_sg_rules_quota())
 
+    @decorators.idempotent_id('4459e066-d9c8-4a13-9e98-018f95ce2dbf')
+    def test_create_sg_rules_when_quota_disabled(self):
+        sg_rules_amount = self._get_sg_rules_amount()
+        self._set_sg_rules_quota(-1)
+        self._create_security_group_rules(10, port_index=100)
+        new_sg_rules_amount = self._get_sg_rules_amount()
+        self.assertGreater(new_sg_rules_amount, sg_rules_amount)
+
+    @decorators.idempotent_id('3fc39bd6-3132-4e6f-a09c-456fb18d600c')
+    def test_sg_rules_quota_decrease_less_than_created(self):
+        self._create_max_allowed_sg_rules_amount()
+        new_quota = self._decrease_sg_rules_quota()
+        self.assertEqual(self._get_sg_rules_quota(), new_quota)
+
 
 class SecGroupProtocolTest(base.BaseNetworkTest):
 
diff --git a/neutron_tempest_plugin/fwaas/common/fwaas_v2_client.py b/neutron_tempest_plugin/fwaas/common/fwaas_v2_client.py
index 44b0952..84d6432 100644
--- a/neutron_tempest_plugin/fwaas/common/fwaas_v2_client.py
+++ b/neutron_tempest_plugin/fwaas/common/fwaas_v2_client.py
@@ -121,6 +121,11 @@
             firewall_rule_id=firewall_rule_id)
         self._wait_firewall_group_ready(firewall_group_id)
 
+    def update_firewall_group_and_wait(self, firewall_group_id, **kwargs):
+        self.firewall_groups_client.update_firewall_group(
+            firewall_group_id, **kwargs)
+        self._wait_firewall_group_ready(firewall_group_id)
+
     @staticmethod
     def _call_and_ignore_exceptions(exc_list, func, *args, **kwargs):
         """Call the given function and pass if a given exception is raised."""
diff --git a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
index e9dad0b..4681b88 100644
--- a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
+++ b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
@@ -299,5 +299,4 @@
             should_connect=False)
 
         # Disassociate ports of this firewall group for cleanup resources
-        self.firewall_groups_client.update_firewall_group(
-            fw_group['id'], ports=[])
+        self.update_firewall_group_and_wait(fw_group['id'], ports=[])
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index 566ac95..b2ea8ae 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -224,7 +224,7 @@
             message=self.multicast_message,
             result_file=self.sender_output_file)
         server['ssh_client'].execute_script(
-            'echo "%s" > ~/multicast_traffic_sender.py' % check_script)
+            'echo "%s" > /tmp/multicast_traffic_sender.py' % check_script)
 
     def _prepare_receiver(self, server, mcast_address):
         check_script = get_receiver_script(
@@ -238,7 +238,7 @@
         self._check_cmd_installed_on_server(ssh_client, server['id'],
                                             PYTHON3_BIN)
         server['ssh_client'].execute_script(
-            'echo "%s" > ~/multicast_traffic_receiver.py' % check_script)
+            'echo "%s" > /tmp/multicast_traffic_receiver.py' % check_script)
 
     def _prepare_unregistered(self, server, mcast_address):
         check_script = get_unregistered_script(
@@ -250,7 +250,7 @@
         self._check_cmd_installed_on_server(ssh_client, server['id'],
                                             'tcpdump')
         server['ssh_client'].execute_script(
-            'echo "%s" > ~/unregistered_traffic_receiver.sh' % check_script)
+            'echo "%s" > /tmp/unregistered_traffic_receiver.sh' % check_script)
 
     @test.unstable_test("bug 1850288")
     @decorators.idempotent_id('113486fc-24c9-4be4-8361-03b1c9892867')
@@ -259,6 +259,8 @@
 
         [Sender server] -> (Multicast network) -> [Receiver server]
         """
+        LOG.debug("IGMP snooping enabled: %s",
+                  CONF.neutron_plugin_options.is_igmp_snooping_enabled)
         sender = self._create_server()
         receivers = [self._create_server() for _ in range(1)]
         # Sender can be also receiver of multicast traffic
@@ -279,7 +281,7 @@
 
         [0] https://tools.ietf.org/html/rfc4541 (See section 2.1.2)
         """
-        return (mcast_address.startswith('224.0.0') or not
+        return (str(mcast_address).startswith('224.0.0') or not
                 CONF.neutron_plugin_options.is_igmp_snooping_enabled)
 
     def _check_multicast_conectivity(self, sender, receivers, unregistered):
@@ -300,14 +302,14 @@
 
         # Run the unregistered node script
         unregistered['ssh_client'].execute_script(
-            "bash ~/unregistered_traffic_receiver.sh", become_root=True)
+            "bash /tmp/unregistered_traffic_receiver.sh", become_root=True)
 
         self._prepare_sender(sender, mcast_address)
         receiver_ids = []
         for receiver in receivers:
             self._prepare_receiver(receiver, mcast_address)
             receiver['ssh_client'].execute_script(
-                "%s ~/multicast_traffic_receiver.py &" % PYTHON3_BIN,
+                "%s /tmp/multicast_traffic_receiver.py &" % PYTHON3_BIN,
                 shell="bash")
             utils.wait_until_true(
                 lambda: _message_received(
@@ -321,7 +323,7 @@
 
         # Now lets run scripts on sender
         sender['ssh_client'].execute_script(
-            "%s ~/multicast_traffic_sender.py" % PYTHON3_BIN)
+            "%s /tmp/multicast_traffic_sender.py" % PYTHON3_BIN)
 
         # And check if message was received
         for receiver in receivers:
@@ -348,9 +350,11 @@
         unregistered_result = unregistered['ssh_client'].execute_script(
             "cat {path} || echo '{path} not exists yet'".format(
                 path=self.unregistered_output_file))
-        num_of_pckt = (1 if self._is_multicast_traffic_expected(mcast_address)
-                       else 0)
-        self.assertIn('%d packets captured' % num_of_pckt, unregistered_result)
+        LOG.debug("Unregistered VM result: %s", unregistered_result)
+        expected_result = '0 packets captured'
+        if self._is_multicast_traffic_expected(mcast_address):
+            expected_result = '1 packet captured'
+        self.assertIn(expected_result, unregistered_result)
 
 
 class MulticastTestIPv4(BaseMulticastTest, base.BaseTempestTestCase):
diff --git a/setup.cfg b/setup.cfg
index 79f30be..544ea90 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -21,29 +21,6 @@
 packages =
     neutron_tempest_plugin
 
-[build_sphinx]
-all-files = 1
-warning-is-error = 1
-source-dir = doc/source
-build-dir = doc/build
-
-[upload_sphinx]
-upload-dir = doc/build/html
-
-[compile_catalog]
-directory = neutron_tempest_plugin/locale
-domain = neutron-tempest-plugin
-
-[update_catalog]
-domain = neutron-tempest-plugin
-output_dir = neutron_tempest_plugin/locale
-input_file = neutron_tempest_plugin/locale/neutron_tempest_plugin.pot
-
-[extract_messages]
-keywords = _ gettext ngettext l_ lazy_gettext
-mapping_file = babel.cfg
-output_file = neutron_tempest_plugin/locale/neutron_tempest_plugin.pot
-
 [entry_points]
 tempest.test_plugins =
     neutron_tests = neutron_tempest_plugin.plugin:NeutronTempestPlugin
diff --git a/test-requirements.txt b/test-requirements.txt
index 905420c..6cff185 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -7,10 +7,10 @@
 coverage!=4.4,>=4.0 # Apache-2.0
 flake8-import-order==0.12 # LGPLv3
 python-subunit>=1.0.0 # Apache-2.0/BSD
-sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2  # BSD
+sphinx>=2.0.0,!=2.1.0 # BSD
 oslotest>=3.2.0 # Apache-2.0
 stestr>=1.0.0 # Apache-2.0
 testtools>=2.2.0 # MIT
-openstackdocstheme>=1.20.0 # Apache-2.0
+openstackdocstheme>=2.0.0 # Apache-2.0
 # releasenotes
 reno>=2.5.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 19e006a..760cc47 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,8 +13,6 @@
    OS_LOG_CAPTURE={env:OS_LOG_CAPTURE:true}
    OS_STDOUT_CAPTURE={env:OS_STDOUT_CAPTURE:true}
    OS_STDERR_CAPTURE={env:OS_STDERR_CAPTURE:true}
-install_command =
-  pip install {opts} {packages}
 deps =
   -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/test-requirements.txt
@@ -41,7 +39,7 @@
     coverage xml -o cover/coverage.xml
 
 [testenv:docs]
-commands = python setup.py build_sphinx
+commands = sphinx-build -W -b html doc/source doc/build/html
 
 [testenv:releasenotes]
 commands =