Remove usage of testscenarios and replace it with ddt library

As our internal QE reported to us, ddt is producing more consistent
names of the same tests with different variables then testscenarios.
With testscenarios it is something like:

foo_tempest_plugin.tests.something.SomeClass.test_foo[id-123456](c1,c2)

and with ddt is more similar to tests without scenarios:

foo_tempest_plugin.tests.something.SomeClass.test_foo_1[id-123456]

Apparently due to this inconsistency results of some tests couldn't be
properly reported properly to some tools which we are using downstream.

So this patch proposes to remove usage of testscenarios in
neutron_tempest_plugin and replace it with ddt where it is needed.
Actually ddt was already used in some of the tests here so this will
make it also more consistent across the tests in that repo.

Also as part of this effort I relalised that in some cases testscenarios
where used, tests were running e.g. 2 times but actually variable set to
different value in different scenarios were not used at all. So in such
case I simply dropped usage of testscenarios and left only one variant
of the test to be run.

Change-Id: Ieabab4ccaa0e2a365939425dff0c0776839251eb
diff --git a/neutron_tempest_plugin/api/admin/test_logging.py b/neutron_tempest_plugin/api/admin/test_logging.py
index b76377d..dda31b4 100644
--- a/neutron_tempest_plugin/api/admin/test_logging.py
+++ b/neutron_tempest_plugin/api/admin/test_logging.py
@@ -15,12 +15,9 @@
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
-import testscenarios
 
 from neutron_tempest_plugin.api import base
 
-load_tests = testscenarios.load_tests_apply_scenarios
-
 
 class LoggingTestJSON(base.BaseAdminNetworkTest):
 
diff --git a/neutron_tempest_plugin/api/test_qos.py b/neutron_tempest_plugin/api/test_qos.py
index 448f391..f1867d1 100644
--- a/neutron_tempest_plugin/api/test_qos.py
+++ b/neutron_tempest_plugin/api/test_qos.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+
+import ddt
 from neutron_lib.api.definitions import qos as qos_apidef
 from neutron_lib import constants as n_constants
 from neutron_lib.services.qos import constants as qos_consts
@@ -20,14 +22,11 @@
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
-
-import testscenarios
 import testtools
 
 from neutron_tempest_plugin.api import base
 from neutron_tempest_plugin import config
 
-load_tests = testscenarios.load_tests_apply_scenarios
 CONF = config.CONF
 
 
@@ -484,15 +483,6 @@
             policy_id, rule['id'])
         return rule
 
-    @property
-    def opposite_direction(self):
-        if self.direction == "ingress":
-            return "egress"
-        elif self.direction == "egress":
-            return "ingress"
-        else:
-            return None
-
     @decorators.idempotent_id('8a59b00b-3e9c-4787-92f8-93a5cdf5e378')
     def test_rule_create(self):
         policy = self.create_qos_policy(name=self.policy_name,
@@ -544,17 +534,20 @@
 
     @decorators.idempotent_id('149a6988-2568-47d2-931e-2dbc858943b3')
     def test_rule_update(self):
+        self._test_rule_update(opposite_direction=None)
+
+    def _test_rule_update(self, opposite_direction=None):
         policy = self.create_qos_policy(name=self.policy_name,
                                         description='test policy',
                                         shared=False)
         rule = self._create_qos_bw_limit_rule(
             policy['id'], {'max_kbps': 1, 'max_burst_kbps': 1})
 
-        if self.opposite_direction:
+        if opposite_direction:
             self.qos_bw_limit_rule_client.update_limit_bandwidth_rule(
                 policy['id'], rule['id'],
                 **{'max_kbps': 200, 'max_burst_kbps': 1337,
-                   'direction': self.opposite_direction})
+                   'direction': opposite_direction})
         else:
             self.qos_bw_limit_rule_client.update_limit_bandwidth_rule(
                 policy['id'], rule['id'],
@@ -564,8 +557,8 @@
         retrieved_policy = retrieved_policy['bandwidth_limit_rule']
         self.assertEqual(200, retrieved_policy['max_kbps'])
         self.assertEqual(1337, retrieved_policy['max_burst_kbps'])
-        if self.opposite_direction:
-            self.assertEqual(self.opposite_direction,
+        if opposite_direction:
+            self.assertEqual(opposite_direction,
                              retrieved_policy['direction'])
 
     @decorators.idempotent_id('67ee6efd-7b33-4a68-927d-275b4f8ba958')
@@ -697,16 +690,13 @@
             policy['id'])
 
 
+@ddt.ddt
 class QosBandwidthLimitRuleWithDirectionTestJSON(
         QosBandwidthLimitRuleTestJSON):
     required_extensions = (
         QosBandwidthLimitRuleTestJSON.required_extensions +
         ['qos-bw-limit-direction']
     )
-    scenarios = [
-        ('ingress', {'direction': 'ingress'}),
-        ('egress', {'direction': 'egress'}),
-    ]
 
     @classmethod
     @base.require_qos_rule_type(qos_consts.RULE_TYPE_BANDWIDTH_LIMIT)
@@ -753,6 +743,13 @@
             {'max_kbps': 1025, 'max_burst_kbps': 1025,
              'direction': n_constants.INGRESS_DIRECTION})
 
+    @decorators.idempotent_id('7ca7c83b-0555-4a0f-a422-4338f77f79e5')
+    @ddt.unpack
+    @ddt.data({'opposite_direction': 'ingress'},
+              {'opposite_direction': 'egress'})
+    def test_rule_update(self, opposite_direction):
+        self._test_rule_update(opposite_direction=opposite_direction)
+
 
 class RbacSharedQosPoliciesTest(base.BaseAdminNetworkTest):
 
diff --git a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
index 4d5fdac..9896073 100644
--- a/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
+++ b/neutron_tempest_plugin/fwaas/scenario/test_fwaas_v2.py
@@ -14,8 +14,6 @@
 #    under the License.
 
 
-import testscenarios
-
 from oslo_log import log as logging
 from tempest.common import utils
 from tempest import config
@@ -28,7 +26,6 @@
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
-load_tests = testscenarios.load_tests_apply_scenarios
 
 
 class TestFWaaS_v2(base.FWaaSScenarioTest_V2):
diff --git a/neutron_tempest_plugin/scenario/test_floatingip.py b/neutron_tempest_plugin/scenario/test_floatingip.py
index 804683d..ee1b192 100644
--- a/neutron_tempest_plugin/scenario/test_floatingip.py
+++ b/neutron_tempest_plugin/scenario/test_floatingip.py
@@ -15,6 +15,7 @@
 
 import time
 
+import ddt
 from neutron_lib import constants as lib_constants
 from neutron_lib.services.qos import constants as qos_consts
 from neutron_lib.utils import test
@@ -24,8 +25,6 @@
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
-import testscenarios
-from testscenarios.scenarios import multiply_scenarios
 import testtools
 
 from neutron_tempest_plugin.api import base as base_api
@@ -41,9 +40,6 @@
 LOG = log.getLogger(__name__)
 
 
-load_tests = testscenarios.load_tests_apply_scenarios
-
-
 class FloatingIpTestCasesMixin(object):
     credentials = ['primary', 'admin']
 
@@ -104,10 +100,10 @@
                                        constants.SERVER_STATUS_ACTIVE)
         return {'port': port, 'fip': fip, 'server': server}
 
-    def _test_east_west(self):
+    def _test_east_west(self, src_has_fip, dest_has_fip):
         # The proxy VM is used to control the source VM when it doesn't
         # have a floating-ip.
-        if self.src_has_fip:
+        if src_has_fip:
             proxy = None
             proxy_client = None
         else:
@@ -117,7 +113,7 @@
                                       pkey=self.keypair['private_key'])
 
         # Source VM
-        if self.src_has_fip:
+        if src_has_fip:
             src_server = self._create_server()
             src_server_ip = src_server['fip']['floating_ip_address']
         else:
@@ -129,7 +125,7 @@
                                 proxy_client=proxy_client)
 
         # Destination VM
-        if self.dest_has_fip:
+        if dest_has_fip:
             dest_server = self._create_server(network=self._dest_network)
         else:
             dest_server = self._create_server(create_floating_ip=False,
@@ -139,46 +135,46 @@
         self.check_remote_connectivity(ssh_client,
             dest_server['port']['fixed_ips'][0]['ip_address'],
             servers=[src_server, dest_server])
-        if self.dest_has_fip:
+        if dest_has_fip:
             self.check_remote_connectivity(ssh_client,
                 dest_server['fip']['floating_ip_address'],
                 servers=[src_server, dest_server])
 
 
+@ddt.ddt
 class FloatingIpSameNetwork(FloatingIpTestCasesMixin,
                             base.BaseTempestTestCase):
-    scenarios = multiply_scenarios([
-        ('SRC with FIP', dict(src_has_fip=True)),
-        ('SRC without FIP', dict(src_has_fip=False)),
-    ], [
-        ('DEST with FIP', dict(dest_has_fip=True)),
-        ('DEST without FIP', dict(dest_has_fip=False)),
-    ])
 
     same_network = True
 
     @test.unstable_test("bug 1717302")
     @decorators.idempotent_id('05c4e3b3-7319-4052-90ad-e8916436c23b')
-    def test_east_west(self):
-        self._test_east_west()
+    @ddt.unpack
+    @ddt.data({'src_has_fip': True, 'dest_has_fip': True},
+              {'src_has_fip': True, 'dest_has_fip': False},
+              {'src_has_fip': False, 'dest_has_fip': True},
+              {'src_has_fip': True, 'dest_has_fip': False})
+    def test_east_west(self, src_has_fip, dest_has_fip):
+        self._test_east_west(src_has_fip=src_has_fip,
+                             dest_has_fip=dest_has_fip)
 
 
+@ddt.ddt
 class FloatingIpSeparateNetwork(FloatingIpTestCasesMixin,
                                 base.BaseTempestTestCase):
-    scenarios = multiply_scenarios([
-        ('SRC with FIP', dict(src_has_fip=True)),
-        ('SRC without FIP', dict(src_has_fip=False)),
-    ], [
-        ('DEST with FIP', dict(dest_has_fip=True)),
-        ('DEST without FIP', dict(dest_has_fip=False)),
-    ])
 
     same_network = False
 
     @test.unstable_test("bug 1717302")
     @decorators.idempotent_id('f18f0090-3289-4783-b956-a0f8ac511e8b')
-    def test_east_west(self):
-        self._test_east_west()
+    @ddt.unpack
+    @ddt.data({'src_has_fip': True, 'dest_has_fip': True},
+              {'src_has_fip': True, 'dest_has_fip': False},
+              {'src_has_fip': False, 'dest_has_fip': True},
+              {'src_has_fip': True, 'dest_has_fip': False})
+    def test_east_west(self, src_has_fip, dest_has_fip):
+        self._test_east_west(src_has_fip=src_has_fip,
+                             dest_has_fip=dest_has_fip)
 
 
 class DefaultSnatToExternal(FloatingIpTestCasesMixin,
diff --git a/requirements.txt b/requirements.txt
index 34531e9..9423079 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -16,6 +16,5 @@
 tenacity>=3.2.1 # Apache-2.0
 ddt>=1.0.1 # MIT
 testtools>=2.2.0 # MIT
-testscenarios>=0.4 # Apache-2.0/BSD
 eventlet!=0.18.3,!=0.20.1,>=0.18.2 # MIT
 debtcollector>=1.2.0 # Apache-2.0