Add tempest test for l3-ha extension

Add missing l3-ha extension under neutron tempest tests.

Change-Id: Ia608d3f5d63a88eefa4e61da6df2f3656c8446a0
Closes-Bug: #1684065
diff --git a/neutron/tests/tempest/api/admin/test_routers_ha.py b/neutron/tests/tempest/api/admin/test_routers_ha.py
new file mode 100644
index 0000000..187eb6d
--- /dev/null
+++ b/neutron/tests/tempest/api/admin/test_routers_ha.py
@@ -0,0 +1,93 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest import test
+
+from neutron.tests.tempest.api import base_routers as base
+
+
+class RoutersTestHA(base.BaseRouterTest):
+
+    @classmethod
+    @test.requires_ext(extension="router", service="network")
+    @test.requires_ext(extension="l3-ha", service="network")
+    def resource_setup(cls):
+        # The check above will pass if api_extensions=all, which does
+        # not mean "l3-ha" extension itself is present.
+        # Instead, we have to check whether "ha" is actually present by using
+        # admin credentials to create router with ha=True attribute
+        # and checking for BadRequest exception and that the resulting router
+        # has a high availability attribute.
+        super(RoutersTestHA, cls).resource_setup()
+        name = data_utils.rand_name('pretest-check')
+        router = cls.admin_client.create_router(name)
+        if 'ha' not in router['router']:
+            cls.admin_client.delete_router(router['router']['id'])
+            msg = "'ha' attribute not found. HA Possibly not enabled"
+            raise cls.skipException(msg)
+
+    @decorators.idempotent_id('8abc177d-14f1-4018-9f01-589b299cbee1')
+    def test_ha_router_creation(self):
+        """
+        Test uses administrative credentials to create a
+        HA (High Availability) router using the ha=True.
+
+        Acceptance
+        The router is created and the "ha" attribute is set to True
+        """
+        name = data_utils.rand_name('router')
+        router = self.admin_client.create_router(name, ha=True)
+        self.addCleanup(self.admin_client.delete_router,
+                        router['router']['id'])
+        self.assertTrue(router['router']['ha'])
+
+    @decorators.idempotent_id('97b5f7ef-2192-4fa3-901e-979cd5c1097a')
+    def test_legacy_router_creation(self):
+        """
+        Test uses administrative credentials to create a
+        SF (Single Failure) router using the ha=False.
+
+        Acceptance
+        The router is created and the "ha" attribute is
+        set to False, thus making it a "Single Failure Router"
+        as opposed to a "High Availability Router"
+        """
+        name = data_utils.rand_name('router')
+        router = self.admin_client.create_router(name, ha=False)
+        self.addCleanup(self.admin_client.delete_router,
+                        router['router']['id'])
+        self.assertFalse(router['router']['ha'])
+
+    @decorators.idempotent_id('5a6bfe82-5b23-45a4-b027-5160997d4753')
+    def test_legacy_router_update_to_ha(self):
+        """
+        Test uses administrative credentials to create a
+        SF (Single Failure) router using the ha=False.
+        Then it will "update" the router ha attribute to True
+
+        Acceptance
+        The router is created and the "ha" attribute is
+        set to False. Once the router is updated, the ha
+        attribute will be set to True
+        """
+        name = data_utils.rand_name('router')
+        # router needs to be in admin state down in order to be upgraded to HA
+        router = self.admin_client.create_router(name, ha=False,
+                                                 admin_state_up=False)
+        self.addCleanup(self.admin_client.delete_router,
+                        router['router']['id'])
+        self.assertFalse(router['router']['ha'])
+        router = self.admin_client.update_router(router['router']['id'],
+                                                 ha=True)
+        self.assertTrue(router['router']['ha'])
diff --git a/neutron/tests/tempest/api/test_routers.py b/neutron/tests/tempest/api/test_routers.py
index 7a1e458..85bfe82 100644
--- a/neutron/tests/tempest/api/test_routers.py
+++ b/neutron/tests/tempest/api/test_routers.py
@@ -259,6 +259,26 @@
         self.assertNotIn('distributed', show_body['router'])
 
 
+class HaRoutersTest(base_routers.BaseRouterTest):
+
+    @classmethod
+    @test.requires_ext(extension="l3-ha", service="network")
+    def skip_checks(cls):
+        super(HaRoutersTest, cls).skip_checks()
+
+    @decorators.idempotent_id('77db8eae-3aa3-4e61-bf2a-e739ce042e53')
+    def test_convert_legacy_router(self):
+        router = self._create_router(data_utils.rand_name('router'))
+        self.assertNotIn('ha', router)
+        update_body = self.admin_client.update_router(router['id'],
+                                                      ha=True)
+        self.assertTrue(update_body['router']['ha'])
+        show_body = self.admin_client.show_router(router['id'])
+        self.assertTrue(show_body['router']['ha'])
+        show_body = self.client.show_router(router['id'])
+        self.assertNotIn('ha', show_body['router'])
+
+
 class RoutersSearchCriteriaTest(base.BaseSearchCriteriaTest):
 
     resource = 'router'
diff --git a/neutron/tests/tempest/api/test_routers_negative.py b/neutron/tests/tempest/api/test_routers_negative.py
index 049b9c8..b97e30d 100644
--- a/neutron/tests/tempest/api/test_routers_negative.py
+++ b/neutron/tests/tempest/api/test_routers_negative.py
@@ -85,3 +85,18 @@
         with testtools.ExpectedException(lib_exc.Forbidden):
             self.create_router(
                 data_utils.rand_name('router'), distributed=True)
+
+
+class HaRoutersNegativeTest(RoutersNegativeTestBase):
+
+    @classmethod
+    @test.requires_ext(extension="l3-ha", service="network")
+    def skip_checks(cls):
+        super(HaRoutersNegativeTest, cls).skip_checks()
+
+    @test.attr(type='negative')
+    @decorators.idempotent_id('821b85b9-9c51-40f3-831f-bf223a7e0084')
+    def test_router_create_tenant_ha_returns_forbidden(self):
+        with testtools.ExpectedException(lib_exc.Forbidden):
+            self.create_router(
+                data_utils.rand_name('router'), ha=True)