From a9c8f1643de38ab6ca80f94e08a2ff7c2e672f1a Mon Sep 17 00:00:00 2001 From: Benjamin Blanc <benjamin.blanc@tiolive.com> Date: Mon, 17 Jun 2013 16:02:57 +0200 Subject: [PATCH] Fix bug(s) and add a scalability unit test --- erp5/tests/testERP5TestNode.py | 109 +++++++++++++++++--- erp5/util/testnode/ScalabilityTestRunner.py | 27 ++--- erp5/util/testnode/testnode.py | 25 +++-- erp5/util/testnode/testnodeUtils.py | 8 +- 4 files changed, 128 insertions(+), 41 deletions(-) diff --git a/erp5/tests/testERP5TestNode.py b/erp5/tests/testERP5TestNode.py index d0a38b540c..72d66e6f53 100644 --- a/erp5/tests/testERP5TestNode.py +++ b/erp5/tests/testERP5TestNode.py @@ -475,9 +475,9 @@ branch = foo def patch_getSlaposAccountCertificate(self, *args, **kw): return "Certificate" def patch_generateConfiguration(self, *args, **kw): - return '{"configuration_list": [], "involved_nodes_computer_guid"\ -: [], "error_message": "No error.", "launcher_nodes_computer_guid": {}, \ -"launchable": false, "randomized_path" : "azertyuiop"}' + return json.dumps({"configuration_list": [], "involved_nodes_computer_guid"\ +: [], "error_message": "No error.", "launcher_nodes_computer_guid": [], \ +"launchable": False, "randomized_path" : "azertyuiop"}) def patch_isMasterTestnode(self, *args, **kw): return (grade == 'master') test_self = self @@ -490,7 +490,10 @@ branch = foo config_list = [] # Sclalability slave testnode is not directly in charge of testsuites if my_test_type == 'ScalabilityTest' and grade == 'slave': - return [] + if counter == 5: + raise StopIteration + counter += 1 + return json.dumps([]) def _checkExistingTestSuite(reference_set): test_self.assertEquals(set(reference_set), @@ -564,12 +567,7 @@ branch = foo SlapOSControler.initializeSlapOSControler = doNothing # Inside test_node a runner is created using new UnitTestRunner methods test_node.run() - # Doesn't have to install sofwtare themself - if my_test_type == 'ScalabilityTest' and grade == 'slave' : - self.assertEquals(0, counter) - else : - self.assertEquals(5, counter) - + self.assertEquals(5, counter) time.sleep = original_sleep # Restore old class methods if my_test_type == "ScalabilityTest": @@ -632,11 +630,11 @@ branch = foo def patch_getSlaposAccountCertificate(self, *args, **kw): return "Certificate" def patch_generateConfiguration(self, *args, **kw): - return '{"configuration_list": [], "involved_nodes_computer_guid"\ -: [], "error_message": "No error.", "launcher_nodes_computer_guid": {}, \ -"launchable": false, "randomized_path" : "azertyuiop"}' + return json.dumps({"configuration_list": [], "involved_nodes_computer_guid"\ +: [], "error_message": "No error.", "launcher_nodes_computer_guid": [], \ +"launchable": False, "randomized_path" : "azertyuiop"}) def patch_isMasterTestnode(self, *args, **kw): - return (grade == 'master') + return grade == 'master' test_self = self test_result_path_root = os.path.join(test_self._temp_dir,'test/results') os.makedirs(test_result_path_root) @@ -854,4 +852,85 @@ branch = foo def test_scalability_18_resetSoftwareAfterManyBuildFailures(self, my_test_type='ScalabilityTest'): # TODO : write own scalability test pass - #TODO : add more test for scalability case + + def test_zzzz_scalability_19_xxxx(self): + def patch_createTestResult(self, revision, test_name_list, node_title, + allow_restart=False, test_title=None, project_title=None): + test_result_path = os.path.join(test_result_path_root, test_title) + result = TestResultProxy(self._proxy, self._retry_time, + self._logger, test_result_path, node_title, revision) + return result + global startTestSuiteDone + startTestSuiteDone = False + def patch_startTestSuite(self,test_node_title): + config_list = [] + global startTestSuiteDone + if not startTestSuiteDone: + startTestSuiteDone = True + config_list.append(test_self.getTestSuiteData(reference='foo')[0]) + config_list.append(test_self.getTestSuiteData(reference='bar')[0]) + else: + raise StopIteration + return json.dumps(config_list) + def patch_isMasterTestnode(self, *args, **kw): + return True + def patch_generateConfiguration(self, *args, **kw): + return json.dumps({"configuration_list": [{"ok":"ok"}], "involved_nodes_computer_guid"\ +: ["COMP1", "COMP2", "COMP3"], "error_message": "No error.", "launcher_nodes_computer_guid": ["COMP1"], \ +"launchable": False, "randomized_path" : "azertyuiop"}) + def doNothing(self, *args, **kw): + pass + def patch_getSlaposAccountKey(self, *args, **kw): + return "key" + def patch_getSlaposAccountCertificate(self, *args, **kw): + return "Certificate" + def patch_getTestType(self, *args, **kw): + return "ScalabilityTest" + test_self = self + test_result_path_root = os.path.join(test_self._temp_dir,'test/results') + os.makedirs(test_result_path_root) + self.generateTestRepositoryList() + # Select the good runner to modify + RunnerClass = self.returnGoodClassRunner('ScalabilityTest') + # Patch methods + original_sleep = time.sleep + original_getSlaposAccountKey = TaskDistributor.getSlaposAccountKey + original_getSlaposAccountCertificate = TaskDistributor.getSlaposAccountCertificate + original_generateConfiguration = TaskDistributor.generateConfiguration + original_isMasterTestnode = TaskDistributor.isMasterTestnode + original_startTestSuite = TaskDistributor.startTestSuite + original_subscribeNode = TaskDistributor.subscribeNode + original_getTestType = TaskDistributor.getTestType + original_createTestResult = TaskDistributionTool.createTestResult + original_prepareSlapOS = RunnerClass._prepareSlapOS + original_runTestSuite = RunnerClass.runTestSuite + original_supply = SlapOSControler.supply + # + time.sleep = doNothing + TaskDistributor.getSlaposAccountKey = patch_getSlaposAccountKey + TaskDistributor.getSlaposAccountCertificate = patch_getSlaposAccountCertificate + TaskDistributor.generateConfiguration = patch_generateConfiguration + TaskDistributor.isMasterTestnode = patch_isMasterTestnode + TaskDistributor.startTestSuite = patch_startTestSuite + TaskDistributor.subscribeNode = doNothing + TaskDistributor.getTestType = patch_getTestType + TaskDistributionTool.createTestResult = patch_createTestResult + RunnerClass._prepareSlapOS = doNothing + RunnerClass.runTestSuite = doNothing + SlapOSControler.supply = doNothing + # Run + test_node = self.getTestNode() + test_node.run() + # Restore methods + TaskDistributor.getSlaposAccountKey = original_getSlaposAccountKey + TaskDistributor.getSlaposAccountCertificate = original_getSlaposAccountCertificate + TaskDistributor.generateConfiguration = original_generateConfiguration + TaskDistributor.isMasterTestnode = original_isMasterTestnode + TaskDistributor.startTestSuite = original_startTestSuite + TaskDistributionTool.createTestResult = original_createTestResult + TaskDistributionTool.subscribeNode = original_subscribeNode + TaskDistributionTool.getTestType = original_getTestType + RunnerClass._prepareSlapOS = original_prepareSlapOS + RunnerClass.runTestSuite = original_runTestSuite + SlapOSControler.supply = original_supply + time.sleep =original_sleep diff --git a/erp5/util/testnode/ScalabilityTestRunner.py b/erp5/util/testnode/ScalabilityTestRunner.py index 6ab146d15e..f590a533b5 100644 --- a/erp5/util/testnode/ScalabilityTestRunner.py +++ b/erp5/util/testnode/ScalabilityTestRunner.py @@ -49,17 +49,18 @@ import signal class ScalabilityTestRunner(): def __init__(self, testnode): self.testnode = testnode + self.log = self.testnode.log + self.slapos_controler = SlapOSControler.SlapOSControler( self.testnode.working_directory, self.testnode.config, - self.testnode.log) + self.log) # Create the slapos account configuration file and dir key = self.testnode.test_suite_portal.getSlaposAccountKey() certificate = self.testnode.test_suite_portal.getSlaposAccountCertificate() self.slapos_controler.createSlaposConfigurationFileAccount(key,certificate, self.testnode.config) - self.remaining_software_installation_dict = {} # Protection to prevent installation of softwares after checking @@ -72,7 +73,7 @@ class ScalabilityTestRunner(): """ A proxy to supply : Install a software on a specific node """ - self.testnode.log("testnode, supply : %s %s", software_path, computer_guid) + self.log("testnode, supply : %s %s", software_path, computer_guid) if self.authorize_supply : self.remaining_software_installation_dict[computer_guid] = software_path self.slapos_controler.supply(software_path, computer_guid) @@ -94,7 +95,7 @@ class ScalabilityTestRunner(): # Dummy slapos answering def _getSignal(self, signal, frame): - self.testnode.log("Dummy SlapOS Master answer received.") + self.log("Dummy SlapOS Master answer received.") self.last_slapos_answer.append(True) def _prepareDummySlapOSAnswer(self): print "Dummy slapOS answer enabled, send signal to %s (=PID) to simu\ @@ -155,21 +156,21 @@ late a SlapOS (positive) answer." %(str(os.getpid()),) # Avoid the test if it is not launchable if not self.launchable: - self.testnode.log("Test suite %s is not actually launchable with \ + self.log("Test suite %s is not actually launchable with \ the current cluster configuration." %(node_test_suite.test_suite_title,)) - self.testnode.log("ERP5 Master indicates : %s" %(self.error_message,)) + self.log("ERP5 Master indicates : %s" %(self.error_message,)) # error : wich code to return ? return {'status_code' : 1} # create an obfuscated link to the testsuite directory - self.testnode.log("self.testnode.config['software_directory']\ + self.log("self.testnode.config['software_directory']\ : %s" %(self.testnode.config['software_directory'])) - self.testnode.log("self.randomized_path\ + self.log("self.randomized_path\ : %s" %(self.randomized_path)) path_to_suite = os.path.join( self.testnode.config['working_directory'], node_test_suite.reference) - self.testnode.log("path_to_suite\ + self.log("path_to_suite\ : %s" %(path_to_suite)) self.ofuscated_link_path = os.path.join( self.testnode.config['software_directory'], @@ -181,7 +182,7 @@ late a SlapOS (positive) answer." %(str(os.getpid()),) except : raise ValueError("testnode, Unable to create symbolic link to the testsuite.") - self.testnode.log("Sym link : %s %s" %(path_to_suite, self.ofuscated_link_path)) + self.log("Sym link : %s %s" %(path_to_suite, self.ofuscated_link_path)) involved_nodes_computer_guid = test_configuration['involved_nodes_computer_guid'] @@ -192,7 +193,7 @@ late a SlapOS (positive) answer." %(str(os.getpid()),) self.reachable_profile = os.path.join( "https://","["+self.testnode.config['httpd_ip']+"]"+":"+self.testnode.config['httpd_software_access_port'], self.randomized_path, "software.cfg") - self.testnode.log("Software reachable profile path is : %s " + self.log("Software reachable profile path is : %s " %(self.reachable_profile,)) software_path_list.append(self.reachable_profile) # Ask for softwares installation @@ -206,7 +207,7 @@ late a SlapOS (positive) answer." %(str(os.getpid()),) # Waiting until all softwares are installed while ( self.remainSoftwareToInstall() and (max_time > (time.time()-start_time))): - self.testnode.log("Master testnode is waiting\ + self.log("Master testnode is waiting\ for the end of all software installation (for %ss).", str(int(time.time()-start_time))) time.sleep(interval_time) @@ -215,7 +216,7 @@ late a SlapOS (positive) answer." %(str(os.getpid()),) self._comeBackFromDummySlapOS() if self.remainSoftwareToInstall() : return {'status_code' : 1} - self.testnode.log("Softwares installed") + self.log("Softwares installed") return {'status_code' : 0} def _cleanUpNodesInformation(self): diff --git a/erp5/util/testnode/testnode.py b/erp5/util/testnode/testnode.py index 4621aa7850..a10e6f10aa 100644 --- a/erp5/util/testnode/testnode.py +++ b/erp5/util/testnode/testnode.py @@ -38,6 +38,9 @@ import logging import string import random import testnodeUtils + +import traceback + from ProcessManager import SubprocessError, ProcessManager, CancellationError from subprocess import CalledProcessError from Updater import Updater @@ -298,7 +301,6 @@ branch = %(branch)s test_node_slapos = SlapOSInstance() test_node_slapos.edit(working_directory=self.config['slapos_directory']) ## /BLOCK OK - try: while True: try: @@ -310,9 +312,10 @@ branch = %(branch)s portal_url = config['test_suite_master_url'] portal = taskdistribution.TaskDistributionTool(portal_url, logger=DummyLogger(log)) self.test_suite_portal = taskdistribution.TaskDistributor(portal_url, logger=DummyLogger(log)) - self.test_suite_portal.subscribeNode(config['test_node_title'], config['computer_id']) - + self.test_suite_portal.subscribeNode(config['test_node_title'], config['computer_id']) + test_suite_json = self.test_suite_portal.startTestSuite(config['test_node_title']) + test_suite_data = testnodeUtils.deunicodeData(json.loads(test_suite_json)) log("Got following test suite data from master : %r" % \ (test_suite_data,)) @@ -337,8 +340,11 @@ from the distributor.") # master testnode gets test_suites, slaves get nothing runner.prepareSlapOSForTestNode(test_node_slapos) # Clean-up test suites - self.checkOldTestSuite(test_suite_data) + self.checkOldTestSuite(test_suite_data) + + + for test_suite in test_suite_data: remote_test_result_needs_cleanup = False node_test_suite = self.getNodeTestSuite( @@ -360,13 +366,15 @@ from the distributor.") node_test_suite.project_title) remote_test_result_needs_cleanup = True log("testnode, test_result : %r" % (test_result, )) - + if test_result is not None: self.registerSuiteLog(test_result, node_test_suite) self.checkRevision(test_result,node_test_suite) + # Now prepare the installation of SlapOS and create instance status_dict = runner.prepareSlapOSForTestSuite(node_test_suite) - + + # Give some time so computer partitions may start # as partitions can be of any kind we have and likely will never have # a reliable way to check if they are up or not ... @@ -396,6 +404,9 @@ from the distributor.") node_test_suite.retry = True continue except: + log("Errror") + ex_type, ex, tb = sys.exc_info() + traceback.print_tb(tb) log("erp5testnode exception", exc_info=sys.exc_info()) raise now = time.time() @@ -407,6 +418,8 @@ from the distributor.") except: log("Exception in error handling", exc_info=sys.exc_info()) finally: + if 'tb' in locals(): + del tb # Nice way to kill *everything* generated by run process -- process # groups working only in POSIX compilant systems # Exceptions are swallowed during cleanup phase diff --git a/erp5/util/testnode/testnodeUtils.py b/erp5/util/testnode/testnodeUtils.py index 2fb8c12bd7..efd46890ae 100644 --- a/erp5/util/testnode/testnodeUtils.py +++ b/erp5/util/testnode/testnodeUtils.py @@ -4,13 +4,7 @@ import shutil import string def deunicodeData(data): - if isinstance(data, int): - new_data = data - elif isinstance(data, str): - new_data = data - elif isinstance(data, bool): - new_data = data - elif isinstance(data, list): + if isinstance(data, list): new_data = [] for sub_data in data: new_data.append(deunicodeData(sub_data)) -- 2.30.9