Addresses lp#948243 - Tempest handles misconfig better

* Added Tempest base test class with test data
* Added logic to base test to reconfigure Tempest
  if the flavor/image sections are missing or if
  the provided values do not exist

Change-Id: I0c1bb16a65e36a99e6e49493325451c9a3eadaad
diff --git a/tempest/tests/base_compute_test.py b/tempest/tests/base_compute_test.py
new file mode 100644
index 0000000..216f506
--- /dev/null
+++ b/tempest/tests/base_compute_test.py
@@ -0,0 +1,83 @@
+from tempest import exceptions
+from tempest import openstack
+from tempest.config import TempestConfig
+
+import unittest2 as unittest
+
+
+class BaseComputeTest(unittest.TestCase):
+
+    os = openstack.Manager()
+    servers_client = os.servers_client
+    flavors_client = os.flavors_client
+    images_client = os.images_client
+    extensions_client = os.extensions_client
+    floating_ips_client = os.floating_ips_client
+    keypairs_client = os.keypairs_client
+    floating_ips_client = os.floating_ips_client
+    security_groups_client = os.security_groups_client
+    limits_client = os.limits_client
+    config = os.config
+    build_interval = config.compute.build_interval
+    build_timeout = config.compute.build_timeout
+
+    # Validate reference data exists
+    # If not, attempt to auto-configure
+    try:
+        image_ref = config.compute.image_ref
+        image_ref_alt = config.compute.image_ref_alt
+        images_client.get_image(image_ref)
+        images_client.get_image(image_ref_alt)
+    except:
+        # Make a reasonable attempt to get usable images
+        params = {'status': 'ACTIVE'}
+        _, images = images_client.list_images_with_detail(params)
+        if len(images) is 0:
+            message = "No usable image exists. Upload an image to Glance."
+            raise exceptions.InvalidConfiguration(message=message)
+        if len(images) is 1:
+            image_ref = images[0]['id']
+            image_ref_alt = images[0]['id']
+        else:
+            # Try to determine if this is a devstack environment.
+            # If so, some of the images are not usable
+
+            # For now, the useable image in devstack has this property
+            usable = [i for i in images if 'ramdisk_id' in i['metadata']]
+            if len(usable) > 0:
+                # We've found at least one image we can use
+                image_ref = usable[0]['id']
+                image_ref_alt = usable[0]['id']
+            else:
+                # We've done our due dillegence, take the first two images
+                image_ref = images[0]['id']
+                image_ref_alt = images[1]['id']
+
+    try:
+        flavor_ref = config.compute.flavor_ref
+        flavor_ref_alt = config.compute.flavor_ref_alt
+        flavors_client.get_flavor_details(flavor_ref)
+        flavors_client.get_flavor_details(flavor_ref_alt)
+    except:
+        # Reload both with new values
+        # Sort so the smallest flavors are used. This is for efficiency.
+        _, flavors = flavors_client.list_flavors_with_detail()
+        flavors = sorted(flavors, key=lambda k: k['ram'])
+
+        if len(flavors) is 0:
+            message = "No flavors exists. Add flavors via the admin API."
+            raise exceptions.InvalidConfiguration(message=message)
+        if len(flavors) is 1:
+            flavor_ref = flavors[0]['id']
+            flavor_ref_alt = flavors[0]['id']
+        else:
+            flavor_ref = flavors[0]['id']
+            # Make sure the second flavor does not have the same RAM
+            for i in range(1, len(flavors)):
+                if flavors[i] == flavors[-1]:
+                    # We've tried. Take the last flavor
+                    flavor_ref_alt = flavors[i]['id']
+                else:
+                    if flavors[i]['ram'] > flavors[0]['ram']:
+                        flavor_ref_alt = flavors[i]['id']
+                        break
diff --git a/tempest/tests/test_authorization.py b/tempest/tests/test_authorization.py
index 5b2eeca..9f3c34d 100644
--- a/tempest/tests/test_authorization.py
+++ b/tempest/tests/test_authorization.py
@@ -153,15 +153,15 @@
         A create server request should fail if the tenant id does not match
         the current user
         """
+        saved_base_url = self.other_client.base_url
         try:
-            saved_base_url = self.other_client.client.base_url
             # Change the base URL to impersonate another user
-            self.other_client.client.base_url = self.client.client.base_url
+            self.other_client.base_url = self.client.base_url
             self.other_client.create_server('test', self.image['id'],
                                                     self.flavor_ref)
         finally:
             # Reset the base_url...
-            self.other_client.client.base_url = saved_base_url
+            self.other_client.base_url = saved_base_url
 
     @classmethod
     def _parse_image_id(self, image_ref):
diff --git a/tempest/tests/test_extensions.py b/tempest/tests/test_extensions.py
index 9bfffe3..9c1bac6 100644
--- a/tempest/tests/test_extensions.py
+++ b/tempest/tests/test_extensions.py
@@ -1,16 +1,14 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
 import tempest.config
-import unittest2 as unittest
+from base_compute_test import BaseComputeTest
 
 
-class ExtentionsTest(unittest.TestCase):
+class ExtentionsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.extensions_client
-        cls.config = cls.os.config
+        cls.client = cls.extensions_client
 
     @attr(type='smoke')
     def test_list_extensions(self):
diff --git a/tempest/tests/test_flavors.py b/tempest/tests/test_flavors.py
index 187fac7..34aa68c 100644
--- a/tempest/tests/test_flavors.py
+++ b/tempest/tests/test_flavors.py
@@ -3,16 +3,15 @@
 from tempest import exceptions
 from tempest import openstack
 import tempest.config
+from base_compute_test import BaseComputeTest
 
 
-class FlavorsTest(unittest.TestCase):
+class FlavorsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.flavors_client
-        cls.config = cls.os.config
-        cls.flavor_id = cls.config.compute.flavor_ref
+        cls.client = cls.flavors_client
+        cls.flavor_id = cls.flavor_ref
 
     @attr(type='smoke')
     def test_list_flavors(self):
diff --git a/tempest/tests/test_floating_ips_actions.py b/tempest/tests/test_floating_ips_actions.py
index 9d7ed6c..cc69048 100644
--- a/tempest/tests/test_floating_ips_actions.py
+++ b/tempest/tests/test_floating_ips_actions.py
@@ -1,22 +1,20 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
-import unittest2 as unittest
 from tempest import exceptions
 from tempest.common.utils.data_utils import rand_name
+from base_compute_test import BaseComputeTest
 
 
-class FloatingIPsTest(unittest.TestCase):
+class FloatingIPsTest(BaseComputeTest):
     server_id = None
     floating_ip = None
 
     @classmethod
     def setUpClass(cls):
         cls.os = openstack.Manager()
-        cls.client = cls.os.floating_ips_client
-        cls.servers_client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.floating_ips_client
+        cls.servers_client = cls.servers_client
+
         #Server creation
         resp, server = cls.servers_client.create_server('floating-server',
                                                         cls.image_ref,
diff --git a/tempest/tests/test_image_metadata.py b/tempest/tests/test_image_metadata.py
index bf8b509..7309bcb 100644
--- a/tempest/tests/test_image_metadata.py
+++ b/tempest/tests/test_image_metadata.py
@@ -1,20 +1,16 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
 from tempest.common.utils.data_utils import rand_name
-import unittest2 as unittest
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 
 
-class ImagesMetadataTest(unittest.TestCase):
+class ImagesMetadataTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.servers_client = cls.os.servers_client
-        cls.client = cls.os.images_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.servers_client = cls.servers_client
+        cls.client = cls.images_client
 
         name = rand_name('server')
         resp, server = cls.servers_client.create_server(name, cls.image_ref,
diff --git a/tempest/tests/test_images.py b/tempest/tests/test_images.py
index 8217d2a..716da65 100644
--- a/tempest/tests/test_images.py
+++ b/tempest/tests/test_images.py
@@ -2,6 +2,7 @@
 import unittest2 as unittest
 
 from tempest.common.utils.data_utils import rand_name
+from base_compute_test import BaseComputeTest
 import tempest.config
 from tempest import openstack
 
@@ -11,19 +12,15 @@
     return temp[1]
 
 
-class ImagesTest(unittest.TestCase):
+class ImagesTest(BaseComputeTest):
 
     create_image_enabled = tempest.config.TempestConfig().\
             compute.create_image_enabled
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.images_client
-        cls.servers_client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.images_client
+        cls.servers_client = cls.servers_client
         cls.create_image_enabled = cls.config.compute.create_image_enabled
 
     @attr(type='smoke')
diff --git a/tempest/tests/test_keypairs.py b/tempest/tests/test_keypairs.py
index 40d00dc..14e1317 100644
--- a/tempest/tests/test_keypairs.py
+++ b/tempest/tests/test_keypairs.py
@@ -1,16 +1,17 @@
 from nose.plugins.attrib import attr
 import unittest2 as unittest
 from tempest import openstack
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 
 
-class KeyPairsTest(unittest.TestCase):
+class KeyPairsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
         cls.os = openstack.Manager()
-        cls.client = cls.os.keypairs_client
+        cls.client = cls.keypairs_client
 
     @attr(type='smoke')
     def test_keypairs_create_list_delete(self):
diff --git a/tempest/tests/test_list_floating_ips.py b/tempest/tests/test_list_floating_ips.py
index e22dd58..d100c01 100644
--- a/tempest/tests/test_list_floating_ips.py
+++ b/tempest/tests/test_list_floating_ips.py
@@ -1,16 +1,16 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
-import unittest2 as unittest
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
+import unittest2 as unittest
 
 
-class FloatingIPDetailsTest(unittest.TestCase):
+class FloatingIPDetailsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.floating_ips_client
+        cls.client = cls.floating_ips_client
         cls.floating_ip = []
         cls.floating_ip_id = []
         cls.random_number = 0
diff --git a/tempest/tests/test_list_images.py b/tempest/tests/test_list_images.py
index e63c447..9d2bb1b 100644
--- a/tempest/tests/test_list_images.py
+++ b/tempest/tests/test_list_images.py
@@ -1,9 +1,8 @@
-import unittest2 as unittest
-
 from nose.plugins.attrib import attr
 
 from tempest import exceptions
 from tempest import openstack
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 
 
@@ -12,16 +11,11 @@
     return temp[len(temp) - 1]
 
 
-class ListImagesTest(unittest.TestCase):
+class ListImagesTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.images_client
-        cls.servers_client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.images_client
 
         name = rand_name('server')
         resp, cls.server1 = cls.servers_client.create_server(name,
diff --git a/tempest/tests/test_list_servers.py b/tempest/tests/test_list_servers.py
index de69cb3..fbdce4b 100644
--- a/tempest/tests/test_list_servers.py
+++ b/tempest/tests/test_list_servers.py
@@ -4,22 +4,16 @@
 
 from tempest import openstack
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 from tempest.tests import utils
 
 
-class ServerDetailsTest(unittest.TestCase):
+class ServerDetailsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.images_client = cls.os.images_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
-        cls.image_ref_alt = cls.config.compute.image_ref_alt
-        cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
+        cls.client = cls.servers_client
 
         # Check to see if the alternate image ref actually exists...
         images_client = cls.os.images_client
diff --git a/tempest/tests/test_security_group_rules.py b/tempest/tests/test_security_group_rules.py
index c07f869..6c8cb8f 100644
--- a/tempest/tests/test_security_group_rules.py
+++ b/tempest/tests/test_security_group_rules.py
@@ -1,17 +1,16 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
-import unittest2 as unittest
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 import time
 
 
-class SecurityGroupsTest(unittest.TestCase):
+class SecurityGroupsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.security_groups_client
+        cls.client = cls.security_groups_client
 
     @attr(type='positive')
     def test_security_group_rules_create(self):
diff --git a/tempest/tests/test_security_groups.py b/tempest/tests/test_security_groups.py
index bbbe777..fdd0077 100644
--- a/tempest/tests/test_security_groups.py
+++ b/tempest/tests/test_security_groups.py
@@ -1,17 +1,16 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
-import unittest2 as unittest
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 import time
 
 
-class SecurityGroupsTest(unittest.TestCase):
+class SecurityGroupsTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.security_groups_client
+        cls.client = cls.security_groups_client
 
     @attr(type='positive')
     def test_security_groups_create_list_delete(self):
diff --git a/tempest/tests/test_server_actions.py b/tempest/tests/test_server_actions.py
index e15fd10..4515b5e 100644
--- a/tempest/tests/test_server_actions.py
+++ b/tempest/tests/test_server_actions.py
@@ -1,29 +1,23 @@
 import base64
 import time
-
-from nose.plugins.attrib import attr
 import unittest2 as unittest
+
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 import tempest.config
 from tempest import openstack
 
+from nose.plugins.attrib import attr
 
-class ServerActionsTest(unittest.TestCase):
+
+class ServerActionsTest(BaseComputeTest):
 
     resize_available = tempest.config.TempestConfig().compute.resize_available
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.image_ref_alt = cls.config.compute.image_ref_alt
-        cls.flavor_ref = cls.config.compute.flavor_ref
-        cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
-        cls.build_interval = cls.config.compute.build_interval
-        cls.build_timeout = cls.config.compute.build_timeout
+        cls.client = cls.servers_client
 
     def setUp(self):
         self.name = rand_name('server')
diff --git a/tempest/tests/test_server_metadata.py b/tempest/tests/test_server_metadata.py
index e2dc111..61254f2 100644
--- a/tempest/tests/test_server_metadata.py
+++ b/tempest/tests/test_server_metadata.py
@@ -1,18 +1,14 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
-import unittest2 as unittest
 
 
-class ServerMetadataTest(unittest.TestCase):
+class ServerMetadataTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.servers_client
 
         #Create a server to be used for all read only tests
         name = rand_name('server')
diff --git a/tempest/tests/test_server_personality.py b/tempest/tests/test_server_personality.py
index 3b516c5..0d90857 100644
--- a/tempest/tests/test_server_personality.py
+++ b/tempest/tests/test_server_personality.py
@@ -1,21 +1,17 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
 from tempest import exceptions
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 import base64
-import unittest2 as unittest
 
 
-class ServerPersonalityTest(unittest.TestCase):
+class ServerPersonalityTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.config = cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
-        cls.user_client = cls.os.limits_client
+        cls.client = cls.servers_client
+        cls.user_client = cls.limits_client
 
     def test_personality_files_exceed_limit(self):
         """
diff --git a/tempest/tests/test_servers.py b/tempest/tests/test_servers.py
index cdb2e89..414d58a 100644
--- a/tempest/tests/test_servers.py
+++ b/tempest/tests/test_servers.py
@@ -1,19 +1,15 @@
 from nose.plugins.attrib import attr
 from tempest import openstack
+from base_compute_test import BaseComputeTest
 from tempest.common.utils.data_utils import rand_name
 import base64
-import unittest2 as unittest
 
 
-class ServersTest(unittest.TestCase):
+class ServersTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.servers_client
 
     @attr(type='smoke')
     def test_create_delete_server(self):
diff --git a/tempest/tests/test_servers_negative.py b/tempest/tests/test_servers_negative.py
index 6c738ea..0d97532 100644
--- a/tempest/tests/test_servers_negative.py
+++ b/tempest/tests/test_servers_negative.py
@@ -1,19 +1,15 @@
-import unittest2 as unittest
 from tempest import openstack
 from tempest.common.utils.data_utils import rand_name
+from base_compute_test import BaseComputeTest
 from tempest import exceptions
 import tempest.config
 
 
-class ServersNegativeTest(unittest.TestCase):
+class ServersNegativeTest(BaseComputeTest):
 
     @classmethod
     def setUpClass(cls):
-        cls.os = openstack.Manager()
-        cls.client = cls.os.servers_client
-        cls.config = cls.os.config
-        cls.image_ref = cls.config.compute.image_ref
-        cls.flavor_ref = cls.config.compute.flavor_ref
+        cls.client = cls.servers_client
 
     def test_server_name_blank(self):
         """Create a server with name parameter empty"""