run-ci.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. #!/usr/bin/env python
  2. import subprocess
  3. import os
  4. import sys
  5. import glob
  6. import json
  7. import traceback
  8. import re
  9. import logging
  10. log = logging.getLogger('run-ci')
  11. import time
  12. import threading
  13. from benchmark import framework_test
  14. from benchmark.utils import gather_tests
  15. from benchmark.utils import header
  16. # Cross-platform colored text
  17. from colorama import Fore, Back, Style
  18. # Needed for various imports
  19. sys.path.append('.')
  20. sys.path.append('toolset/setup/linux')
  21. sys.path.append('toolset/benchmark')
  22. from setup.linux import setup_util
  23. class CIRunnner:
  24. '''
  25. Manages running TFB on the Travis Continuous Integration system.
  26. Makes a best effort to avoid wasting time and resources by running
  27. useless jobs.
  28. Only verifies the first test in each directory
  29. '''
  30. SUPPORTED_DATABASES = "mysql postgres mongodb cassandra elasticsearch sqlite none".split()
  31. def __init__(self, mode, testdir=None):
  32. '''
  33. mode = [cisetup|prereq|install|verify] for what we want to do
  34. testdir = framework directory we are running
  35. '''
  36. self.directory = testdir
  37. self.mode = mode
  38. if mode == "cisetup":
  39. logging.basicConfig(level=logging.DEBUG)
  40. else:
  41. logging.basicConfig(level=logging.INFO)
  42. try:
  43. # NOTE: THIS IS VERY TRICKY TO GET RIGHT!
  44. #
  45. # Our goal: Look at the files changed and determine if we need to
  46. # run a verification for this folder. For a pull request, we want to
  47. # see the list of files changed by any commit in that PR. For a
  48. # push to master, we want to see a list of files changed by the pushed
  49. # commits. If this list of files contains the current directory, or
  50. # contains the toolset/ directory, then we need to run a verification
  51. #
  52. # If modifying, please consider:
  53. # - the commit range for a pull request is the first PR commit to
  54. # the github auto-merge commit
  55. # - the commits in the commit range may include merge commits
  56. # other than the auto-merge commit. An git log with -m
  57. # will know that *all* the files in the merge were changed,
  58. # but that is not the changeset that we care about
  59. # - git diff shows differences, but we care about git log, which
  60. # shows information on what was changed during commits
  61. # - master can (and will!) move during a build. This is one
  62. # of the biggest problems with using git diff - master will
  63. # be updated, and those updates will include changes to toolset,
  64. # and suddenly every job in the build will start to run instead
  65. # of fast-failing
  66. # - commit_range is not set if there was only one commit pushed,
  67. # so be sure to test for that on both master and PR
  68. # - commit_range and commit are set very differently for pushes
  69. # to an owned branch versus pushes to a pull request, test
  70. # - For merge commits, the TRAVIS_COMMIT and TRAVIS_COMMIT_RANGE
  71. # will become invalid if additional commits are pushed while a job is
  72. # building. See https://github.com/travis-ci/travis-ci/issues/2666
  73. # - If you're really insane, consider that the last commit in a
  74. # pull request could have been a merge commit. This means that
  75. # the github auto-merge commit could have more than two parents
  76. # - Travis cannot really support rebasing onto an owned branch, the
  77. # commit_range they provide will include commits that are non-existant
  78. # in the repo cloned on the workers. See https://github.com/travis-ci/travis-ci/issues/2668
  79. #
  80. # - TEST ALL THESE OPTIONS:
  81. # - On a branch you own (e.g. your fork's master)
  82. # - single commit
  83. # - multiple commits pushed at once
  84. # - commit+push, then commit+push again before the first
  85. # build has finished. Verify all jobs in the first build
  86. # used the correct commit range
  87. # - multiple commits, including a merge commit. Verify that
  88. # the unrelated merge commit changes are not counted as
  89. # changes the user made
  90. # - On a pull request
  91. # - repeat all above variations
  92. #
  93. #
  94. # ==== CURRENT SOLUTION FOR PRs ====
  95. #
  96. # For pull requests, we will examine Github's automerge commit to see
  97. # what files would be touched if we merged this into the current master.
  98. # You can't trust the travis variables here, as the automerge commit can
  99. # be different for jobs on the same build. See https://github.com/travis-ci/travis-ci/issues/2666
  100. # We instead use the FETCH_HEAD, which will always point to the SHA of
  101. # the lastest merge commit. However, if we only used FETCH_HEAD than any
  102. # new commits to a pull request would instantly start affecting currently
  103. # running jobs and the the list of changed files may become incorrect for
  104. # those affected jobs. The solution is to walk backward from the FETCH_HEAD
  105. # to the last commit in the pull request. Based on how github currently
  106. # does the automerge, this is the second parent of FETCH_HEAD, and
  107. # therefore we use FETCH_HEAD^2 below
  108. #
  109. # This may not work perfectly in situations where the user had advanced
  110. # merging happening in their PR. We correctly handle them merging in
  111. # from upstream, but if they do wild stuff then this will likely break
  112. # on that. However, it will also likely break by seeing a change in
  113. # toolset and triggering a full run when a partial run would be
  114. # acceptable
  115. #
  116. # ==== CURRENT SOLUTION FOR OWNED BRANCHES (e.g. master) ====
  117. #
  118. # This one is fairly simple. Find the commit or commit range, and
  119. # examine the log of files changes. If you encounter any merges,
  120. # then fully explode the two parent commits that made the merge
  121. # and look for the files changed there. This is an aggressive
  122. # strategy to ensure that commits to master are always tested
  123. # well
  124. log.debug("TRAVIS_COMMIT_RANGE: %s", os.environ['TRAVIS_COMMIT_RANGE'])
  125. log.debug("TRAVIS_COMMIT : %s", os.environ['TRAVIS_COMMIT'])
  126. is_PR = (os.environ['TRAVIS_PULL_REQUEST'] != "false")
  127. if is_PR:
  128. log.debug('I am testing a pull request')
  129. first_commit = os.environ['TRAVIS_COMMIT_RANGE'].split('...')[0]
  130. last_commit = subprocess.check_output("git rev-list -n 1 FETCH_HEAD^2", shell=True).rstrip('\n')
  131. log.debug("Guessing that first commit in PR is : %s", first_commit)
  132. log.debug("Guessing that final commit in PR is : %s", last_commit)
  133. if first_commit == "":
  134. # Travis-CI is not yet passing a commit range for pull requests
  135. # so we must use the automerge's changed file list. This has the
  136. # negative effect that new pushes to the PR will immediately
  137. # start affecting any new jobs, regardless of the build they are on
  138. log.debug("No first commit, using Github's automerge commit")
  139. self.commit_range = "--first-parent -1 -m FETCH_HEAD"
  140. elif first_commit == last_commit:
  141. # There is only one commit in the pull request so far,
  142. # or Travis-CI is not yet passing the commit range properly
  143. # for pull requests. We examine just the one commit using -1
  144. #
  145. # On the oddball chance that it's a merge commit, we pray
  146. # it's a merge from upstream and also pass --first-parent
  147. log.debug("Only one commit in range, examining %s", last_commit)
  148. self.commit_range = "-m --first-parent -1 %s" % last_commit
  149. else:
  150. # In case they merged in upstream, we only care about the first
  151. # parent. For crazier merges, we hope
  152. self.commit_range = "--first-parent %s...%s" % (first_commit, last_commit)
  153. if not is_PR:
  154. log.debug('I am not testing a pull request')
  155. # Three main scenarios to consider
  156. # - 1 One non-merge commit pushed to master
  157. # - 2 One merge commit pushed to master (e.g. a PR was merged).
  158. # This is an example of merging a topic branch
  159. # - 3 Multiple commits pushed to master
  160. #
  161. # 1 and 2 are actually handled the same way, by showing the
  162. # changes being brought into to master when that one commit
  163. # was merged. Fairly simple, `git log -1 COMMIT`. To handle
  164. # the potential merge of a topic branch you also include
  165. # `--first-parent -m`.
  166. #
  167. # 3 needs to be handled by comparing all merge children for
  168. # the entire commit range. The best solution here would *not*
  169. # use --first-parent because there is no guarantee that it
  170. # reflects changes brought into master. Unfortunately we have
  171. # no good method inside Travis-CI to easily differentiate
  172. # scenario 1/2 from scenario 3, so I cannot handle them all
  173. # separately. 1/2 are the most common cases, 3 with a range
  174. # of non-merge commits is the next most common, and 3 with
  175. # a range including merge commits is the least common, so I
  176. # am choosing to make our Travis-CI setup potential not work
  177. # properly on the least common case by always using
  178. # --first-parent
  179. # Handle 3
  180. # Note: Also handles 2 because Travis-CI sets COMMIT_RANGE for
  181. # merged PR commits
  182. self.commit_range = "--first-parent -m %s" % os.environ['TRAVIS_COMMIT_RANGE']
  183. # Handle 1
  184. if self.commit_range == "":
  185. self.commit_range = "--first-parent -m -1 %s" % os.environ['TRAVIS_COMMIT']
  186. except KeyError:
  187. log.warning("I should only be used for automated integration tests e.g. Travis-CI")
  188. log.warning("Were you looking for run-tests.py?")
  189. self.commit_range = "-m HEAD^...HEAD"
  190. #
  191. # Find the one test from benchmark_config that we are going to run
  192. #
  193. tests = gather_tests()
  194. self.fwroot = setup_util.get_fwroot()
  195. target_dir = self.fwroot + '/frameworks/' + testdir
  196. log.debug("Target directory is %s", target_dir)
  197. dirtests = [t for t in tests if t.directory == target_dir]
  198. # Travis-CI is linux only
  199. osvalidtests = [t for t in dirtests if t.os.lower() == "linux"
  200. and (t.database_os.lower() == "linux" or t.database_os.lower() == "none")]
  201. # Our Travis-CI only has some databases supported
  202. validtests = [t for t in osvalidtests if t.database.lower() in self.SUPPORTED_DATABASES]
  203. supported_databases = ','.join(self.SUPPORTED_DATABASES)
  204. log.info("Found %s usable tests (%s valid for linux, %s valid for linux and {%s}) in directory '%s'",
  205. len(dirtests), len(osvalidtests), len(validtests), supported_databases, '$FWROOT/frameworks/' + testdir)
  206. if len(validtests) == 0:
  207. log.critical("Found no test that is possible to run in Travis-CI! Aborting!")
  208. if len(osvalidtests) != 0:
  209. log.critical("Note: Found these tests that could run in Travis-CI if more databases were supported")
  210. log.critical("Note: %s", osvalidtests)
  211. databases_needed = [t.database for t in osvalidtests]
  212. databases_needed = list(set(databases_needed))
  213. log.critical("Note: Here are the needed databases:")
  214. log.critical("Note: %s", databases_needed)
  215. sys.exit(1)
  216. self.names = [t.name for t in validtests]
  217. log.info("Using tests %s to verify directory %s", self.names, '$FWROOT/frameworks/' + testdir)
  218. def _should_run(self):
  219. '''
  220. Decides if the current framework test should be tested.
  221. Examines git commits included in the latest push to see if any files relevant to
  222. this framework were changed.
  223. If you do rewrite history (e.g. rebase) then it's up to you to ensure that both
  224. old and new (e.g. old...new) are available in the public repository. For simple
  225. rebase onto the public master this is not a problem, only more complex rebases
  226. may have issues
  227. '''
  228. # Don't use git diff multiple times, it's mega slow sometimes\
  229. # Put flag on filesystem so that future calls to run-ci see it too
  230. if os.path.isfile('.run-ci.should_run'):
  231. return True
  232. if os.path.isfile('.run-ci.should_not_run'):
  233. return False
  234. def touch(fname):
  235. open(fname, 'a').close()
  236. log.debug("Using commit range `%s`", self.commit_range)
  237. log.debug("Running `git log --name-only --pretty=\"format:\" %s`" % self.commit_range)
  238. changes = ""
  239. try:
  240. changes = subprocess.check_output("git log --name-only --pretty=\"format:\" %s" % self.commit_range, shell=True)
  241. except subprocess.CalledProcessError, e:
  242. log.error("Got errors when using git to detect your changes, assuming that we must run this verification!")
  243. log.error("Error was: %s", e.output)
  244. log.error("Did you rebase a branch? If so, you can safely disregard this error, it's a Travis limitation")
  245. return True
  246. changes = os.linesep.join([s for s in changes.splitlines() if s]) # drop empty lines
  247. if len(changes.splitlines()) > 1000:
  248. log.debug("Change list is >1000 lines, uploading to sprunge.us instead of printing to console")
  249. url = subprocess.check_output("git log --name-only %s | curl -F 'sprunge=<-' http://sprunge.us" % self.commit_range, shell=True)
  250. log.debug("Uploaded to %s", url)
  251. else:
  252. log.debug("Result:\n%s", changes)
  253. # Look for changes to core TFB framework code
  254. if re.search(r'^toolset/', changes, re.M) is not None:
  255. log.info("Found changes to core framework code")
  256. touch('.run-ci.should_run')
  257. return True
  258. # Look for changes relevant to this test
  259. if re.search("^frameworks/%s/" % re.escape(self.directory), changes, re.M) is None:
  260. log.info("No changes found for directory %s", self.directory)
  261. touch('.run-ci.should_not_run')
  262. return False
  263. log.info("Changes found for directory %s", self.directory)
  264. touch('.run-ci.should_run')
  265. return True
  266. def run(self):
  267. ''' Do the requested command using TFB '''
  268. if not self._should_run():
  269. log.info("I found no changes to `%s` or `toolset/`, aborting verification", self.directory)
  270. return 0
  271. if self.mode == 'cisetup':
  272. self.run_travis_setup()
  273. return 0
  274. names = ' '.join(self.names)
  275. command = 'toolset/run-tests.py '
  276. if self.mode == 'prereq':
  277. command = command + "--install server --install-only --test '' --verbose"
  278. elif self.mode == 'install':
  279. command = command + "--install server --install-only --test %s" % names
  280. elif self.mode == 'verify':
  281. command = command + "--mode verify --test %s" % names
  282. else:
  283. log.critical('Unknown mode passed')
  284. return 1
  285. # Run the command
  286. log.info("Running mode %s with commmand %s", self.mode, command)
  287. try:
  288. p = subprocess.Popen(command, shell=True)
  289. p.wait()
  290. return p.returncode
  291. except subprocess.CalledProcessError:
  292. log.critical("Subprocess Error")
  293. print traceback.format_exc()
  294. return 1
  295. except Exception as err:
  296. log.critical("Exception from running+wait on subprocess")
  297. log.error(err.child_traceback)
  298. return 1
  299. def run_travis_setup(self):
  300. log.info("Setting up Travis-CI")
  301. script = '''
  302. export DEBIAN_FRONTEND=noninteractive
  303. # Turn on command tracing
  304. set -x
  305. # Setup Apt For MongoDB
  306. # Due to TechEmpower/FrameworkBenchmarks#989 and travis-ci/travis-ci#2655,
  307. # we put this into a loop
  308. until timeout 15s sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10; do echo 'Waiting for apt-key' ; done
  309. echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
  310. # Setup apt for Apache Cassandra
  311. until timeout 15s sudo apt-key adv --keyserver pgp.mit.edu --recv 4BD736A82B5C1B00; do echo 'Waiting for apt-key' ; done
  312. sudo apt-add-repository 'deb http://www.apache.org/dist/cassandra/debian 20x main'
  313. # Run installation
  314. # DO NOT COPY --force-yes TO ANY NON-TRAVIS-CI SCRIPTS! Seriously, it can cause some
  315. # major damage and should only be used inside a VM or Linux Container
  316. sudo apt-get -q update
  317. sudo apt-get -q -y --force-yes install -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" \
  318. mongodb-org \
  319. cassandra \
  320. openssh-server
  321. # Run as travis user (who already has passwordless sudo)
  322. ssh-keygen -f /home/travis/.ssh/id_rsa -N '' -t rsa
  323. cat /home/travis/.ssh/id_rsa.pub > /home/travis/.ssh/authorized_keys
  324. chmod 600 /home/travis/.ssh/authorized_keys
  325. # Set up the benchmark.cfg for travis user
  326. # NOTE: Please don't just copy the example config - it causes unexpected
  327. # issues when those example variables change
  328. echo "[Defaults]" > benchmark.cfg
  329. echo "client_identity_file=/home/travis/.ssh/id_rsa" >> benchmark.cfg
  330. echo "database_identity_file=/home/travis/.ssh/id_rsa" >> benchmark.cfg
  331. echo "client_host=127.0.0.1" >> benchmark.cfg
  332. echo "database_host=127.0.0.1" >> benchmark.cfg
  333. echo "server_host=127.0.0.1" >> benchmark.cfg
  334. echo "client_user=travis" >> benchmark.cfg
  335. echo "database_user=travis" >> benchmark.cfg
  336. echo "runner_user=testrunner" >> benchmark.cfg
  337. # Create the new testrunner user
  338. sudo useradd testrunner
  339. # Give him a home dir
  340. sudo mkdir /home/testrunner
  341. # Make testrunner the owner of his home dir
  342. sudo chown testrunner:testrunner /home/testrunner
  343. # Add the testrunner user to every group that the travis user is in
  344. sudo sed -i 's|:travis|:travis,testrunner|g' /etc/group
  345. # Add the testrunner user to the travis group specifically
  346. sudo sed -i 's|travis:x:\(.*\):|travis:x:\\1:testrunner|g' /etc/group
  347. # Maybe unneeded - add the travis user to the testrunner group
  348. sudo sed -i 's|testrunner:x:\(.*\):|testrunner:x:\\1:travis|g' /etc/group
  349. # Need to add testrunner to the sudoers group AND default him to a sudoers
  350. # because the travis user isn't in the sudo group - he's a sudoer.
  351. echo "testrunner ALL=(ALL:ALL) NOPASSWD: ALL" | sudo tee -a /etc/sudoers
  352. # Set the default shell for testrunner to /bin/bash
  353. sudo sed -i 's|/home/testrunner:/bin/sh|/home/testrunner:/bin/bash|g' /etc/passwd
  354. # =============Setup Databases===========================
  355. # NOTE: Do not run `--install database` in travis-ci!
  356. # It changes DB configuration files and will break everything
  357. # =======================================================
  358. # Setup MySQL
  359. echo "Populating MySQL database"
  360. mysql -uroot < config/create.sql
  361. # Setup Postgres
  362. echo "Removing Postgres 9.1 from Travis-CI"
  363. sudo apt-get remove -qy postgresql postgresql-9.1 postgresql-client-9.1
  364. sudo apt-get install -qy postgresql-9.3 postgresql-client-9.3
  365. echo "Populating Postgres database"
  366. psql --version
  367. sudo useradd benchmarkdbuser -p benchmarkdbpass
  368. sudo -u postgres psql template1 < config/create-postgres-database.sql
  369. sudo -u benchmarkdbuser psql hello_world < config/create-postgres.sql
  370. # Setup Apache Cassandra
  371. echo "Populating Apache Cassandra database"
  372. for i in {1..45}; do
  373. nc -z localhost 9160 && break || sleep 1;
  374. echo "Waiting for Cassandra ($i/45}"
  375. done
  376. nc -z localhost 9160
  377. if [ $? -eq 0 ]; then
  378. cat config/cassandra/cleanup-keyspace.cql | sudo cqlsh
  379. python config/cassandra/db-data-gen.py > config/cassandra/tfb-data.cql
  380. sudo cqlsh -f config/cassandra/create-keyspace.cql
  381. sudo cqlsh -f config/cassandra/tfb-data.cql
  382. else
  383. >&2 echo "Cassandra did not start, skipping"
  384. fi
  385. # Setup Elasticsearch
  386. curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.5.0.deb
  387. sudo dpkg -i --force-confnew elasticsearch-1.5.0.deb
  388. sudo update-rc.d elasticsearch defaults 95 10
  389. sudo service elasticsearch restart
  390. echo "Populating Elasticsearch database"
  391. for i in {1..45}; do
  392. nc -z localhost 9200 && break || sleep 1;
  393. echo "Waiting for Elasticsearch ($i/45}"
  394. done
  395. nc -z localhost 9200
  396. if [ $? -eq 0 ]; then
  397. curl localhost:9200
  398. sh config/elasticsearch/es-create-index.sh
  399. python config/elasticsearch/es-db-data-gen.py > config/elasticsearch/tfb-data.json
  400. curl -sS -D - -o /dev/null -XPOST localhost:9200/tfb/world/_bulk --data-binary @config/elasticsearch/tfb-data.json
  401. echo "Elasticsearch DB populated"
  402. else
  403. >&2 echo "Elasticsearch did not start, skipping"
  404. fi
  405. # Setup MongoDB
  406. echo "Populating MongoDB database"
  407. for i in {1..45}; do
  408. nc -z localhost 27017 && break || sleep 1;
  409. echo "Waiting for MongoDB ($i/45}"
  410. done
  411. nc -z localhost 27017
  412. if [ $? -eq 0 ]; then
  413. mongo < create.js
  414. mongod --version
  415. else
  416. >&2 echo "MongoDB did not start, skipping"
  417. fi
  418. # =============Modify Configurations===========================
  419. # It can be useful to enable debug features for verification
  420. # inside Travis-CI
  421. # =======================================================
  422. sed -i 's|display_errors\] = off|display_errors\] = on|' config/php-fpm.conf
  423. exit $?
  424. '''
  425. p = subprocess.Popen(["bash"], stdin=subprocess.PIPE)
  426. p.communicate(script)
  427. if p.wait() != 0:
  428. log.critical("Non-zero exit from running+wait on subprocess")
  429. if __name__ == "__main__":
  430. args = sys.argv[1:]
  431. usage = '''Usage: toolset/run-ci.py [cisetup|prereq|install|verify] <framework-directory>
  432. run-ci.py selects one test from <framework-directory>/benchark_config, and
  433. automates a number of calls into run-tests.py specific to the selected test.
  434. It is guaranteed to always select the same test from the benchark_config, so
  435. multiple runs with the same <framework-directory> reference the same test.
  436. The name of the selected test will be printed to standard output.
  437. cisetup - configure the Travis-CI environment for our test suite
  438. prereq - trigger standard prerequisite installation
  439. install - trigger server installation for the selected test_directory
  440. verify - run a verification on the selected test using `--mode verify`
  441. run-ci.py expects to be run inside the Travis-CI build environment, and
  442. will expect environment variables such as $TRAVIS_BUILD'''
  443. if len(args) != 2:
  444. print usage
  445. sys.exit(1)
  446. mode = args[0]
  447. testdir = args[1]
  448. if len(args) == 2 and (mode == "install"
  449. or mode == "verify"
  450. or mode == 'prereq'
  451. or mode == 'cisetup'):
  452. runner = CIRunnner(mode, testdir)
  453. else:
  454. print usage
  455. sys.exit(1)
  456. retcode = 0
  457. try:
  458. retcode = runner.run()
  459. except KeyError as ke:
  460. log.warning("Environment key missing, are you running inside Travis-CI?")
  461. print traceback.format_exc()
  462. retcode = 1
  463. except Exception:
  464. log.critical("Unknown error")
  465. print traceback.format_exc()
  466. retcode = 1
  467. finally: # Ensure that logs are printed
  468. # Only print logs if we ran a verify
  469. if mode != 'verify':
  470. sys.exit(retcode)
  471. # Only print logs if we actually did something
  472. if os.path.isfile('.run-ci.should_not_run'):
  473. sys.exit(retcode)
  474. log.error("Running inside Travis-CI, so I will print err and out to console...")
  475. for name in runner.names:
  476. log.error("Test %s", name)
  477. try:
  478. log.error("Here is ERR:")
  479. with open("results/ec2/latest/logs/%s/err.txt" % name, 'r') as err:
  480. for line in err:
  481. log.info(line.rstrip('\n'))
  482. except IOError:
  483. log.error("No ERR file found")
  484. try:
  485. log.error("Here is OUT:")
  486. with open("results/ec2/latest/logs/%s/out.txt" % name, 'r') as out:
  487. for line in out:
  488. log.info(line.rstrip('\n'))
  489. except IOError:
  490. log.error("No OUT file found")
  491. log.error("Running inside Travis-CI, so I will print a copy of the verification summary")
  492. results = None
  493. try:
  494. with open('results/ec2/latest/results.json', 'r') as f:
  495. results = json.load(f)
  496. except IOError:
  497. log.critical("No results.json found, unable to print verification summary")
  498. sys.exit(retcode)
  499. target_dir = setup_util.get_fwroot() + '/frameworks/' + testdir
  500. dirtests = [t for t in gather_tests() if t.directory == target_dir]
  501. # Normally you don't have to use Fore.* before each line, but
  502. # Travis-CI seems to reset color codes on newline (see travis-ci/travis-ci#2692)
  503. # or stream flush, so we have to ensure that the color code is printed repeatedly
  504. prefix = Fore.CYAN
  505. for line in header("Verification Summary", top='=', bottom='').split('\n'):
  506. print prefix + line
  507. for test in dirtests:
  508. print prefix + "| Test: %s" % test.name
  509. if test.name not in runner.names:
  510. print prefix + "| " + Fore.YELLOW + "Unable to verify in Travis-CI"
  511. elif test.name in results['verify'].keys():
  512. for test_type, result in results['verify'][test.name].iteritems():
  513. if result.upper() == "PASS":
  514. color = Fore.GREEN
  515. elif result.upper() == "WARN":
  516. color = Fore.YELLOW
  517. else:
  518. color = Fore.RED
  519. print prefix + "| " + test_type.ljust(11) + ' : ' + color + result.upper()
  520. else:
  521. print prefix + "| " + Fore.RED + "NO RESULTS (Did framework launch?)"
  522. print prefix + header('', top='', bottom='=') + Style.RESET_ALL
  523. sys.exit(retcode)
  524. # vim: set sw=2 ts=2 expandtab