summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMemo Garcia <sirmemogarcia@gmail.com>2016-08-08 17:16:54 +0100
committerMemo GarcĂ­a <sirmemogarcia@gmail.com>2016-09-04 18:08:50 +0100
commitd91aff5de8e8a7a43a640e2a11953e4bd7aa7551 (patch)
tree556ce7ef0d2964bdfe69b5030da3f69b9abb3e7d
parentddc6321e6d49025bea560b24a3d4043a1af0ef26 (diff)
Updated tox.ini to support new test environment
Notes
Notes (review): Code-Review+2: Pierre Mathieu <pierre-arthur.mathieu@hpe.com> Code-Review+1: Ryan Peters <rjpeter2@gmail.com> Workflow+1: Saad Zaher <saad.zaher@hpe.com> Verified+2: Jenkins Submitted-by: Jenkins Submitted-at: Wed, 07 Sep 2016 15:48:27 +0000 Reviewed-on: https://review.openstack.org/352501 Project: openstack/freezer-web-ui Branch: refs/heads/master
-rw-r--r--disaster_recovery/api/api.py8
-rw-r--r--disaster_recovery/sessions/tables.py2
-rw-r--r--disaster_recovery/sessions/workflows/create.py3
-rw-r--r--disaster_recovery/tests/__init__.py (renamed from tests/__init__.py)0
-rw-r--r--disaster_recovery/tests/settings.py86
-rw-r--r--disaster_recovery/tests/test_api.py (renamed from tests/test_api.py)0
-rwxr-xr-xmanage.py23
-rwxr-xr-xrun_tests.sh583
-rw-r--r--test-requirements.txt42
-rw-r--r--tests/api_tests.py94
-rw-r--r--tests/rest_api_tests.py44
-rw-r--r--tests/settings.py20
-rw-r--r--tools/install_venv.py58
-rw-r--r--tools/install_venv_common.py165
-rwxr-xr-xtools/with_venv.sh7
-rw-r--r--tox.ini45
16 files changed, 982 insertions, 198 deletions
diff --git a/disaster_recovery/api/api.py b/disaster_recovery/api/api.py
index 85d9be6..6204a2b 100644
--- a/disaster_recovery/api/api.py
+++ b/disaster_recovery/api/api.py
@@ -465,13 +465,13 @@ class Backup(object):
465 self.request = request 465 self.request = request
466 self.client = client(request) 466 self.client = client(request)
467 467
468 def list(self, json=False, limit=500, offset=0, search=None): 468 def list(self, json=False, limit=500, offset=0, search={}):
469 if search: 469 if search:
470 search = {"match": [{"_all": search}, ], } 470 search = {"match": [{"_all": search}, ], }
471 471
472 backups = self.client.backups.list(limit=limit, 472 backups = self.client.backups.list_all(limit=limit,
473 offset=offset, 473 offset=offset,
474 search=search) 474 search=search)
475 475
476 if json: 476 if json:
477 return backups 477 return backups
diff --git a/disaster_recovery/sessions/tables.py b/disaster_recovery/sessions/tables.py
index 8ac09d4..06a551e 100644
--- a/disaster_recovery/sessions/tables.py
+++ b/disaster_recovery/sessions/tables.py
@@ -17,9 +17,9 @@ import logging
17 17
18from django.utils.translation import ugettext_lazy as _ 18from django.utils.translation import ugettext_lazy as _
19from django.utils.translation import ungettext_lazy 19from django.utils.translation import ungettext_lazy
20from django.core.urlresolvers import reverse
20 21
21from horizon import tables 22from horizon import tables
22from django.core.urlresolvers import reverse
23 23
24import disaster_recovery.api.api as freezer_api 24import disaster_recovery.api.api as freezer_api
25from disaster_recovery.utils import shield 25from disaster_recovery.utils import shield
diff --git a/disaster_recovery/sessions/workflows/create.py b/disaster_recovery/sessions/workflows/create.py
index 321821f..e02a3c9 100644
--- a/disaster_recovery/sessions/workflows/create.py
+++ b/disaster_recovery/sessions/workflows/create.py
@@ -15,8 +15,9 @@
15import datetime 15import datetime
16import logging 16import logging
17 17
18from django.utils.translation import ugettext_lazy as _
19from django.core.urlresolvers import reverse 18from django.core.urlresolvers import reverse
19from django.utils.translation import ugettext_lazy as _
20
20 21
21from horizon import exceptions 22from horizon import exceptions
22from horizon import forms 23from horizon import forms
diff --git a/tests/__init__.py b/disaster_recovery/tests/__init__.py
index e69de29..e69de29 100644
--- a/tests/__init__.py
+++ b/disaster_recovery/tests/__init__.py
diff --git a/disaster_recovery/tests/settings.py b/disaster_recovery/tests/settings.py
new file mode 100644
index 0000000..f24d56a
--- /dev/null
+++ b/disaster_recovery/tests/settings.py
@@ -0,0 +1,86 @@
1# (c) Copyright 2014-2016 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import socket
16
17from horizon.test.settings import * # noqa
18
19SECRET_KEY = 'HELLA_SECRET!'
20
21DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3',
22 'NAME': 'test'}}
23
24
25socket.setdefaulttimeout(1)
26
27DEBUG = False
28TEMPLATE_DEBUG = DEBUG
29
30TESTSERVER = 'http://testserver'
31
32
33MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
34
35TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
36NOSE_ARGS = ['--nocapture',
37 '--nologcapture',
38 '--cover-package=windc']
39
40EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
41SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
42
43OPENSTACK_ADDRESS = "localhost"
44OPENSTACK_ADMIN_TOKEN = "openstack"
45OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_ADDRESS
46OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_ADDRESS
47OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"
48FREEZER_API_URL = "test"
49
50# Silence logging output during tests.
51LOGGING = {
52 'version': 1,
53 'disable_existing_loggers': False,
54 'handlers': {
55 'null': {
56 'level': 'DEBUG',
57 'class': 'logging.NullHandler'
58 },
59 },
60 'loggers': {
61 'django.db.backends': {
62 'handlers': ['null'],
63 'propagate': False,
64 },
65 'horizon': {
66 'handlers': ['null'],
67 'propagate': False,
68 },
69 'novaclient': {
70 'handlers': ['null'],
71 'propagate': False,
72 },
73 'keystoneclient': {
74 'handlers': ['null'],
75 'propagate': False,
76 },
77 'quantum': {
78 'handlers': ['null'],
79 'propagate': False,
80 },
81 'nose.plugins.manager': {
82 'handlers': ['null'],
83 'propagate': False,
84 }
85 }
86}
diff --git a/tests/test_api.py b/disaster_recovery/tests/test_api.py
index e69de29..e69de29 100644
--- a/tests/test_api.py
+++ b/disaster_recovery/tests/test_api.py
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..6fd19f1
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,23 @@
1#!/usr/bin/env python
2# Copyright 2014 Hewlett-Packard Development Company, L.P.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15import os
16import sys
17
18
19if __name__ == "__main__":
20 os.environ.setdefault(
21 "DJANGO_SETTINGS_MODULE", "disaster_recovery.tests.settings")
22 from django.core.management import execute_from_command_line # noqa
23 execute_from_command_line(sys.argv)
diff --git a/run_tests.sh b/run_tests.sh
new file mode 100755
index 0000000..aed8402
--- /dev/null
+++ b/run_tests.sh
@@ -0,0 +1,583 @@
1#!/bin/bash
2
3set -o errexit
4
5function usage {
6 echo "Usage: $0 [OPTION]..."
7 echo "Run Horizon's test suite(s)"
8 echo ""
9 echo " -V, --virtual-env Always use virtualenv. Install automatically"
10 echo " if not present"
11 echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local"
12 echo " environment"
13 echo " -c, --coverage Generate reports using Coverage"
14 echo " -f, --force Force a clean re-build of the virtual"
15 echo " environment. Useful when dependencies have"
16 echo " been added."
17 echo " -m, --manage Run a Django management command."
18 echo " --makemessages Create/Update English translation files."
19 echo " --compilemessages Compile all translation files."
20 echo " --check-only Do not update translation files (--makemessages only)."
21 echo " --pseudo Pseudo translate a language."
22 echo " -p, --pep8 Just run pep8"
23 echo " -8, --pep8-changed [<basecommit>]"
24 echo " Just run PEP8 and HACKING compliance check"
25 echo " on files changed since HEAD~1 (or <basecommit>)"
26 echo " -P, --no-pep8 Don't run pep8 by default"
27 echo " -t, --tabs Check for tab characters in files."
28 echo " -y, --pylint Just run pylint"
29 echo " -e, --eslint Just run eslint"
30 echo " -k, --karma Just run karma"
31 echo " -q, --quiet Run non-interactively. (Relatively) quiet."
32 echo " Implies -V if -N is not set."
33 echo " --only-selenium Run only the Selenium unit tests"
34 echo " --with-selenium Run unit tests including Selenium tests"
35 echo " --selenium-headless Run Selenium tests headless"
36 echo " --integration Run the integration tests (requires a running "
37 echo " OpenStack environment)"
38 echo " --runserver Run the Django development server for"
39 echo " openstack_dashboard in the virtual"
40 echo " environment."
41 echo " --docs Just build the documentation"
42 echo " --backup-environment Make a backup of the environment on exit"
43 echo " --restore-environment Restore the environment before running"
44 echo " --destroy-environment Destroy the environment and exit"
45 echo " -h, --help Print this usage message"
46 echo ""
47 echo "Note: with no options specified, the script will try to run the tests in"
48 echo " a virtual environment, If no virtualenv is found, the script will ask"
49 echo " if you would like to create one. If you prefer to run tests NOT in a"
50 echo " virtual environment, simply pass the -N option."
51 exit
52}
53
54# DEFAULTS FOR RUN_TESTS.SH
55#
56root=`pwd -P`
57venv=$root/.venv
58venv_env_version=$venv/environments
59with_venv=tools/with_venv.sh
60included_dirs="disaster_recovery"
61
62always_venv=0
63backup_env=0
64command_wrapper=""
65destroy=0
66force=0
67just_pep8=0
68just_pep8_changed=0
69no_pep8=0
70just_pylint=0
71just_docs=0
72just_tabs=0
73just_eslint=0
74just_karma=0
75never_venv=0
76quiet=0
77restore_env=0
78runserver=0
79only_selenium=0
80with_selenium=0
81selenium_headless=0
82integration=0
83testopts=""
84testargs=""
85with_coverage=0
86makemessages=0
87compilemessages=0
88check_only=0
89pseudo=0
90manage=0
91
92# Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default"
93[ "$JOB_NAME" ] || JOB_NAME="default"
94
95function process_option {
96 # If running manage command, treat the rest of options as arguments.
97 if [ $manage -eq 1 ]; then
98 testargs="$testargs $1"
99 return 0
100 fi
101
102 case "$1" in
103 -h|--help) usage;;
104 -V|--virtual-env) always_venv=1; never_venv=0;;
105 -N|--no-virtual-env) always_venv=0; never_venv=1;;
106 -p|--pep8) just_pep8=1;;
107 -8|--pep8-changed) just_pep8_changed=1;;
108 -P|--no-pep8) no_pep8=1;;
109 -y|--pylint) just_pylint=1;;
110 -e|--eslint) just_eslint=1;;
111 -k|--karma) just_karma=1;;
112 -f|--force) force=1;;
113 -t|--tabs) just_tabs=1;;
114 -q|--quiet) quiet=1;;
115 -c|--coverage) with_coverage=1;;
116 -m|--manage) manage=1;;
117 --makemessages) makemessages=1;;
118 --compilemessages) compilemessages=1;;
119 --check-only) check_only=1;;
120 --pseudo) pseudo=1;;
121 --only-selenium) only_selenium=1;;
122 --with-selenium) with_selenium=1;;
123 --selenium-headless) selenium_headless=1;;
124 --integration) integration=1;;
125 --docs) just_docs=1;;
126 --runserver) runserver=1;;
127 --backup-environment) backup_env=1;;
128 --restore-environment) restore_env=1;;
129 --destroy-environment) destroy=1;;
130 -*) testopts="$testopts $1";;
131 *) testargs="$testargs $1"
132 esac
133}
134
135function run_management_command {
136 ${command_wrapper} python $root/manage.py $testopts $testargs
137}
138
139function run_server {
140 echo "Starting Django development server..."
141 ${command_wrapper} python $root/manage.py runserver $testopts $testargs
142 echo "Server stopped."
143}
144
145function run_pylint {
146 echo "Running pylint ..."
147 PYTHONPATH=$root ${command_wrapper} pylint --rcfile=.pylintrc -f parseable $included_dirs > pylint.txt || true
148 CODE=$?
149 grep Global -A2 pylint.txt
150 if [ $CODE -lt 32 ]; then
151 echo "Completed successfully."
152 exit 0
153 else
154 echo "Completed with problems."
155 exit $CODE
156 fi
157}
158
159function run_eslint {
160 echo "Running eslint ..."
161 if [ "`which npm`" == '' ] ; then
162 echo "npm is not present; please install, e.g. sudo apt-get install npm"
163 else
164 npm install
165 npm run lint
166 fi
167}
168
169function run_karma {
170 echo "Running karma ..."
171 npm install
172 npm run test
173}
174
175function warn_on_flake8_without_venv {
176 set +o errexit
177 ${command_wrapper} python -c "import hacking" 2>/dev/null
178 no_hacking=$?
179 set -o errexit
180 if [ $never_venv -eq 1 -a $no_hacking -eq 1 ]; then
181 echo "**WARNING**:" >&2
182 echo "OpenStack hacking is not installed on your host. Its detection will be missed." >&2
183 echo "Please install or use virtual env if you need OpenStack hacking detection." >&2
184 fi
185}
186
187function run_pep8 {
188 echo "Running flake8 ..."
189 warn_on_flake8_without_venv
190 DJANGO_SETTINGS_MODULE=disaster_recovery.test.settings ${command_wrapper} flake8
191}
192
193function run_pep8_changed {
194 # NOTE(gilliard) We want use flake8 to check the entirety of every file that has
195 # a change in it. Unfortunately the --filenames argument to flake8 only accepts
196 # file *names* and there are no files named (eg) "nova/compute/manager.py". The
197 # --diff argument behaves surprisingly as well, because although you feed it a
198 # diff, it actually checks the file on disk anyway.
199 local base_commit=${testargs:-HEAD~1}
200 files=$(git diff --name-only $base_commit | tr '\n' ' ')
201 echo "Running flake8 on ${files}"
202 warn_on_flake8_without_venv
203 diff -u --from-file /dev/null ${files} | DJANGO_SETTINGS_MODULE=disaster_recovery.test.settings ${command_wrapper} flake8 --diff
204 exit
205}
206
207function run_sphinx {
208 echo "Building sphinx..."
209 DJANGO_SETTINGS_MODULE=disaster_recovery.test.settings ${command_wrapper} python setup.py build_sphinx
210 echo "Build complete."
211}
212
213function tab_check {
214 TAB_VIOLATIONS=`find $included_dirs -type f -regex ".*\.\(css\|js\|py\|html\)" -print0 | xargs -0 awk '/\t/' | wc -l`
215 if [ $TAB_VIOLATIONS -gt 0 ]; then
216 echo "TABS! $TAB_VIOLATIONS of them! Oh no!"
217 HORIZON_FILES=`find $included_dirs -type f -regex ".*\.\(css\|js\|py|\html\)"`
218 for TABBED_FILE in $HORIZON_FILES
219 do
220 TAB_COUNT=`awk '/\t/' $TABBED_FILE | wc -l`
221 if [ $TAB_COUNT -gt 0 ]; then
222 echo "$TABBED_FILE: $TAB_COUNT"
223 fi
224 done
225 fi
226 return $TAB_VIOLATIONS;
227}
228
229function destroy_venv {
230 echo "Cleaning environment..."
231 echo "Removing virtualenv..."
232 rm -rf $venv
233 echo "Virtualenv removed."
234}
235
236function environment_check {
237 echo "Checking environment."
238 if [ -f $venv_env_version ]; then
239 set +o errexit
240 cat requirements.txt test-requirements.txt | cmp $venv_env_version - > /dev/null
241 local env_check_result=$?
242 set -o errexit
243 if [ $env_check_result -eq 0 ]; then
244 # If the environment exists and is up-to-date then set our variables
245 command_wrapper="${root}/${with_venv}"
246 echo "Environment is up to date."
247 return 0
248 fi
249 fi
250
251 if [ $always_venv -eq 1 ]; then
252 install_venv
253 else
254 if [ ! -e ${venv} ]; then
255 echo -e "Environment not found. Install? (Y/n) \c"
256 else
257 echo -e "Your environment appears to be out of date. Update? (Y/n) \c"
258 fi
259 read update_env
260 if [ "x$update_env" = "xY" -o "x$update_env" = "x" -o "x$update_env" = "xy" ]; then
261 install_venv
262 else
263 # Set our command wrapper anyway.
264 command_wrapper="${root}/${with_venv}"
265 fi
266 fi
267}
268
269function sanity_check {
270 # Anything that should be determined prior to running the tests, server, etc.
271 # Don't sanity-check anything environment-related in -N flag is set
272 if [ $never_venv -eq 0 ]; then
273 if [ ! -e ${venv} ]; then
274 echo "Virtualenv not found at $venv. Did install_venv.py succeed?"
275 exit 1
276 fi
277 fi
278 # Remove .pyc files. This is sanity checking because they can linger
279 # after old files are deleted.
280 find . -name "*.pyc" -exec rm -rf {} \;
281}
282
283function backup_environment {
284 if [ $backup_env -eq 1 ]; then
285 echo "Backing up environment \"$JOB_NAME\"..."
286 if [ ! -e ${venv} ]; then
287 echo "Environment not installed. Cannot back up."
288 return 0
289 fi
290 if [ -d /tmp/.horizon_environment/$JOB_NAME ]; then
291 mv /tmp/.horizon_environment/$JOB_NAME /tmp/.horizon_environment/$JOB_NAME.old
292 rm -rf /tmp/.horizon_environment/$JOB_NAME
293 fi
294 mkdir -p /tmp/.horizon_environment/$JOB_NAME
295 cp -r $venv /tmp/.horizon_environment/$JOB_NAME/
296 # Remove the backup now that we've completed successfully
297 rm -rf /tmp/.horizon_environment/$JOB_NAME.old
298 echo "Backup completed"
299 fi
300}
301
302function restore_environment {
303 if [ $restore_env -eq 1 ]; then
304 echo "Restoring environment from backup..."
305 if [ ! -d /tmp/.horizon_environment/$JOB_NAME ]; then
306 echo "No backup to restore from."
307 return 0
308 fi
309
310 cp -r /tmp/.horizon_environment/$JOB_NAME/.venv ./ || true
311 echo "Environment restored successfully."
312 fi
313}
314
315function install_venv {
316 # Install with install_venv.py
317 export PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE-/tmp/.pip_download_cache}
318 export PIP_USE_MIRRORS=true
319 if [ $quiet -eq 1 ]; then
320 export PIP_NO_INPUT=true
321 fi
322 echo "Fetching new src packages..."
323 rm -rf $venv/src
324 python tools/install_venv.py
325 command_wrapper="$root/${with_venv}"
326 # Make sure it worked and record the environment version
327 sanity_check
328 chmod -R 754 $venv
329 cat requirements.txt test-requirements.txt > $venv_env_version
330}
331
332function run_tests {
333 sanity_check
334
335 if [ $with_selenium -eq 1 ]; then
336 export WITH_SELENIUM=1
337 elif [ $only_selenium -eq 1 ]; then
338 export WITH_SELENIUM=1
339 export SKIP_UNITTESTS=1
340 fi
341
342 if [ $with_selenium -eq 0 -a $integration -eq 0 ]; then
343 testopts="$testopts --exclude-dir=disaster_recovery/test/integration_tests"
344 fi
345
346 if [ $selenium_headless -eq 1 ]; then
347 export SELENIUM_HEADLESS=1
348 fi
349
350 if [ -z "$testargs" ]; then
351 run_tests_all
352 else
353 run_tests_subset
354 fi
355}
356
357function run_tests_subset {
358 project=`echo $testargs | awk -F. '{print $1}'`
359 ${command_wrapper} python $root/manage.py test --settings=$project.test.settings $testopts $testargs
360}
361
362function run_tests_all {
363 echo "Running Freezer Web UI tests"
364 export NOSE_XUNIT_FILE=disaster_recovery/nosetests.xml
365 if [ "$NOSE_WITH_HTML_OUTPUT" = '1' ]; then
366 export NOSE_HTML_OUT_FILE='dashboard_nose_results.html'
367 fi
368 ${command_wrapper} ${coverage_run} $root/manage.py test disaster_recovery --settings=disaster_recovery.test.settings $testopts
369 # get results of the openstack_dashboard tests
370 DASHBOARD_RESULT=$?
371
372 if [ $with_coverage -eq 1 ]; then
373 echo "Generating coverage reports"
374 ${command_wrapper} python -m coverage.__main__ combine
375 ${command_wrapper} python -m coverage.__main__ xml -i --include="horizon/*,openstack_dashboard/*" --omit='/usr*,setup.py,*egg*,.venv/*'
376 ${command_wrapper} python -m coverage.__main__ html -i --include="horizon/*,openstack_dashboard/*" --omit='/usr*,setup.py,*egg*,.venv/*' -d reports
377 fi
378 # Remove the leftover coverage files from the -p flag earlier.
379 rm -f .coverage.*
380
381 PEP8_RESULT=0
382 if [ $no_pep8 -eq 0 ] && [ $only_selenium -eq 0 ]; then
383 run_pep8
384 PEP8_RESULT=$?
385 fi
386
387 TEST_RESULT=$(($DASHBOARD_RESULT || $PEP8_RESULT))
388 if [ $TEST_RESULT -eq 0 ]; then
389 echo "Tests completed successfully."
390 else
391 echo "Tests failed."
392 fi
393 exit $TEST_RESULT
394}
395
396function run_integration_tests {
397 export INTEGRATION_TESTS=1
398
399 if [ $selenium_headless -eq 1 ]; then
400 export SELENIUM_HEADLESS=1
401 fi
402
403 echo "Running Horizon integration tests..."
404 if [ -z "$testargs" ]; then
405 ${command_wrapper} nosetests openstack_dashboard/test/integration_tests/tests
406 else
407 ${command_wrapper} nosetests $testargs
408 fi
409 exit 0
410}
411
412function babel_extract {
413 DOMAIN=$1
414 KEYWORDS="-k gettext_noop -k gettext_lazy -k ngettext_lazy:1,2"
415 KEYWORDS+=" -k ugettext_noop -k ugettext_lazy -k ungettext_lazy:1,2"
416 KEYWORDS+=" -k npgettext:1c,2,3 -k pgettext_lazy:1c,2 -k npgettext_lazy:1c,2,3"
417
418 ${command_wrapper} pybabel extract -F ../babel-${DOMAIN}.cfg -o locale/${DOMAIN}.pot $KEYWORDS .
419}
420
421function run_makemessages {
422
423 echo -n "freezer web ui: "
424 cd disaster_recovery
425 babel_extract django
426 FREEZER_PY_RESULT=$?
427
428 echo -n "freezer web ui javascript: "
429 babel_extract djangojs
430 FREEZER_JS_RESULT=$?
431
432 cd ..
433 if [ $check_only -eq 1 ]; then
434 rm disaster_recovery/locale/django*.pot
435 fi
436
437 exit $(($FREEZER_PY_RESULT || $FREEZER_JS_RESULT))
438}
439
440function run_compilemessages {
441 cd horizon
442 ${command_wrapper} $root/manage.py compilemessages
443 HORIZON_PY_RESULT=$?
444 cd ../openstack_dashboard
445 ${command_wrapper} $root/manage.py compilemessages
446 DASHBOARD_RESULT=$?
447 exit $(($HORIZON_PY_RESULT || $DASHBOARD_RESULT))
448}
449
450function run_pseudo {
451 for lang in $testargs
452 # Use English pot file as the source file/pot file just like real Horizon translations
453 do
454 ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/django.pot openstack_dashboard/locale/$lang/LC_MESSAGES/django.po $lang
455 ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/djangojs.pot openstack_dashboard/locale/$lang/LC_MESSAGES/djangojs.po $lang
456 ${command_wrapper} $root/tools/pseudo.py horizon/locale/django.pot horizon/locale/$lang/LC_MESSAGES/django.po $lang
457 ${command_wrapper} $root/tools/pseudo.py horizon/locale/djangojs.pot horizon/locale/$lang/LC_MESSAGES/djangojs.po $lang
458 done
459 exit $?
460}
461
462
463# ---------PREPARE THE ENVIRONMENT------------ #
464
465# PROCESS ARGUMENTS, OVERRIDE DEFAULTS
466for arg in "$@"; do
467 process_option $arg
468done
469
470if [ $quiet -eq 1 ] && [ $never_venv -eq 0 ] && [ $always_venv -eq 0 ]
471then
472 always_venv=1
473fi
474
475# If destroy is set, just blow it away and exit.
476if [ $destroy -eq 1 ]; then
477 destroy_venv
478 exit 0
479fi
480
481# Ignore all of this if the -N flag was set
482if [ $never_venv -eq 0 ]; then
483
484 # Restore previous environment if desired
485 if [ $restore_env -eq 1 ]; then
486 restore_environment
487 fi
488
489 # Remove the virtual environment if --force used
490 if [ $force -eq 1 ]; then
491 destroy_venv
492 fi
493
494 # Then check if it's up-to-date
495 environment_check
496
497 # Create a backup of the up-to-date environment if desired
498 if [ $backup_env -eq 1 ]; then
499 backup_environment
500 fi
501fi
502
503# ---------EXERCISE THE CODE------------ #
504
505# Run management commands
506if [ $manage -eq 1 ]; then
507 run_management_command
508 exit $?
509fi
510
511# Build the docs
512if [ $just_docs -eq 1 ]; then
513 run_sphinx
514 exit $?
515fi
516
517# Update translation files
518if [ $makemessages -eq 1 ]; then
519 run_makemessages
520 exit $?
521fi
522
523# Compile translation files
524if [ $compilemessages -eq 1 ]; then
525 run_compilemessages
526 exit $?
527fi
528
529# Generate Pseudo translation
530if [ $pseudo -eq 1 ]; then
531 run_pseudo
532 exit $?
533fi
534
535# PEP8
536if [ $just_pep8 -eq 1 ]; then
537 run_pep8
538 exit $?
539fi
540
541if [ $just_pep8_changed -eq 1 ]; then
542 run_pep8_changed
543 exit $?
544fi
545
546# Pylint
547if [ $just_pylint -eq 1 ]; then
548 run_pylint
549 exit $?
550fi
551
552# ESLint
553if [ $just_eslint -eq 1 ]; then
554 run_eslint
555 exit $?
556fi
557
558# Karma
559if [ $just_karma -eq 1 ]; then
560 run_karma
561 exit $?
562fi
563
564# Tab checker
565if [ $just_tabs -eq 1 ]; then
566 tab_check
567 exit $?
568fi
569
570# Integration tests
571if [ $integration -eq 1 ]; then
572 run_integration_tests
573 exit $?
574fi
575
576# Django development server
577if [ $runserver -eq 1 ]; then
578 run_server
579 exit $?
580fi
581
582# Full test suite
583run_tests || exit \ No newline at end of file
diff --git a/test-requirements.txt b/test-requirements.txt
index c2281ea..e3be0de 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,22 +1,26 @@
1# The order of packages is significant, because pip processes them in the order 1# The order of packages is significant, because pip processes them in the order
2# of appearance. Changing the order has an impact on the overall integration 2# of appearance. Changing the order has an impact on the overall integration
3# process, which may cause wedges in the gate later. 3# process, which may cause wedges in the gate later.
4astroid<1.4.0 # breaks pylint 1.4.4 4hacking>=0.11.0,<0.12 # Apache-2.0
5hacking>=0.10.2,<0.11 5
6coverage>=3.6 6coverage>=3.6 # Apache-2.0
7discover 7mock>=2.0 # BSD
8python-subunit>=0.0.18 8mox>=0.5.3 # Apache-2.0
9sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3 9mox3>=0.7.0 # Apache-2.0
10oslosphinx>=2.5.0 # Apache-2.0 10oslo.config>=3.14.0 # Apache-2.0
11oslotest>=1.10.0 # Apache-2.0 11pylint==1.4.5 # GPLv2
12testrepository>=0.0.18 12testrepository>=0.0.18 # Apache-2.0/BSD
13testscenarios>=0.4 13testtools>=1.4.0 # MIT
14testtools>=1.4.0 14unittest2 # BSD
15pbr>=1.6 15sphinx>=1.2.1,!=1.3b1,<1.3 # BSD
16flake8>=2.2.4,<=2.4.1 16oslosphinx>=2.5.0,!=3.4.0 # Apache-2.0
17pytest 17nose # LGPL
18pytest-cov 18nosehtmloutput>=0.0.3 # Apache-2.0
19pytest-xdist 19openstack.nose_plugin>=0.7 # Apache-2.0
20pylint==1.4.4 # GNU GPL v2 20django-nose>=1.4.4 # BSD
21testresources>=0.2.4 21nosexcover # BSD
22mock>=1.2 22
23# Horizon requirements
24Django<1.9,>=1.8 # BSD
25django-compressor>=2.0 # MIT
26django_openstack_auth>=2.4.0 # Apache-2.0 \ No newline at end of file
diff --git a/tests/api_tests.py b/tests/api_tests.py
deleted file mode 100644
index f0736a9..0000000
--- a/tests/api_tests.py
+++ /dev/null
@@ -1,94 +0,0 @@
1# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from django.conf import settings
16from horizon_web_ui.freezer_ui.api import api
17from mock import patch
18from openstack_auth import utils
19import openstack_dashboard.test.helpers as helpers
20
21
22@patch('freezer.apiclient.client')
23class TestApi(helpers.TestCase):
24 CONFIG = {u'user_name': u'admin',
25 u'config_id': u'053a62e0-66a9-4a1c-ba58-6b7348d22166',
26 u'config_file': {u'start_datetime': u'1432736797',
27 u'repeat': u'1440',
28 u'max_priority': False,
29 u'encryption_password': u'secret',
30 u'src_file': u'fdsfsdds',
31 u'clients': [u'test-client'],
32 u'levels': 0,
33 u'proxy': u'',
34 u'container_name': u'dummy_container',
35 u'exclude': u'/tmp',
36 u'compression': u'gzip',
37 u'log_file': u'',
38 u'optimize': u'speed',
39 u'name': u'fdsfs'},
40 u'user_id': u'13c2b15308c04cdf86989ee7335eb504'}
41
42 def setUp(self):
43 super(TestApi, self).setUp()
44
45 # Usually this monkey patching happens in urls.py. This doesn't work
46 # here because we never invoke urls.py in this test. So we have to do
47 # it manually.
48 utils.patch_middleware_get_user()
49
50 def _setup_request(self):
51 super(TestApi, self)._setup_request()
52 # For some strange reason, Horizon sets the token to the token id
53 # rather than the token object. This fixes it.
54 self.request.session['token'] = self.token
55
56 def assert_client_got_created(self, client_mock):
57 client_mock.Client.assert_called_with(
58 token=self.request.session['token'].id,
59 auth_url=settings.OPENSTACK_KEYSTONE_URL,
60 endpoint=settings.FREEZER_API_URL)
61
62 def test_configuration_delete(self, client_mock):
63 api.configuration_delete(
64 self.request, u'053a62e0-66a9-4a1c-ba58-6b7348d22166')
65
66 self.assert_client_got_created(client_mock)
67 client_mock.Client().configs.delete.\
68 assert_called_once_with(u'053a62e0-66a9-4a1c-ba58-6b7348d22166')
69
70 def test_configuration_clone(self, client_mock):
71 client_mock.Client().configs.get.return_value = [self.CONFIG]
72 client_mock.Client().configs.\
73 create.return_value = u'28124cf0-6cd3-4b38-a0e9-b6f41568fa37'
74
75 result = api.configuration_clone(
76 self.request, u'053a62e0-66a9-4a1c-ba58-6b7348d22166')
77
78 self.assertEqual(result, u'28124cf0-6cd3-4b38-a0e9-b6f41568fa37')
79 self.assert_client_got_created(client_mock)
80 data = self.CONFIG[u'config_file']
81 data['name'] = 'fdsfs_clone'
82 client_mock.Client().configs.create.assert_called_once_with(data)
83
84 def test_configuration_get(self, client_mock):
85 client_mock.Client().configs.get.return_value = [self.CONFIG]
86
87 result = api.configuration_get(
88 self.request, u'053a62e0-66a9-4a1c-ba58-6b7348d22166')
89
90 self.assertEqual(1, len(result))
91 # Test if properties are accessible via object properties
92 self.assertEqual(u'admin', result[0].user_name)
93 # Test if nested properties are accessible via object properties
94 self.assertEqual(u'1432736797', result[0].start_datetime)
diff --git a/tests/rest_api_tests.py b/tests/rest_api_tests.py
deleted file mode 100644
index 7a66b2d..0000000
--- a/tests/rest_api_tests.py
+++ /dev/null
@@ -1,44 +0,0 @@
1# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import json
16from mock import patch
17
18from django.core.urlresolvers import reverse
19import openstack_dashboard.test.helpers as helpers
20
21
22@patch('freezer.apiclient.client')
23class TestRestApi(helpers.TestCase):
24 CLIENT_1 = {u'client': {u'hostname': u'jonas',
25 u'description': u'client description',
26 u'client_id': u'test-client',
27 u'config_ids': [u'fdaf2fwf2', u'fdsfdsfdsfs']},
28 u'user_id': u'13c2b15308c04cdf86989ee7335eb504'}
29
30 JSON_PREFIX = ')]}\',\n'
31
32 def test_clients_get(self, client_mock):
33 client_mock.Client().registration.list.return_value = [self.CLIENT_1]
34 url = reverse("horizon:freezer_ui:api_clients")
35
36 res = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
37
38 self.assertEqual(200, res.status_code)
39 self.assertEqual('application/json', res['content-type'])
40 self.assertEqual(self.JSON_PREFIX + json.dumps([self.CLIENT_1]),
41 res.content)
42 # there is no get ALL api at the moment, so we just fetch a big number
43 client_mock.Client().registration.list.assert_called_once_with(
44 limit=9999)
diff --git a/tests/settings.py b/tests/settings.py
deleted file mode 100644
index 80c2ef2..0000000
--- a/tests/settings.py
+++ /dev/null
@@ -1,20 +0,0 @@
1# (c) Copyright 2014,2015 Hewlett-Packard Development Company, L.P.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15from horizon.test.settings import * # noqa
16
17INSTALLED_APPS = ()
18OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0"
19OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"
20FREEZER_API_URL = "test"
diff --git a/tools/install_venv.py b/tools/install_venv.py
new file mode 100644
index 0000000..0e955c5
--- /dev/null
+++ b/tools/install_venv.py
@@ -0,0 +1,58 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13import os
14import sys
15
16import install_venv_common as install_venv # noqa
17
18
19def print_help(venv, root):
20 help = """
21 OpenStack development environment setup is complete.
22 OpenStack development uses virtualenv to track and manage Python
23 dependencies while in development and testing.
24 To activate the OpenStack virtualenv for the extent of your current shell
25 session you can run:
26 $ source %s/bin/activate
27 Or, if you prefer, you can run commands in the virtualenv on a case by case
28 basis by running:
29 $ %s/tools/with_venv.sh <your command>
30 Also, make test will automatically use the virtualenv.
31 """
32 print(help % (venv, root))
33
34
35def main(argv):
36 root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
37
38 if os.environ.get('tools_path'):
39 root = os.environ['tools_path']
40 venv = os.path.join(root, '.venv')
41 if os.environ.get('venv'):
42 venv = os.environ['venv']
43
44 pip_requires = os.path.join(root, 'requirements.txt')
45 test_requires = os.path.join(root, 'test-requirements.txt')
46 py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1])
47 project = 'OpenStack'
48 install = install_venv.InstallVenv(root, venv, pip_requires, test_requires,
49 py_version, project)
50 options = install.parse_args(argv)
51 install.check_python_version()
52 install.check_dependencies()
53 install.create_virtualenv(no_site_packages=options.no_site_packages)
54 install.install_dependencies()
55 print_help(venv, root)
56
57if __name__ == '__main__':
58 main(sys.argv)
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
new file mode 100644
index 0000000..431d206
--- /dev/null
+++ b/tools/install_venv_common.py
@@ -0,0 +1,165 @@
1# Licensed under the Apache License, Version 2.0 (the "License"); you may
2# not use this file except in compliance with the License. You may obtain
3# a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10# License for the specific language governing permissions and limitations
11# under the License.
12
13
14"""Provides methods needed by installation script for OpenStack development
15virtual environments.
16Since this script is used to bootstrap a virtualenv from the system's Python
17environment, it should be kept strictly compatible with Python 2.6.
18Synced in from openstack-common
19"""
20
21from __future__ import print_function
22
23import optparse
24import os
25import subprocess
26import sys
27
28
29class InstallVenv(object):
30
31 def __init__(self, root, venv, requirements,
32 test_requirements, py_version,
33 project):
34 self.root = root
35 self.venv = venv
36 self.requirements = requirements
37 self.test_requirements = test_requirements
38 self.py_version = py_version
39 self.project = project
40
41 def die(self, message, *args):
42 print(message % args, file=sys.stderr)
43 sys.exit(1)
44
45 def check_python_version(self):
46 if sys.version_info < (2, 6):
47 self.die("Need Python Version >= 2.6")
48
49 def run_command_with_code(self, cmd, redirect_output=True,
50 check_exit_code=True):
51 """Runs a command in an out-of-process shell.
52 Returns the output of that command. Working directory is self.root.
53 """
54 if redirect_output:
55 stdout = subprocess.PIPE
56 else:
57 stdout = None
58
59 proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout)
60 output = proc.communicate()[0]
61 if check_exit_code and proc.returncode != 0:
62 self.die('Command "%s" failed.\n%s', ' '.join(cmd), output)
63 return (output, proc.returncode)
64
65 def run_command(self, cmd, redirect_output=True, check_exit_code=True):
66 return self.run_command_with_code(cmd, redirect_output,
67 check_exit_code)[0]
68
69 def get_distro(self):
70 if (os.path.exists('/etc/fedora-release') or
71 os.path.exists('/etc/redhat-release')):
72 return Fedora(
73 self.root, self.venv, self.requirements,
74 self.test_requirements, self.py_version, self.project)
75 else:
76 return Distro(
77 self.root, self.venv, self.requirements,
78 self.test_requirements, self.py_version, self.project)
79
80 def check_dependencies(self):
81 self.get_distro().install_virtualenv()
82
83 def create_virtualenv(self, no_site_packages=True):
84 """Creates the virtual environment and installs PIP.
85 Creates the virtual environment and installs PIP only into the
86 virtual environment.
87 """
88 if not os.path.isdir(self.venv):
89 print('Creating venv...', end=' ')
90 if no_site_packages:
91 self.run_command(['virtualenv', '-q', '--no-site-packages',
92 self.venv])
93 else:
94 self.run_command(['virtualenv', '-q', self.venv])
95 print('done.')
96 else:
97 print("venv already exists...")
98 pass
99
100 def pip_install(self, *args):
101 self.run_command(['tools/with_venv.sh',
102 'pip', 'install', '--upgrade'] + list(args),
103 redirect_output=False)
104
105 def install_dependencies(self):
106 print('Installing dependencies with pip (this can take a while)...')
107
108 # First things first, make sure our venv has the latest pip and
109 # setuptools and pbr
110 self.pip_install('pip>=1.4')
111 self.pip_install('setuptools')
112 self.pip_install('pbr')
113
114 self.pip_install('-r', self.requirements, '-r', self.test_requirements)
115
116 def parse_args(self, argv):
117 """Parses command-line arguments."""
118 parser = optparse.OptionParser()
119 parser.add_option('-n', '--no-site-packages',
120 action='store_true',
121 help="Do not inherit packages from global Python "
122 "install.")
123 return parser.parse_args(argv[1:])[0]
124
125
126class Distro(InstallVenv):
127
128 def check_cmd(self, cmd):
129 return bool(self.run_command(['which', cmd],
130 check_exit_code=False).strip())
131
132 def install_virtualenv(self):
133 if self.check_cmd('virtualenv'):
134 return
135
136 if self.check_cmd('easy_install'):
137 print('Installing virtualenv via easy_install...', end=' ')
138 if self.run_command(['easy_install', 'virtualenv']):
139 print('Succeeded')
140 return
141 else:
142 print('Failed')
143
144 self.die('ERROR: virtualenv not found.\n\n%s development'
145 ' requires virtualenv, please install it using your'
146 ' favorite package management tool' % self.project)
147
148
149class Fedora(Distro):
150 """This covers all Fedora-based distributions.
151 Includes: Fedora, RHEL, CentOS, Scientific Linux
152 """
153
154 def check_pkg(self, pkg):
155 return self.run_command_with_code(['rpm', '-q', pkg],
156 check_exit_code=False)[1] == 0
157
158 def install_virtualenv(self):
159 if self.check_cmd('virtualenv'):
160 return
161
162 if not self.check_pkg('python-virtualenv'):
163 self.die("Please install 'python-virtualenv'.")
164
165 super(Fedora, self).install_virtualenv()
diff --git a/tools/with_venv.sh b/tools/with_venv.sh
new file mode 100755
index 0000000..b15965f
--- /dev/null
+++ b/tools/with_venv.sh
@@ -0,0 +1,7 @@
1#!/bin/bash
2TOOLS_PATH=${TOOLS_PATH:-$(dirname $0)}
3VENV_PATH=${VENV_PATH:-${TOOLS_PATH}}
4VENV_DIR=${VENV_NAME:-/../.venv}
5TOOLS=${TOOLS_PATH}
6VENV=${VENV:-${VENV_PATH}/${VENV_DIR}}
7source ${VENV}/bin/activate && "$@" \ No newline at end of file
diff --git a/tox.ini b/tox.ini
index 5130477..84288ac 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,35 +1,50 @@
1[tox] 1[tox]
2envlist = py27,pep8,pylint 2envlist = py27,py27dj18,pep8,py34,pylint
3minversion = 1.6
3skipsdist = True 4skipsdist = True
4 5
5[testenv] 6[testenv]
6usedevelop = True 7usedevelop = True
8setenv = VIRTUAL_ENV={envdir}
9 NOSE_WITH_OPENSTACK=1
10 NOSE_OPENSTACK_COLOR=1
11 NOSE_OPENSTACK_RED=0.05
12 NOSE_OPENSTACK_YELLOW=0.025
13 NOSE_OPENSTACK_SHOW_ELAPSED=1
7install_command = pip install -U {opts} {packages} 14install_command = pip install -U {opts} {packages}
8setenv =
9 VIRTUAL_ENV={envdir}
10deps = -r{toxinidir}/requirements.txt 15deps = -r{toxinidir}/requirements.txt
11 -r{toxinidir}/test-requirements.txt 16 -r{toxinidir}/test-requirements.txt
12commands = py.test -v --cov-report term-missing --cov disaster_recovery 17 http://tarballs.openstack.org/horizon/horizon-master.tar.gz
18commands = python manage.py test {posargs}
13 19
14[testenv:pep8] 20[testenv:pep8]
15commands = flake8 21commands = flake8 {posargs}
16 22
17[testenv:venv] 23[testenv:venv]
18commands = {posargs} 24commands = {posargs}
19 25
20[testenv:cover] 26[testenv:cover]
21commands = python setup.py testr --coverage --testr-args='{posargs}' 27commands = python setup.py test --coverage --testr-args='{posargs}'
22 28
23[flake8] 29[testenv:py27dj18]
24show-source = True 30basepython = python2.7
25ignore = E123,E125,H405,H238,H306,H701 31commands =
26builtins = _ 32 python manage.py test {posargs}
27exclude=.venv,.tox,dist,doc,test,*egg,tests,runtests.py
28 33
29[testenv:pylint]
30commands = pylint --rcfile .pylintrc disaster_recovery
31 34
32[testenv:docs] 35[testenv:py34dj18]
36basepython = python3.4
33commands = 37commands =
34 python setup.py build_sphinx 38 python manage.py test {posargs}
35 39
40[testenv:docs]
41setenv = DJANGO_SETTINGS_MODULE=disaster_recovery.test.settings
42commands = python setup.py build_sphinx
43
44[testenv:pylint]
45commands = pylint --rcfile .pylintrc disaster_recovery
46
47[flake8]
48exclude = .venv,.git,.tox,dist,*openstack/common*,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,tools,doc
49max-complexity = 20
50ignore = H405,H404,H403,H401,H238,H306,H701 \ No newline at end of file