ptl_test_info.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. # coding: utf-8
  2. # Copyright (C) 1994-2018 Altair Engineering, Inc.
  3. # For more information, contact Altair at www.altair.com.
  4. #
  5. # This file is part of the PBS Professional ("PBS Pro") software.
  6. #
  7. # Open Source License Information:
  8. #
  9. # PBS Pro is free software. You can redistribute it and/or modify it under the
  10. # terms of the GNU Affero General Public License as published by the Free
  11. # Software Foundation, either version 3 of the License, or (at your option) any
  12. # later version.
  13. #
  14. # PBS Pro is distributed in the hope that it will be useful, but WITHOUT ANY
  15. # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16. # FOR A PARTICULAR PURPOSE.
  17. # See the GNU Affero General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU Affero General Public License
  20. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. #
  22. # Commercial License Information:
  23. #
  24. # For a copy of the commercial license terms and conditions,
  25. # go to: (http://www.pbspro.com/UserArea/agreement.html)
  26. # or contact the Altair Legal Department.
  27. #
  28. # Altair’s dual-license business model allows companies, individuals, and
  29. # organizations to create proprietary derivative works of PBS Pro and
  30. # distribute them - whether embedded or bundled with other software -
  31. # under a commercial license agreement.
  32. #
  33. # Use of Altair’s trademarks, including but not limited to "PBS™",
  34. # "PBS Professional®", and "PBS Pro™" and Altair’s logos is subject to Altair's
  35. # trademark licensing policies.
  36. import sys
  37. import logging
  38. from nose.plugins.base import Plugin
  39. from ptl.utils.pbs_testsuite import PBSTestSuite
  40. from ptl.utils.plugins.ptl_test_tags import TAGKEY
  41. from copy import deepcopy
  42. log = logging.getLogger('nose.plugins.PTLTestInfo')
  43. class FakeRunner(object):
  44. def __init__(self, config):
  45. self.config = config
  46. def run(self, test):
  47. self.config.plugins.finalize(None)
  48. sys.exit(0)
  49. class PTLTestInfo(Plugin):
  50. """
  51. Load test cases from given parameter
  52. """
  53. name = 'PTLTestInfo'
  54. score = sys.maxint - 1
  55. logger = logging.getLogger(__name__)
  56. def __init__(self):
  57. self.list_test = None
  58. self.showinfo = None
  59. self.verbose = None
  60. self.gen_ts_tree = None
  61. self.suites = []
  62. self._tree = {}
  63. self.total_suite = 0
  64. self.total_case = 0
  65. self.__ts_tree = {}
  66. self.__tags_tree = {'NoTags': {}}
  67. def options(self, parser, env):
  68. """
  69. Register command line options
  70. """
  71. pass
  72. def set_data(self, suites, list_test, showinfo, verbose, gen_ts_tree):
  73. """
  74. Set the data required for running the tests
  75. :param suites: Test suites to run
  76. :param list_test: List of test to run
  77. :param gen_ts_tree: Generate test suite tree
  78. """
  79. self.suites = suites.split(',')
  80. self.list_test = list_test
  81. self.showinfo = showinfo
  82. self.verbose = verbose
  83. self.gen_ts_tree = gen_ts_tree
  84. def configure(self, options, config):
  85. """
  86. Configure the plugin and system, based on selected options
  87. :param options: Options to configure plugin and system
  88. """
  89. self.config = config
  90. self.enabled = True
  91. def prepareTestRunner(self, runner):
  92. return FakeRunner(config=self.config)
  93. def wantClass(self, cls):
  94. """
  95. Is the class wanted?
  96. """
  97. if not issubclass(cls, PBSTestSuite):
  98. return False
  99. if cls.__name__ == 'PBSTestSuite':
  100. return False
  101. self._tree.setdefault(cls.__name__, cls)
  102. if len(cls.__bases__) > 0:
  103. self.wantClass(cls.__bases__[0])
  104. return False
  105. def wantFunction(self, function):
  106. """
  107. Is the function wanted?
  108. """
  109. return False
  110. def wantMethod(self, method):
  111. """
  112. Is the method wanted?
  113. """
  114. return False
  115. def _get_hierarchy(self, cls, level=0):
  116. delim = ' ' * level
  117. msg = [delim + cls.__name__]
  118. subclses = cls.__subclasses__()
  119. for subcls in subclses:
  120. msg.extend(self._get_hierarchy(subcls, level + 1))
  121. return msg
  122. def _print_suite_info(self, suite):
  123. w = sys.stdout
  124. self.total_suite += 1
  125. if self.list_test:
  126. w.write('\n\n')
  127. w.write('Test Suite: %s\n\n' % suite.__name__)
  128. w.write(' file: %s.py\n\n' % suite.__module__.replace('.', '/'))
  129. w.write(' module: %s\n\n' % suite.__module__)
  130. tags = getattr(suite, TAGKEY, None)
  131. if tags is not None:
  132. w.write(' Tags: %s\n\n' % (', '.join(tags)))
  133. w.write(' Suite Doc: \n')
  134. for l in str(suite.__doc__).split('\n'):
  135. w.write(' %s\n' % l)
  136. dcl = suite.__dict__
  137. cases = []
  138. for k in dcl.keys():
  139. if k.startswith('test_'):
  140. k = getattr(suite, k)
  141. try:
  142. k.__name__
  143. except:
  144. # not a test case, ignore
  145. continue
  146. self.total_case += 1
  147. cases.append('\t%s\n' % (k.__name__))
  148. if self.verbose:
  149. tags = getattr(k, TAGKEY, None)
  150. if tags is not None:
  151. cases.append('\n\t Tags: %s\n\n' %
  152. (', '.join(tags)))
  153. doc = k.__doc__
  154. if doc is not None:
  155. cases.append('\t Test Case Doc: \n')
  156. for l in str(doc).split('\n'):
  157. cases.append('\t%s\n' % (l))
  158. if len(cases) > 0:
  159. w.write(' Test Cases: \n')
  160. w.writelines(cases)
  161. if self.list_test or self.showinfo:
  162. lines = self._get_hierarchy(suite, 1)[1:]
  163. if len(lines) > 0:
  164. w.write('\n Test suite hierarchy:\n')
  165. for l in lines:
  166. w.write(l + '\n')
  167. def _gen_ts_tree(self, suite):
  168. n = suite.__name__
  169. tsd = {}
  170. tsd['doc'] = str(suite.__doc__)
  171. tstags = getattr(suite, TAGKEY, [])
  172. numnodes = 1
  173. for tag in tstags:
  174. if 'numnodes' in tag:
  175. numnodes = tag.split('=')[1].strip()
  176. break
  177. tsd['tags'] = tstags if len(tstags) > 0 else "None"
  178. tsd['numnodes'] = str(numnodes)
  179. tsd['file'] = suite.__module__.replace('.', '/') + '.py'
  180. tsd['module'] = suite.__module__
  181. dcl = suite.__dict__
  182. tcs = {}
  183. for k in dcl.keys():
  184. if k.startswith('test_'):
  185. tcd = {}
  186. tc = getattr(suite, k)
  187. try:
  188. tc.__name__
  189. except:
  190. # not a test case, ignore
  191. continue
  192. tcd['doc'] = str(tc.__doc__)
  193. tctags = sorted(set(tstags + getattr(tc, TAGKEY, [])))
  194. numnodes = 1
  195. for tag in tctags:
  196. if 'numnodes' in tag:
  197. numnodes = tag.split('=')[1].strip()
  198. break
  199. tcd['tags'] = tctags if len(tctags) > 0 else "None"
  200. tcd['numnodes'] = str(numnodes)
  201. tcs[k] = deepcopy(tcd)
  202. if len(tctags) > 0:
  203. for tag in tctags:
  204. if tag not in self.__tags_tree.keys():
  205. self.__tags_tree[tag] = {}
  206. if n not in self.__tags_tree[tag].keys():
  207. self.__tags_tree[tag][n] = deepcopy(tsd)
  208. if 'tclist' not in self.__tags_tree[tag][n].keys():
  209. self.__tags_tree[tag][n]['tclist'] = {}
  210. self.__tags_tree[tag][n]['tclist'][k] = deepcopy(tcd)
  211. else:
  212. if n not in self.__tags_tree['NoTags'].keys():
  213. self.__tags_tree['NoTags'][n] = deepcopy(tsd)
  214. if 'tclist' not in self.__tags_tree['NoTags'][n].keys():
  215. self.__tags_tree['NoTags'][n]['tclist'] = {}
  216. self.__tags_tree['NoTags'][n]['tclist'][k] = deepcopy(tcd)
  217. if len(tcs.keys()) > 0:
  218. self.__ts_tree[n] = deepcopy(tsd)
  219. self.__ts_tree[n]['tclist'] = tcs
  220. def finalize(self, result):
  221. if self.list_test or self.gen_ts_tree:
  222. suites = self._tree.keys()
  223. else:
  224. suites = self.suites
  225. suites.sort()
  226. unknown = []
  227. if self.gen_ts_tree:
  228. func = self._gen_ts_tree
  229. else:
  230. func = self._print_suite_info
  231. for k in suites:
  232. try:
  233. suite = eval(k, globals(), self._tree)
  234. except:
  235. unknown.append(k)
  236. continue
  237. func(suite)
  238. if self.list_test:
  239. w = sys.stdout
  240. w.write('\n\n')
  241. w.write('Total number of Test Suites: %d\n' % (self.total_suite))
  242. w.write('Total number of Test Cases: %d\n' % (self.total_case))
  243. elif self.gen_ts_tree:
  244. tsdata = ''
  245. tagsdata = ''
  246. try:
  247. import json
  248. tsdata = json.dumps(self.__ts_tree, indent=4)
  249. tagsdata = json.dumps(self.__tags_tree, indent=4)
  250. except ImportError:
  251. try:
  252. import simplejson
  253. tsdata = simplejson.dumps(self.__ts_tree, indent=4)
  254. tagsdata = simplejson.dumps(self.__tags_tree, indent=4)
  255. except ImportError:
  256. _pre = str(self.__ts_tree).replace('"', '\\"')
  257. tsdata = _pre.replace('\'', '"')
  258. _pre = str(self.__tags_tree).replace('"', '\\"')
  259. tagsdata = _pre.replace('\'', '"')
  260. f = open('ptl_ts_tree.json', 'w+')
  261. f.write(tsdata)
  262. f.close()
  263. f = open('ptl_tags_tree.json', 'w+')
  264. f.write(tagsdata)
  265. f.close()
  266. if len(unknown) > 0:
  267. self.logger.error('Unknown testsuite(s): %s' % (','.join(unknown)))