]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Improve debugging ability for functional tests
authorZane Bitter <zbitter@redhat.com>
Thu, 20 Sep 2012 09:14:53 +0000 (11:14 +0200)
committerZane Bitter <zbitter@redhat.com>
Thu, 20 Sep 2012 13:57:24 +0000 (15:57 +0200)
Use proper assert*() functions so that we can get some information out of
any failed tests.

Change-Id: I92d937015562371c2b39bbcf5b9cbd2b6ca19d52
Signed-off-by: Zane Bitter <zbitter@redhat.com>
18 files changed:
heat/tests/functional/test_AutoScalingMultiAZSample.py
heat/tests/functional/test_CFN_API_Actions.py
heat/tests/functional/test_HAProxy_Single_Instance.py
heat/tests/functional/test_OpenShift_Prebuilt_JEOS.py
heat/tests/functional/test_WordPress_2_Instances.py
heat/tests/functional/test_WordPress_2_Instances_With_EBS.py
heat/tests/functional/test_WordPress_2_Instances_With_EBS_EIP.py
heat/tests/functional/test_WordPress_Composed_Instances.py
heat/tests/functional/test_WordPress_Single_Instance.py
heat/tests/functional/test_WordPress_Single_Instance_Boto.py
heat/tests/functional/test_WordPress_Single_Instance_With_EBS.py
heat/tests/functional/test_WordPress_Single_Instance_With_EBS_EIP.py
heat/tests/functional/test_WordPress_Single_Instance_With_EIP.py
heat/tests/functional/test_WordPress_Single_Instance_With_HA.py
heat/tests/functional/test_WordPress_Single_Instance_With_IHA.py
heat/tests/functional/test_WordPress_With_LB.py
heat/tests/functional/test_WordPress_With_RDS.py
heat/tests/functional/util.py

index 2bb644b6b3fd64c39d7155c8dd6a62b3fb0f13ea..397967f9e54b1ebe8a0d0f4d077a7d2b464f83d8 100644 (file)
@@ -31,9 +31,9 @@ class AutoScalingMultiAZSampleFunctionalTest(unittest.TestCase):
                          'DBUsername=dbuser',
                          'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WebServerGroup0 = util.Instance('WebServerGroup-0')
+        self.WebServerGroup0 = util.Instance(self, 'WebServerGroup-0')
 
     def tearDown(self):
         pass
@@ -54,7 +54,7 @@ class AutoScalingMultiAZSampleFunctionalTest(unittest.TestCase):
         # Give the load balancer 2 minutes to react
         sleep(2 * 60)
 
-        self.WebServerGroup1 = util.Instance('WebServerGroup-1')
+        self.WebServerGroup1 = util.Instance(self, 'WebServerGroup-1')
         # Verify the second instance gets launched
         self.assertTrue(self.WebServerGroup1.exists())
         self.WebServerGroup1.wait_for_boot()
index 86f95fa6bff2f1efe5ca8aa14b6b03b7ce5cfbe6..7e2fa64e694b9860306f44f2a94ddbe7b822f4c6 100644 (file)
@@ -41,7 +41,7 @@ class CfnApiFunctionalTest(unittest.TestCase):
     Contrary to the nose docs, the class can be a unittest.TestCase subclass
     '''
     @classmethod
-    def setupAll(self):
+    def setupAll(cls):
         print "SETUPALL"
         template = 'WordPress_Single_Instance.template'
 
@@ -49,37 +49,51 @@ class CfnApiFunctionalTest(unittest.TestCase):
                          'DBUsername=dbuser',
                          'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.logical_resource_name = 'WikiDatabase'
-        self.logical_resource_type = 'AWS::EC2::Instance'
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        cls.logical_resource_name = 'WikiDatabase'
+        cls.logical_resource_type = 'AWS::EC2::Instance'
+
+        # Just to get the assert*() methods
+        class CfnApiFunctions(unittest.TestCase):
+            @unittest.skip('Not a real test case')
+            def runTest(self):
+                pass
+
+        inst = CfnApiFunctions()
+        cls.stack = util.Stack(inst, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiDatabase = util.Instance(self.logical_resource_name)
-        self.stack.create()
-        self.WikiDatabase.wait_for_boot()
-        self.WikiDatabase.check_cfntools()
-        self.WikiDatabase.wait_for_provisioning()
-
-        self.logical_resource_status = "CREATE_COMPLETE"
-
-        # Save some compiled regexes and strings for response validation
-        self.stack_id_re = re.compile("^arn:openstack:heat::admin:stacks/"
-                                      + self.stack.stackname)
-        self.time_re = re.compile(
-            "[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$")
-        self.description_re = re.compile("^AWS CloudFormation Sample Template")
-        self.stack_status = "CREATE_COMPLETE"
-        self.stack_status_reason = "Stack successfully created"
-        self.stack_timeout = str(60)
-        self.stack_disable_rollback = "True"
-
-        # Match the expected format for physical resource ID for an instance
-        self.phys_res_id_re = re.compile(
-            "^[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*$")
+        cls.WikiDatabase = util.Instance(inst, cls.logical_resource_name)
+
+        try:
+            cls.stack.create()
+            cls.WikiDatabase.wait_for_boot()
+            cls.WikiDatabase.check_cfntools()
+            cls.WikiDatabase.wait_for_provisioning()
+
+            cls.logical_resource_status = "CREATE_COMPLETE"
+
+            # Save some compiled regexes and strings for response validation
+            cls.stack_id_re = re.compile("^arn:openstack:heat::admin:stacks/"
+                                          + cls.stack.stackname)
+            cls.time_re = re.compile(
+                "[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$")
+            cls.description_re = re.compile(
+                "^AWS CloudFormation Sample Template")
+            cls.stack_status = "CREATE_COMPLETE"
+            cls.stack_status_reason = "Stack successfully created"
+            cls.stack_timeout = str(60)
+            cls.stack_disable_rollback = "True"
+
+            # Match the expected format for an instance's physical resource ID
+            cls.phys_res_id_re = re.compile(
+                "^[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*-[0-9a-z]*$")
+        except:
+            cls.stack.cleanup()
+            raise
 
     @classmethod
-    def teardownAll(self):
+    def teardownAll(cls):
         print "TEARDOWNALL"
-        self.stack.cleanup()
+        cls.stack.cleanup()
 
     def test_instance(self):
         # ensure wordpress was installed by checking for expected
index b8d0a8f0a59313c470c433e7d8cc8c5de169dde1..6dd2ab3523bbc5b4fc6b9181f4afe73b1d35995f 100644 (file)
@@ -33,9 +33,11 @@ class HAProxyFunctionalTest(unittest.TestCase):
                          'DBUsername=dbuser',
                          'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(wp_template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, wp_template, 'F17', 'x86_64', 'cfntools',
                                 wp_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
+
+        self.hap_stack = None
 
     def tearDown(self):
         self.stack.cleanup()
@@ -63,14 +65,16 @@ class HAProxyFunctionalTest(unittest.TestCase):
 
         # So wordpress instance is up, we now launch the HAProxy instance
         # and prove wordpress is accessable via the proxy instance IP
+        hap_stackname = 'hap_teststack'
         hap_template = 'HAProxy_Single_Instance.template'
         hap_paramstr = ';'.join(['InstanceType=m1.xlarge',
                        "Server1=%s:80" % self.WikiDatabase.ip])
 
-        self.hap_stack = util.Stack(hap_template, 'F17', 'x86_64', 'cfntools',
-                                    hap_paramstr, stackname='hap_teststack')
-        self.LoadBalancerInstance = util.Instance('LoadBalancerInstance',
-                                                  self.hap_stack.stackname)
+        self.hap_stack = util.Stack(self, hap_template,
+                                    'F17', 'x86_64', 'cfntools',
+                                    hap_paramstr, stackname=hap_stackname)
+        self.LoadBalancerInstance = util.Instance(self, 'LoadBalancerInstance',
+                                                  hap_stackname)
         self.hap_stack.create()
         self.LoadBalancerInstance.wait_for_boot()
         self.LoadBalancerInstance.check_cfntools()
index f48fb149d1ab43d88bc643e597b4c775c5597e36..58d8af6aad8a7ffea30a775a05ed3c29fbe82084 100644 (file)
@@ -32,11 +32,11 @@ class OpenShiftFunctionalTest(unittest.TestCase):
         template = 'OpenShift_Prebuilt_JEOS.template'
         stack_paramstr = ';'.join(['InstanceType=m1.xlarge'])
 
-        self.stack = util.Stack(template, 'F16', 'x86_64',
+        self.stack = util.Stack(self, template, 'F16', 'x86_64',
                 'cfntools-openshift', stack_paramstr)
 
-        self.Node = util.Instance('OpenShiftNodeServer')
-        self.Broker = util.Instance('OpenShiftBrokerServer')
+        self.Node = util.Instance(self, 'OpenShiftNodeServer')
+        self.Broker = util.Instance(self, 'OpenShiftBrokerServer')
 
     def test_instance(self):
         self.stack.create()
index 8cb716fbbabd496a801a0d2b9e82da83076f310d..cf2ed8d4443afc3a3c81f27880e3135d815f21de 100644 (file)
@@ -34,10 +34,10 @@ class WordPress2Instances(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.DatabaseServer = util.Instance('DatabaseServer')
-        self.WebServer = util.Instance('WebServer')
+        self.DatabaseServer = util.Instance(self, 'DatabaseServer')
+        self.WebServer = util.Instance(self, 'WebServer')
 
     def tearDown(self):
         self.stack.cleanup()
index ca877289ead1eb3edd66f880897338c47e012e49..9e369ef88ba4332383f83455aae1583ed742aa14 100644 (file)
@@ -34,11 +34,11 @@ class WordPress2InstancesWithEBS(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
 
-        self.WikiDatabase = util.Instance('WikiDatabase')
-        self.WebServer = util.Instance('WebServer')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
+        self.WebServer = util.Instance(self, 'WebServer')
 
     def tearDown(self):
         self.stack.cleanup()
index 855ba6c83888af0859bc05ee2fe46f5bc889784d..29ed0fba09f776802e37ccd2e39f75f11776e375 100644 (file)
@@ -30,12 +30,13 @@ class WordPress2EBSEIPFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(self.template, 'F17', 'x86_64', 'cfntools',
-            stack_paramstr)
+        self.stack = util.Stack(self, self.template,
+                                'F17', 'x86_64', 'cfntools',
+                                stack_paramstr)
 
-        self.webserver = util.Instance('WebServer')
+        self.webserver = util.Instance(self, 'WebServer')
 
-        self.database = util.Instance('WikiDatabase')
+        self.database = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
index 3a9ee886f59a7ffba855d4b8530b33db1c9e2cc0..606649bd89518df0292c5b87f1d89800c5b8db9d 100644 (file)
@@ -31,13 +31,13 @@ class WordPressComposedInstancesFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
 
-        self.WebServer = util.Instance('WebServer')
+        self.WebServer = util.Instance(self, 'WebServer')
 
-        self.MySqlDatabaseServer = \
-            util.Instance('DatabaseTemplate.MySqlDatabaseServer')
+        self.MySqlDatabaseServer = util.Instance(self,
+                'DatabaseTemplate.MySqlDatabaseServer')
 
     def tearDown(self):
         self.stack.cleanup()
index c82702d76426909feb9f0fcff47902891c4ec37f..375a57cddd6f3c377e1f4dea7d9645cd77fbfc08 100644 (file)
@@ -30,9 +30,9 @@ class WordPressFunctionalTest(unittest.TestCase):
                          'DBUsername=dbuser',
                          'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
index 32124979344d24ab9f726ffedae86f3c7e1f300d..f0350c8a9d756cb7235835ed61e8cb7354276831 100644 (file)
@@ -31,9 +31,10 @@ class WordPressBotoFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.StackBoto(template, 'F17', 'x86_64', 'cfntools',
-            stack_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.stack = util.StackBoto(self, template,
+                                    'F17', 'x86_64', 'cfntools',
+                                    stack_paramstr)
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
index 52318ddf3b81e91fd0fb36822dad1339cf8cf51f..29db9786e493503f176dc70e22b0b6477d703c22 100644 (file)
@@ -34,9 +34,9 @@ class WordPressSingleEBSFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
index 9a1d2fa7404d643f06d9bc889f813b87356bd98d..e4a4951f83ccebbc1581c9314eae32bfa1ae0054 100644 (file)
@@ -34,9 +34,9 @@ class WordPressEBSEIPFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiServer = util.Instance('WikiServer')
+        self.WikiServer = util.Instance(self, 'WikiServer')
 
     def tearDown(self):
         self.stack.cleanup()
index 0998895a13a08dc8248c6430cf5493bb8d761544..7a2d670dda338349d0453ccb8968c648236ce86f 100644 (file)
@@ -34,9 +34,9 @@ class WordPressEIPFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WebServer = util.Instance('WebServer')
+        self.WebServer = util.Instance(self, 'WebServer')
 
     def tearDown(self):
         self.stack.cleanup()
index e2412b86f7ca18accdba80055a26d895b52a9beb..550e634704416e59e7860c4e60be1bd10a960213 100644 (file)
@@ -30,9 +30,9 @@ class HaFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
index e4525d5cf340e753686e6964ba6ed7727ee3f2b8..19b783b49093e52c24a68299125f4932d14e03d2 100644 (file)
@@ -31,9 +31,9 @@ class WordPressIHAFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WikiDatabase = util.Instance('WikiDatabase')
+        self.WikiDatabase = util.Instance(self, 'WikiDatabase')
 
     def tearDown(self):
         self.stack.cleanup()
@@ -85,7 +85,7 @@ class WordPressIHAFunctionalTest(unittest.TestCase):
         self.assertTrue(tries < 500)
 
         # Create a new Instance object and wait for boot
-        self.WikiDatabaseNew = util.Instance('WikiDatabase')
+        self.WikiDatabaseNew = util.Instance(self, 'WikiDatabase')
         self.WikiDatabaseNew.wait_for_boot()
         self.WikiDatabaseNew.check_cfntools()
         self.WikiDatabaseNew.wait_for_provisioning()
index 005562d5ee5813d88b6de3ffbc782b2caddd716f..b8f5ec0c3e7648c8225a1c1578712a931582de92 100644 (file)
@@ -30,12 +30,12 @@ class WordPressWithLBFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
 
-        self.WikiServerOne = util.Instance('WikiServerOne')
-        self.LBInstance = util.Instance('LoadBalancer.LB_instance')
-        self.MySqlDatabaseServer = util.Instance(
+        self.WikiServerOne = util.Instance(self, 'WikiServerOne')
+        self.LBInstance = util.Instance(self, 'LoadBalancer.LB_instance')
+        self.MySqlDatabaseServer = util.Instance(self,
                 'DatabaseServer.MySqlDatabaseServer')
 
     def tearDown(self):
index 4ef14913b2443369ca746d3b5d8d4d6084a020ed..d5a2e049ade7f306ea96362bf27e833a7d8a7831 100644 (file)
@@ -30,9 +30,9 @@ class WordPressRDSFunctionalTest(unittest.TestCase):
             'DBUsername=dbuser',
             'DBPassword=' + os.environ['OS_PASSWORD']])
 
-        self.stack = util.Stack(template, 'F17', 'x86_64', 'cfntools',
+        self.stack = util.Stack(self, template, 'F17', 'x86_64', 'cfntools',
             stack_paramstr)
-        self.WebServer = util.Instance('WebServer')
+        self.WebServer = util.Instance(self, 'WebServer')
 
     def tearDown(self):
         self.stack.cleanup()
index 1dd22728b47b0db15228b2123cb6b3a6e5a277ff..0837ba9dce298a71342ef77805b5276e6becfe5e 100644 (file)
@@ -35,6 +35,7 @@ from nose.exc import SkipTest
 
 from glance import client as glance_client
 from novaclient.v1_1 import client as nova_client
+import heat
 from heat import utils
 from heat.engine import parser
 from heat import client as heat_client
@@ -44,8 +45,13 @@ from keystoneclient.v2_0 import client
 DEFAULT_STACKNAME = 'teststack'
 
 
+# this test is in heat/tests/functional, so go up 3 dirs
+basepath = os.path.join(heat.__path__[0], os.path.pardir)
+
+
 class Instance(object):
-    def __init__(self, instance_name, stackname=DEFAULT_STACKNAME):
+    def __init__(self, testcase, instance_name, stackname=DEFAULT_STACKNAME):
+        self.testcase = testcase
         self.name = '%s.%s' % (stackname, instance_name)
 
         # during nose test execution this file will be imported even if
@@ -55,9 +61,9 @@ class Instance(object):
         except KeyError:
             raise SkipTest('OS_AUTH_STRATEGY unset, skipping functional test')
 
-        if os.environ['OS_AUTH_STRATEGY'] != 'keystone':
-            print 'keystone authentication required'
-            assert False
+        self.testcase.assertEqual(os.environ['OS_AUTH_STRATEGY'],
+                                  'keystone',
+                                  'keystone authentication required')
 
         self.creds = dict(username=os.environ['OS_USERNAME'],
                 password=os.environ['OS_PASSWORD'],
@@ -66,10 +72,6 @@ class Instance(object):
                 strategy=os.environ['OS_AUTH_STRATEGY'])
         dbusername = 'testuser'
 
-        # this test is in heat/tests/functional, so go up 3 dirs
-        basepath = os.path.abspath(
-                os.path.dirname(os.path.realpath(__file__)) + '/../../..')
-
         self.novaclient = nova_client.Client(self.creds['username'],
             self.creds['password'], self.creds['tenant'],
             self.creds['auth_url'], service_type='compute')
@@ -91,7 +93,7 @@ class Instance(object):
                         self.ip = address.items()[0][1][0]['addr']
                 time.sleep(10)
                 tries += 1
-                assert tries < 500
+                self.testcase.assertTrue(tries < 500, 'Timed out')
             print 'Instance (%s) ip (%s) status (%s)' % (self.name, self.ip,
                  server.status)
 
@@ -104,7 +106,7 @@ class Instance(object):
                       (self.name, self.ip))
                 time.sleep(10)
                 tries += 1
-                assert tries < 50
+                self.testcase.assertTrue(tries < 50, 'Timed out')
             else:
                 print 'Instance (%s) ip (%s) SSH detected.' % (self.name,
                         self.ip)
@@ -114,7 +116,7 @@ class Instance(object):
         while True:
             try:
                 tries += 1
-                assert tries < 50
+                self.testcase.assertTrue(tries < 50, 'Timed out')
                 self.ssh.connect(self.ip, username='ec2-user',
                     allow_agent=True, look_for_keys=True, password='password')
             except paramiko.AuthenticationException:
@@ -139,7 +141,7 @@ class Instance(object):
             except IOError, e:
                 tries += 1
                 if e.errno == errno.ENOENT:
-                    assert tries < 50
+                    self.testcase.assertTrue(tries < 50, 'Timed out')
                     print("Instance (%s) ip (%s) not booted, waiting..." %
                           (self.name, self.ip))
                     time.sleep(15)
@@ -165,7 +167,7 @@ class Instance(object):
         print "Verifying file '%s' exists" % path
         stdin, stdout, sterr = self.ssh.exec_command('ls "%s"' % path)
         lines = stdout.readlines()
-        assert len(lines) == 1
+        self.testcase.assertEqual(len(lines), 1)
         result = lines.pop().rstrip()
         return result == path
 
@@ -195,7 +197,7 @@ class Instance(object):
             data = files.pop().split('  ')
             cur_file = data[1].rstrip()
             if cur_file in cfn_tools_files:
-                assert data[0] == cfntools[cur_file]
+                self.testcase.assertEqual(data[0], cfntools[cur_file])
         print 'Instance (%s) cfntools integrity verified.' % self.name
 
     def wait_for_provisioning(self):
@@ -207,7 +209,7 @@ class Instance(object):
             except IOError, e:
                 tries += 1
                 if e.errno == errno.ENOENT:
-                    assert tries < 500
+                    self.testcase.assertTrue(tries < 500, 'Timed out')
                     print("Instance (%s) provisioning incomplete, waiting..." %
                           self.name)
                     time.sleep(15)
@@ -229,7 +231,7 @@ class Instance(object):
 #            sudo chmod 777 /var/lib/cloud/instance/user-data.txt.i\n')
 #        time.sleep(1)  # necessary for sendall to complete
 
-        f = open(self.basepath + '/templates/' + template_file)
+        f = open(basepath + '/templates/' + template_file)
         t = json.loads(f.read())
         f.close()
 
@@ -255,15 +257,15 @@ class Instance(object):
         t_data_list.insert(len(t_data_list) - 1,
                 u'touch /var/lib/cloud/instance/provision-finished')
 
-        assert t_data_list == remote_file_list_u
+        self.testcase.assertEqual(t_data_list, remote_file_list_u)
 
         remote_file = self.sftp.open('/var/lib/cloud/instance/user-data.txt.i')
         msg = email.message_from_file(remote_file)
         remote_file.close()
 
         filepaths = {
-            'cloud-config': self.basepath + '/heat/cloudinit/config',
-            'part-handler.py': self.basepath +
+            'cloud-config': basepath + '/heat/cloudinit/config',
+            'part-handler.py': basepath +
             '/heat/cloudinit/part-handler.py'
         }
 
@@ -278,7 +280,7 @@ class Instance(object):
 
             if file in filepaths.keys():
                 with open(filepaths[file]) as f:
-                    assert data == f.read()
+                    self.testcase.assertEqual(data, f.read())
 
     def get_ssh_client(self):
         if self.ssh.get_transport() != None:
@@ -295,13 +297,27 @@ class Instance(object):
 
 
 class Stack(object):
-    def __init__(self, template_file, distribution, arch, jeos_type,
+
+    def __init__(self, testcase, template_file, distribution, arch, jeos_type,
             stack_paramstr, stackname=DEFAULT_STACKNAME):
 
+        self.testcase = testcase
         self.stackname = stackname
         self.template_file = template_file
         self.distribution = distribution
         self.stack_paramstr = stack_paramstr
+
+        self.creds = dict(username=os.environ['OS_USERNAME'],
+                          password=os.environ['OS_PASSWORD'],
+                          tenant=os.environ['OS_TENANT_NAME'],
+                          auth_url=os.environ['OS_AUTH_URL'],
+                          strategy=os.environ['OS_AUTH_STRATEGY'])
+        self.dbusername = 'testuser'
+
+        self.testcase.assertEqual(os.environ['OS_AUTH_STRATEGY'],
+                                  'keystone',
+                                  'keystone authentication required')
+
         self.prepare_jeos(distribution, arch, jeos_type)
 
         self.novaclient = nova_client.Client(self.creds['username'],
@@ -313,7 +329,7 @@ class Stack(object):
     def create(self):
         self.keyname = self.novaclient.keypairs.list().pop().name
 
-        assert self.heatclient
+        self.testcase.assertTrue(self.heatclient)
 
         full_paramstr = ';'.join([self.stack_paramstr,
                                   'KeyName=' + self.keyname,
@@ -323,7 +339,9 @@ class Stack(object):
         # Format parameters and create the stack
         parameters = {}
         parameters['StackName'] = self.stackname
-        template_path = self.basepath + '/templates/' + self.template_file
+        template_path = os.path.join(basepath,
+                                     'templates',
+                                     self.template_file)
         parameters['TemplateBody'] = open(template_path).read()
         parameters.update(self.heatclient.format_parameters(template_params))
         result = self.heatclient.create_stack(**parameters)
@@ -334,25 +352,25 @@ class Stack(object):
         tries = 0
 
         print 'Waiting for stack creation to be completed'
-        while self.in_state('CREATE_IN_PROGRESS'):
+        while self.get_state() == 'CREATE_IN_PROGRESS':
             tries += 1
-            assert tries < 500
+            self.testcase.assertTrue(tries < 500, 'Timed out')
             time.sleep(10)
 
-        assert self.in_state('CREATE_COMPLETE')
+        self.testcase.assertEqual(self.get_state(), 'CREATE_COMPLETE')
 
     def _check_create_result(self, result):
         # Check result looks OK
         root = etree.fromstring(result)
         create_list = root.xpath('/CreateStackResponse/CreateStackResult')
-        assert create_list
-        assert len(create_list) == 1
+        self.testcase.assertTrue(create_list)
+        self.testcase.assertEqual(len(create_list), 1)
 
         # Extract StackId from the result, and check the StackName part
         stackid = create_list[0].findtext('StackId')
         idname = stackid.split('/')[1]
         print "Checking %s contains name %s" % (stackid, self.stackname)
-        assert idname == self.stackname
+        self.testcase.assertEqual(idname, self.stackname)
 
     def _create_heat_client(self):
         return heat_client.get_client('0.0.0.0', 8000,
@@ -360,32 +378,6 @@ class Stack(object):
             self.creds['tenant'], self.creds['auth_url'],
             self.creds['strategy'], None, None, False)
 
-    # during nose test execution this file will be imported even if
-    # the unit tag was specified
-    try:
-        os.environ['OS_AUTH_STRATEGY']
-    except KeyError:
-        raise SkipTest('OS_AUTH_STRATEGY not set, skipping functional test')
-
-    if os.environ['OS_AUTH_STRATEGY'] != 'keystone':
-        print 'keystone authentication required'
-        assert False
-
-    creds = dict(username=os.environ['OS_USERNAME'],
-            password=os.environ['OS_PASSWORD'],
-            tenant=os.environ['OS_TENANT_NAME'],
-            auth_url=os.environ['OS_AUTH_URL'],
-            strategy=os.environ['OS_AUTH_STRATEGY'])
-    dbusername = 'testuser'
-
-    # this test is in heat/tests/functional, so go up 3 dirs
-    basepath = os.path.abspath(
-            os.path.dirname(os.path.realpath(__file__)) + '/../../..')
-
-    novaclient = None
-    glanceclient = None
-    heatclient = None
-
     def get_state(self):
         stack_list = self.heatclient.list_stacks(StackName=self.stackname)
         root = etree.fromstring(stack_list)
@@ -395,11 +387,10 @@ class Stack(object):
         if len(alist):
             item = alist.pop()
             result = item.findtext("StackStatus")
+        if result and result.find('FAILED') >= 0:
+            print stack_list
         return result
 
-    def in_state(self, state):
-        return state == self.get_state()
-
     def cleanup(self):
         parameters = {'StackName': self.stackname}
         c = self.get_heat_client()
@@ -407,16 +398,17 @@ class Stack(object):
 
         print 'Waiting for stack deletion to be completed'
         tries = 0
-        while self.in_state('DELETE_IN_PROGRESS'):
+        while self.get_state() == 'DELETE_IN_PROGRESS':
             tries += 1
-            assert tries < 50
+            self.testcase.assertTrue(tries < 50, 'Timed out')
             time.sleep(10)
 
         # final state for all stacks is DELETE_COMPLETE, but then they
         # dissappear hence no result from list_stacks/get_state
         # depending on timing, we could get either result here
         end_state = self.get_state()
-        assert (end_state == 'DELETE_COMPLETE' or end_state == None)
+        if end_state is not None:
+            self.testcase.assertEqual(end_state, 'DELETE_COMPLETE')
 
     def get_nova_client(self):
         if self.novaclient != None:
@@ -441,9 +433,8 @@ class Stack(object):
 
         # skip creating jeos if image already available
         if not self.poll_glance(self.glanceclient, imagename, False):
-            if os.geteuid() != 0:
-                print 'test must be run as root to create jeos'
-                assert False
+            self.testcase.assertEqual(os.geteuid(), 0,
+                                      'No JEOS found - run as root to create')
 
             # -d: debug, -G: register with glance
             subprocess.call(['heat-jeos', '-d', '-G', 'create', imagename])
@@ -457,7 +448,7 @@ class Stack(object):
         tries = 0
         while imagelistname != imagename:
             tries += 1
-            assert tries < 50
+            self.testcase.assertTrue(tries < 50, 'Timed out')
             if block:
                 time.sleep(15)
             print "Checking glance for image registration"
@@ -509,8 +500,8 @@ class Stack(object):
         '''
         root = etree.fromstring(response)
         output_list = root.xpath(prefix)
-        assert output_list
-        assert len(output_list) == 1
+        self.testcase.assertTrue(output_list)
+        self.testcase.assertEqual(len(output_list), 1)
         output = output_list.pop()
         value = output.findtext(key)
         return value
@@ -534,12 +525,12 @@ class StackBoto(Stack):
                              auth_url=self.creds['auth_url'])
         ksusers = keystone.users.list()
         ksuid = [u.id for u in ksusers if u.name == self.creds['username']]
-        assert len(ksuid) == 1
+        self.testcase.assertEqual(len(ksuid), 1)
 
         ec2creds = keystone.ec2.list(ksuid[0])
-        assert len(ec2creds) == 1
-        assert ec2creds[0].access
-        assert ec2creds[0].secret
+        self.testcase.assertEqual(len(ec2creds), 1)
+        self.testcase.assertTrue(ec2creds[0].access)
+        self.testcase.assertTrue(ec2creds[0].secret)
         print "Got EC2 credentials from keystone"
 
         # most of the arguments passed to heat_client_boto are for
@@ -571,7 +562,7 @@ class StackBoto(Stack):
         return [e.physical_resource_id for e in events if match(e)]
 
     def _find_stack_output(self, result, output_key):
-        assert len(result) == 1
+        self.testcase.assertEqual(len(result), 1)
 
         for o in result[0].outputs:
             if o.key == output_key: