PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/tool/admin/app/batserver/qxtest.py

http://github.com/qooxdoo/qooxdoo
Python | 1727 lines | 1674 code | 10 blank | 43 comment | 18 complexity | 4ac7ac7bec18dc0f9e200638e87d2312 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-3.0, MIT

Large files files are truncated, but you can click here to view the full file

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ################################################################################
  4. #
  5. # qooxdoo - the new era of web development
  6. #
  7. # http://qooxdoo.org
  8. #
  9. # Copyright:
  10. # 2007-2009 1&1 Internet AG, Germany, http://www.1und1.de
  11. #
  12. # License:
  13. # LGPL: http://www.gnu.org/licenses/lgpl.html
  14. # EPL: http://www.eclipse.org/org/documents/epl-v10.php
  15. # See the LICENSE file in the project's top-level directory for details.
  16. #
  17. # Authors:
  18. # * Daniel Wagner (d_wagner)
  19. #
  20. ################################################################################
  21. import sys, os, time, codecs, unicodedata, re
  22. sys.path.append( os.path.join('..', '..', 'bin') )
  23. ##
  24. # <p>This class holds the test configuration and provides methods that set up
  25. # and control the actual Selenium test runs. It can be used for tests against
  26. # a local qooxdoo trunk checkout as well as tests against qooxdoo applications
  27. # located on a remote server.</p>
  28. #
  29. # @param testType {str} "local" or "remote"
  30. # @param seleniumConf {dict} Selenium RC server configuration details
  31. # @param testConf {dict} Basic test settings
  32. # @param autConf {dict} Information about the applications to be tested
  33. # @param browserConf {dict} Information about the browsers to be used for
  34. # testing
  35. # @param mailConf {dict} Report email configuration
  36. class QxTest:
  37. def __init__(self, testType="remote", seleniumConf=None, testConf=None,
  38. autConf=None, browserConf=None, mailConf=None):
  39. defaultSeleniumConf = {
  40. 'seleniumDir' : '../../selenium',
  41. 'seleniumVersion' : 'current',
  42. 'seleniumJar' : 'selenium-server.jar',
  43. 'seleniumHost' : 'http://localhost:4444',
  44. 'ieSingleWindow' : True,
  45. 'trustAllSSLCertificates' : False,
  46. 'options' : "",
  47. 'serverStartTimeout' : 60
  48. }
  49. defaultTestConf = {
  50. 'runType' : '',
  51. 'qxBranch' : 'trunk',
  52. 'simulateTest' : False,
  53. 'getReportFrom' : 'testLog',
  54. 'testLogDir' : '../../logs',
  55. 'testReportDir' : '../../reports',
  56. 'seleniumClientDriverJar' : 'selenium-java-client-driver.jar',
  57. 'rhinoJar' : '../../rhino/current/js.jar',
  58. 'javaBin' : 'java',
  59. 'classPathSeparator' : ';',
  60. 'proxyEnable' : 'wscript ../../tool/proxyEnable.vbs',
  61. 'proxyDisable' : 'wscript ../../tool/proxyDisable.vbs',
  62. 'compatEnable' : 'wscript ../../tool/compatEnable.vbs',
  63. 'compatDisable' : 'wscript ../../tool/compatDisable.vbs',
  64. 'killSelenium' : 'wscript ../../tool/killselenium.vbs',
  65. 'remoteLogDir' : None
  66. }
  67. self.testType = testType
  68. self.seleniumConf = self.getConfig(defaultSeleniumConf, seleniumConf)
  69. self.testConf = self.getConfig(defaultTestConf, testConf)
  70. self.mailConf = mailConf
  71. self.autConf = autConf
  72. self.browserConf = browserConf
  73. self.timeFormat = '%Y-%m-%d_%H-%M-%S'
  74. self.startTimeString = time.strftime(self.timeFormat)
  75. self.logFile = self.getLogFile(self.testConf["testLogDir"])
  76. self.logFile.write("################################################################################\n")
  77. self.log("Starting " + self.testType + " test session.")
  78. self.qxRevision = self.getRevision()
  79. self.scm = None
  80. self.buildStatus = self.getBuildStatus()
  81. self.sim = False
  82. if ('simulateTest' in self.testConf):
  83. self.sim = testConf['simulateTest']
  84. self.os = self.getOperatingSystem()
  85. if self.os == "Darwin":
  86. self.os = "Mac OS X"
  87. import socket
  88. socket.setdefaulttimeout(10)
  89. ##
  90. # Opens a new log file and returns the file object. Attempts to create the log
  91. # directory if it doesn't already exist.
  92. #
  93. # @param logDirectory {str} The directory to create the log file in
  94. def getLogFile(self, logDirectory):
  95. try:
  96. if not os.path.isdir(logDirectory):
  97. os.makedirs(logDirectory)
  98. filename = "testLog_" + self.startTimeString + ".txt"
  99. fullpath = os.path.join(logDirectory, filename)
  100. logFile = codecs.open(fullpath, 'a', 'utf-8')
  101. return logFile
  102. except Exception, e:
  103. errMsg = ""
  104. if (e.args):
  105. errMsg = repr(e.args)
  106. print("ERROR: Unable to open log file, quitting " + errMsg)
  107. sys.exit(1)
  108. ##
  109. # Adds options from the default configuration dictionary to the custom
  110. # configuration dictionary if they're not already defined.
  111. #
  112. # @param default {dict} The default configuration
  113. # @param custom {dict} The custom configuration
  114. def getConfig(self, default, custom):
  115. for option in default:
  116. if not option in custom:
  117. custom[option] = default[option]
  118. return custom
  119. ##
  120. # Writes a message to the test log file
  121. #
  122. # @param msg {str} The message to be logged
  123. def log(self, msg):
  124. if type(msg).__name__ == "unicode":
  125. msg = unicodedata.normalize('NFKD', msg).encode('ascii','ignore')
  126. timeFormatLog = '%Y-%m-%d %H:%M:%S'
  127. logTime = time.strftime(timeFormatLog)
  128. logMsg = logTime + " " + msg
  129. print(logMsg)
  130. if (self.logFile):
  131. try:
  132. self.logFile.write(logMsg + "\n")
  133. except UnicodeDecodeError, e:
  134. self.logFile.write("%s %s\n" %(logTime,repr(e)))
  135. ##
  136. # Attempts to determine the name of the operating system by using os.uname(),
  137. # falling back to platform.system()
  138. def getOperatingSystem(self):
  139. oSys = "Unknown"
  140. msg = "ERROR: Couldn't determine operating system!"
  141. try:
  142. oSys = os.uname()[0]
  143. except AttributeError:
  144. try:
  145. import platform
  146. oSys = platform.system()
  147. self.log("Operating system: " + oSys)
  148. except:
  149. self.logError(e, msg)
  150. except Exception, e:
  151. self.logError(e, msg)
  152. return oSys
  153. ##
  154. # Starts the Selenium RC server and checks its status. If the server doesn't
  155. # respond correctly after 20 seconds, another attempt is made. If this also
  156. # fails the script is ended.
  157. #
  158. # @param version {string} name of a subdirectory of seleniumConf["seleniumDir"]
  159. # @param options {string} command line options, e.g. -singleWindow -trustAllSSLCertificates
  160. def startSeleniumServer(self, version=None, jar=None, options=""):
  161. seleniumVersion = version or self.seleniumConf["seleniumVersion"]
  162. seleniumJar = jar or self.seleniumConf["seleniumJar"]
  163. cmd = self.testConf["javaBin"]
  164. cmd += " -jar " + self.seleniumConf["seleniumDir"] + "/"
  165. cmd += seleniumVersion + "/"
  166. cmd += seleniumJar
  167. if (self.sim):
  168. if "-singleWindow" in options:
  169. self.log("SIMULATION: Starting Selenium RC server in single window mode.")
  170. else:
  171. self.log("SIMULATION: Starting Selenium RC server in default mode.")
  172. return
  173. import subprocess, time
  174. if (self.isSeleniumServer()):
  175. self.log("Selenium server already running.")
  176. return
  177. if 'seleniumLog' in self.seleniumConf:
  178. cmd += " -browserSideLog -log " + self.seleniumConf['seleniumLog']
  179. cmd += options
  180. self.log("Starting Selenium server: %s" %cmd)
  181. selserv = subprocess.Popen(cmd, shell=True)
  182. # wait a while for the server to start up
  183. time.sleep(10)
  184. # check if it's up and running
  185. if ( not(self.isSeleniumServer()) ):
  186. self.log("Selenium server not responding, waiting for %s seconds..." %self.seleniumConf["serverStartTimeout"])
  187. time.sleep(self.seleniumConf["serverStartTimeout"])
  188. if ( not(self.isSeleniumServer()) ):
  189. self.log("ERROR: Selenium server not responding.")
  190. sys.exit(1)
  191. ##
  192. # Terminates the Selenium server process using a VBScript (Windows) or the
  193. # pkill shell command (Linux/OS X)
  194. def killSeleniumServer(self):
  195. if (self.sim):
  196. self.log("SIMULATION: Killing Selenium server process")
  197. return
  198. else:
  199. self.log("Killing Selenium server process")
  200. if self.os == "Linux":
  201. invokeExternal("pkill -f selenium-server")
  202. return
  203. if self.os == "Mac OS X":
  204. invokeExternal("pkill selenium-server")
  205. else:
  206. invokeExternal(self.testConf['killSelenium'])
  207. ##
  208. # Sends a shutdown command to the Selenium server
  209. #
  210. # @return Whether the server was shut down (Bool)
  211. def shutdownSeleniumServer(self):
  212. from urllib2 import Request, urlopen, URLError
  213. self.log("Shutting down Selenium server")
  214. req = Request(self.seleniumConf['seleniumHost'] + "/selenium-server/driver/?cmd=shutDownSeleniumServer")
  215. try:
  216. response = urlopen(req)
  217. content = response.read()
  218. if "OK" in content:
  219. self.log("Selenium server acknowledged shutdown request.")
  220. return True
  221. except URLError, e:
  222. self.log("Selenium server shutdown failed: " + repr(e))
  223. if hasattr(e, 'code'):
  224. self.log("Shutdown request status code: " + repr(e.code))
  225. except Exception, e:
  226. self.logError(e, "Shutting down Selenium server")
  227. return False
  228. ##
  229. # Checks the status of the Selenium RC server by sending an HTTP request.
  230. #
  231. # @return Whether the server is running (Bool)
  232. def isSeleniumServer(self):
  233. from urllib2 import Request, urlopen, URLError
  234. status = False
  235. #self.log("Checking Selenium server")
  236. req = Request(self.seleniumConf['seleniumHost'])
  237. try:
  238. response = urlopen(req)
  239. # Selenium should always refuse this request, so we should never get here
  240. except URLError, e:
  241. if hasattr(e, 'code'):
  242. if (e.code == 403):
  243. status = True
  244. except Exception, e:
  245. self.logError(e, "Checking if Selenium server is active")
  246. return status
  247. ##
  248. # Opens a new build log file and returns the file object. Attempts to create
  249. # the log directory if it doesn't already exist.
  250. #
  251. # @param buildLogDir {str} The directory to create the log file in
  252. def getBuildLogFile(self, buildLogDir, target):
  253. try:
  254. if not os.path.isdir(os.path.join(buildLogDir, target)):
  255. os.makedirs(os.path.join(buildLogDir, target))
  256. except Exception, e:
  257. self.logError(e, "Creating build log directory")
  258. return False
  259. buildLog = os.path.join(buildLogDir, target, self.startTimeString + '.log')
  260. self.log("Opening build log file " + buildLog)
  261. try:
  262. buildLogFile = codecs.open(buildLog, 'a', 'utf-8')
  263. except Exception, e:
  264. self.logError(e, "Opening build log file")
  265. return buildLogFile
  266. ##
  267. # Writes build Errors to the log file
  268. def logBuildErrors(self, buildLogFile, target, cmd, err):
  269. self.log("Error while building " + target + ", see build log file for details.")
  270. err = err.rstrip('\n')
  271. err = err.rstrip('\r')
  272. buildLogFile.write(target + "\n" + cmd + "\n" + err)
  273. buildLogFile.write("\n========================================================\n\n")
  274. ##
  275. # Starts the SVN update/build process for one or more targets. Logs errors
  276. # during build and writes the current trunk revision number and build status
  277. # to files.
  278. #
  279. # @param buildConf {dict} Build configuration
  280. def buildAll(self, buildConf):
  281. defaultBuildConf = {
  282. 'buildLogLevel' : 'error',
  283. 'buildLogDir' : '../../logs/build',
  284. 'batbuild' : 'tool/admin/app/batserver/batbuild.py'
  285. }
  286. buildConf = self.getConfig(defaultBuildConf, buildConf)
  287. buildResults = {}
  288. if "targets" in buildConf:
  289. for target in sorted(buildConf['targets'].iterkeys()):
  290. buildResult = self.buildTarget(target, buildConf)
  291. if buildResult:
  292. buildResults[target] = buildResult
  293. if "shellJobs" in buildConf:
  294. for shellJob in sorted(buildConf['shellJobs'].iterkeys()):
  295. config = buildConf['shellJobs'][shellJob]
  296. if "directory" in config:
  297. shellResult = self.runShellCommands(config["commands"], config["directory"])
  298. else:
  299. shellResult = self.runShellCommands(config["commands"])
  300. if shellResult:
  301. buildResults[shellJob] = shellResult
  302. # Store the results of this build run
  303. self.storeBuildStatus(buildConf["buildLogDir"], buildResults)
  304. # Update the 'total' build status with the results of this run
  305. for target in buildResults:
  306. self.buildStatus[target] = buildResults[target]
  307. # Store results including the last result of any job that wasn't in this
  308. # config
  309. self.storeBuildStatus(buildConf["buildLogDir"])
  310. self.qxRevision = self.getLocalRevision()
  311. self.storeRevision(buildConf["buildLogDir"])
  312. def buildTarget(self, target, buildConf):
  313. buildResult = {
  314. "BuildError" : None,
  315. "BuildWarning" : None,
  316. "BuildStarted" : time.strftime(self.timeFormat),
  317. "BuildFinished" : False,
  318. "BuildJob" : None
  319. }
  320. # Assemble batbuild command line
  321. if (os.path.isabs(buildConf['batbuild'])):
  322. cmd = buildConf['batbuild']
  323. else:
  324. cmd = os.path.join(self.testConf['qxPathAbs'], buildConf['batbuild'])
  325. cmd += " -w " + buildConf['stageDir']
  326. #if target[0] == target[0].capitalize():
  327. cmd += " " + buildConf['targets'][target]
  328. self.log("Building " + target + "\n " + cmd)
  329. reg = re.compile("-g\ (.*?)\ -")
  330. match = reg.search(cmd)
  331. if match:
  332. job = match.group(1)
  333. else:
  334. job = cmd
  335. buildResult["BuildJob"] = job
  336. if (self.sim):
  337. status = 0
  338. self.log("SIMULATION: Invoking build command:\n " + cmd)
  339. return buildResult
  340. status, std, err = invokePiped(cmd)
  341. if status > 0:
  342. if ('buildLogDir' in buildConf):
  343. buildLogFile = self.getBuildLogFile(buildConf["buildLogDir"], target)
  344. self.logBuildErrors(buildLogFile, target, cmd, err)
  345. buildLogFile.close()
  346. if err:
  347. buildResult["BuildError"] = err
  348. else:
  349. buildResult["BuildError"] = "Unknown build error"
  350. elif err != "":
  351. self.log("Warning while building " + target + ", see build log file for details.")
  352. err = err.rstrip('\n')
  353. err = err.rstrip('\r')
  354. if ('buildLogDir' in buildConf):
  355. buildLogFile = self.getBuildLogFile(buildConf["buildLogDir"], target)
  356. buildLogFile.write(target + "\n" + cmd + "\n" + err)
  357. buildLogFile.write("\n========================================================\n\n")
  358. buildLogFile.close()
  359. buildResult["BuildFinished"] = time.strftime(self.timeFormat)
  360. buildResult["BuildWarning"] = err
  361. else:
  362. self.log(target + " build finished without errors.")
  363. buildResult["BuildFinished"] = time.strftime(self.timeFormat)
  364. revision = self.getLocalRevision()
  365. buildResult[self.scm + "Revision"] = revision.rstrip()
  366. return buildResult
  367. ##
  368. # Generates one or more application skeletons. Logs any
  369. # errors encountered during the build and stores the build status.
  370. #
  371. # @param buildConf {dict} Build configuration. Must have a key "targets"
  372. # containing an array of qooxdoo application types, e.g. "bom", "gui", "inline"
  373. def buildSkeletonApps(self, buildConf):
  374. self.log("Building skeleton applications")
  375. if not os.path.isdir(buildConf["buildLogDir"]):
  376. self.log("Creating build log directory %s" %buildConf["buildLogDir"])
  377. os.makedirs(buildConf["buildLogDir"])
  378. for target in sorted(buildConf["targets"]):
  379. self.buildStatus[target] = {
  380. "BuildError" : None,
  381. "BuildWarning" : None,
  382. "BuildStarted" : time.strftime(self.timeFormat),
  383. "BuildFinished" : False,
  384. "BuildJob" : None
  385. }
  386. # generate the skeleton
  387. buildLogFile = self.getBuildLogFile(buildConf["buildLogDir"], target)
  388. cmd = buildConf["createApplication"] + " --type " + target
  389. cmd += " --name " + target + "application"
  390. #cmd += " --logfile " + buildLogFile.name
  391. cmd += " --out " + buildConf["stageDir"]
  392. self.log("Building %s skeleton." %target)
  393. status, std, err = invokePiped(cmd)
  394. if status > 0:
  395. self.logBuildErrors(buildLogFile, target, cmd, err)
  396. self.buildStatus[target]["BuildError"] = err.rstrip('\n')
  397. else:
  398. if err:
  399. self.buildStatus[target]["BuildWarning"] = err
  400. # generate the application
  401. self.log("Generating %s application." %target)
  402. buildcmd = sys.executable + " "
  403. if target == "contribution":
  404. buildcmd += os.path.join(buildConf["stageDir"], target + "application", "trunk", "demo", "default", "generate.py")
  405. else:
  406. buildcmd += os.path.join(buildConf["stageDir"], target + "application", "generate.py")
  407. jobs = ",".join(buildConf["targets"][target])
  408. self.buildStatus[target]["BuildJob"] = jobs
  409. buildcmd += " " + jobs
  410. status, std, err = invokePiped(buildcmd)
  411. if status > 0:
  412. self.logBuildErrors(buildLogFile, target, buildcmd, err)
  413. self.buildStatus[target]["BuildError"] = err.rstrip('\n')
  414. elif err != "":
  415. err = err.rstrip('\n')
  416. err = err.rstrip('\r')
  417. if not self.buildStatus[target]["BuildWarning"]:
  418. self.buildStatus[target]["BuildWarning"] = ""
  419. self.buildStatus[target]["BuildWarning"] += err.rstrip('\n')
  420. self.buildStatus[target]["BuildFinished"] = time.strftime(self.timeFormat)
  421. else:
  422. self.buildStatus[target]["BuildFinished"] = time.strftime(self.timeFormat)
  423. revision = self.getLocalRevision()
  424. self.storeRevision(buildConf["buildLogDir"])
  425. self.buildStatus[target][self.scm + "Revision"] = revision.rstrip()
  426. self.storeBuildStatus(buildConf["buildLogDir"])
  427. def runShellCommands(self, commands, workdir = os.getcwd()):
  428. result = {
  429. "BuildError": None,
  430. "BuildFinished": False,
  431. "BuildJob": ";".join(commands),
  432. "BuildStarted": time.strftime(self.timeFormat),
  433. "BuildWarning": None
  434. }
  435. if not os.path.isdir(workdir):
  436. result["BuildError"] = "'%s' is not a directory!" %workdir
  437. return result
  438. startdir = os.getcwd()
  439. if workdir != startdir:
  440. os.chdir(workdir)
  441. for cmd in commands:
  442. self.log("Running shell command " + cmd)
  443. ret,out,err = invokePiped(cmd)
  444. if ret == 0:
  445. if err != "":
  446. if not result["BuildWarning"]:
  447. result["BuildWarning"] = ""
  448. err = err.rstrip("\n")
  449. err = err.rstrip("\r")
  450. result["BuildWarning"] += err + " "
  451. else:
  452. if not result["BuildError"]:
  453. result["BuildError"] = ""
  454. err = err.rstrip("\n")
  455. err = err.rstrip("\r")
  456. result["BuildError"] += err + " "
  457. if not result["BuildError"]:
  458. result["BuildFinished"] = time.strftime(self.timeFormat)
  459. revision = self.getLocalRevision()
  460. result[self.scm + "Revision"] = revision.rstrip()
  461. os.chdir(startdir)
  462. return result
  463. ##
  464. # Runs an SVN update on a Simulator contribution checkout
  465. def updateSimulator(self):
  466. if (self.sim):
  467. self.log("SIMULATION: Updating Simulator checkout: "
  468. + self.testConf["simulatorSvn"])
  469. else:
  470. self.log("Updating Simulator checkout.")
  471. ret,out,err = invokePiped("svn up " + self.testConf["simulatorSvn"])
  472. if (out):
  473. try:
  474. self.log(out)
  475. except Exception, e:
  476. print(repr(e))
  477. if (err):
  478. self.log(err)
  479. ##
  480. # Converts the buildStatus map to JSON and stores it in a file in the root
  481. # directory of the local qooxdoo checkout where remote test runs can access
  482. # it.
  483. def storeBuildStatus(self, logDir=None, buildResult=None):
  484. try:
  485. import json
  486. except ImportError, e:
  487. try:
  488. import simplejson as json
  489. except ImportError, e:
  490. self.log("ERROR: simplejson module not found, unable to store build status!")
  491. return False
  492. if not logDir:
  493. logDir = self.testConf['qxPathAbs']
  494. if not os.path.isdir(logDir):
  495. os.makedirs(logDir)
  496. if buildResult:
  497. jsonData = json.dumps(buildResult, sort_keys=True, indent=2)
  498. fPath = os.path.join(logDir,'buildStatus_%s.json' %self.startTimeString)
  499. else:
  500. jsonData = json.dumps(self.buildStatus, sort_keys=True, indent=2)
  501. fPath = os.path.join(logDir,'buildStatus.json')
  502. if (self.sim):
  503. self.log("SIMULATION: Storing build status in file " + fPath)
  504. else:
  505. self.log("Storing build status in file " + fPath)
  506. rFile = codecs.open(fPath, 'w', 'utf-8')
  507. rFile.write(jsonData)
  508. rFile.close()
  509. ##
  510. # Reads the build status stored by a previous test run from the file system
  511. # @return Build status dictionary
  512. def getLocalBuildStatus(self):
  513. status = {}
  514. try:
  515. import json
  516. except ImportError, e:
  517. try:
  518. import simplejson as json
  519. except ImportError, e:
  520. self.log("ERROR: simplejson module not found, unable to get build status!")
  521. return status
  522. path = os.path.join(self.testConf['qxPathAbs'],'buildStatus.json')
  523. if not os.path.isfile(path):
  524. return status
  525. statusFile = codecs.open(path, "r")
  526. try:
  527. status = json.load(statusFile)
  528. except Exception, e:
  529. self.logError(e, "Reading local build status")
  530. finally:
  531. return status
  532. ##
  533. # Reads the build status from a file on a remote test host
  534. #
  535. # @return Build status dictionary
  536. def getRemoteBuildStatus(self):
  537. import urllib
  538. status = {}
  539. try:
  540. import json
  541. except ImportError, e:
  542. try:
  543. import simplejson as json
  544. except ImportError, e:
  545. self.log("ERROR: simplejson module not found, unable to retrieve remote build status!")
  546. return status
  547. if "remoteLogDir" in self.testConf:
  548. remoteFile = self.testConf["remoteLogDir"]
  549. else:
  550. remoteFile = self.autConf['autHost']
  551. if 'autQxPath' in self.autConf:
  552. remoteFile += self.autConf['autQxPath']
  553. remoteFile += '/buildStatus.json'
  554. self.log("Retrieving remote build status from file " + remoteFile)
  555. try:
  556. jsonData = urllib.urlopen(remoteFile)
  557. except IOError, e:
  558. self.log("ERROR: Unable to open remote build status file " + remoteFile + ": "
  559. + e.message)
  560. return status
  561. except Exception, e:
  562. self.logError(e, "Opening remote build file")
  563. return status
  564. # Try to determine the requests's HTTP status (Python >= 2.6 only).
  565. try:
  566. reqStat = jsonData.getcode()
  567. if (reqStat != 200):
  568. self.log("ERROR: Request to remote build status file returned status " + repr(reqStat))
  569. except AttributeError:
  570. pass
  571. try:
  572. status = json.load(jsonData)
  573. self.log("Remote build status retrieved successfully.")
  574. except ValueError, e:
  575. self.log("ERROR: Unable to parse buildStatus JSON: " + repr(e))
  576. except Exception, e:
  577. self.logError(e, "Parsing remote build file")
  578. return status
  579. def getBuildStatus(self):
  580. if self.testType == "local":
  581. return self.getLocalBuildStatus()
  582. elif self.testType == "remote":
  583. return self.getRemoteBuildStatus()
  584. else:
  585. return {}
  586. def getRevision(self):
  587. if self.testType == "local":
  588. return self.getLocalRevision()
  589. elif self.testType == "remote":
  590. return self.getRemoteRevision()
  591. else:
  592. return False
  593. def getLocalRevision(self):
  594. svnDir = os.path.join(self.testConf["qxPathAbs"], ".svn")
  595. if os.path.isdir(svnDir):
  596. self.scm = "SVN"
  597. return self.getLocalSvnRevision()
  598. gitDir = os.path.join(self.testConf["qxPathAbs"], ".git")
  599. if os.path.isdir(gitDir):
  600. self.scm = "Git"
  601. return self.getLocalGitDescription()
  602. ##
  603. # Retrieves a local qooxdoo SVN checkout's revision number
  604. #
  605. # @return The revision number (String)
  606. def getLocalSvnRevision(self):
  607. ret,out,err = invokePiped("svnversion " + self.testConf["qxPathAbs"])
  608. if ret > 0:
  609. self.log("Error determining SVN revision: " + err)
  610. return False
  611. rev = out.rstrip('\n')
  612. self.log("Local qooxdoo SVN checkout at revision " + rev)
  613. return rev
  614. def getLocalGitDescription(self):
  615. desc = git("describe --tags", self.testConf["qxPathAbs"])
  616. reg = re.compile("\-g(.*?)$")
  617. match = reg.search(desc)
  618. if match:
  619. desc = match.group(1)
  620. desc = desc.rstrip()
  621. self.log("Local qooxdoo Git repository description " + desc)
  622. return desc
  623. ##
  624. # Writes the current revision number of the local qooxdoo checkout to a file
  625. # named 'revision.txt' in the qooxdoo checkout's root directory.
  626. def storeRevision(self, logDir=None):
  627. if not self.qxRevision:
  628. self.log("No revision number to store!")
  629. return
  630. if not logDir:
  631. self.log("No log directory specified!")
  632. return
  633. fPath = os.path.join(logDir,'revision.txt')
  634. if (self.sim):
  635. self.log("SIMULATION: Storing revision number " + self.qxRevision
  636. + " in file " + fPath)
  637. else:
  638. self.log("Storing revision number " + self.qxRevision + " in file " + fPath)
  639. rFile = codecs.open(fPath, 'w', 'utf-8')
  640. rFile.write(self.qxRevision)
  641. rFile.close()
  642. ##
  643. # Reads the qooxdoo checkout's revision number from a file on a remote test
  644. # host
  645. #
  646. # @return The revision number (String)
  647. def getRemoteRevision(self):
  648. import urllib, re
  649. if "remoteLogDir" in self.testConf:
  650. remoteFile = self.testConf["remoteLogDir"]
  651. remoteFile += '/revision.txt'
  652. elif 'autQxPath' in self.autConf:
  653. remoteFile = self.autConf['autHost']
  654. remoteFile += self.autConf['autQxPath']
  655. remoteFile += '/revision.txt'
  656. if remoteFile:
  657. try:
  658. handle = urllib.urlopen(remoteFile)
  659. if handle.getcode() != 404:
  660. rev = handle.read()
  661. else:
  662. self.log("ERROR: Remote revision file " + remoteFile + " not found!")
  663. return False
  664. except IOError, e:
  665. self.log("ERROR: Unable to open remote revision file " + remoteFile + ": "
  666. + e.message)
  667. return False
  668. except Exception, e:
  669. self.logError(e, "Opening remote revision file")
  670. return False
  671. else:
  672. self.log("Remote qooxdoo checkout at revision " + rev)
  673. return rev
  674. return False
  675. ##
  676. # Generates a fake test log file so that a report email can be generated even
  677. # if the test didn't run due to build errors.
  678. #
  679. # @param appConf {dict} Settings for the application(s) to be tested
  680. # @return {file} The file handle of the dummy log
  681. def getDummyLog(self, appConf):
  682. import random
  683. dummyLogFile = os.path.join(self.testConf['testLogDir'], appConf['appName'], "DUMMY_" + appConf['appName'] + self.startTimeString + ".log")
  684. dummyLog = codecs.open(dummyLogFile, "w", "utf-8")
  685. for browser in appConf['browsers']:
  686. prefix = "qxSimulator_" + str(random.randint(100000, 999999)) + ": "
  687. dummyLog.write(prefix + "<h1>" + appConf['appName'] + " results from " + self.startTimeString + "</h1>\n")
  688. platform = self.os
  689. if platform == "Windows":
  690. platform = "Win32"
  691. dummyLog.write(prefix + "<p>Platform: " + platform + "</p>\n")
  692. dummyLog.write(prefix + "<p>User agent: " + browser['browserId'] + "</p>\n")
  693. dummyLog.write(prefix + "<div class=\"qxappender\"><div class=\"level-error\">BUILD ERROR: " + self.buildStatus[appConf['appName']]["BuildError"] + "</div></div>\n")
  694. dummyLog.close()
  695. return dummyLogFile
  696. def runTestsWrapped(self, appConf):
  697. try:
  698. self.runTests(appConf)
  699. except Exception, e:
  700. self.log("Error running tests for %s: %s" %(appConf["appName"], repr(e)) )
  701. ##
  702. # Launches the actual tests (Simulations) for defined applications
  703. #
  704. # @param appConf {dict} Settings for the application(s) to be tested
  705. def runTests(self, appConf):
  706. import time
  707. testStartDate = time.strftime(self.timeFormat)
  708. getReportFrom = self.testConf['getReportFrom']
  709. if getReportFrom == 'testLog':
  710. logPath = os.path.join(self.testConf['testLogDir'], appConf['appName'])
  711. if not os.path.isdir(logPath):
  712. os.makedirs(logPath)
  713. tf = '%Y-%m-%d_%H-%M-%S'
  714. logFile = os.path.join(logPath, testStartDate + ".log")
  715. if not os.path.isabs(logFile):
  716. logFile = os.path.abspath(logFile)
  717. lf = codecs.open(logFile, 'w', 'utf-8')
  718. lf.close()
  719. reportPath = os.path.join(self.testConf['testReportDir'], appConf['appName'])
  720. if not os.path.isdir(reportPath):
  721. os.makedirs(reportPath)
  722. reportFile = os.path.join( reportPath, testStartDate + '.html')
  723. if appConf['appName'] in self.buildStatus:
  724. if self.buildStatus[appConf['appName']]["BuildError"]:
  725. self.log("ERROR: Skipping " + appConf['appName'] + " test because there "
  726. + "was an error during build:\n " + self.buildStatus[appConf['appName']]["BuildError"])
  727. sendReport = True
  728. if 'sendReport' in appConf:
  729. sendReport = appConf['sendReport']
  730. if sendReport:
  731. dummyLogFile = self.getDummyLog(appConf)
  732. ignore = None
  733. if "ignoreLogEntries" in appConf:
  734. ignore = appConf["ignoreLogEntries"]
  735. logFormatted = self.formatLog(dummyLogFile, reportFile, ignore)
  736. if logFormatted:
  737. self.sendReport(appConf['appName'], reportFile)
  738. else:
  739. self.log("No report HTML to send.")
  740. if "reportServerUrl" in self.testConf:
  741. try:
  742. self.reportResults(appConf['appName'], testStartDate, dummyLogFile)
  743. except Exception, e:
  744. self.logError(e, "Sending test results")
  745. return
  746. clearLogs = True
  747. if 'clearLogs' in appConf:
  748. clearLogs = appConf['clearLogs']
  749. if clearLogs:
  750. self.clearLogs()
  751. seleniumVersion = self.seleniumConf["seleniumVersion"]
  752. if 'seleniumVersion' in appConf:
  753. seleniumVersion = appConf["seleniumVersion"]
  754. seleniumJar = self.seleniumConf["seleniumJar"]
  755. if 'seleniumJar' in appConf:
  756. seleniumJar = appConf["seleniumJar"]
  757. seleniumOptions = ""
  758. # Use trustAllSSLCertificates option?
  759. trustAllCerts = False
  760. if self.seleniumConf['trustAllSSLCertificates']:
  761. seleniumOptions += " -trustAllSSLCertificates"
  762. # Any additional options
  763. seleniumOptions += " %s" %self.seleniumConf["options"]
  764. individual = True
  765. if 'individualServer' in appConf:
  766. individual = appConf['individualServer']
  767. if not individual:
  768. self.log("individualServer set to False, using one server instance for "
  769. + "all tests")
  770. # Use single window mode if IE is among the browsers to be tested in.
  771. # This is necessary due to cross-window/tab JavaScript access restrictions.
  772. for browser in appConf['browsers']:
  773. browserLauncher = self.browserConf[browser['browserId']]
  774. if self.seleniumConf['ieSingleWindow'] and ("iexplore" in browserLauncher or "iepreview" in browserLauncher):
  775. seleniumOptions += " -singleWindow"
  776. break
  777. self.startSeleniumServer(seleniumVersion, seleniumJar, seleniumOptions)
  778. for browser in appConf['browsers']:
  779. if "seleniumVersion" in browser:
  780. seleniumVersion = browser["seleniumVersion"]
  781. if "seleniumJar" in browser:
  782. seleniumJar = browser["seleniumJar"]
  783. killBrowser = True
  784. if "kill" in browser:
  785. killBrowser = browser['kill']
  786. if individual:
  787. browserLauncher = self.browserConf[browser['browserId']]
  788. if self.seleniumConf['ieSingleWindow'] and ("iexplore" in browserLauncher or "iepreview" in browserLauncher):
  789. seleniumOptions += " -singleWindow"
  790. self.log("individualServer set to True, using one server instance per "
  791. + "test run")
  792. self.startSeleniumServer(seleniumVersion, seleniumJar, seleniumOptions)
  793. options = False
  794. if "options" in browser:
  795. options = browser["options"]
  796. else:
  797. if "options" in appConf:
  798. options = appConf["options"]
  799. simulationScript = False
  800. if "simulationScript" in browser:
  801. simulationScript = browser["simulationScript"]
  802. else:
  803. if "simulationScript" in appConf:
  804. simulationScript = appConf["simulationScript"]
  805. seleniumVersion = self.seleniumConf["seleniumVersion"]
  806. if "seleniumVersion" in browser:
  807. seleniumVersion = browser["seleniumVersion"]
  808. else:
  809. if "seleniumVersion" in appConf:
  810. seleniumVersion = appConf["seleniumVersion"]
  811. cmd = self.getStartCmd(appConf['appName'], browser['browserId'], options, simulationScript, seleniumVersion)
  812. if getReportFrom == 'testLog':
  813. cmd += " logFile=" + logFile
  814. try:
  815. if (browser['setProxy']):
  816. self.setProxy(True)
  817. except KeyError:
  818. pass
  819. try:
  820. if (browser['setIE8Compatibility']):
  821. self.setIE8Compatibility(True)
  822. except KeyError:
  823. pass
  824. if (self.sim):
  825. self.log("SIMULATION: Starting test:\n " + cmd)
  826. else:
  827. self.log("Testing: " + appConf['appName'] + " on "
  828. + browser['browserId'] + "\n " + cmd)
  829. invokeExternal(cmd)
  830. try:
  831. if (browser['setProxy']):
  832. self.setProxy(False)
  833. except KeyError:
  834. pass
  835. try:
  836. if (browser['setIE8Compatibility']):
  837. self.setIE8Compatibility(False)
  838. except KeyError:
  839. pass
  840. try:
  841. if (killBrowser):
  842. self.killBrowser(browser['browserId'])
  843. except KeyError:
  844. pass
  845. if individual:
  846. self.shutdownSeleniumServer()
  847. time.sleep(5)
  848. if self.isSeleniumServer():
  849. self.killSeleniumServer()
  850. if not individual:
  851. self.shutdownSeleniumServer()
  852. time.sleep(5)
  853. if self.isSeleniumServer():
  854. self.killSeleniumServer()
  855. sendReport = True
  856. if 'sendReport' in appConf:
  857. sendReport = appConf['sendReport']
  858. if sendReport:
  859. ignore = None
  860. if "ignoreLogEntries" in browser:
  861. ignore = browser["ignoreLogEntries"]
  862. else:
  863. if "ignoreLogEntries" in appConf:
  864. ignore = appConf["ignoreLogEntries"]
  865. if (self.sim):
  866. self.log("SIMULATION: Formatting log and sending report.\n")
  867. else:
  868. if getReportFrom == 'testLog':
  869. self.formatLog(logFile, reportFile, ignore)
  870. else:
  871. self.formatLog(None, reportFile, ignore)
  872. self.sendReport(appConf['appName'], reportFile)
  873. if "reportServerUrl" in self.testConf:
  874. if (self.sim):
  875. self.log("SIMULATION: Sending results to report server.\n")
  876. else:
  877. self.reportResults(appConf['appName'], testStartDate, logFile, ignore)
  878. ##
  879. # Assembles the shell command used to launch the Simulation
  880. #
  881. # @param aut {str} The name of the application to be tested. Must correspond
  882. # to the name of a subdirectory of "/trunk/tool/selenium/simulation/" in the
  883. # local Simulator contrib checkout
  884. # @param browser {str} A browser identifier (one of the keys in browserConf)
  885. # @param options {arr} An array of options to be passed to the test script,
  886. # e.g. ["ignore=qx.test.ui","foo=bar"]
  887. # @param simulationScript {str} Optional: Path to the Simulation script to be used.
  888. # By default, the script found in the Simulator contrib checkout under
  889. # /trunk/tool/selenium/simulation/[APPNAME]/test_[APPNAME].js is used
  890. # @param seleniumVersion {str} Optional: Selenium Client Driver version to be used.
  891. # @return {str} The shell command
  892. def getStartCmd(self, aut, browser, options, simulationScript=None, seleniumVersion=None):
  893. path = self.seleniumConf["seleniumDir"] + "/" + seleniumVersion
  894. cmd = self.testConf["javaBin"]
  895. if ('seleniumClientDriverJar' in self.testConf or 'rhinoJar' in self.testConf):
  896. cmd += " -cp "
  897. if ('seleniumClientDriverJar' in self.testConf):
  898. cmd += path + "/" + self.testConf['seleniumClientDriverJar']
  899. if ('seleniumClientDriverJar' in self.testConf and 'rhinoJar' in self.testConf):
  900. if ('classPathSeparator' in self.testConf):
  901. cmd += self.testConf['classPathSeparator']
  902. else:
  903. cmd += ";"
  904. if ('rhinoJar' in self.testConf):
  905. cmd += self.testConf['rhinoJar']
  906. cmd += " org.mozilla.javascript.tools.shell.Main"
  907. script = ""
  908. if simulationScript:
  909. script = simulationScript
  910. else:
  911. script = self.testConf['simulatorSvn'] + "/trunk/tool/selenium/simulation/" + aut.lower() + "/test_" + aut.lower() + ".js"
  912. cmd += " " + script
  913. cmd += " autHost=" + self.autConf['autHost']
  914. cmd += " autPath="
  915. if 'autQxPath' in self.autConf:
  916. cmd += self.autConf['autQxPath']
  917. cmd += self.autConf['autPath' + aut]
  918. cmd += " simulatorSvn=" + self.testConf['simulatorSvn']
  919. if (self.os == "Windows"):
  920. cmd += " testBrowser=" + self.browserConf[browser]
  921. else:
  922. cmd += " testBrowser='" + self.browserConf[browser] + "'"
  923. cmd += " browserId=\"" + browser + "\""
  924. cmd += " branch=" + self.testConf["qxBranch"]
  925. if options:
  926. for opt in options:
  927. cmd += ' "' + opt + '"'
  928. return cmd
  929. def reportResults(self, aut, start_date, log_file, ignore=None):
  930. from simulationLogParser import SimulationLogParser
  931. if (self.sim):
  932. self.log("SIMULATION: Getting report data for " + aut)
  933. return
  934. else:
  935. self.log("Getting report data for " + aut)
  936. try:
  937. import json
  938. except ImportError, e:
  939. try:
  940. import simplejson as json
  941. except ImportError, e:
  942. self.log("ERROR: Unable to import JSON module: " + repr(e))
  943. return
  944. import urllib2
  945. from urllib import urlencode
  946. testRunDict = self.getTestRunDict(aut, start_date)
  947. slp = SimulationLogParser(log_file, ignore)
  948. simulationData = slp.getSimulationData()
  949. testRunDict["simulations"] = simulationData
  950. try:
  951. if simulationData[0]["platform"] != "Unknown":
  952. testRunDict["test_hostos"] = simulationData[0]["platform"]
  953. except Exception:
  954. pass
  955. testRunJson = json.dumps(testRunDict)
  956. self.log("Report data aggregated, sending request")
  957. postdata = urlencode({"testRun": testRunJson})
  958. req = urllib2.Request(self.testConf["reportServerUrl"], postdata)
  959. try:
  960. if sys.version[:3] == "2.5":
  961. import socket
  962. import urllib2
  963. socket.setdefaulttimeout(120)
  964. response = urllib2.urlopen(req)
  965. else:
  966. response = urllib2.urlopen(req, None, 120)
  967. except Exception, e:
  968. msg = repr(e)
  969. if hasattr(e, "code"):
  970. msg += " Code: " + repr(e.code)
  971. self.log("Unable to contact report server: Error %s" %msg)
  972. return
  973. content = response.read()
  974. self.log("Report server response: " + content)
  975. def getTestRunDict(self, aut, start_date):
  976. import socket
  977. hostname = socket.gethostname()
  978. try:
  979. test_host = socket.gethostbyname(hostname)
  980. except socket.gaierror:
  981. test_host = '172.17.12.142'
  982. autName = aut
  983. if "Source" in aut:
  984. autName = aut[0:aut.find("Source")]
  985. testRun = {
  986. "aut_name" : autName,
  987. "aut_host" : self.autConf["autHost"],
  988. "aut_qxpath" : "",
  989. "aut_path" : self.autConf["autPath" + aut],
  990. "test_host" : test_host,
  991. "test_hostos" : self.os,
  992. "test_hostid" : "",
  993. "test_type" : self.testConf["runType"],
  994. "revision" : "",
  995. "branch" : self.testConf["qxBranch"],
  996. "start_date" : start_date,
  997. "end_date" : time.strftime(self.timeFormat),
  998. "simulations": [],
  999. "dev_run" : True
  1000. }
  1001. if self.qxRevision:
  1002. testRun["revision"] = self.qxRevision
  1003. if "autQxPath" in self.autConf:
  1004. testRun["aut_qxpath"] = self.autConf["autQxPath"]
  1005. if self.mailConf:
  1006. if "hostId" in self.mailConf:
  1007. testRun["test_hostid"] = self.mailConf["hostId"]
  1008. if ("webtechnologies" in self.mailConf["mailTo"]):
  1009. testRun["dev_run"] = False
  1010. return testRun
  1011. ##
  1012. # Sends the generated test report file by email.
  1013. #
  1014. # @param aut {str} The name of the tested application
  1015. def sendReport(self, aut, reportfile):
  1016. self.log("Preparing to send " + aut + " report: " + reportfile)
  1017. if not os.path.exists(reportfile):
  1018. self.log("sendReport: Report file not found!")
  1019. return
  1020. if not "mailTo" in self.mailConf:
  1021. self.log("sendReport: No mail recipient configured!")
  1022. return
  1023. self.mailConf['subject'] = "[qooxdoo-test] " + aut
  1024. reportFile = open(reportfile, 'rb')
  1025. self.mailConf['html'] = reportFile.read()
  1026. reportFile.seek(0)
  1027. osRe = re.compile('<p>Platform: (.*)</p>')
  1028. failedTestsRe = re.compile('<p class="failedtests">([\d]*)')
  1029. totalErrorsRe = re.compile('<p class="totalerrors">Total errors in report: ([\d]*)</p>')
  1030. osystem = ""
  1031. failed = ""
  1032. totalE = ""
  1033. for line in reportFile:
  1034. osys = osRe.search(line)
  1035. if (osys):
  1036. osystem = osys.group(1)
  1037. # Some browsers return "Linux i686" as the platform
  1038. if "Linux" in osystem:
  1039. osystem = "Linux"
  1040. else:
  1041. if "Win" in osystem:
  1042. osystem = "Win32"
  1043. failedTests = failedTestsRe.search(line)
  1044. if (failedTests):
  1045. failed = failedTests.group(1)
  1046. totalErrors = totalErrorsRe.search(line)
  1047. if (totalErrors):
  1048. totalE = totalErrors.group(1)
  1049. self.mailConf['subject'] += " " + osystem
  1050. if ('hostId' in self.mailConf):
  1051. self.mailConf['subject'] += " " + self.mailConf['hostId']
  1052. if (self.qxRevision):
  1053. self.mailConf['subject'] += " (%s r%s)" %(self.testConf["qxBranch"],self.qxRevision)
  1054. if (aut in self.buildStatus):
  1055. if (self.buildStatus[aut]["BuildError"]):
  1056. self.mailConf['subject'] += " BUILD ERROR"
  1057. if (failed != ""):
  1058. self.mailConf['subject'] += ": " + failed + " test run(s) failed!"
  1059. else:
  1060. self.mailConf['subject'] += ": " + totalE + " issues"
  1061. # Send mail
  1062. if (self.sim):
  1063. self.log("SIMULATION; Prepared report email:\n"
  1064. + " Subject: " + self.mailConf['subject'] + "\n"
  1065. + " Recipient: " + self.mailConf['mailTo'])
  1066. if (osystem !=""):
  1067. try:
  1068. sendMultipartMail(self.mailConf)
  1069. except Exception, e:
  1070. self.logError(e, "Sending report email")
  1071. else:
  1072. self.log("Report email sent successfully")
  1073. else:
  1074. self.log("ERROR: Report file seems incomplete, report not sent.")
  1075. ##
  1076. # Runs logFormatter on a file containg "qxSimulator" entries. Uses the
  1077. # Selenium RC server's log file as a fallback if the specified file doesn't
  1078. # exist or is empty.
  1079. #
  1080. # @param inputfile {str} Path to the log file to be formatted.
  1081. def formatLog(self, inputfile=None, reportfile=None, ignore=None):
  1082. from logFormatter import QxLogFormat
  1083. class FormatterOpts:
  1084. def __init__(self,logfile,htmlfile,ignore=None):
  1085. self.logfile = logfile
  1086. self.htmlfile = htmlfile
  1087. self.ignore = ignore
  1088. if not inputfile:
  1089. if 'seleniumLog' in self.seleniumConf:
  1090. inputfile = self.seleniumConf['seleniumLog']
  1091. if inputfile:
  1092. try:
  1093. if os.path.isfile(inputfile):
  1094. if os.path.getsize(inputfile) != "0L":
  1095. log = inputfile
  1096. except:
  1097. pass
  1098. if not inputfile:
  1099. self.log("ERROR: No log file to work with")
  1100. return False
  1101. options = FormatterOpts(inputfile, reportfile, ignore)
  1102. if (self.sim):
  1103. self.log("SIMULATION: Formatting log file " + inputfile)
  1104. else:
  1105. self.log("Formatting log file " + inputfile)
  1106. logformat = QxLogFormat(options)
  1107. logformat.writeHtmlReport()
  1108. return True
  1109. ##
  1110. # Clears the Selenium RC server log file.
  1111. def clearLogs(self):
  1112. if ('seleniumLog' in self.seleniumConf and os.path.exists(self.seleniumConf['seleniumLog'])):
  1113. f = open(self.seleniumConf['seleniumLog'], 'w')
  1114. if (self.sim):
  1115. self.log("SIMULATION: Emptying server log file " + self.seleniumConf['seleniumLog'])
  1116. else:
  1117. self.log("Emptying server log file " + self.seleniumConf['seleniumLog'])
  1118. f.write('')
  1119. f.close()
  1120. ##
  1121. # Kills a browser process to make sure subsequent tests can launch the same
  1122. # browser. This is somewhat unreliable as it tries to determine the process
  1123. # name from the command used to tell Selenium which browser to use.
  1124. #
  1125. # @param browser {str} A browser identifier (one of the keys in browserConf)
  1126. def killBrowser(self, browser):
  1127. browserFull = self.browserConf[browser].lower()
  1128. procName = None
  1129. if "opera" in browserFull:
  1130. procName = "opera"
  1131. if "safari" in browserFull:
  1132. procName = "safari"
  1133. if "chrome" in browserFull:
  1134. procName = "chrome"
  1135. if "arora" in browserFull:
  1136. procName = "arora"
  1137. if "iexplore" in browserFull:
  1138. procName = "iexplore"
  1139. if "firefox" in browserFull:
  1140. procName = "firefox"
  1141. time.sleep(3)
  1142. if procName:
  1143. if self.os == "Linux" or self.os == "Mac OS X":
  1144. if (self.sim):
  1145. self.log("SIMULATION: Killing *nix browser process: " + procName)
  1146. else:
  1147. self.log("Killing Linux browser process: " + procName)
  1148. invokeExternal("pkill " + procName)
  1149. else:
  1150. script = "kill" + procName + ".vbs"
  1151. if (os.path.isfile(script)):
  1152. if (self.sim):
  1153. self.log("SIMULATION: Killing Windows browser process: " + procName)
  1154. else:
  1155. self.log("Killing Windows browser process: " + procName)
  1156. invokeExternal("wscript " + script)
  1157. else:
  1158. self.log("ERROR: Unable to determine browser process name")
  1159. ##
  1160. # Executes a shell command that should (de)activate the proxy setting in the
  1161. # Windows registry for browsers started with the *custom launcher (Safari,
  1162. # Chrome, etc.)
  1163. #
  1164. # @param prox {bool} Enable (True) or disable (False) the proxy setting
  1165. def setProxy(self, prox):
  1166. if (prox):
  1167. if (self.os == "Windows"):
  1168. if (self.sim):
  1169. self.log("SIMULATION: Activating proxy setting in Windows registry: "
  1170. + self.testConf['proxyEnable'])
  1171. else:
  1172. self.log("Activating proxy setting in Windows registry")
  1173. invokeExternal(self.testConf['proxyEnable'])
  1174. else:
  1175. self.log("ERROR: Can't enable proxy on non-Windows system!")
  1176. else:
  1177. if (self.os == "Windows"):
  1178. if (self.sim):
  1179. self.log("SIMULATION: Deactivating proxy setting in Windows registry: "
  1180. + self.testConf['proxyDisable'])
  1181. else:
  1182. self.log("Deactivating proxy setting in Windows registry")
  1183. invokeExternal(self.testConf['proxyDisable'])
  1184. else:
  1185. self.log("Error: Can't disable proxy on non-Windows system!")
  1186. ##
  1187. # Executes a shell command that should (de)activate the IE8 compatibility
  1188. # setting in the Windows registry
  1189. #
  1190. # @param compat {bool} Enable (True) or disable (False) the compatibility
  1191. # setting
  1192. def setIE8Compatibility(self, compat):
  1193. if (compat):
  1194. if (self.os == "Windows"):
  1195. if (self.sim):
  1196. self.log("SIMULATION: Activating IE8 compatibility mode in Windows registry: "
  1197. + self.testConf['compatEnable'])
  1198. else:
  1199. self.log("Activating IE8 compatibility mode in Windows registry")
  1200. invokeExternal(self.testConf['compatEnable'])
  1201. else:
  1202. self.log("ERROR: Can't enable IE8 compatibility mode on non-Windows system!")
  1203. else:
  1204. if (self.os == "Windows"):
  1205. if (self.sim):
  1206. self.log("SIMULATION: Deactivating IE8 compatibility mode in Windows registry: "
  1207. + self.testConf['compatDisable'])
  1208. else:
  1209. self.log("Deactivating IE8 compatibility mode in Windows registry")
  1210. invokeExternal(self.testConf['compatDisable'])
  1211. else:
  1212. self.log("Error: Can't disable IE8 compatibility mode on non-Windows system!")
  1213. ##
  1214. # Invokes lintRunner on one ore more targets
  1215. #
  1216. # @param lintConf {dict} Lint run configuration
  1217. def runLint(self,lintConf):
  1218. from lintRunner import QxLint
  1219. class LintOpts:
  1220. def __init__(self,workdir,mailto):
  1221. self.workdir = workdir
  1222. self.mailto = mailto
  1223. self.outputfile = None
  1224. for key in lintConf:
  1225. for target in lintConf[key]:
  1226. options = LintOpts(None,self.mailConf['mailTo'])
  1227. if key == "other":
  1228. options.workdir = os.path.join(self.testConf['qxPathAbs'], target['directory'])
  1229. elif key == "external":
  1230. options.workdir = target['directory']
  1231. else:
  1232. options.workdir = os.path.join(self.testConf['qxPathAbs'], key, target['directory'])
  1233. if ('ignoreClasses' in target):
  1234. options.ignoreClasses = target['ignoreClasses']
  1235. if ('ignoreErrors' in target):
  1236. options.ignoreErrors = target['ignoreErrors']
  1237. if (self.sim):
  1238. self.log("SIMULATION: Starting Lint runner:\n " + options.workdir)
  1239. else:
  1240. self.log("Running Lint for " + options.workdir)
  1241. try:
  1242. qxlint = QxLint(options)
  1243. if "reportServerUrl" in self.testConf:
  1244. try:
  1245. if self.qxRevision:
  1246. revision = self.qxRevision
  1247. else:
  1248. revision = ""

Large files files are truncated, but you can click here to view the full file