Horizon Web interface for Freezer backup, restore and disaster recovery platform
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

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