1
0

create_test.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. #!/usr/bin/python3
  2. #
  3. # --- BEGIN COPYRIGHT BLOCK ---
  4. # Copyright (C) 2020 Red Hat, Inc.
  5. # All rights reserved.
  6. #
  7. # License: GPL (version 3 or any later version).
  8. # See LICENSE for details.
  9. # --- END COPYRIGHT BLOCK ---
  10. import optparse
  11. import os
  12. import re
  13. import sys
  14. import uuid
  15. from lib389 import topologies
  16. """This script generates a template test script that handles the
  17. non-interesting parts of a test script:
  18. - topology fixture that doesn't exist in in lib389/topologies.py
  19. - test function (to be completed by the user),
  20. - run-isolated function
  21. """
  22. def displayUsage():
  23. """Display the usage"""
  24. print ('\nUsage:\ncreate_ticket.py -t|--ticket <ticket number> ' +
  25. '-s|--suite <suite name> ' +
  26. '[ i|--instances <number of standalone instances> ' +
  27. '[ -m|--suppliers <number of suppliers> -h|--hubs <number of hubs> ' +
  28. '-c|--consumers <number of consumers> ] -o|--outputfile ]\n')
  29. print ('If only "-t" is provided then a single standalone instance is ' +
  30. 'created. Or you can create a test suite script using ' +
  31. '"-s|--suite" instead of using "-t|--ticket". The "-i" option ' +
  32. 'can add multiple standalone instances (maximum 99). However, you' +
  33. ' can not mix "-i" with the replication options (-m, -h , -c). ' +
  34. 'There is a maximum of 99 suppliers, 99 hubs, and 99 consumers.')
  35. print('If "-s|--suite" option was chosen, then no topology would be added ' +
  36. 'to the test script. You can find predefined fixtures in the lib389/topologies.py ' +
  37. 'and use them or write a new one if you have a special case.')
  38. exit(1)
  39. def writeFinalizer():
  40. """Write the finalizer function - delete/stop each instance"""
  41. def writeInstanceOp(action):
  42. TEST.write(' map(lambda inst: inst.{}(), topology.all_insts.values())\n'.format(action))
  43. TEST.write('\n def fin():\n')
  44. TEST.write(' """If we are debugging just stop the instances, otherwise remove them"""\n\n')
  45. TEST.write(' if DEBUGGING:\n')
  46. writeInstanceOp('stop')
  47. TEST.write(' else:\n')
  48. writeInstanceOp('delete')
  49. TEST.write('\n request.addfinalizer(fin)')
  50. TEST.write('\n\n')
  51. def get_existing_topologies(inst, suppliers, hubs, consumers):
  52. """Check if the requested topology exists"""
  53. setup_text = ""
  54. if inst:
  55. if inst == 1:
  56. i = 'st'
  57. setup_text = "Standalone Instance"
  58. else:
  59. i = 'i{}'.format(inst)
  60. setup_text = "{} Standalone Instances".format(inst)
  61. else:
  62. i = ''
  63. if suppliers:
  64. ms = 'm{}'.format(suppliers)
  65. if len(setup_text) > 0:
  66. setup_text += ", "
  67. if suppliers == 1:
  68. setup_text += "Supplier Instance"
  69. else:
  70. setup_text += "{} Supplier Instances".format(suppliers)
  71. else:
  72. ms = ''
  73. if hubs:
  74. hs = 'h{}'.format(hubs)
  75. if len(setup_text) > 0:
  76. setup_text += ", "
  77. if hubs == 1:
  78. setup_text += "Hub Instance"
  79. else:
  80. setup_text += "{} Hub Instances".format(hubs)
  81. else:
  82. hs = ''
  83. if consumers:
  84. cs = 'c{}'.format(consumers)
  85. if len(setup_text) > 0:
  86. setup_text += ", "
  87. if consumers == 1:
  88. setup_text += "Consumer Instance"
  89. else:
  90. setup_text += "{} Consumer Instances".format(consumers)
  91. else:
  92. cs = ''
  93. my_topology = 'topology_{}{}{}{}'.format(i, ms, hs, cs)
  94. # Returns True in the first element of a list, if topology was found
  95. if my_topology in dir(topologies):
  96. return [True, my_topology, setup_text]
  97. else:
  98. return [False, my_topology, setup_text]
  99. def check_id_uniqueness(id_value):
  100. """Checks if ID is already present in other tests.
  101. create_test.py script should exist in the directory
  102. with a 'tests' dir.
  103. """
  104. tests_dir = os.path.join(os.getcwd(), 'tests')
  105. for root, dirs, files in os.walk(tests_dir):
  106. for name in files:
  107. if name.endswith('.py'):
  108. with open(os.path.join(root, name), "r") as cifile:
  109. for line in cifile:
  110. if re.search(str(id_value), line):
  111. return False
  112. return True
  113. desc = 'Script to generate an initial lib389 test script. ' + \
  114. 'This generates the topology, test, final, and run-isolated functions.'
  115. if len(sys.argv) > 0:
  116. parser = optparse.OptionParser(description=desc, add_help_option=False)
  117. # Script options
  118. parser.add_option('-t', '--ticket', dest='ticket', default=None)
  119. parser.add_option('-s', '--suite', dest='suite', default=None)
  120. parser.add_option('-i', '--instances', dest='inst', default='0')
  121. parser.add_option('-m', '--suppliers', dest='suppliers', default='0')
  122. parser.add_option('-h', '--hubs', dest='hubs', default='0')
  123. parser.add_option('-c', '--consumers', dest='consumers', default='0')
  124. parser.add_option('-o', '--outputfile', dest='filename', default=None)
  125. # Validate the options
  126. try:
  127. (args, opts) = parser.parse_args()
  128. except:
  129. displayUsage()
  130. if args.ticket is None and args.suite is None:
  131. print('Missing required ticket number/suite name')
  132. displayUsage()
  133. if args.ticket and args.suite:
  134. print('You must choose either "-t|--ticket" or "-s|--suite", ' +
  135. 'but not both.')
  136. displayUsage()
  137. if int(args.suppliers) == 0:
  138. if int(args.hubs) > 0 or int(args.consumers) > 0:
  139. print('You must use "-m|--suppliers" if you want to have hubs ' +
  140. 'and/or consumers')
  141. displayUsage()
  142. if not args.suppliers.isdigit() or \
  143. int(args.suppliers) > 99 or \
  144. int(args.suppliers) < 0:
  145. print('Invalid value for "--suppliers", it must be a number and it can' +
  146. ' not be greater than 99')
  147. displayUsage()
  148. if not args.hubs.isdigit() or int(args.hubs) > 99 or int(args.hubs) < 0:
  149. print('Invalid value for "--hubs", it must be a number and it can ' +
  150. 'not be greater than 99')
  151. displayUsage()
  152. if not args.consumers.isdigit() or \
  153. int(args.consumers) > 99 or \
  154. int(args.consumers) < 0:
  155. print('Invalid value for "--consumers", it must be a number and it ' +
  156. 'can not be greater than 99')
  157. displayUsage()
  158. if args.inst:
  159. if not args.inst.isdigit() or \
  160. int(args.inst) > 99 or \
  161. int(args.inst) < 0:
  162. print('Invalid value for "--instances", it must be a number ' +
  163. 'greater than 0 and not greater than 99')
  164. displayUsage()
  165. if int(args.inst) > 0:
  166. if int(args.suppliers) > 0 or \
  167. int(args.hubs) > 0 or \
  168. int(args.consumers) > 0:
  169. print('You can not mix "--instances" with replication.')
  170. displayUsage()
  171. # Extract usable values
  172. ticket = args.ticket
  173. suite = args.suite
  174. if args.inst == '0' and args.suppliers == '0' and args.hubs == '0' \
  175. and args.consumers == '0':
  176. instances = 1
  177. my_topology = [True, 'topology_st', "Standalone Instance"]
  178. else:
  179. instances = int(args.inst)
  180. suppliers = int(args.suppliers)
  181. hubs = int(args.hubs)
  182. consumers = int(args.consumers)
  183. my_topology = get_existing_topologies(instances, suppliers, hubs, consumers)
  184. filename = args.filename
  185. setup_text = my_topology[2]
  186. # Create/open the new test script file
  187. if not filename:
  188. if ticket:
  189. filename = 'ticket' + ticket + '_test.py'
  190. else:
  191. filename = suite + '_test.py'
  192. try:
  193. TEST = open(filename, "w")
  194. except IOError:
  195. print("Can\'t open file:", filename)
  196. exit(1)
  197. # Write the imports
  198. if my_topology[0]:
  199. topology_import = 'from lib389.topologies import {} as topo\n'.format(my_topology[1])
  200. else:
  201. topology_import = 'from lib389.topologies import create_topology\n'
  202. TEST.write('import logging\nimport pytest\nimport os\n')
  203. TEST.write('from lib389._constants import *\n')
  204. TEST.write('{}\n'.format(topology_import))
  205. TEST.write('log = logging.getLogger(__name__)\n\n')
  206. # Add topology function for non existing (in lib389/topologies.py) topologies only
  207. if not my_topology[0]:
  208. # Write the replication or standalone classes
  209. topologies_str = ""
  210. if suppliers > 0:
  211. topologies_str += " {} suppliers".format(suppliers)
  212. if hubs > 0:
  213. topologies_str += " {} hubs".format(hubs)
  214. if consumers > 0:
  215. topologies_str += " {} consumers".format(consumers)
  216. if instances > 0:
  217. topologies_str += " {} standalone instances".format(instances)
  218. # Write the 'topology function'
  219. TEST.write('\[email protected](scope="module")\n')
  220. TEST.write('def topo(request):\n')
  221. TEST.write(' """Create a topology with{}"""\n\n'.format(topologies_str))
  222. TEST.write(' topology = create_topology({\n')
  223. if suppliers > 0:
  224. TEST.write(' ReplicaRole.SUPPLIER: {},\n'.format(suppliers))
  225. if hubs > 0:
  226. TEST.write(' ReplicaRole.HUB: {},\n'.format(hubs))
  227. if consumers > 0:
  228. TEST.write(' ReplicaRole.CONSUMER: {},\n'.format(consumers))
  229. if instances > 0:
  230. TEST.write(' ReplicaRole.STANDALONE: {},\n'.format(instances))
  231. TEST.write(' })\n')
  232. TEST.write(' # You can write replica test here. Just uncomment the block and choose instances\n')
  233. TEST.write(' # replicas = Replicas(topology.ms["supplier1"])\n')
  234. TEST.write(' # replicas.test(DEFAULT_SUFFIX, topology.cs["consumer1"])\n')
  235. writeFinalizer()
  236. TEST.write(' return topology\n\n')
  237. tc_id = '0'
  238. while not check_id_uniqueness(tc_id): tc_id = uuid.uuid4()
  239. # Write the test function
  240. if ticket:
  241. TEST.write('\ndef test_ticket{}(topo):\n'.format(ticket))
  242. else:
  243. TEST.write('\ndef test_something(topo):\n')
  244. TEST.write(' """Specify a test case purpose or name here\n\n')
  245. TEST.write(' :id: {}\n'.format(tc_id))
  246. TEST.write(' :setup: ' + setup_text + '\n')
  247. TEST.write(' :steps:\n')
  248. TEST.write(' 1. Fill in test case steps here\n')
  249. TEST.write(' 2. And indent them like this (RST format requirement)\n')
  250. TEST.write(' :expectedresults:\n')
  251. TEST.write(' 1. Fill in the result that is expected\n')
  252. TEST.write(' 2. For each test step\n')
  253. TEST.write(' """\n\n')
  254. TEST.write(' # If you need any test suite initialization,\n')
  255. TEST.write(' # please, write additional fixture for that (including finalizer).\n'
  256. ' # Topology for suites are predefined in lib389/topologies.py.\n\n')
  257. TEST.write(' # If you need host, port or any other data about instance,\n')
  258. TEST.write(' # Please, use the instance object attributes for that (for example, topo.ms["supplier1"].serverid)\n\n\n')
  259. # Write the main function
  260. TEST.write("if __name__ == '__main__':\n")
  261. TEST.write(' # Run isolated\n')
  262. TEST.write(' # -s for DEBUG mode\n')
  263. TEST.write(' CURRENT_FILE = os.path.realpath(__file__)\n')
  264. TEST.write(' pytest.main(["-s", CURRENT_FILE])\n\n')
  265. # Done, close things up
  266. TEST.close()
  267. print('Created: ' + filename)