PageRenderTime 66ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/python/gaia-ui-tests/gaiatest/tests/endurance/submit_to_datazilla.py

https://gitlab.com/learnability/gaia
Python | 323 lines | 242 code | 46 blank | 35 comment | 57 complexity | 26c2e6aee93728e4f63788f5f9cd0a44 MD5 | raw file
  1. #!/usr/bin/env python
  2. #
  3. # How to submit gaia-ui endurance test results to Datazilla:
  4. # 1) Attach a b2g device with an engineering build
  5. # 2) Issue 'adb forward tcp:2828 tcp:2828' cmd
  6. # 3) Run a gaia-ui endurance test, resulting in a checkpoint_*_summary.log results file
  7. # 4) Keep the device connected, and turn on wifi (so device can get a macAddress), then
  8. # 5) Run this script and provide the command line options/values, including '--print'
  9. # 6) Review the results as displayed in the console, verify
  10. # 7) To submit the results, repeat the cmd but use '--submit' instead of '--print'
  11. from optparse import OptionParser
  12. from StringIO import StringIO
  13. import os
  14. from urlparse import urlparse
  15. import xml.dom.minidom
  16. import zipfile
  17. import time
  18. import dzclient
  19. import gaiatest
  20. from marionette_driver import Marionette
  21. import mozdevice
  22. class DatazillaPerfPoster(object):
  23. def __init__(self, marionette, datazilla_config=None, sources=None):
  24. self.marionette = marionette
  25. settings = gaiatest.GaiaData(self.marionette).all_settings # get all settings
  26. mac_address = self.marionette.execute_script('return navigator.mozWifiManager && navigator.mozWifiManager.macAddress;')
  27. self.submit_report = True
  28. self.ancillary_data = {}
  29. if gaiatest.GaiaDevice(self.marionette).is_android_build:
  30. # get gaia, gecko and build revisions
  31. try:
  32. device_manager = mozdevice.DeviceManagerADB()
  33. app_zip = device_manager.pullFile('/data/local/webapps/settings.gaiamobile.org/application.zip')
  34. with zipfile.ZipFile(StringIO(app_zip)).open('resources/gaia_commit.txt') as f:
  35. self.ancillary_data['gaia_revision'] = f.read().splitlines()[0]
  36. except zipfile.BadZipfile:
  37. # the zip file will not exist if Gaia has not been flashed to
  38. # the device, so we fall back to the sources file
  39. pass
  40. try:
  41. sources_xml = sources and xml.dom.minidom.parse(sources) or xml.dom.minidom.parseString(device_manager.catFile('system/sources.xml'))
  42. for element in sources_xml.getElementsByTagName('project'):
  43. path = element.getAttribute('path')
  44. revision = element.getAttribute('revision')
  45. if not self.ancillary_data.get('gaia_revision') and path in 'gaia':
  46. self.ancillary_data['gaia_revision'] = revision
  47. if path in ['gecko', 'build']:
  48. self.ancillary_data['_'.join([path, 'revision'])] = revision
  49. except:
  50. pass
  51. self.required = {
  52. 'gaia revision': self.ancillary_data.get('gaia_revision'),
  53. 'gecko revision': self.ancillary_data.get('gecko_revision'),
  54. 'build revision': self.ancillary_data.get('build_revision'),
  55. 'protocol': datazilla_config['protocol'],
  56. 'host': datazilla_config['host'],
  57. 'project': datazilla_config['project'],
  58. 'branch': datazilla_config['branch'],
  59. 'oauth key': datazilla_config['oauth_key'],
  60. 'oauth secret': datazilla_config['oauth_secret'],
  61. 'machine name': mac_address or 'unknown',
  62. 'device name': datazilla_config['device_name'],
  63. 'os version': settings.get('deviceinfo.os'),
  64. 'id': settings.get('deviceinfo.platform_build_id')}
  65. for key, value in self.required.items():
  66. if not value:
  67. self.submit_report = False
  68. print '\nMissing required DataZilla field: %s' % key
  69. if not self.submit_report:
  70. print '\n***Reports will not be submitted to DataZilla***'
  71. def post_to_datazilla(self, results, app_name):
  72. # Prepare DataZilla results
  73. res = dzclient.DatazillaResult()
  74. test_suite = app_name.replace(' ', '_').lower()
  75. res.add_testsuite(test_suite)
  76. for metric in results.keys():
  77. res.add_test_results(test_suite, metric, results[metric])
  78. req = dzclient.DatazillaRequest(
  79. protocol=self.required.get('protocol'),
  80. host=self.required.get('host'),
  81. project=self.required.get('project'),
  82. oauth_key=self.required.get('oauth key'),
  83. oauth_secret=self.required.get('oauth secret'),
  84. machine_name=self.required.get('machine name'),
  85. os='Firefox OS',
  86. os_version=self.required.get('os version'),
  87. platform='Gonk',
  88. build_name='B2G',
  89. version='prerelease',
  90. revision=self.ancillary_data.get('gaia_revision'),
  91. branch=self.required.get('branch'),
  92. id=self.required.get('id'))
  93. # Send DataZilla results
  94. req.add_datazilla_result(res)
  95. for dataset in req.datasets():
  96. dataset['test_build'].update(self.ancillary_data)
  97. dataset['test_machine'].update({'type': self.required.get('device name')})
  98. print '\nSubmitting results to DataZilla: %s' % dataset
  99. response = req.send(dataset)
  100. print 'Response: %s\n' % response.read()
  101. class dzOptionParser(OptionParser):
  102. def __init__(self, **kwargs):
  103. OptionParser.__init__(self, **kwargs)
  104. self.add_option('--file',
  105. action='store',
  106. dest='results_file',
  107. metavar='str',
  108. help='Json checkpoint results file from the endurance test')
  109. self.add_option('--dz-url',
  110. action='store',
  111. dest='datazilla_url',
  112. default='https://datazilla.mozilla.org',
  113. metavar='str',
  114. help='datazilla server url (default: %default)')
  115. self.add_option('--dz-project',
  116. action='store',
  117. dest='datazilla_project',
  118. metavar='str',
  119. help='datazilla project name')
  120. self.add_option('--dz-branch',
  121. action='store',
  122. dest='datazilla_branch',
  123. metavar='str',
  124. help='datazilla branch name')
  125. self.add_option('--dz-device',
  126. action='store',
  127. dest='datazilla_device_name',
  128. metavar='str',
  129. help='datazilla device name')
  130. self.add_option('--dz-key',
  131. action='store',
  132. dest='datazilla_key',
  133. metavar='str',
  134. help='oauth key for datazilla server')
  135. self.add_option('--dz-secret',
  136. action='store',
  137. dest='datazilla_secret',
  138. metavar='str',
  139. help='oauth secret for datazilla server')
  140. self.add_option('--sources',
  141. action='store',
  142. dest='sources',
  143. metavar='str',
  144. help='Optional path to sources.xml containing project revisions')
  145. self.add_option('--submit',
  146. action='store_true',
  147. dest='send_to_datazilla',
  148. help='Send results to datazilla')
  149. self.add_option('--process-dir',
  150. action='store',
  151. dest='process_dir',
  152. metavar='str',
  153. help='Process all *_summary.log files in the given folder')
  154. def datazilla_config(self, options):
  155. if options.sources:
  156. if not os.path.exists(options.sources):
  157. raise Exception('--sources file does not exist')
  158. datazilla_url = urlparse(options.datazilla_url)
  159. datazilla_config = {
  160. 'protocol': datazilla_url.scheme,
  161. 'host': datazilla_url.hostname,
  162. 'project': options.datazilla_project,
  163. 'branch': options.datazilla_branch,
  164. 'device_name': options.datazilla_device_name,
  165. 'oauth_key': options.datazilla_key,
  166. 'oauth_secret': options.datazilla_secret}
  167. return datazilla_config
  168. def cli():
  169. parser = dzOptionParser(usage='%prog file [options]')
  170. options, args = parser.parse_args()
  171. # Ensure have all required options
  172. if (not options.datazilla_project or not options.datazilla_branch
  173. or not options.datazilla_key or not options.datazilla_secret):
  174. parser.print_help()
  175. parser.exit()
  176. # Either a single file or option to process all in given folder
  177. if (not options.results_file) and (not options.process_dir):
  178. parser.print_help()
  179. parser.exit()
  180. if options.results_file and options.process_dir:
  181. parser.print_help()
  182. parser.exit()
  183. # Ensure results file actually exists
  184. if options.results_file:
  185. if not os.path.exists(options.results_file):
  186. raise Exception('%s file does not exist' %options.results_file)
  187. if options.process_dir:
  188. if not os.path.exists(options.process_dir):
  189. raise Exception("Process all path '%s' does not exist" %options.process_dir)
  190. # Parse config options
  191. datazilla_config = parser.datazilla_config(options)
  192. # Start marionette session
  193. marionette = Marionette(host='localhost', port=2828) # TODO command line option for address
  194. marionette.start_session()
  195. # Create datazilla post object
  196. poster = DatazillaPerfPoster(marionette, datazilla_config=datazilla_config, sources=options.sources)
  197. # If was an error getting required values then poster.submit_report will be false;
  198. # if it is true then ok to submit if user wants to
  199. if poster.submit_report:
  200. if not options.send_to_datazilla:
  201. poster.submit_report = False
  202. # Parse checkpoint results from provided summary log file
  203. checkpoint_summary = {}
  204. results = {}
  205. summary_file_list = []
  206. if options.process_dir:
  207. # All files in the given path
  208. file_path = options.process_dir
  209. print "\nSearching for *_summary.log files in %s\n" % options.process_dir
  210. entire_file_list = os.listdir(file_path)
  211. if len(entire_file_list) == 0:
  212. raise Exception("No checkpoint *_summary.log files were found in the given path")
  213. for found_file in entire_file_list:
  214. if found_file.endswith("summary.log") and found_file != "avg_b2g_rss_suite_summary.log":
  215. summary_file_list.append("%s/%s" % (file_path, found_file))
  216. if len(summary_file_list) == 0:
  217. raise Exception("No checkpoint *_summary.log files were found in the given path")
  218. print "Found the following checkpoint summary files to process:\n"
  219. for x in summary_file_list:
  220. print "%s" % x
  221. print "\n" + "-" * 50
  222. else:
  223. # Just one file
  224. summary_file_list = [options.results_file]
  225. for next_file in summary_file_list:
  226. # Clear results as only want results for current file being processed
  227. results = {}
  228. print "\nProcessing results in '%s'\n" % next_file
  229. summary_file = open(next_file, 'r')
  230. read_in = summary_file.read().split("\n")
  231. summary_file.close()
  232. for x in read_in:
  233. try:
  234. if x.find(':') != -1: # Ignore empty lines ie. last line of file which is empty
  235. k, v = x.split(': ')
  236. if k in "total_iterations" or k in "checkpoint_interval":
  237. checkpoint_summary[k] = int(v)
  238. elif k in "b2g_rss":
  239. checkpoint_summary[k] = v.split(',') # list of strings
  240. checkpoint_summary[k] = map(int, checkpoint_summary[k]) # list of ints
  241. elif k in "test_name":
  242. # Prefix test name so all tests are grouped together in datazilla
  243. checkpoint_summary[k] = "endurance_" + v
  244. else:
  245. checkpoint_summary[k] = v
  246. except:
  247. raise Exception("Value missing from '%s', cannot proceed." % options.results_file)
  248. # Make sure we have app_under_test
  249. if (checkpoint_summary['app_under_test'] == "none"):
  250. raise Exception("Checkpoint summary file is missing value for 'app_under_test'. Cannot proceed.")
  251. # Results dictionary required format example
  252. # {'test_name': [180892, 180892, 181980, 181852, 180828, 182012, 183652, 182972, 183052, 183052]}
  253. results[checkpoint_summary['test_name']] = checkpoint_summary['b2g_rss']
  254. # Display the Datazilla configuration
  255. print 'Datazilla configuration:'
  256. print "\napplication (datazilla 'suite'): %s" % checkpoint_summary['app_under_test']
  257. for key, value in poster.required.items():
  258. print key + ":", value
  259. # Submit or print the results
  260. if poster.submit_report:
  261. #poster.post_to_datazilla(results, checkpoint_summary['test_name'])
  262. poster.post_to_datazilla(results, checkpoint_summary['app_under_test'])
  263. else:
  264. print "\nCheckpoint summary for test '%s':\n" % checkpoint_summary['test_name']
  265. print checkpoint_summary
  266. print '\nEndurance test results data:\n'
  267. print results
  268. print "\nTo submit results, fix any missing fields and use the '--submit' option.\n"
  269. if options.process_dir:
  270. # Sleep between submissions
  271. print "Pausing...\n"
  272. time.sleep(30)
  273. print "-" * 50
  274. if options.process_dir:
  275. print "\nFinished processing all files.\n"
  276. if __name__ == '__main__':
  277. cli()