[asterisk-scf-commits] asterisk-scf/integration/testsuite.git branch "review" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Thu May 26 13:04:31 CDT 2011


branch "review" has been updated
       via  186633752f88b475d0c59eb5bc9dd9e19d388def (commit)
      from  2397333b2869f584c86fc7b96acb44ca580c53e5 (commit)

Summary of changes:
 lib/python/TestSuite.py |   91 +++++++++++++++++++++++
 lib/python/util.py      |  188 -----------------------------------------------
 plugins/failover.py     |   47 ++++++------
 testsuite.py            |  117 +++++++++++++++++++++++++----
 4 files changed, 216 insertions(+), 227 deletions(-)
 create mode 100644 lib/python/TestSuite.py
 delete mode 100644 lib/python/util.py


- Log -----------------------------------------------------------------
commit 186633752f88b475d0c59eb5bc9dd9e19d388def
Author: Darren Sessions <dsessions at digium.com>
Date:   Thu May 26 13:04:23 2011 -0500

    did some cleanup with the utility functions and incorporated them into the base classes being used by the plugins via a super class. added some checks in the failover code to make sure the shared ip address specified in the configs isnt already in use on the network.

diff --git a/lib/python/TestSuite.py b/lib/python/TestSuite.py
new file mode 100644
index 0000000..c6322cb
--- /dev/null
+++ b/lib/python/TestSuite.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python
+'''
+
+ Test-Suite Support Classes
+
+ Asterisk SCF Test-Suite
+ Copyright (C) 2011, Digium, Inc.
+
+ This program is free software, distributed under the terms of
+ the GNU General Public License Version 2.
+
+'''
+
+import sys
+import xmlrpclib
+import subprocess
+
+from urlparse import urlparse
+
+class utils():
+    def ping(self, host):
+        process = subprocess.Popen(
+                'ping -c1 %s' % host,
+                stdin=subprocess.PIPE,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+                shell=True)
+        process.wait()
+        if process.returncode == 0:
+            return True 
+        else:
+            return False
+
+    def rpc(self, host):
+        rpc = xmlrpclib.Server('http://%s:8000' % host)
+        try:
+            rpc.reset()
+        except:
+            return {'success':False,'msg':'Connection to %s was refused.' % host}
+        return {'success':True,'rpc':rpc}
+
+    class file:
+        def write(self, component):
+            try:
+                f = open("%s/temp_config_%s.conf" % (self._cwd, component), "w")
+            except:
+                return "Unexpected error: %s" % sys.exc_info()
+            f.write(config)
+            f.close()
+            self._results['file_cleanup'].append('%s/temp_config_%s.conf' % (self._cwd, component))
+
+        def read(self, fn):
+            try:
+                f = open("%s" % fn, "r")
+            except IOError:
+                print "Failed to open test results output file:"
+            except:
+                print "Unexpected error: %s" % sys.exc_info()[0]
+            else:
+                fc = f.read()
+                f.close()
+            return fc.strip()
+
+    class url:
+        def fetchRepoInfo(self, url):
+            repoName = ''
+            url = urlparse(url)
+            if not url[0] == 'git' and not url[0] == 'svn':
+                return {'success':False,'msg':'The URL must be a properly formatted git or svn url.'}
+            for part in url[2].split('/'):
+                repoName = part
+            return {'success':True, 'repoName':repoName, 'repoType':'%s' % url[0]}
+
+class BaseClass(utils):
+    def run(self, testData, testPath):
+        if not 'cmd' in testData:
+            return {'success':False,'msg':'No command specified.'}
+        return self.main(testData, testPath)
+
+class RemoteBaseClass(utils):
+    def run(self, testData, testPath):
+        if not 'cmd' in testData:
+            return {'success':False,'msg':'No command specified.'}
+        if not 'testsuite_remote' in testData:
+            return {'success':False,'msg':'No testsuite remote specified.'}
+        rpc = xmlrpclib.Server('http://%s:8000' % testData['testsuite_remote'])
+        try:
+            rpc.reset()
+        except:
+            return {'success':False,'msg':'Connection to %s was refused.' % testData['testsuite_remote']}
+        return self.main(testData, testPath, rpc)
diff --git a/lib/python/util.py b/lib/python/util.py
deleted file mode 100644
index 2a7a170..0000000
--- a/lib/python/util.py
+++ /dev/null
@@ -1,188 +0,0 @@
-#!/usr/bin/env python
-'''
-
- Utility Classes
-
- Asterisk SCF Test-Suite
- Copyright (C) 2011, Digium, Inc.
-
- This program is free software, distributed under the terms of
- the GNU General Public License Version 2.
-
-'''
-
-import os
-import imp
-import sys
-import time
-import inspect
-import xmlrpclib
-
-from xml.dom import minidom
-from xml.etree.ElementTree import Element, SubElement, tostring
-from urlparse import urlparse
-
-class TestSuiteBaseClass:
-    def run(self, testData, testPath):
-        if not 'cmd' in testData:
-            return {'success':False,'msg':'No command specified.'}
-        return self.main(testData, testPath)
-
-    def rpc(self, host):
-        rpc = xmlrpclib.Server('http://%s:8000' % host)
-        try:
-            rpc.reset()
-        except:
-            return {'success':False,'msg':'Connection to %s was refused.' % host}
-        return {'success':True,'rpc':rpc}
-        
-class TestSuiteRemoteBaseClass:
-    def run(self, testData, testPath):
-        if not 'cmd' in testData:
-            return {'success':False,'msg':'No command specified.'}
-        if not 'testsuite_remote' in testData:
-            return {'success':False,'msg':'No testsuite remote specified.'}
-        rpc = xmlrpclib.Server('http://%s:8000' % testData['testsuite_remote'])
-        try:
-            rpc.reset()
-        except:
-            return {'success':False,'msg':'Connection to %s was refused.' % testData['testsuite_remote']}
-        return self.main(testData, testPath, rpc)
-
-class url:
-    def fetchRepoInfo(self, url):
-        repoName = ''
-        url = urlparse(url)
-        if not url[0] == 'git' and not url[0] == 'svn':
-            return {'success':False,'msg':'The URL must be a properly formatted git or svn url.'}
-        for part in url[2].split('/'):
-            repoName = part
-        return {'success':True, 'repoName':repoName, 'repoType':'%s' % url[0]}
-
-class plugins:
-    def execute(self, name, module, testData, testPath):
-        try:
-            func = getattr(module, 'testsuite')
-        except AttributeError:
-            return {'success':False,'msg':"Unable to execute module '%s'. %s" % (name, sys.exc_info()[1])}
-        else:
-            results = func().run(testData, testPath)
-        if not type(results) == dict:
-            return {'success':False,'msg':"The '%s' module return invalid or missing data." % name}
-        return results
-
-    def init(self, name):
-        loadResults = self.load(name)
-        if not loadResults['success'] == True:
-            return loadResults
-        checkResults = self.check(name, loadResults['module'])
-        if not checkResults['success'] == True:
-            return checkResults
-        return loadResults
-
-    def load(self, name):
-        try:
-            return {'success':True,'module':sys.modules[name]}
-        except KeyError:
-            pass
-        try:
-            fp, pathName, desc = imp.find_module(name)
-        except ImportError:
-            return {'success':False,'msg':'%s' % sys.exc_info()[1]}
-        try:
-            return {'success':True,'module':imp.load_module(name, fp, pathName, desc)}
-        finally:
-            if fp:
-                fp.close()
-
-    def check(self, name, module):
-        try: 
-            inspect.ismethod(module.testsuite().main)
-        except AttributeError: 
-            return {'success':False,'msg':'The required "main" method in the "testsuite" class is not implemented in the "%s" plugin.' % name}
-        except: 
-            return {'success':False,'msg':'The "main" method in the "testsuite" class in "%s" is not responding properly. %s.' % (name, sys.exc_info())}
-
-        argCheck = inspect.getargspec(module.testsuite().main)
-        if argCheck[0] != ['self','testData', 'testPath'] and argCheck[0] != ['self','testData', 'testPath', 'rpc']:
-            return {'success':False,'msg':"The 'main' method in the 'testsuite' class within '%s' has improperly labeled args! i.e. def main(self, testData, testPath)." % name}
-
-        return {'success':True}
-
-class file:
-    def write(self, component):
-        try:
-            f = open("%s/temp_config_%s.conf" % (self._cwd, component), "w")
-        except:
-            return "Unexpected error: %s" % sys.exc_info()
-        f.write(config)
-        f.close()
-        self._results['file_cleanup'].append('%s/temp_config_%s.conf' % (self._cwd, component))
-
-    def read(self, fn):
-        try:
-            f = open("%s" % fn, "r")
-        except IOError:
-            print "Failed to open test results output file:"
-        except:
-            print "Unexpected error: %s" % sys.exc_info()[0]
-        else:
-            fc = f.read()
-            f.close()
-        return fc.strip()
-
-class general:
-    def flattenDict(self, d):
-        s = [d]
-        while s:
-            e = s[-1]
-            for k, v in e.items():
-                if isinstance(v, dict):
-                    s.append(v)
-                else:
-                    yield k, v
-            s.remove(e)
-
-    def logFailure(self, x, errorMsgs, name):
-        print '  |- %s .. FAILED' % (name)
-        print "   \  - %s" % '\n    | - '.join(errorMsgs)
-        return x, []
-
-    def fatal(self, msg):
-        return {'success':False,'execute':False,'errorMsg':['%s' % msg]}
-
-    def status(self, status):
-        if status == False: return("FAILED!!")
-        elif status == True: return("succeeded!")
-
-class xml:
-    def initTestSuite(self):
-        return Element('testsuites')
-
-    def prettyXml(self, x):
-        rough_string = tostring(x, 'utf-8')
-        reparsed = minidom.parseString(rough_string)
-        return reparsed.toprettyxml(indent="  ")
-
-    def convToString(self, x):
-        return tostring(x)
-
-    def addTestType(self, element, name, type):
-        subElement = SubElement(element, type)
-        subElement.set('name', name)
-        return element, subElement
-
-    def addTestSuite(self, element, name):
-        return self.addTestType(element, name, 'testsuite')
-
-    def addTestCase(self, element, name):
-        return self.addTestType(element, name, 'testcase')
-
-    def addFailure(self, element, msgs):
-        subElement = SubElement(element, 'failure')
-        subElement.text = unicode(' '.join(msgs))
-        return element, []
-
-    def setProperty(self, element, key, val):
-        element.set(key, '%s' % val)
-        return element
diff --git a/plugins/failover.py b/plugins/failover.py
index c1da885..0498b2b 100644
--- a/plugins/failover.py
+++ b/plugins/failover.py
@@ -9,10 +9,10 @@
 
 '''
 
-import util
 import time
+import TestSuite
 
-class testsuite(util.TestSuiteBaseClass):
+class plugin(TestSuite.BaseClass):
     def main(self, testData, testPath):
         corosyncExec = ['corosync','-f']
         pacemakerExec = ['pacemaker']
@@ -23,26 +23,28 @@ class testsuite(util.TestSuiteBaseClass):
         standbyNode = {}
 
         if not 'testsuite_remote_active' in testData['cmd']:
-            return {'success':False,'msg':'No testsuite-remote specified for the active failover configuration.'}
+            return {'success':False,'msg':'No testsuite-remote specified for the active failover configuration.','shutdownExempt':True}
 
         if not 'testsuite_remote_standby' in testData['cmd']:
-            return {'success':False,'msg':'No testsuite-remote specified for the standby failover configuration.'}
+            return {'success':False,'msg':'No testsuite-remote specified for the standby failover configuration.','shutdownExempt':True}
 
         if not 'ipv4oripv6' in testData['cmd']:
-            return {'success':False,'msg':'No ip version specified.'}
+            return {'success':False,'msg':'No ip version specified.','shutdownExempt':True}
         else:
             if not testData['cmd']['ipv4oripv6'] == 'ipv4' and not testData['cmd']['ipv4oripv6'] == 'ipv6':
-                return {'success':False,'msg':'IP version must be ipv4 or ipv6.'}
+                return {'success':False,'msg':'IP version must be ipv4 or ipv6.','shutdownExempt':True}
             else:
                 ipv = testData['cmd']['ipv4oripv6']
     
         if not 'shared_ip' in testData['cmd']:
-            return {'success':False,'msg':'No shared IP address specified.'}
+            return {'success':False,'msg':'No shared IP address specified.','shutdownExempt':True}
         else:
             sharedIP = testData['cmd']['shared_ip']
+            if self.ping(sharedIP):
+                return {'success':False, 'msg':'The %s shared ip address is responding before cluster services have been started.' % sharedIP, 'shutdownList':shutdownList}
 
         if ipv and not 'ipv4_network_addr' in testData['cmd']:
-            return {'success':False,'msg':'The ipv4_network_addr must be specified on IPv4 networks.'}
+            return {'success':False,'msg':'The ipv4_network_addr must be specified on IPv4 networks.','shutdownExempt':True}
         else:
             if ipv == 'ipv4':
                 activeNode['nAddr'] = testData['cmd']['ipv4_network_addr']
@@ -81,27 +83,18 @@ class testsuite(util.TestSuiteBaseClass):
         if not results['success'] == True:
             return self._addShutdownList(results, shutdownList)
 
-        time.sleep(100)
-
-        activeNode['rpc'].writeFile('pacemaker.cli', '\n'.join(self._pacemakerConfig(testData['cmd']['shared_ip'], testData['cmd']['testsuite_remote_active'])))
+        activeNode['rpc'].writeFile('pacemaker.cli', '\n'.join(self._pacemakerConfig(sharedIP, testData['cmd']['testsuite_remote_active'])))
         if not results['success'] == True:
             return self._addShutdownList(results, shutdownList)
         results = activeNode['rpc'].run('failover', 'crm', ['crm', '-f', '!!TMP!!/pacemaker.cli'], True)
-        
-#        results = activeNode['rpc'].run('failover', 'cibadmin', ['cibadmin', '-E', '--force'], True)
-#        if not results['success'] == True:
-#            return self._addShutdownList(results, shutdownList)
-#        results = standbyNode['rpc'].run('failover', 'cibadmin', ['cibadmin', '-E', '--force'], True)
-#        if not results['success'] == True:
-#            return self._addShutdownList(results, shutdownList)
 
         time.sleep(100)
 
-        
+        if not self.ping(sharedIP):
+            return {'success':False, 'msg':'The %s shared ip address is failing to respond.' % sharedIP, 'shutdownList':shutdownList}
 
         return {'success':True,'shutdownList':shutdownList}
 
-
     def _addShutdownList(self, results, shutdownList):
         results['shutdownList'] = shutdownList
         return results
@@ -111,6 +104,12 @@ class testsuite(util.TestSuiteBaseClass):
             'compatibility: whitetank',
             'totem {',
             '   version: 2',
+            '   token: 160',
+            '   token_retransmits_before_loss_const: 3',
+            '   join: 30',
+            '   consensus: 300',
+            '   max_messages: 20',
+            '   threads: 0',
             '   secauth: off',
             '   nodeid: %s' % nodeID,
             '   interface {',
@@ -145,7 +144,7 @@ class testsuite(util.TestSuiteBaseClass):
             '    to_logfile: no',
             '    to_syslog: yes',
             '    syslog_facility: daemon',
-            '    debug: off',
+            '    debug: on',
             '    timestamp: on',
             '    logger_subsys {',
             '        subsys: AMF',
@@ -157,16 +156,18 @@ class testsuite(util.TestSuiteBaseClass):
 
     def _pacemakerConfig(self, sharedIP, activeHost):
         config = [
+            'resource stop failover-ip',
             'configure',
             'erase',
             'commit',
-            'primitive failover-ip ocf:heartbeat:IPaddr params ip="%s" op monitor interval=1s meta is-managed="true" target-role="Started"' % sharedIP,
-            'location cli-prefer-failover-ip failover-ip rule $id="cli-prefer-rule-failover-ip" inf: #uname eq %s' % activeHost,
             'property cluster-infrastructure="openais"',
             'property expected-quorum-votes="2"',
             'property stonith-enabled=false',
             'property no-quorum-policy="ignore"',
             'property default-resource-stickiness="infinity"',
+            'commit',
+            'primitive failover-ip ocf:heartbeat:IPaddr params ip="%s" op monitor interval=1s meta is-managed="true" target-role="Started"' % sharedIP,
+            'location cli-prefer-failover-ip failover-ip rule $id="cli-prefer-rule-failover-ip" inf: #uname eq %s' % activeHost,
             'commit']
         return config
 
diff --git a/testsuite.py b/testsuite.py
index a235426..c590046 100755
--- a/testsuite.py
+++ b/testsuite.py
@@ -11,15 +11,19 @@
 '''
 
 import os
+import imp
 import sys
+import inspect
 import platform
 import xmlrpclib
 
+from xml.dom import minidom
+from xml.etree.ElementTree import Element, SubElement, tostring
+
 homeDir = os.path.dirname(os.path.realpath(__file__))
 sys.path.append("%s/lib/python" % homeDir)
 sys.path.append("%s/plugins" % homeDir)
 
-import util
 import yaml_parser
 
 class __main__:
@@ -32,48 +36,48 @@ class __main__:
         pluginData = {}
         shutdownList = []
 
-        x = util.xml().initTestSuite()
+        x = xml().initTestSuite()
 
         for list in self.yamlData:
             for testCategory in list:
-                x, categoryElement = util.xml().addTestSuite(x, testCategory)
+                x, categoryElement = xml().addTestSuite(x, testCategory)
                 print "\n Starting '%s' tests . . \n ---------------------------------" % testCategory
             
                 for testData in list[testCategory]:
-                    categoryElement, testElement = util.xml().addTestSuite(categoryElement, testData['name'])
+                    categoryElement, testElement = xml().addTestSuite(categoryElement, testData['name'])
                     print ' |- Testcase "%s" ' % testData['name']
                     #print testData['options']
                     for subTestCase in testData['tests']:
                         for testName in subTestCase:
-                            testElement, subTestElement = util.xml().addTestCase(testElement, testName)
+                            testElement, subTestElement = xml().addTestCase(testElement, testName)
                             if subTestCase[testName]:
                                 success = True
                 
                                 if 'expected_failure' in subTestCase[testName]:
                                     if subTestCase[testName]['expected_failure']:
-                                       subTestElement = util.xml().setProperty(subTestElement, 'expected_failure', subTestCase[testName]['expected_failure'])
+                                       subTestElement = xml().setProperty(subTestElement, 'expected_failure', subTestCase[testName]['expected_failure'])
 
                                 #print subTestCase[testName]['expected_failure']
 
                                 ''' import plugins '''
                                 for plugin in [plugin for timeLine in subTestCase[testName]['timeline'] for plugin in timeLine]:
-                                    pluginData[plugin] = util.plugins().init(plugin)
+                                    pluginData[plugin] = plugins().init(plugin)
                                     if not pluginData[plugin]['success'] == True:
                                         errorMsgs.append(pluginData[plugin]['msg'])
                                         success = False
 
                                 if success == False:
                                     print '   |- Test "' + testName + '" - FAILED!\n    \- ' + '\n'.join(errorMsgs)
-                                    subTestElement, errorMsgs = util.xml().addFailure(subTestElement, errorMsgs)
+                                    subTestElement, errorMsgs = xml().addFailure(subTestElement, errorMsgs)
                                     break
 
                                 ''' execute testcase timeline '''
                                 for timeLine in subTestCase[testName]['timeline']:
                                     for plugin in timeLine:
-                                        runResults = util.plugins().execute(plugin, pluginData[plugin]['module'], timeLine[plugin], testData['path'])
+                                        runResults = plugins().execute(plugin, pluginData[plugin]['module'], timeLine[plugin], testData['path'])
                                         if not 'shutdownList' in runResults:
                                             if not 'shutdownExempt' in runResults:
-                                               shutdownList.append({testData['testsuite_remote']:plugin})
+                                                shutdownList.append({testData['testsuite_remote']:plugin})
                                         else:
                                             for remote in runResults['shutdownList']:
                                                shutdownList.append({remote:plugin})
@@ -83,27 +87,108 @@ class __main__:
                                         runResults['msg'] = '%s: %s' % (plugin, runResults['msg'])
                                         break
 
-                                print shutdownList
                                 ''' shutdown if 'restart_persistant_plugins_between_tests' is true or not specified '''
                                 for d in shutdownList:
                                     for host in d:
                                         remote = xmlrpclib.Server('http://%s:8000' % host)
-                                        remote.shutdown(d[host]) 
+                                        try:
+                                            remote.shutdown(d[host]) 
+                                        except:
+                                            pass
 
                                 if runResults['success'] == False:
                                     print '   |- Test "' + testName + '" - FAILED!\n    \- ' + runResults['msg']
-                                    subTestElement, errorMsgs = util.xml().addFailure(subTestElement, ['%s' % runResults['msg']])
+                                    subTestElement, errorMsgs = xml().addFailure(subTestElement, ['%s' % runResults['msg']])
                                     break
                 
                                 print '   |- Test "' + testName + '" - PASSED!'
                                 # setProperty(self, element, key, val): for xml results
                             else:
                                 print '   |- Test "' + testName + '" - FAILED!\n    \- No test data defined!'
-                                subTestElement, errorMsgs = util.xml().addFailure(subTestElement, ['No test data defined!'])
+                                subTestElement, errorMsgs = xml().addFailure(subTestElement, ['No test data defined!'])
                                 break
         #print xml().convToString(x)
-        print "\n\n" + util.xml().prettyXml(x)
+        print "\n\n" + xml().prettyXml(x)
         return
 
-__main__()
+class plugins:
+    def execute(self, name, module, testData, testPath):
+        try:
+            func = getattr(module, 'plugin')
+        except AttributeError:
+            return {'success':False,'msg':"Unable to execute module '%s'. %s" % (name, sys.exc_info()[1])}
+        else:
+            results = func().run(testData, testPath)
+        if not type(results) == dict:
+            return {'success':False,'msg':"The '%s' module return invalid or missing data." % name}
+        return results
+
+    def init(self, name):
+        loadResults = self.load(name)
+        if not loadResults['success'] == True:
+            return loadResults
+        checkResults = self.check(name, loadResults['module'])
+        if not checkResults['success'] == True:
+            return checkResults
+        return loadResults
+
+    def load(self, name):
+        try:
+            return {'success':True,'module':sys.modules[name]}
+        except KeyError:
+            pass
+        try:
+            fp, pathName, desc = imp.find_module(name)
+        except ImportError:
+            return {'success':False,'msg':'%s' % sys.exc_info()[1]}
+        try:
+            return {'success':True,'module':imp.load_module(name, fp, pathName, desc)}
+        finally:
+            if fp:
+                fp.close()
+
+    def check(self, name, module):
+        try:
+            inspect.ismethod(module.plugin().main)
+        except AttributeError:
+            return {'success':False,'msg':'The required "main" method in the "plugin" class is not implemented in the "%s" plugin.' % name}
+        except:
+            return {'success':False,'msg':'The "main" method in the "plugin" class in "%s" is not responding properly. %s.' % (name, sys.exc_info())}
+        argCheck = inspect.getargspec(module.plugin().main)
+        if argCheck[0] != ['self','testData', 'testPath'] and argCheck[0] != ['self','testData', 'testPath', 'rpc']:
+            return {'success':False,'msg':"The 'main' method in the 'plugin' class within '%s' has improperly labeled args! i.e. def main(self, testData, testPath)." % name}
+        return {'success':True}
+
+class xml:
+    def initTestSuite(self):
+        return Element('testsuites')
+
+    def prettyXml(self, x):
+        rough_string = tostring(x, 'utf-8')
+        reparsed = minidom.parseString(rough_string)
+        return reparsed.toprettyxml(indent="  ")
+
+    def convToString(self, x):
+        return tostring(x)
+
+    def addTestType(self, element, name, type):
+        subElement = SubElement(element, type)
+        subElement.set('name', name)
+        return element, subElement
+
+    def addTestSuite(self, element, name):
+        return self.addTestType(element, name, 'testsuite')
+
+    def addTestCase(self, element, name):
+        return self.addTestType(element, name, 'testcase')
+
+    def addFailure(self, element, msgs):
+        subElement = SubElement(element, 'failure')
+        subElement.text = unicode(' '.join(msgs))
+        return element, []
+
+    def setProperty(self, element, key, val):
+        element.set(key, '%s' % val)
+        return element
 
+__main__()

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/testsuite.git



More information about the asterisk-scf-commits mailing list