framework_test.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import os
  2. import subprocess
  3. import traceback
  4. from requests import ConnectionError
  5. from toolset.utils.output_helper import log, FNULL
  6. from toolset.utils import docker_helper
  7. # Cross-platform colored text
  8. from colorama import Fore, Style
  9. class FrameworkTest:
  10. def __init__(self, name, directory, benchmarker_config, results, runTests,
  11. args):
  12. '''
  13. Constructor
  14. '''
  15. self.name = name
  16. self.directory = directory
  17. self.benchmarker_config = benchmarker_config
  18. self.results = results
  19. self.runTests = runTests
  20. self.fwroot = benchmarker_config.fwroot
  21. self.approach = ""
  22. self.classification = ""
  23. self.database = ""
  24. self.framework = ""
  25. self.language = ""
  26. self.orm = ""
  27. self.platform = ""
  28. self.webserver = ""
  29. self.os = ""
  30. self.database_os = ""
  31. self.display_name = ""
  32. self.notes = ""
  33. self.port = ""
  34. self.versus = ""
  35. self.docker_files = None
  36. # Used in setup.sh scripts for consistency with
  37. # the bash environment variables
  38. self.troot = self.directory
  39. self.__dict__.update(args)
  40. ##########################################################################################
  41. # Public Methods
  42. ##########################################################################################
  43. def start(self, database_container_id):
  44. '''
  45. Start the test implementation
  46. '''
  47. test_docker_files = self.get_docker_files()
  48. test_log_dir = os.path.join(self.results.directory, self.name.lower())
  49. build_log_dir = os.path.join(test_log_dir, 'build')
  50. run_log_dir = os.path.join(test_log_dir, 'run')
  51. try:
  52. os.makedirs(build_log_dir)
  53. except OSError:
  54. pass
  55. try:
  56. os.makedirs(run_log_dir)
  57. except OSError:
  58. pass
  59. result = docker_helper.build(self.benchmarker_config, [self.name],
  60. build_log_dir)
  61. if result != 0:
  62. return result
  63. return docker_helper.run(self.benchmarker_config, test_docker_files,
  64. run_log_dir)
  65. def is_running(self):
  66. '''
  67. Determines whether this test implementation is up and accepting
  68. requests.
  69. '''
  70. test_type = None
  71. for any_type in self.runTests:
  72. test_type = any_type
  73. break
  74. url = "http://%s:%s/%s" % (self.benchmarker_config.server_host,
  75. self.port,
  76. self.runTests[test_type].get_url())
  77. try:
  78. subprocess.check_call(
  79. ['curl', '-sSfl', url], stdout=FNULL, stderr=subprocess.STDOUT)
  80. except:
  81. return False
  82. return True
  83. def get_docker_files(self):
  84. '''
  85. Returns all the docker_files for this test.
  86. '''
  87. test_docker_files = ["%s.dockerfile" % self.name]
  88. if self.docker_files is not None:
  89. if type(self.docker_files) is list:
  90. test_docker_files.extend(self.docker_files)
  91. else:
  92. raise Exception(
  93. "docker_files in benchmark_config.json must be an array")
  94. return test_docker_files
  95. def verify_urls(self):
  96. '''
  97. Verifys each of the URLs for this test. This will simply curl the URL and
  98. check for it's return status. For each url, a flag will be set on this
  99. object for whether or not it passed.
  100. Returns True if all verifications succeeded
  101. '''
  102. log_path = os.path.join(self.results.directory, self.name.lower())
  103. result = True
  104. def verify_type(test_type):
  105. verificationPath = os.path.join(log_path, test_type)
  106. try:
  107. os.makedirs(verificationPath)
  108. except OSError:
  109. pass
  110. with open(os.path.join(verificationPath, 'verification.txt'),
  111. 'w') as verification:
  112. test = self.runTests[test_type]
  113. log("VERIFYING %s" % test_type.upper(),
  114. file=verification, border='-', color=Fore.WHITE + Style.BRIGHT)
  115. base_url = "http://%s:%s" % (
  116. self.benchmarker_config.server_host, self.port)
  117. try:
  118. # Verifies headers from the server. This check is made from the
  119. # App Server using Pythons requests module. Will do a second check from
  120. # the client to make sure the server isn't only accepting connections
  121. # from localhost on a multi-machine setup.
  122. results = test.verify(base_url)
  123. # Now verify that the url is reachable from the client machine, unless
  124. # we're already failing
  125. if not any(result == 'fail'
  126. for (result, reason, url) in results):
  127. p = subprocess.call(
  128. [
  129. "ssh", self.benchmarker_config.client_host,
  130. "curl -sSf %s" % base_url + test.get_url()
  131. ],
  132. shell=False,
  133. stdout=subprocess.PIPE,
  134. stderr=subprocess.PIPE)
  135. if p is not 0:
  136. results = [(
  137. 'fail',
  138. "Server did not respond to request from client machine.",
  139. base_url)]
  140. log("""This error usually means your server is only accepting
  141. requests from localhost.""")
  142. except ConnectionError as e:
  143. results = [('fail', "Server did not respond to request",
  144. base_url)]
  145. log("Verifying test %s for %s caused an exception: %s" %
  146. (test_type, self.name, e), color=Fore.RED)
  147. except Exception as e:
  148. results = [('fail', """Caused Exception in TFB
  149. This almost certainly means your return value is incorrect,
  150. but also that you have found a bug. Please submit an issue
  151. including this message: %s\n%s""" % (e, traceback.format_exc()),
  152. base_url)]
  153. log("Verifying test %s for %s caused an exception: %s" %
  154. (test_type, self.name, e), color=Fore.RED)
  155. traceback.format_exc()
  156. test.failed = any(
  157. result == 'fail' for (result, reason, url) in results)
  158. test.warned = any(
  159. result == 'warn' for (result, reason, url) in results)
  160. test.passed = all(
  161. result == 'pass' for (result, reason, url) in results)
  162. def output_result(result, reason, url):
  163. specific_rules_url = "http://frameworkbenchmarks.readthedocs.org/en/latest/Project-Information/Framework-Tests/#specific-test-requirements"
  164. color = Fore.GREEN
  165. if result.upper() == "WARN":
  166. color = Fore.YELLOW
  167. elif result.upper() == "FAIL":
  168. color = Fore.RED
  169. log(" {!s}{!s}{!s} for {!s}".format(
  170. color, result.upper(), Style.RESET_ALL, url),
  171. file=verification)
  172. if reason is not None and len(reason) != 0:
  173. for line in reason.splitlines():
  174. log(" " + line, file=verification)
  175. if not test.passed:
  176. log(" See {!s}".format(specific_rules_url),
  177. file=verification)
  178. [output_result(r1, r2, url) for (r1, r2, url) in results]
  179. if test.failed:
  180. self.results.report_verify_results(self, test_type, 'fail')
  181. elif test.warned:
  182. self.results.report_verify_results(self, test_type, 'warn')
  183. elif test.passed:
  184. self.results.report_verify_results(self, test_type, 'pass')
  185. else:
  186. raise Exception(
  187. "Unknown error - test did not pass,warn,or fail")
  188. result = True
  189. for test_type in self.runTests:
  190. verify_type(test_type)
  191. if self.runTests[test_type].failed:
  192. result = False
  193. return result