diff --git a/setup/dev/advanced.cfg b/setup/dev/advanced.cfg index 216314ff6bc..23981f0f34d 100644 --- a/setup/dev/advanced.cfg +++ b/setup/dev/advanced.cfg @@ -137,16 +137,10 @@ "port": 3306, "user": "cloud" }, - "logger": [ + "logger": { - "name": "TestClient", - "file": "/tmp/testclient.log" + "LogFolderPath": "/tmp/" }, - { - "name": "TestCase", - "file": "/tmp/testcase.log" - } - ], "globalConfig": [ { "name": "network.gc.wait", diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py index 23f81fb48c2..48a2d21e514 100644 --- a/tools/marvin/marvin/cloudstackConnection.py +++ b/tools/marvin/marvin/cloudstackConnection.py @@ -20,24 +20,24 @@ import urllib import base64 import hmac import hashlib -import logging import time import cloudstackException from cloudstackAPI import * import jsonHelper -from requests import ConnectionError -from requests import HTTPError -from requests import Timeout -from requests import RequestException +from requests import ( + ConnectionError, + HTTPError, + Timeout, + RequestException + ) class cloudConnection(object): """ Connections to make API calls to the cloudstack management server """ - def __init__(self, mgmtDet, asyncTimeout=3600, logging=None, + def __init__(self, mgmtDet, asyncTimeout=3600, logger=None, path='client/api'): - self.loglevel() # Turn off requests logs self.apiKey = mgmtDet.apiKey self.securityKey = mgmtDet.securityKey self.mgtSvr = mgmtDet.mgtSvrIp @@ -46,7 +46,7 @@ class cloudConnection(object): self.passwd = mgmtDet.passwd self.certCAPath = mgmtDet.certCAPath self.certPath = mgmtDet.certPath - self.logging = logging + self.logger = logger self.path = path self.retries = 5 self.mgtDetails = mgmtDet @@ -67,13 +67,6 @@ class cloudConnection(object): self.logging, self.path) - def loglevel(self, lvl=logging.WARNING): - """ - Turns off the INFO/DEBUG logs from `requests` - """ - requests_log = logging.getLogger("requests") - requests_log.setLevel(lvl) - def poll(self, jobid, response): """ polls the completion of a given jobid @@ -95,9 +88,9 @@ class cloudConnection(object): return asyncResonse time.sleep(5) - if self.logging is not None: - self.logging.debug("job: %s still processing," - " will timeout in %ds" % (jobid, timeout)) + if self.logger is not None: + self.logger.debug("job: %s still processing," + "will timeout in %ds" % (jobid, timeout)) timeout = timeout - 5 raise cloudstackException.cloudstackAPIException( @@ -122,7 +115,7 @@ class cloudConnection(object): ) signature = base64.encodestring(hmac.new( self.securityKey, hashStr, hashlib.sha1).digest()).strip() - self.logging.debug("Computed Signature by Marvin: %s" % signature) + self.logger.debug("Computed Signature by Marvin: %s" % signature) return signature def request(self, command, auth=True, payload={}, method='GET'): @@ -186,7 +179,7 @@ class cloudConnection(object): then try with default certs, \ we dont need to mention here the cert path ''' - self.logging.debug("Creating CS connection over https \ + self.logger.debug("Creating CS connection over https \ didnt worked with user provided certs \ , so trying with no certs %s" % e) if method == 'POST': @@ -198,20 +191,20 @@ class cloudConnection(object): params=payload, verify=https_flag) except ConnectionError, c: - self.logging.debug("Connection refused. Reason: %s : %s" - % (self.baseurl, c)) + self.logger.debug("Connection refused. Reason: %s : %s" % + (self.baseurl, c)) raise c except HTTPError, h: - self.logging.debug("Http Error.Server returned error code: %s" % h) + self.logger.debug("Http Error.Server returned error code: %s" % h) raise h except Timeout, t: - self.logging.debug("Connection timed out with %s" % t) + self.logger.debug("Connection timed out with %s" % t) raise t except RequestException, r: - self.logging.debug("RequestException from server %s" % r) + self.logger.debug("RequestException from server %s" % r) raise r except Exception, e: - self.logging.debug("Error returned by server %s" % r) + self.logger.debug("Error returned by server %s" % r) raise e else: return response @@ -265,16 +258,16 @@ class cloudConnection(object): @return: """ cmdname, isAsync, payload = self.sanitizeCommand(cmd) - self.logging.debug("sending %s request: %s %s" % (method, cmdname, - str(payload))) + self.logger.debug("sending %s request: %s %s" % (method, cmdname, + str(payload))) response = self.request(cmdname, self.auth, payload=payload, method=method) if response is None: return None - self.logging.debug("Request: %s Response: %s" % - (response.url, response.text)) + self.logger.debug("Request: %s Response: %s" % (response.url, + response.text)) try: response = jsonHelper.getResultObj(response.json(), response_type) except TypeError: diff --git a/tools/marvin/marvin/codes.py b/tools/marvin/marvin/codes.py index f409c7c8d13..8f0f88d928e 100644 --- a/tools/marvin/marvin/codes.py +++ b/tools/marvin/marvin/codes.py @@ -42,3 +42,8 @@ PASS = 1 MATCH_NOT_FOUND = "ELEMENT NOT FOUND IN THE INPUT" SUCCESS = "SUCCESS" EXCEPTION_OCCURRED = "Exception Occurred" +NO = "no" +YES = "yes" +FAILED = "FAILED" +UNKNOWN_ERROR = "Unknown Error" +EXCEPTION = "Exception" diff --git a/tools/marvin/marvin/configGenerator.py b/tools/marvin/marvin/configGenerator.py index 631e40fce43..3f98aca9ff1 100644 --- a/tools/marvin/marvin/configGenerator.py +++ b/tools/marvin/marvin/configGenerator.py @@ -534,18 +534,6 @@ def descSetupInBasicMode(): cfg.value = v zs.globalConfig.append(cfg) - ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = "TestClient" - testClientLogger.file = "/tmp/testclient.log" - - testCaseLogger = logger() - testCaseLogger.name = "TestCase" - testCaseLogger.file = "/tmp/testcase.log" - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) - return zs @@ -669,18 +657,6 @@ def descSetupInEipMode(): cfg.value = v zs.globalConfig.append(cfg) - ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = "TestClient" - testClientLogger.file = "/tmp/testclient.log" - - testCaseLogger = logger() - testCaseLogger.name = "TestCase" - testCaseLogger.file = "/tmp/testcase.log" - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) - return zs @@ -801,18 +777,6 @@ def descSetupInAdvancedMode(): cfg.value = v zs.globalConfig.append(cfg) - ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = "TestClient" - testClientLogger.file = "/tmp/testclient.log" - - testCaseLogger = logger() - testCaseLogger.name = "TestCase" - testCaseLogger.file = "/tmp/testcase.log" - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) - return zs '''sample code to generate setup configuration file''' @@ -926,18 +890,6 @@ def descSetupInAdvancedsgMode(): cfg.value = v zs.globalConfig.append(cfg) - ''''add loggers''' - testClientLogger = logger() - testClientLogger.name = "TestClient" - testClientLogger.file = "/tmp/testclient.log" - - testCaseLogger = logger() - testCaseLogger.name = "TestCase" - testCaseLogger.file = "/tmp/testcase.log" - - zs.logger.append(testClientLogger) - zs.logger.append(testCaseLogger) - return zs diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py index 3f7eebbc21b..0a175d9a06e 100644 --- a/tools/marvin/marvin/deployDataCenter.py +++ b/tools/marvin/marvin/deployDataCenter.py @@ -28,16 +28,9 @@ from optparse import OptionParser class deployDataCenters(object): - def __init__(self, cfgFile): - if not path.exists(cfgFile) \ - and not path.exists(path.abspath(cfgFile)): - raise IOError("config file %s not found. please \ - specify a valid config file" % cfgFile) - self.configFile = cfgFile - ''' - parsed configuration information - ''' - self.config = None + def __init__(self, cfg, logger=None): + self.config = cfg + self.tcRunLogger = logger def addHosts(self, hosts, zoneId, podId, clusterId, hypervisor): if hosts is None: @@ -507,51 +500,17 @@ class deployDataCenters(object): self.config.mgtSvr[0].securityKey = securityKey return apiKey, securityKey - def getCfg(self): - if self.config is not None: - return self.config - return None - def loadCfg(self): - try: - self.config = configGenerator.getSetupConfig(self.configFile) - except: - raise cloudstackException.InvalidParameterException( - "Failed to load config %s" % self.configFile) - ''' Retrieving Management Server Connection Details ''' mgtDetails = self.config.mgtSvr[0] ''' Retrieving Database Connection Details''' dbSvrDetails = self.config.dbSvr - loggers = self.config.logger - testClientLogFile = None - self.testCaseLogFile = None - self.testResultLogFile = None - if loggers is not None and len(loggers) > 0: - for log in loggers: - if log.name == "TestClient": - testClientLogFile = log.file - elif log.name == "TestCase": - self.testCaseLogFile = log.file - elif log.name == "TestResult": - self.testResultLogFile = log.file - - testClientLogger = None - if testClientLogFile is not None: - testClientLogger = logging.getLogger("testclient.testengine.run") - fh = logging.FileHandler(testClientLogFile) - fh.setFormatter(logging.Formatter( - "%(asctime)s - %(levelname)s - %(name)s\ - %(message)s") - ) - testClientLogger.addHandler(fh) - testClientLogger.setLevel(logging.INFO) - self.testClientLogger = testClientLogger self.testClient = \ cloudstackTestClient.\ cloudstackTestClient(mgtDetails, dbSvrDetails, - logging=self.testClientLogger) + logging=self.tcRunLogger) if mgtDetails.apiKey is None: mgtDetails.apiKey, mgtDetails.securityKey = self.registerApiKey() @@ -560,8 +519,7 @@ class deployDataCenters(object): cloudstackTestClient.cloudstackTestClient( mgtDetails, dbSvrDetails, - logging= - self.testClientLogger) + logging=self.tcRunLogger) self.apiClient = self.testClient.getApiClient() """set hypervisor""" @@ -606,7 +564,11 @@ if __name__ == "__main__": ./datacenterCfg") (options, args) = parser.parse_args() - deploy = deployDataCenters(options.input) + from marvin.marvinLog import MarvinLog + cfg = configGenerator.getSetupConfig(options.input) + log_obj = MarvinLog("CSLog") + tcRunLogger = log_obj.setLogHandler("/tmp/debug.log") + deploy = deployDataCenters(cfg, tcRunLogger) deploy.deploy() """ diff --git a/tools/marvin/marvin/marvinPlugin.py b/tools/marvin/marvin/marvinPlugin.py index 0e52bab9d33..852b84af7d7 100644 --- a/tools/marvin/marvin/marvinPlugin.py +++ b/tools/marvin/marvin/marvinPlugin.py @@ -20,9 +20,16 @@ import sys import logging import nose.core from marvin.cloudstackTestCase import cloudstackTestCase -from marvin import deployDataCenter +from marvin.marvinInit import MarvinInit from nose.plugins.base import Plugin +from marvin.codes import (SUCCESS, + FAILED, + EXCEPTION, + UNKNOWN_ERROR + ) +import traceback import time +import os class MarvinPlugin(Plugin): @@ -32,7 +39,21 @@ class MarvinPlugin(Plugin): name = "marvin" - def configure(self, options, config): + def __init__(self): + self.identifier = None + self.testClient = None + self.parsedConfig = None + self.configFile = None + self.loadFlag = None + self.conf = None + self.debugStream = sys.stdout + self.testRunner = None + self.startTime = None + self.testName = None + self.tcRunLogger = None + Plugin.__init__(self) + + def configure(self, options, conf): """enable the marvin plugin when the --with-marvin directive is given to nose. The enableOpt value is set from the command line directive and self.enabled (True|False) determines whether marvin's tests will run. @@ -44,34 +65,13 @@ class MarvinPlugin(Plugin): return else: self.enabled = True - - self.logformat = logging.Formatter("%(asctime)s - %(levelname)s - " + - "%(name)s - %(message)s") - - if options.debug_log: - self.logger = logging.getLogger("NoseTestExecuteEngine") - self.debug_stream = logging.FileHandler(options.debug_log) - self.debug_stream.setFormatter(self.logformat) - self.logger.addHandler(self.debug_stream) - self.logger.setLevel(logging.DEBUG) - - if options.result_log: - ch = logging.StreamHandler() - ch.setLevel(logging.ERROR) - ch.setFormatter(self.logformat) - self.logger.addHandler(ch) - self.result_stream = open(options.result_log, "w") - else: - self.result_stream = sys.stdout - - deploy = deployDataCenter.deployDataCenters(options.config_file) - deploy.loadCfg() if options.load else deploy.deploy() - self.setClient(deploy.testClient) - self.setConfig(deploy.getCfg()) - - self.testrunner = nose.core.TextTestRunner(stream=self.result_stream, - descriptions=True, - verbosity=2, config=config) + self.configFile = options.config_file + self.loadFlag = options.load + self.conf = conf + ''' + Initializes the marvin with required settings + ''' + self.startMarvin() def options(self, parser, env): """ @@ -83,29 +83,11 @@ class MarvinPlugin(Plugin): help="Marvin's configuration file where the " + "datacenter information is specified " + "[MARVIN_CONFIG]") - parser.add_option("--result-log", action="store", - default=env.get('RESULT_LOG', None), - dest="result_log", - help="The path to the results file where test " + - "summary will be written to [RESULT_LOG]") - parser.add_option("--client-log", action="store", - default=env.get('DEBUG_LOG', 'debug.log'), - dest="debug_log", - help="The path to the testcase debug logs " + - "[DEBUG_LOG]") parser.add_option("--load", action="store_true", default=False, dest="load", help="Only load the deployment configuration given") - Plugin.options(self, parser, env) - def __init__(self): - self.identifier = None - Plugin.__init__(self) - - def prepareTestRunner(self, runner): - return self.testrunner - def wantClass(self, cls): if cls.__name__ == 'cloudstackTestCase': return False @@ -118,18 +100,13 @@ class MarvinPlugin(Plugin): self.identifier = cls.__name__ self._injectClients(cls) - def setClient(self, client): - if client is not None: - self.testclient = client - - def setConfig(self, config): - if config is not None: - self.config = config - def beforeTest(self, test): self.testName = test.__str__().split()[0] - self.testclient.identifier = '-'.join([self.identifier, self.testName]) - self.logger.name = test.__str__() + self.testClient.identifier = '-'.join([self.identifier, self.testName]) + self.tcRunLogger.name = test.__str__() + + def prepareTestRunner(self, runner): + return self.testRunner def startTest(self, test): """ @@ -137,6 +114,58 @@ class MarvinPlugin(Plugin): """ self.startTime = time.time() + def getErrorInfo(self, err): + ''' + Extracts and returns the sanitized error message + ''' + if err is not None: + return str(traceback.format_exc()) + else: + return UNKNOWN_ERROR + + def handleError(self, test, err): + ''' + Adds Exception throwing test cases and information to log. + ''' + err_msg = self.getErrorInfo(err) + self.tcRunLogger.fatal("%s: %s: %s" % + (EXCEPTION, self.testName, err_msg)) + + def handleFailure(self, test, err): + ''' + Adds Failing test cases and information to log. + ''' + err_msg = self.getErrorInfo(err) + self.tcRunLogger.fatal("%s: %s: %s" % + (FAILED, self.testName, err_msg)) + + def startMarvin(self): + ''' + Initializes the Marvin + creates the test Client + creates the runlogger for logging + Parses the config and creates a parsedconfig + Creates a debugstream for tc debug log + ''' + try: + obj_marvininit = MarvinInit(self.configFile, self.loadFlag) + if obj_marvininit.init() == SUCCESS: + self.testClient = obj_marvininit.getTestClient() + self.tcRunLogger = obj_marvininit.getLogger() + self.parsedConfig = obj_marvininit.getParsedConfig() + self.debugStream = obj_marvininit.getDebugFile() + self.testRunner = nose.core.TextTestRunner(stream= + self.debugStream, + descriptions=True, + verbosity=2, + config=self.conf) + return SUCCESS + else: + return FAILED + except Exception, e: + print "Exception Occurred under startMarvin: %s" % str(e) + return FAILED + def stopTest(self, test): """ Currently used to record end time for tests @@ -144,22 +173,24 @@ class MarvinPlugin(Plugin): endTime = time.time() if self.startTime is not None: totTime = int(endTime - self.startTime) - self.logger.debug( - "TestCaseName: %s; Time Taken: %s Seconds; \ - StartTime: %s; EndTime: %s" - % (self.testName, str(totTime), - str(time.ctime(self.startTime)), str(time.ctime(endTime)))) + self.tcRunLogger.debug("TestCaseName: %s; Time Taken: " + "%s Seconds; " + "StartTime: %s; EndTime: %s" + % (self.testName, str(totTime), + str(time.ctime(self.startTime)), + str(time.ctime(endTime)))) def _injectClients(self, test): - setattr(test, "debug", self.logger.debug) - setattr(test, "info", self.logger.info) - setattr(test, "warn", self.logger.warning) - setattr(test, "testClient", self.testclient) - setattr(test, "config", self.config) - if self.testclient.identifier is None: - self.testclient.identifier = self.identifier - setattr(test, "clstestclient", self.testclient) + setattr(test, "debug", self.tcRunLogger.debug) + setattr(test, "info", self.tcRunLogger.info) + setattr(test, "warn", self.tcRunLogger.warning) + setattr(test, "error", self.tcRunLogger.error) + setattr(test, "testClient", self.testClient) + setattr(test, "config", self.parsedConfig) + if self.testClient.identifier is None: + self.testClient.identifier = self.identifier + setattr(test, "clstestclient", self.testClient) if hasattr(test, "user"): # when the class-level attr applied. all test runs as 'user' - self.testclient.createUserApiClient(test.UserName, test.DomainName, + self.testClient.createUserApiClient(test.UserName, test.DomainName, test.AcctType)