integration-check 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. #!/usr/bin/env python
  2. # This Source Code Form is subject to the terms of the Mozilla Public
  3. # License, v. 2.0. If a copy of the MPL was not distributed with this
  4. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  5. import os
  6. import signal
  7. import threading
  8. import urllib2, urllib
  9. import zipfile
  10. import tarfile
  11. import subprocess
  12. import optparse
  13. import sys, re
  14. #import win32api
  15. class SDK:
  16. def __init__(self):
  17. try:
  18. # Take the current working directory
  19. self.default_path = os.getcwd()
  20. if sys.platform == "win32":
  21. self.mswindows = True
  22. else:
  23. self.mswindows = False
  24. # Take the default home path of the user.
  25. home = os.path.expanduser('~')
  26. # The following are the parameters that can be used to pass a dynamic URL, a specific path or a binry. The binary is not used yet. It will be used in version 2.0
  27. # If a dynamic path is to be mentioned, it should start with a '/'. For eg. "/Desktop"
  28. parser = optparse.OptionParser()
  29. parser.add_option('-u', '--url', dest = 'url', default = 'https://ftp.mozilla.org/pub/mozilla.org/labs/jetpack/addon-sdk-latest.zip')
  30. parser.add_option('-p', '--path', dest = 'path', default = self.default_path)
  31. parser.add_option('-b', '--binary', dest = 'binary')#, default='/Applications/Firefox.app')
  32. (options, args) = parser.parse_args()
  33. # Get the URL from the parameter
  34. self.link = options.url
  35. # Set the base path for the user. If the user supplies the path, use the home variable as well. Else, take the default path of this script as the installation directory.
  36. if options.path!=self.default_path:
  37. if self.mswindows:
  38. self.base_path = home + str(options.path).strip() + '\\'
  39. else:
  40. self.base_path = home + str(options.path).strip() + '/'
  41. else:
  42. if self.mswindows:
  43. self.base_path = str(options.path).strip() + '\\'
  44. else:
  45. self.base_path = str(options.path).strip() + '/'
  46. assert ' ' not in self.base_path, "You cannot have a space in your home path. Please remove the space before you continue."
  47. print('Your Base path is =' + self.base_path)
  48. # This assignment is not used in this program. It will be used in version 2 of this script.
  49. self.bin = options.binary
  50. # if app or bin is empty, dont pass anything
  51. # Search for the .zip file or tarball file in the URL.
  52. i = self.link.rfind('/')
  53. self.fname = self.link[i+1:]
  54. z = re.search('zip',self.fname,re.I)
  55. g = re.search('gz',self.fname,re.I)
  56. if z:
  57. print 'zip file present in the URL.'
  58. self.zip = True
  59. self.gz = False
  60. elif g:
  61. print 'gz file present in the URL'
  62. self.gz = True
  63. self.zip = False
  64. else:
  65. print 'zip/gz file not present. Check the URL.'
  66. return
  67. print("File name is =" + self.fname)
  68. # Join the base path and the zip/tar file name to crate a complete Local file path.
  69. self.fpath = self.base_path + self.fname
  70. print('Your local file path will be=' + self.fpath)
  71. except AssertionError, e:
  72. print e.args[0]
  73. sys.exit(1)
  74. # Download function - to download the SDK from the URL to the local machine.
  75. def download(self,url,fpath,fname):
  76. try:
  77. # Start the download
  78. print("Downloading...Please be patient!")
  79. urllib.urlretrieve(url,filename = fname)
  80. print('Download was successful.')
  81. except ValueError: # Handles broken URL errors.
  82. print 'The URL is ether broken or the file does not exist. Please enter the correct URL.'
  83. raise
  84. except urllib2.URLError: # Handles URL errors
  85. print '\nURL not correct. Check again!'
  86. raise
  87. # Function to extract the downloaded zipfile.
  88. def extract(self, zipfilepath, extfile):
  89. try:
  90. # Timeout is set to 30 seconds.
  91. timeout = 30
  92. # Change the directory to the location of the zip file.
  93. try:
  94. os.chdir(zipfilepath)
  95. except OSError:
  96. # Will reach here if zip file doesnt exist
  97. print 'O/S Error:' + zipfilepath + 'does not exist'
  98. raise
  99. # Get the folder name of Jetpack to get the exact version number.
  100. if self.zip:
  101. try:
  102. f = zipfile.ZipFile(extfile, "r")
  103. except IOError as (errno, strerror): # Handles file errors
  104. print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
  105. raise
  106. list = f.namelist()[0]
  107. temp_name = list.split('/')
  108. print('Folder Name= ' +temp_name[0])
  109. self.folder_name = temp_name[0]
  110. elif self.gz:
  111. try:
  112. f = tarfile.open(extfile,'r')
  113. except IOError as (errno, strerror): # Handles file errors
  114. print "I/O error - Cannot perform extract operation: {1}".format(errno, strerror)
  115. raise
  116. list = f.getnames()[0]
  117. temp_name = list.split('/')
  118. print('Folder Name= ' +temp_name[0])
  119. self.folder_name = temp_name[0]
  120. print ('Starting to Extract...')
  121. # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
  122. # timeout, the process is killed.
  123. kill_check = threading.Event()
  124. if self.zip:
  125. # Call the command to unzip the file.
  126. if self.mswindows:
  127. zipfile.ZipFile.extractall(f)
  128. else:
  129. p = subprocess.Popen('unzip '+extfile, stdout=subprocess.PIPE, shell=True)
  130. pid = p.pid
  131. elif self.gz:
  132. # Call the command to untar the file.
  133. if self.mswindows:
  134. tarfile.TarFile.extractall(f)
  135. else:
  136. p = subprocess.Popen('tar -xf '+extfile, stdout=subprocess.PIPE, shell=True)
  137. pid = p.pid
  138. #No need to handle for windows because windows automatically replaces old files with new files. It does not ask the user(as it does in Mac/Unix)
  139. if self.mswindows==False:
  140. watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows ))
  141. watch.start()
  142. (stdout, stderr) = p.communicate()
  143. watch.cancel() # if it's still waiting to run
  144. success = not kill_check.isSet()
  145. # Abort process if process fails.
  146. if not success:
  147. raise RuntimeError
  148. kill_check.clear()
  149. print('Extraction Successful.')
  150. except RuntimeError:
  151. print "Ending the program"
  152. sys.exit(1)
  153. except:
  154. print "Error during file extraction: ", sys.exc_info()[0]
  155. raise
  156. # Function to run the cfx testall comands and to make sure the SDK is not broken.
  157. def run_testall(self, home_path, folder_name):
  158. try:
  159. timeout = 500
  160. self.new_dir = home_path + folder_name
  161. try:
  162. os.chdir(self.new_dir)
  163. except OSError:
  164. # Will reach here if the jetpack 0.X directory doesnt exist
  165. print 'O/S Error: Jetpack directory does not exist at ' + self.new_dir
  166. raise
  167. print '\nStarting tests...'
  168. # Timeout code. The subprocess.popen exeutes the command and the thread waits for a timeout. If the process does not finish within the mentioned-
  169. # timeout, the process is killed.
  170. kill_check = threading.Event()
  171. # Set the path for the logs. They will be in the parent directory of the Jetpack SDK.
  172. log_path = home_path + 'tests.log'
  173. # Subprocess call to set up the jetpack environment and to start the tests. Also sends the output to a log file.
  174. if self.bin != None:
  175. if self.mswindows:
  176. p = subprocess.Popen("bin\\activate && cfx testall -a firefox -b \"" + self.bin + "\"" , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  177. proc_handle = p._handle
  178. (stdout,stderr) = p.communicate()
  179. else:
  180. p = subprocess.Popen('. bin/activate; cfx testall -a firefox -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  181. pid = p.pid
  182. (stdout,stderr) = p.communicate()
  183. elif self.bin == None:
  184. if self.mswindows:
  185. p=subprocess.Popen('bin\\activate && cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  186. proc_handle = p._handle
  187. (stdout,stderr) = p.communicate()
  188. else:
  189. p = subprocess.Popen('. bin/activate; cfx testall -a firefox > '+log_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  190. pid = p.pid
  191. (stdout,stderr) = p.communicate()
  192. #Write the output to log file
  193. f=open(log_path,"w")
  194. f.write(stdout+stderr)
  195. f.close()
  196. #Watchdog for timeout process
  197. if self.mswindows:
  198. watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
  199. else:
  200. watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
  201. watch.start()
  202. watch.cancel() # if it's still waiting to run
  203. success = not kill_check.isSet()
  204. if not success:
  205. raise RuntimeError
  206. kill_check.clear()
  207. if p.returncode!=0:
  208. print('\nAll tests were not successful. Check the test-logs in the jetpack directory.')
  209. result_sdk(home_path)
  210. #sys.exit(1)
  211. raise RuntimeError
  212. else:
  213. ret_code=result_sdk(home_path)
  214. if ret_code==0:
  215. print('\nAll tests were successful. Yay \o/ . Running a sample package test now...')
  216. else:
  217. print ('\nThere were errors during the tests.Take a look at logs')
  218. raise RuntimeError
  219. except RuntimeError:
  220. print "Ending the program"
  221. sys.exit(1)
  222. except:
  223. print "Error during the testall command execution:", sys.exc_info()[0]
  224. raise
  225. def package(self, example_dir):
  226. try:
  227. timeout = 30
  228. print '\nNow Running packaging tests...'
  229. kill_check = threading.Event()
  230. # Set the path for the example logs. They will be in the parent directory of the Jetpack SDK.
  231. exlog_path = example_dir + 'test-example.log'
  232. # Subprocess call to test the sample example for packaging.
  233. if self.bin!=None:
  234. if self.mswindows:
  235. p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data --static-args="{\\"quitWhenDone\\":true}" -b \"" + self.bin + "\"' , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  236. proc_handle = p._handle
  237. (stdout, stderr) = p.communicate()
  238. else:
  239. p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' -b ' + self.bin , stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  240. pid = p.pid
  241. (stdout, stderr) = p.communicate()
  242. elif self.bin==None:
  243. if self.mswindows:
  244. p = subprocess.Popen('bin\\activate && cfx run --pkgdir examples\\reading-data --static-args="{\\"quitWhenDone\\":true}"', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  245. proc_handle = p._handle
  246. (stdout, stderr) = p.communicate()
  247. else:
  248. p = subprocess.Popen('. bin/activate; cfx run --pkgdir examples/reading-data --static-args=\'{\"quitWhenDone\":true}\' ', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  249. pid = p.pid
  250. (stdout, stderr) = p.communicate()
  251. #Write the output to log file
  252. f=open(exlog_path,"w")
  253. f.write(stdout+stderr)
  254. f.close()
  255. #Watch dog for timeout process
  256. if self.mswindows:
  257. watch = threading.Timer(timeout, kill_process, args=(proc_handle, kill_check, self.mswindows))
  258. else:
  259. watch = threading.Timer(timeout, kill_process, args=(pid, kill_check, self.mswindows))
  260. watch.start()
  261. watch.cancel() # if it's still waiting to run
  262. success = not kill_check.isSet()
  263. if not success:
  264. raise RuntimeError
  265. kill_check.clear()
  266. if p.returncode != 0:
  267. print('\nSample tests were not executed correctly. Check the test-example log in jetpack diretory.')
  268. result_example(example_dir)
  269. raise RuntimeError
  270. else:
  271. ret_code=result_example(example_dir)
  272. if ret_code==0:
  273. print('\nAll tests pass. The SDK is working! Yay \o/')
  274. else:
  275. print ('\nTests passed with warning.Take a look at logs')
  276. sys.exit(1)
  277. except RuntimeError:
  278. print "Ending program"
  279. sys.exit(1)
  280. except:
  281. print "Error during running sample tests:", sys.exc_info()[0]
  282. raise
  283. def result_sdk(sdk_dir):
  284. log_path = sdk_dir + 'tests.log'
  285. print 'Results are logged at:' + log_path
  286. try:
  287. f = open(log_path,'r')
  288. # Handles file errors
  289. except IOError :
  290. print 'I/O error - Cannot open test log at ' + log_path
  291. raise
  292. for line in reversed(open(log_path).readlines()):
  293. if line.strip()=='FAIL':
  294. print ('\nOverall result - FAIL. Look at the test log at '+log_path)
  295. return 1
  296. return 0
  297. def result_example(sdk_dir):
  298. exlog_path = sdk_dir + 'test-example.log'
  299. print 'Sample test results are logged at:' + exlog_path
  300. try:
  301. f = open(exlog_path,'r')
  302. # Handles file errors
  303. except IOError :
  304. print 'I/O error - Cannot open sample test log at ' + exlog_path
  305. raise
  306. #Read the file in reverse and check for the keyword 'FAIL'.
  307. for line in reversed(open(exlog_path).readlines()):
  308. if line.strip()=='FAIL':
  309. print ('\nOverall result for Sample tests - FAIL. Look at the test log at '+exlog_path)
  310. return 1
  311. return 0
  312. def kill_process(process, kill_check, mswindows):
  313. print '\nProcess Timedout. Killing the process. Please Rerun this script.'
  314. if mswindows:
  315. win32api.TerminateProcess(process, -1)
  316. else:
  317. os.kill(process, signal.SIGKILL)
  318. kill_check.set()# tell the main routine to kill. Used SIGKILL to hard kill the process.
  319. return
  320. if __name__ == "__main__":
  321. obj = SDK()
  322. obj.download(obj.link,obj.fpath,obj.fname)
  323. obj.extract(obj.base_path,obj.fname)
  324. obj.run_testall(obj.base_path,obj.folder_name)
  325. obj.package(obj.base_path)