Sahara Horizon plugin.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

run_tests.sh 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. #!/bin/bash
  2. set -o errexit
  3. function usage {
  4. echo "Usage: $0 [OPTION]..."
  5. echo "Run Horizon's test suite(s)"
  6. echo ""
  7. echo " -V, --virtual-env Always use virtualenv. Install automatically"
  8. echo " if not present"
  9. echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local"
  10. echo " environment"
  11. echo " -c, --coverage Generate reports using Coverage"
  12. echo " -f, --force Force a clean re-build of the virtual"
  13. echo " environment. Useful when dependencies have"
  14. echo " been added."
  15. echo " -m, --manage Run a Django management command."
  16. echo " --makemessages Create/Update English translation files."
  17. echo " --compilemessages Compile all translation files."
  18. echo " --check-only Do not update translation files (--makemessages only)."
  19. echo " --pseudo Pseudo translate a language."
  20. echo " -p, --pep8 Just run pep8"
  21. echo " -8, --pep8-changed [<basecommit>]"
  22. echo " Just run PEP8 and HACKING compliance check"
  23. echo " on files changed since HEAD~1 (or <basecommit>)"
  24. echo " -P, --no-pep8 Don't run pep8 by default"
  25. echo " -t, --tabs Check for tab characters in files."
  26. echo " -y, --pylint Just run pylint"
  27. echo " -q, --quiet Run non-interactively. (Relatively) quiet."
  28. echo " Implies -V if -N is not set."
  29. echo " --only-selenium Run only the Selenium unit tests"
  30. echo " --with-selenium Run unit tests including Selenium tests"
  31. echo " --selenium-headless Run Selenium tests headless"
  32. echo " --integration Run the integration tests (requires a running "
  33. echo " OpenStack environment)"
  34. echo " --runserver Run the Django development server for"
  35. echo " openstack_dashboard in the virtual"
  36. echo " environment."
  37. echo " --docs Just build the documentation"
  38. echo " --backup-environment Make a backup of the environment on exit"
  39. echo " --restore-environment Restore the environment before running"
  40. echo " --destroy-environment Destroy the environment and exit"
  41. echo " -h, --help Print this usage message"
  42. echo ""
  43. echo "Note: with no options specified, the script will try to run the tests in"
  44. echo " a virtual environment, If no virtualenv is found, the script will ask"
  45. echo " if you would like to create one. If you prefer to run tests NOT in a"
  46. echo " virtual environment, simply pass the -N option."
  47. exit
  48. }
  49. # DEFAULTS FOR RUN_TESTS.SH
  50. #
  51. root=`pwd -P`
  52. venv=$root/.venv
  53. with_venv=tools/with_venv.sh
  54. included_dirs="sahara_dashboard"
  55. always_venv=0
  56. backup_env=0
  57. command_wrapper=""
  58. destroy=0
  59. force=0
  60. just_pep8=0
  61. just_pep8_changed=0
  62. no_pep8=0
  63. just_pylint=0
  64. just_docs=0
  65. just_tabs=0
  66. never_venv=0
  67. quiet=0
  68. restore_env=0
  69. runserver=0
  70. only_selenium=0
  71. with_selenium=0
  72. selenium_headless=0
  73. integration=0
  74. testopts=""
  75. testargs=""
  76. with_coverage=0
  77. makemessages=0
  78. compilemessages=0
  79. check_only=0
  80. pseudo=0
  81. manage=0
  82. # NOTE(tonyb): the release team will automatically update tox.ini to point at
  83. # the correct requirements branch when creating stable/* from master. So go to
  84. # a little effort to get the deault from there to avoid dift and having to
  85. # update this when branching
  86. _default_uc=$(sed -n 's/^.*{env:UPPER_CONSTRAINTS_FILE\:\([^}]*\)}.*$/\1/p' \
  87. tox.ini | head -n1)
  88. # Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default"
  89. [ "$JOB_NAME" ] || JOB_NAME="default"
  90. function process_option {
  91. # If running manage command, treat the rest of options as arguments.
  92. if [ $manage -eq 1 ]; then
  93. testargs="$testargs $1"
  94. return 0
  95. fi
  96. case "$1" in
  97. -h|--help) usage;;
  98. -V|--virtual-env) always_venv=1; never_venv=0;;
  99. -N|--no-virtual-env) always_venv=0; never_venv=1;;
  100. -p|--pep8) just_pep8=1;;
  101. -8|--pep8-changed) just_pep8_changed=1;;
  102. -P|--no-pep8) no_pep8=1;;
  103. -y|--pylint) just_pylint=1;;
  104. -f|--force) force=1;;
  105. -t|--tabs) just_tabs=1;;
  106. -q|--quiet) quiet=1;;
  107. -c|--coverage) with_coverage=1;;
  108. -m|--manage) manage=1;;
  109. --makemessages) makemessages=1;;
  110. --compilemessages) compilemessages=1;;
  111. --check-only) check_only=1;;
  112. --pseudo) pseudo=1;;
  113. --only-selenium) only_selenium=1;;
  114. --with-selenium) with_selenium=1;;
  115. --selenium-headless) selenium_headless=1;;
  116. --integration) integration=1;;
  117. --docs) just_docs=1;;
  118. --runserver) runserver=1;;
  119. --backup-environment) backup_env=1;;
  120. --restore-environment) restore_env=1;;
  121. --destroy-environment) destroy=1;;
  122. -*) testopts="$testopts $1";;
  123. *) testargs="$testargs $1"
  124. esac
  125. }
  126. function run_management_command {
  127. ${command_wrapper} python $root/manage.py $testopts $testargs
  128. }
  129. function run_server {
  130. echo "Starting Django development server..."
  131. ${command_wrapper} python $root/manage.py runserver $testopts $testargs
  132. echo "Server stopped."
  133. }
  134. function run_pylint {
  135. echo "Running pylint ..."
  136. PYTHONPATH=$root ${command_wrapper} pylint --rcfile=.pylintrc -f parseable $included_dirs > pylint.txt || true
  137. CODE=$?
  138. grep Global -A2 pylint.txt
  139. if [ $CODE -lt 32 ]; then
  140. echo "Completed successfully."
  141. exit 0
  142. else
  143. echo "Completed with problems."
  144. exit $CODE
  145. fi
  146. }
  147. function warn_on_flake8_without_venv {
  148. set +o errexit
  149. ${command_wrapper} python -c "import hacking" 2>/dev/null
  150. no_hacking=$?
  151. set -o errexit
  152. if [ $never_venv -eq 1 -a $no_hacking -eq 1 ]; then
  153. echo "**WARNING**:" >&2
  154. echo "OpenStack hacking is not installed on your host. Its detection will be missed." >&2
  155. echo "Please install or use virtual env if you need OpenStack hacking detection." >&2
  156. fi
  157. }
  158. function run_pep8 {
  159. echo "Running flake8 ..."
  160. warn_on_flake8_without_venv
  161. DJANGO_SETTINGS_MODULE=sahara_dashboard.test.settings ${command_wrapper} flake8
  162. }
  163. function run_pep8_changed {
  164. # NOTE(gilliard) We want use flake8 to check the entirety of every file that has
  165. # a change in it. Unfortunately the --filenames argument to flake8 only accepts
  166. # file *names* and there are no files named (eg) "nova/compute/manager.py". The
  167. # --diff argument behaves surprisingly as well, because although you feed it a
  168. # diff, it actually checks the file on disk anyway.
  169. local base_commit=${testargs:-HEAD~1}
  170. files=$(git diff --name-only $base_commit | tr '\n' ' ')
  171. echo "Running flake8 on ${files}"
  172. warn_on_flake8_without_venv
  173. diff -u --from-file /dev/null ${files} | DJANGO_SETTINGS_MODULE=sahara_dashboard.test.settings ${command_wrapper} flake8 --diff
  174. exit
  175. }
  176. function run_sphinx {
  177. echo "Building sphinx..."
  178. DJANGO_SETTINGS_MODULE=sahara_dashboard.test.settings ${command_wrapper} python setup.py build_sphinx
  179. echo "Build complete."
  180. }
  181. function tab_check {
  182. TAB_VIOLATIONS=`find $included_dirs -type f -regex ".*\.\(css\|js\|py\|html\)" -print0 | xargs -0 awk '/\t/' | wc -l`
  183. if [ $TAB_VIOLATIONS -gt 0 ]; then
  184. echo "TABS! $TAB_VIOLATIONS of them! Oh no!"
  185. HORIZON_FILES=`find $included_dirs -type f -regex ".*\.\(css\|js\|py|\html\)"`
  186. for TABBED_FILE in $HORIZON_FILES
  187. do
  188. TAB_COUNT=`awk '/\t/' $TABBED_FILE | wc -l`
  189. if [ $TAB_COUNT -gt 0 ]; then
  190. echo "$TABBED_FILE: $TAB_COUNT"
  191. fi
  192. done
  193. fi
  194. return $TAB_VIOLATIONS;
  195. }
  196. function destroy_venv {
  197. echo "Cleaning environment..."
  198. echo "Removing virtualenv..."
  199. rm -rf $venv
  200. echo "Virtualenv removed."
  201. }
  202. function sanity_check {
  203. # Anything that should be determined prior to running the tests, server, etc.
  204. # Don't sanity-check anything environment-related in -N flag is set
  205. if [ $never_venv -eq 0 ]; then
  206. if [ ! -e ${venv} ]; then
  207. echo "Virtualenv not found at $venv. Did install_venv.py succeed?"
  208. exit 1
  209. fi
  210. fi
  211. # Remove .pyc files. This is sanity checking because they can linger
  212. # after old files are deleted.
  213. find . -name "*.pyc" -exec rm -rf {} \;
  214. }
  215. function backup_environment {
  216. if [ $backup_env -eq 1 ]; then
  217. echo "Backing up environment \"$JOB_NAME\"..."
  218. if [ ! -e ${venv} ]; then
  219. echo "Environment not installed. Cannot back up."
  220. return 0
  221. fi
  222. if [ -d /tmp/.horizon_environment/$JOB_NAME ]; then
  223. mv /tmp/.horizon_environment/$JOB_NAME /tmp/.horizon_environment/$JOB_NAME.old
  224. rm -rf /tmp/.horizon_environment/$JOB_NAME
  225. fi
  226. mkdir -p /tmp/.horizon_environment/$JOB_NAME
  227. cp -r $venv /tmp/.horizon_environment/$JOB_NAME/
  228. # Remove the backup now that we've completed successfully
  229. rm -rf /tmp/.horizon_environment/$JOB_NAME.old
  230. echo "Backup completed"
  231. fi
  232. }
  233. function restore_environment {
  234. if [ $restore_env -eq 1 ]; then
  235. echo "Restoring environment from backup..."
  236. if [ ! -d /tmp/.horizon_environment/$JOB_NAME ]; then
  237. echo "No backup to restore from."
  238. return 0
  239. fi
  240. cp -r /tmp/.horizon_environment/$JOB_NAME/.venv ./ || true
  241. echo "Environment restored successfully."
  242. fi
  243. }
  244. function install_venv {
  245. # Install with install_venv.py
  246. export UPPER_CONSTRAINTS_FILE=${UPPER_CONSTRAINTS_FILE:-$_default_uc}
  247. export PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE-/tmp/.pip_download_cache}
  248. export PIP_USE_MIRRORS=true
  249. if [ $quiet -eq 1 ]; then
  250. export PIP_NO_INPUT=true
  251. fi
  252. echo "Fetching new src packages..."
  253. rm -rf $venv/src
  254. python tools/install_venv.py
  255. command_wrapper="$root/${with_venv}"
  256. # Make sure it worked and record the environment version
  257. sanity_check
  258. chmod -R 754 $venv
  259. }
  260. function run_tests {
  261. sanity_check
  262. if [ $with_selenium -eq 1 ]; then
  263. export WITH_SELENIUM=1
  264. elif [ $only_selenium -eq 1 ]; then
  265. export WITH_SELENIUM=1
  266. export SKIP_UNITTESTS=1
  267. fi
  268. if [ $selenium_headless -eq 1 ]; then
  269. export SELENIUM_HEADLESS=1
  270. fi
  271. if [ -z "$testargs" ]; then
  272. run_tests_all
  273. else
  274. run_tests_subset
  275. fi
  276. }
  277. function run_tests_subset {
  278. project=`echo $testargs | awk -F. '{print $1}'`
  279. ${command_wrapper} python $root/manage.py test --settings=$project.test.settings $testopts $testargs
  280. }
  281. function run_tests_all {
  282. echo "Running sahara_dashboard application tests"
  283. export NOSE_XUNIT_FILE=sahara_dashboard/nosetests.xml
  284. if [ "$NOSE_WITH_HTML_OUTPUT" = '1' ]; then
  285. export NOSE_HTML_OUT_FILE='sahara_dashboard_nose_results.html'
  286. fi
  287. if [ $with_coverage -eq 1 ]; then
  288. ${command_wrapper} python -m coverage.__main__ erase
  289. coverage_run="python -m coverage.__main__ run -p"
  290. fi
  291. if [ $with_selenium -eq 0 -a $integration -eq 0 ]; then
  292. testopts="$testopts --exclude-dir=sahara_dashboard/test/integration_tests"
  293. fi
  294. ${command_wrapper} ${coverage_run} $root/manage.py test sahara_dashboard --settings=sahara_dashboard.test.settings $testopts
  295. # get results of the Horizon tests
  296. SAHARA_DASHBOARD_RESULT=$?
  297. if [ $with_coverage -eq 1 ]; then
  298. echo "Generating coverage reports"
  299. ${command_wrapper} python -m coverage.__main__ combine
  300. ${command_wrapper} python -m coverage.__main__ xml -i --omit='/usr*,setup.py,*egg*,.venv/*'
  301. ${command_wrapper} python -m coverage.__main__ html -i --omit='/usr*,setup.py,*egg*,.venv/*' -d reports
  302. fi
  303. # Remove the leftover coverage files from the -p flag earlier.
  304. rm -f .coverage.*
  305. PEP8_RESULT=0
  306. if [ $no_pep8 -eq 0 ] && [ $only_selenium -eq 0 ]; then
  307. run_pep8
  308. PEP8_RESULT=$?
  309. fi
  310. TEST_RESULT=$(($SAHARA_DASHBOARD_RESULT || $PEP8_RESULT))
  311. if [ $TEST_RESULT -eq 0 ]; then
  312. echo "Tests completed successfully."
  313. else
  314. echo "Tests failed."
  315. fi
  316. exit $TEST_RESULT
  317. }
  318. function run_integration_tests {
  319. export INTEGRATION_TESTS=1
  320. if [ $selenium_headless -eq 1 ]; then
  321. export SELENIUM_HEADLESS=1
  322. fi
  323. export HORIZON_INTEGRATION_TESTS_CONFIG_FILE="sahara_dashboard/test/integration_tests/horizon.conf"
  324. echo "Running Horizon integration tests..."
  325. if [ -z "$testargs" ]; then
  326. ${command_wrapper} nosetests sahara_dashboard/test/integration_tests/tests
  327. else
  328. ${command_wrapper} nosetests $testargs
  329. fi
  330. exit 0
  331. }
  332. function run_makemessages {
  333. OPTS="-l en --no-obsolete --settings=openstack_dashboard.test.settings"
  334. DASHBOARD_OPTS="--extension=html,txt,csv --ignore=openstack"
  335. echo -n "horizon: "
  336. cd horizon
  337. ${command_wrapper} $root/manage.py makemessages $OPTS
  338. HORIZON_PY_RESULT=$?
  339. echo -n "horizon javascript: "
  340. ${command_wrapper} $root/manage.py makemessages -d djangojs $OPTS
  341. HORIZON_JS_RESULT=$?
  342. echo -n "openstack_dashboard: "
  343. cd ../openstack_dashboard
  344. ${command_wrapper} $root/manage.py makemessages $DASHBOARD_OPTS $OPTS
  345. DASHBOARD_RESULT=$?
  346. cd ..
  347. if [ $check_only -eq 1 ]; then
  348. git checkout -- horizon/locale/en/LC_MESSAGES/django*.po
  349. git checkout -- openstack_dashboard/locale/en/LC_MESSAGES/django.po
  350. fi
  351. exit $(($HORIZON_PY_RESULT || $HORIZON_JS_RESULT || $DASHBOARD_RESULT))
  352. }
  353. function run_compilemessages {
  354. OPTS="--settings=openstack_dashboard.test.settings"
  355. cd horizon
  356. ${command_wrapper} $root/manage.py compilemessages $OPTS
  357. HORIZON_PY_RESULT=$?
  358. cd ../openstack_dashboard
  359. ${command_wrapper} $root/manage.py compilemessages $OPTS
  360. DASHBOARD_RESULT=$?
  361. cd ..
  362. # English is the source language, so compiled catalogs are unnecessary.
  363. rm -vf horizon/locale/en/LC_MESSAGES/django*.mo
  364. rm -vf openstack_dashboard/locale/en/LC_MESSAGES/django.mo
  365. exit $(($HORIZON_PY_RESULT || $DASHBOARD_RESULT))
  366. }
  367. function run_pseudo {
  368. for lang in $testargs
  369. # Use English po file as the source file/pot file just like real Horizon translations
  370. do
  371. ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/en/LC_MESSAGES/django.po openstack_dashboard/locale/$lang/LC_MESSAGES/django.po $lang
  372. ${command_wrapper} $root/tools/pseudo.py horizon/locale/en/LC_MESSAGES/django.po horizon/locale/$lang/LC_MESSAGES/django.po $lang
  373. ${command_wrapper} $root/tools/pseudo.py horizon/locale/en/LC_MESSAGES/djangojs.po horizon/locale/$lang/LC_MESSAGES/djangojs.po $lang
  374. done
  375. exit $?
  376. }
  377. # ---------PREPARE THE ENVIRONMENT------------ #
  378. # PROCESS ARGUMENTS, OVERRIDE DEFAULTS
  379. for arg in "$@"; do
  380. process_option $arg
  381. done
  382. if [ $quiet -eq 1 ] && [ $never_venv -eq 0 ] && [ $always_venv -eq 0 ]
  383. then
  384. always_venv=1
  385. fi
  386. # If destroy is set, just blow it away and exit.
  387. if [ $destroy -eq 1 ]; then
  388. destroy_venv
  389. exit 0
  390. fi
  391. # Ignore all of this if the -N flag was set
  392. if [ $never_venv -eq 0 ]; then
  393. # Restore previous environment if desired
  394. if [ $restore_env -eq 1 ]; then
  395. restore_environment
  396. fi
  397. # Remove the virtual environment if --force used
  398. if [ $force -eq 1 ]; then
  399. destroy_venv
  400. fi
  401. # Create or update venv.
  402. install_venv
  403. # Create a backup of the up-to-date environment if desired
  404. if [ $backup_env -eq 1 ]; then
  405. backup_environment
  406. fi
  407. fi
  408. # ---------EXERCISE THE CODE------------ #
  409. # Run management commands
  410. if [ $manage -eq 1 ]; then
  411. run_management_command
  412. exit $?
  413. fi
  414. # Build the docs
  415. if [ $just_docs -eq 1 ]; then
  416. run_sphinx
  417. exit $?
  418. fi
  419. # Update translation files
  420. if [ $makemessages -eq 1 ]; then
  421. run_makemessages
  422. exit $?
  423. fi
  424. # Compile translation files
  425. if [ $compilemessages -eq 1 ]; then
  426. run_compilemessages
  427. exit $?
  428. fi
  429. # Generate Pseudo translation
  430. if [ $pseudo -eq 1 ]; then
  431. run_pseudo
  432. exit $?
  433. fi
  434. # PEP8
  435. if [ $just_pep8 -eq 1 ]; then
  436. run_pep8
  437. exit $?
  438. fi
  439. if [ $just_pep8_changed -eq 1 ]; then
  440. run_pep8_changed
  441. exit $?
  442. fi
  443. # Pylint
  444. if [ $just_pylint -eq 1 ]; then
  445. run_pylint
  446. exit $?
  447. fi
  448. # Tab checker
  449. if [ $just_tabs -eq 1 ]; then
  450. tab_check
  451. exit $?
  452. fi
  453. # Integration tests
  454. if [ $integration -eq 1 ]; then
  455. run_integration_tests
  456. exit $?
  457. fi
  458. # Django development server
  459. if [ $runserver -eq 1 ]; then
  460. run_server
  461. exit $?
  462. fi
  463. # Full test suite
  464. run_tests || exit