Add pep8 check for tempest.lib import

tempest.lib should not import local tempest code to avoid circular dependency,
so this patch adds pep8 check to block such kind of code.

Change-Id: I392d28b3195040a800d96171ef275c6e73f9fef4
diff --git a/HACKING.rst b/HACKING.rst
index efabaf6..44519d4 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -19,6 +19,7 @@
          decorators.skip_because from tempest-lib
 - [T110] Check that service client names of GET should be consistent
 - [T111] Check that service client names of DELETE should be consistent
+- [T112] Check that tempest.lib should not import local tempest code
 - [N322] Method's default argument shouldn't be mutable
 
 Test Data/Configuration
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index c666c96..f4b76e5 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -225,6 +225,27 @@
         yield (0, msg)
 
 
+def dont_import_local_tempest_into_lib(logical_line, filename):
+    """Check that tempest.lib should not import local tempest code
+
+    T112
+    """
+    if 'tempest/lib/' not in filename:
+        return
+
+    if not ('from tempest' in logical_line
+            or 'import tempest' in logical_line):
+        return
+
+    if ('from tempest.lib' in logical_line
+        or 'import tempest.lib' in logical_line):
+        return
+
+    msg = ("T112: tempest.lib should not import local tempest code to avoid "
+           "circular dependency")
+    yield (0, msg)
+
+
 def factory(register):
     register(import_no_clients_in_api_and_scenario_tests)
     register(scenario_tests_need_service_tags)
@@ -236,3 +257,4 @@
     register(no_testtools_skip_decorator)
     register(get_resources_on_service_clients)
     register(delete_resources_on_service_clients)
+    register(dont_import_local_tempest_into_lib)
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 55f00ef..aba2aab 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -147,3 +147,23 @@
             " @testtools.skipUnless(CONF.something, 'msg')"))))
         self.assertEqual(0, len(list(checks.no_testtools_skip_decorator(
             " @testtools.skipIf(CONF.something, 'msg')"))))
+
+    def test_dont_import_local_tempest_code_into_lib(self):
+        self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib(
+            "from tempest.common import waiters",
+            './tempest/common/compute.py'))))
+        self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib(
+            "from tempest import config",
+            './tempest/common/compute.py'))))
+        self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib(
+            "import tempest.exception",
+            './tempest/common/compute.py'))))
+        self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib(
+            "from tempest.common import waiters",
+            './tempest/lib/common/compute.py'))))
+        self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib(
+            "from tempest import config",
+            './tempest/lib/common/compute.py'))))
+        self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib(
+            "import tempest.exception",
+            './tempest/lib/common/compute.py'))))