diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 5000261a..00000000 --- a/.mailmap +++ /dev/null @@ -1,4 +0,0 @@ -# Format is: -# -# -Timur Nurlygayanov diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index eda6a422..00000000 --- a/.testr.conf +++ /dev/null @@ -1,7 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-60} \ - ${PYTHON:-python} -m subunit.run discover saharadashboard/tests $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index a60d5f1a..00000000 --- a/MANIFEST.in +++ /dev/null @@ -1,11 +0,0 @@ -include AUTHORS -include README.rst -include ChangeLog -include LICENSE - -include saharadashboard/templates/**.html - -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc diff --git a/README.rst b/README.rst index ff321470..cf741184 100644 --- a/README.rst +++ b/README.rst @@ -4,14 +4,8 @@ OpenStack Dashboard plugin for Sahara project NOTE: ===== -Sahara Dashboard is now integrated into the Horizon project. http://github.com/openstack/horizon -The panels can now be found in the data_processing module of Projects Dashboard. -https://github.com/openstack/horizon/tree/master/openstack_dashboard/dashboards/project/data_processing - -This repository will now contain only selenium based tests for the Data Processing Panels. - -This change is not meant to be backported to stable/icehouse or any other tags or branches. -So you can still use Sahara Dasboard as a separate dashboard with stable/icehouse version of Horizon. +As of the Mitaka release, the dashboard for sahara is now maintained +outside of the horzon codebase, in the repository. Links: ------ diff --git a/manage.py b/manage.py new file mode 100755 index 00000000..c89c3ba5 --- /dev/null +++ b/manage.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import os +import sys + +from django.core.management import execute_from_command_line + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", + "sahara-dashboard.test.settings") + execute_from_command_line(sys.argv) diff --git a/openstack-common.conf b/openstack-common.conf deleted file mode 100644 index 610937a4..00000000 --- a/openstack-common.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -modules=importutils -base=saharadashboard - diff --git a/requirements.txt b/requirements.txt index 30806d5a..25f60423 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,12 @@ # process, which may cause wedges in the gate later. pbr>=1.6 +# Horizon Core Requirements +Babel>=1.3 +Django<1.9,>=1.8 +django-compressor>=1.4 +django-openstack-auth>=2.0.0 +iso8601>=0.1.9 +python-keystoneclient!=1.8.0,>=1.6.0 +python-manilaclient>=1.3.0 +python-saharaclient>=0.10.0 diff --git a/run_tests.sh b/run_tests.sh new file mode 100644 index 00000000..1f6d0c17 --- /dev/null +++ b/run_tests.sh @@ -0,0 +1,548 @@ +#!/bin/bash + +set -o errexit + +function usage { + echo "Usage: $0 [OPTION]..." + echo "Run Horizon's test suite(s)" + echo "" + echo " -V, --virtual-env Always use virtualenv. Install automatically" + echo " if not present" + echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local" + echo " environment" + echo " -c, --coverage Generate reports using Coverage" + echo " -f, --force Force a clean re-build of the virtual" + echo " environment. Useful when dependencies have" + echo " been added." + echo " -m, --manage Run a Django management command." + echo " --makemessages Create/Update English translation files." + echo " --compilemessages Compile all translation files." + echo " --check-only Do not update translation files (--makemessages only)." + echo " --pseudo Pseudo translate a language." + echo " -p, --pep8 Just run pep8" + echo " -8, --pep8-changed []" + echo " Just run PEP8 and HACKING compliance check" + echo " on files changed since HEAD~1 (or )" + echo " -P, --no-pep8 Don't run pep8 by default" + echo " -t, --tabs Check for tab characters in files." + echo " -y, --pylint Just run pylint" + echo " -q, --quiet Run non-interactively. (Relatively) quiet." + echo " Implies -V if -N is not set." + echo " --only-selenium Run only the Selenium unit tests" + echo " --with-selenium Run unit tests including Selenium tests" + echo " --selenium-headless Run Selenium tests headless" + echo " --integration Run the integration tests (requires a running " + echo " OpenStack environment)" + echo " --runserver Run the Django development server for" + echo " openstack_dashboard in the virtual" + echo " environment." + echo " --docs Just build the documentation" + echo " --backup-environment Make a backup of the environment on exit" + echo " --restore-environment Restore the environment before running" + echo " --destroy-environment Destroy the environment and exit" + echo " -h, --help Print this usage message" + echo "" + echo "Note: with no options specified, the script will try to run the tests in" + echo " a virtual environment, If no virtualenv is found, the script will ask" + echo " if you would like to create one. If you prefer to run tests NOT in a" + echo " virtual environment, simply pass the -N option." + exit +} + +# DEFAULTS FOR RUN_TESTS.SH +# +root=`pwd -P` +venv=$root/.venv +venv_env_version=$venv/environments +with_venv=tools/with_venv.sh +included_dirs="sahara-dashboard" + +always_venv=0 +backup_env=0 +command_wrapper="" +destroy=0 +force=0 +just_pep8=0 +just_pep8_changed=0 +no_pep8=0 +just_pylint=0 +just_docs=0 +just_tabs=0 +never_venv=0 +quiet=0 +restore_env=0 +runserver=0 +only_selenium=0 +with_selenium=0 +selenium_headless=0 +integration=0 +testopts="" +testargs="" +with_coverage=0 +makemessages=0 +compilemessages=0 +check_only=0 +pseudo=0 +manage=0 + +# Jenkins sets a "JOB_NAME" variable, if it's not set, we'll make it "default" +[ "$JOB_NAME" ] || JOB_NAME="default" + +function process_option { + # If running manage command, treat the rest of options as arguments. + if [ $manage -eq 1 ]; then + testargs="$testargs $1" + return 0 + fi + + case "$1" in + -h|--help) usage;; + -V|--virtual-env) always_venv=1; never_venv=0;; + -N|--no-virtual-env) always_venv=0; never_venv=1;; + -p|--pep8) just_pep8=1;; + -8|--pep8-changed) just_pep8_changed=1;; + -P|--no-pep8) no_pep8=1;; + -y|--pylint) just_pylint=1;; + -f|--force) force=1;; + -t|--tabs) just_tabs=1;; + -q|--quiet) quiet=1;; + -c|--coverage) with_coverage=1;; + -m|--manage) manage=1;; + --makemessages) makemessages=1;; + --compilemessages) compilemessages=1;; + --check-only) check_only=1;; + --pseudo) pseudo=1;; + --only-selenium) only_selenium=1;; + --with-selenium) with_selenium=1;; + --selenium-headless) selenium_headless=1;; + --integration) integration=1;; + --docs) just_docs=1;; + --runserver) runserver=1;; + --backup-environment) backup_env=1;; + --restore-environment) restore_env=1;; + --destroy-environment) destroy=1;; + -*) testopts="$testopts $1";; + *) testargs="$testargs $1" + esac +} + +function run_management_command { + ${command_wrapper} python $root/manage.py $testopts $testargs +} + +function run_server { + echo "Starting Django development server..." + ${command_wrapper} python $root/manage.py runserver $testopts $testargs + echo "Server stopped." +} + +function run_pylint { + echo "Running pylint ..." + PYTHONPATH=$root ${command_wrapper} pylint --rcfile=.pylintrc -f parseable $included_dirs > pylint.txt || true + CODE=$? + grep Global -A2 pylint.txt + if [ $CODE -lt 32 ]; then + echo "Completed successfully." + exit 0 + else + echo "Completed with problems." + exit $CODE + fi +} + +function warn_on_flake8_without_venv { + set +o errexit + ${command_wrapper} python -c "import hacking" 2>/dev/null + no_hacking=$? + set -o errexit + if [ $never_venv -eq 1 -a $no_hacking -eq 1 ]; then + echo "**WARNING**:" >&2 + echo "OpenStack hacking is not installed on your host. Its detection will be missed." >&2 + echo "Please install or use virtual env if you need OpenStack hacking detection." >&2 + fi +} + +function run_pep8 { + echo "Running flake8 ..." + warn_on_flake8_without_venv + DJANGO_SETTINGS_MODULE=sahara-dashboard.test.settings ${command_wrapper} flake8 +} + +function run_pep8_changed { + # NOTE(gilliard) We want use flake8 to check the entirety of every file that has + # a change in it. Unfortunately the --filenames argument to flake8 only accepts + # file *names* and there are no files named (eg) "nova/compute/manager.py". The + # --diff argument behaves surprisingly as well, because although you feed it a + # diff, it actually checks the file on disk anyway. + local base_commit=${testargs:-HEAD~1} + files=$(git diff --name-only $base_commit | tr '\n' ' ') + echo "Running flake8 on ${files}" + warn_on_flake8_without_venv + diff -u --from-file /dev/null ${files} | DJANGO_SETTINGS_MODULE=sahara-dashboard.test.settings ${command_wrapper} flake8 --diff + exit +} + +function run_sphinx { + echo "Building sphinx..." + DJANGO_SETTINGS_MODULE=sahara-dashboard.test.settings ${command_wrapper} python setup.py build_sphinx + echo "Build complete." +} + +function tab_check { + TAB_VIOLATIONS=`find $included_dirs -type f -regex ".*\.\(css\|js\|py\|html\)" -print0 | xargs -0 awk '/\t/' | wc -l` + if [ $TAB_VIOLATIONS -gt 0 ]; then + echo "TABS! $TAB_VIOLATIONS of them! Oh no!" + HORIZON_FILES=`find $included_dirs -type f -regex ".*\.\(css\|js\|py|\html\)"` + for TABBED_FILE in $HORIZON_FILES + do + TAB_COUNT=`awk '/\t/' $TABBED_FILE | wc -l` + if [ $TAB_COUNT -gt 0 ]; then + echo "$TABBED_FILE: $TAB_COUNT" + fi + done + fi + return $TAB_VIOLATIONS; +} + +function destroy_venv { + echo "Cleaning environment..." + echo "Removing virtualenv..." + rm -rf $venv + echo "Virtualenv removed." +} + +function environment_check { + echo "Checking environment." + if [ -f $venv_env_version ]; then + set +o errexit + cat requirements.txt test-requirements.txt | cmp $venv_env_version - > /dev/null + local env_check_result=$? + set -o errexit + if [ $env_check_result -eq 0 ]; then + # If the environment exists and is up-to-date then set our variables + command_wrapper="${root}/${with_venv}" + echo "Environment is up to date." + return 0 + fi + fi + + if [ $always_venv -eq 1 ]; then + install_venv + else + if [ ! -e ${venv} ]; then + echo -e "Environment not found. Install? (Y/n) \c" + else + echo -e "Your environment appears to be out of date. Update? (Y/n) \c" + fi + read update_env + if [ "x$update_env" = "xY" -o "x$update_env" = "x" -o "x$update_env" = "xy" ]; then + install_venv + else + # Set our command wrapper anyway. + command_wrapper="${root}/${with_venv}" + fi + fi +} + +function sanity_check { + # Anything that should be determined prior to running the tests, server, etc. + # Don't sanity-check anything environment-related in -N flag is set + if [ $never_venv -eq 0 ]; then + if [ ! -e ${venv} ]; then + echo "Virtualenv not found at $venv. Did install_venv.py succeed?" + exit 1 + fi + fi + # Remove .pyc files. This is sanity checking because they can linger + # after old files are deleted. + find . -name "*.pyc" -exec rm -rf {} \; +} + +function backup_environment { + if [ $backup_env -eq 1 ]; then + echo "Backing up environment \"$JOB_NAME\"..." + if [ ! -e ${venv} ]; then + echo "Environment not installed. Cannot back up." + return 0 + fi + if [ -d /tmp/.horizon_environment/$JOB_NAME ]; then + mv /tmp/.horizon_environment/$JOB_NAME /tmp/.horizon_environment/$JOB_NAME.old + rm -rf /tmp/.horizon_environment/$JOB_NAME + fi + mkdir -p /tmp/.horizon_environment/$JOB_NAME + cp -r $venv /tmp/.horizon_environment/$JOB_NAME/ + # Remove the backup now that we've completed successfully + rm -rf /tmp/.horizon_environment/$JOB_NAME.old + echo "Backup completed" + fi +} + +function restore_environment { + if [ $restore_env -eq 1 ]; then + echo "Restoring environment from backup..." + if [ ! -d /tmp/.horizon_environment/$JOB_NAME ]; then + echo "No backup to restore from." + return 0 + fi + + cp -r /tmp/.horizon_environment/$JOB_NAME/.venv ./ || true + + echo "Environment restored successfully." + fi +} + +function install_venv { + # Install with install_venv.py + export PIP_DOWNLOAD_CACHE=${PIP_DOWNLOAD_CACHE-/tmp/.pip_download_cache} + export PIP_USE_MIRRORS=true + if [ $quiet -eq 1 ]; then + export PIP_NO_INPUT=true + fi + echo "Fetching new src packages..." + rm -rf $venv/src + python tools/install_venv.py + command_wrapper="$root/${with_venv}" + # Make sure it worked and record the environment version + sanity_check + chmod -R 754 $venv + cat requirements.txt test-requirements.txt > $venv_env_version +} + +function run_tests { + sanity_check + + if [ $with_selenium -eq 1 ]; then + export WITH_SELENIUM=1 + elif [ $only_selenium -eq 1 ]; then + export WITH_SELENIUM=1 + export SKIP_UNITTESTS=1 + fi + + if [ $selenium_headless -eq 1 ]; then + export SELENIUM_HEADLESS=1 + fi + + if [ -z "$testargs" ]; then + run_tests_all + else + run_tests_subset + fi +} + +function run_tests_subset { + project=`echo $testargs | awk -F. '{print $1}'` + ${command_wrapper} python $root/manage.py test --settings=$project.test.settings $testopts $testargs +} + +function run_tests_all { + echo "Running Sahara-Dashboard application tests" + export NOSE_XUNIT_FILE=sahara-dashboard/nosetests.xml + if [ "$NOSE_WITH_HTML_OUTPUT" = '1' ]; then + export NOSE_HTML_OUT_FILE='sahara_dashboard_nose_results.html' + fi + if [ $with_coverage -eq 1 ]; then + ${command_wrapper} python -m coverage.__main__ erase + coverage_run="python -m coverage.__main__ run -p" + fi + ${command_wrapper} ${coverage_run} $root/manage.py test sahara-dashboard --settings=sahara-dashboard.test.settings $testopts + # get results of the Horizon tests + SAHARA_DASHBOARD_RESULT=$? + + if [ $with_coverage -eq 1 ]; then + echo "Generating coverage reports" + ${command_wrapper} python -m coverage.__main__ combine + ${command_wrapper} python -m coverage.__main__ xml -i --omit='/usr*,setup.py,*egg*,.venv/*' + ${command_wrapper} python -m coverage.__main__ html -i --omit='/usr*,setup.py,*egg*,.venv/*' -d reports + fi + # Remove the leftover coverage files from the -p flag earlier. + rm -f .coverage.* + + PEP8_RESULT=0 + if [ $no_pep8 -eq 0 ] && [ $only_selenium -eq 0 ]; then + run_pep8 + PEP8_RESULT=$? + fi + + TEST_RESULT=$(($SAHARA_DASHBOARD_RESULT || $PEP8_RESULT)) + if [ $TEST_RESULT -eq 0 ]; then + echo "Tests completed successfully." + else + echo "Tests failed." + fi + exit $TEST_RESULT +} + +function run_integration_tests { + export INTEGRATION_TESTS=1 + + if [ $selenium_headless -eq 1 ]; then + export SELENIUM_HEADLESS=1 + fi + + echo "Running Horizon integration tests..." + if [ -z "$testargs" ]; then + ${command_wrapper} nosetests openstack_dashboard/test/integration_tests/tests + else + ${command_wrapper} nosetests $testargs + fi + exit 0 +} + +function run_makemessages { + OPTS="-l en --no-obsolete --settings=openstack_dashboard.test.settings" + DASHBOARD_OPTS="--extension=html,txt,csv --ignore=openstack" + echo -n "horizon: " + cd horizon + ${command_wrapper} $root/manage.py makemessages $OPTS + HORIZON_PY_RESULT=$? + echo -n "horizon javascript: " + ${command_wrapper} $root/manage.py makemessages -d djangojs $OPTS + HORIZON_JS_RESULT=$? + echo -n "openstack_dashboard: " + cd ../openstack_dashboard + ${command_wrapper} $root/manage.py makemessages $DASHBOARD_OPTS $OPTS + DASHBOARD_RESULT=$? + cd .. + if [ $check_only -eq 1 ]; then + git checkout -- horizon/locale/en/LC_MESSAGES/django*.po + git checkout -- openstack_dashboard/locale/en/LC_MESSAGES/django.po + fi + exit $(($HORIZON_PY_RESULT || $HORIZON_JS_RESULT || $DASHBOARD_RESULT)) +} + +function run_compilemessages { + OPTS="--settings=openstack_dashboard.test.settings" + cd horizon + ${command_wrapper} $root/manage.py compilemessages $OPTS + HORIZON_PY_RESULT=$? + cd ../openstack_dashboard + ${command_wrapper} $root/manage.py compilemessages $OPTS + DASHBOARD_RESULT=$? + cd .. + # English is the source language, so compiled catalogs are unnecessary. + rm -vf horizon/locale/en/LC_MESSAGES/django*.mo + rm -vf openstack_dashboard/locale/en/LC_MESSAGES/django.mo + exit $(($HORIZON_PY_RESULT || $DASHBOARD_RESULT)) +} + +function run_pseudo { + for lang in $testargs + # Use English po file as the source file/pot file just like real Horizon translations + do + ${command_wrapper} $root/tools/pseudo.py openstack_dashboard/locale/en/LC_MESSAGES/django.po openstack_dashboard/locale/$lang/LC_MESSAGES/django.po $lang + ${command_wrapper} $root/tools/pseudo.py horizon/locale/en/LC_MESSAGES/django.po horizon/locale/$lang/LC_MESSAGES/django.po $lang + ${command_wrapper} $root/tools/pseudo.py horizon/locale/en/LC_MESSAGES/djangojs.po horizon/locale/$lang/LC_MESSAGES/djangojs.po $lang + done + exit $? +} + + +# ---------PREPARE THE ENVIRONMENT------------ # + +# PROCESS ARGUMENTS, OVERRIDE DEFAULTS +for arg in "$@"; do + process_option $arg +done + +if [ $quiet -eq 1 ] && [ $never_venv -eq 0 ] && [ $always_venv -eq 0 ] +then + always_venv=1 +fi + +# If destroy is set, just blow it away and exit. +if [ $destroy -eq 1 ]; then + destroy_venv + exit 0 +fi + +# Ignore all of this if the -N flag was set +if [ $never_venv -eq 0 ]; then + + # Restore previous environment if desired + if [ $restore_env -eq 1 ]; then + restore_environment + fi + + # Remove the virtual environment if --force used + if [ $force -eq 1 ]; then + destroy_venv + fi + + # Then check if it's up-to-date + environment_check + + # Create a backup of the up-to-date environment if desired + if [ $backup_env -eq 1 ]; then + backup_environment + fi +fi + +# ---------EXERCISE THE CODE------------ # + +# Run management commands +if [ $manage -eq 1 ]; then + run_management_command + exit $? +fi + +# Build the docs +if [ $just_docs -eq 1 ]; then + run_sphinx + exit $? +fi + +# Update translation files +if [ $makemessages -eq 1 ]; then + run_makemessages + exit $? +fi + +# Compile translation files +if [ $compilemessages -eq 1 ]; then + run_compilemessages + exit $? +fi + +# Generate Pseudo translation +if [ $pseudo -eq 1 ]; then + run_pseudo + exit $? +fi + +# PEP8 +if [ $just_pep8 -eq 1 ]; then + run_pep8 + exit $? +fi + +if [ $just_pep8_changed -eq 1 ]; then + run_pep8_changed + exit $? +fi + +# Pylint +if [ $just_pylint -eq 1 ]; then + run_pylint + exit $? +fi + +# Tab checker +if [ $just_tabs -eq 1 ]; then + tab_check + exit $? +fi + +# Integration tests +if [ $integration -eq 1 ]; then + run_integration_tests + exit $? +fi + +# Django development server +if [ $runserver -eq 1 ]; then + run_server + exit $? +fi + +# Full test suite +run_tests || exit \ No newline at end of file diff --git a/saharadashboard/__init__.py b/sahara-dashboard/__init__.py similarity index 100% rename from saharadashboard/__init__.py rename to sahara-dashboard/__init__.py diff --git a/saharadashboard/tests/__init__.py b/sahara-dashboard/enabled/__init__.py similarity index 100% rename from saharadashboard/tests/__init__.py rename to sahara-dashboard/enabled/__init__.py diff --git a/saharadashboard/tests/cluster_template_tests/__init__.py b/sahara-dashboard/test/__init__.py similarity index 100% rename from saharadashboard/tests/cluster_template_tests/__init__.py rename to sahara-dashboard/test/__init__.py diff --git a/sahara-dashboard/test/settings.py b/sahara-dashboard/test/settings.py new file mode 100644 index 00000000..28dc23da --- /dev/null +++ b/sahara-dashboard/test/settings.py @@ -0,0 +1,185 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import importlib +import os +import six + +from horizon.test.settings import * # noqa +from horizon.utils import secret_key +from openstack_dashboard import exceptions + + +DEBUG = True +TEMPLATE_DEBUG = DEBUG + +TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_PATH = os.path.abspath(os.path.join(TEST_DIR, "..")) + +MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media')) +MEDIA_URL = '/media/' +STATIC_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'static')) +STATIC_URL = '/static/' + +SECRET_KEY = secret_key.generate_or_read_from_file( + os.path.join(TEST_DIR, '.secret_key_store')) +ROOT_URLCONF = 'sahara-dashboard.test.urls' +TEMPLATE_DIRS = ( + os.path.join(TEST_DIR, 'templates'), +) + +TEMPLATE_CONTEXT_PROCESSORS += ( + 'openstack_dashboard.context_processors.openstack', +) + +INSTALLED_APPS = ( + 'django.contrib.contenttypes', + 'django.contrib.auth', + 'django.contrib.sessions', + 'django.contrib.staticfiles', + 'django.contrib.messages', + 'django.contrib.humanize', + 'django_nose', + 'openstack_auth', + 'compressor', + 'horizon', + 'openstack_dashboard', + 'openstack_dashboard.dashboards', +) + +AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',) + +SITE_BRANDING = 'OpenStack' + +HORIZON_CONFIG = { + "password_validator": { + "regex": '^.{8,18}$', + "help_text": "Password must be between 8 and 18 characters." + }, + 'user_home': None, + 'help_url': "http://docs.openstack.org", + 'exceptions': {'recoverable': exceptions.RECOVERABLE, + 'not_found': exceptions.NOT_FOUND, + 'unauthorized': exceptions.UNAUTHORIZED}, + 'angular_modules': [], + 'js_files': [], +} + +# Load the pluggable dashboard settings +from openstack_dashboard.utils import settings +dashboard_module_names = [ + 'openstack_dashboard.enabled', + 'openstack_dashboard.local.enabled', + 'sahara-dashboard.enabled', +] +dashboard_modules = [] +# All dashboards must be enabled for the namespace to get registered, which is +# needed by the unit tests. +for module_name in dashboard_module_names: + module = importlib.import_module(module_name) + dashboard_modules.append(module) + for submodule in six.itervalues(settings.import_submodules(module)): + if getattr(submodule, 'DISABLED', None): + delattr(submodule, 'DISABLED') +INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable +settings.update_dashboards(dashboard_modules, HORIZON_CONFIG, INSTALLED_APPS) + +# Set to True to allow users to upload images to glance via Horizon server. +# When enabled, a file form field will appear on the create image form. +# See documentation for deployment considerations. +HORIZON_IMAGES_ALLOW_UPLOAD = True + +AVAILABLE_REGIONS = [ + ('http://localhost:5000/v2.0', 'local'), + ('http://remote:5000/v2.0', 'remote'), +] + +OPENSTACK_API_VERSIONS = { + "identity": 3 +} + +OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0" +OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_" + +OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True +OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'test_domain' + +OPENSTACK_KEYSTONE_BACKEND = { + 'name': 'native', + 'can_edit_user': True, + 'can_edit_group': True, + 'can_edit_project': True, + 'can_edit_domain': True, + 'can_edit_role': True +} + +OPENSTACK_CINDER_FEATURES = { + 'enable_backup': True, +} + +OPENSTACK_NEUTRON_NETWORK = { + 'enable_lb': True +} + +OPENSTACK_HYPERVISOR_FEATURES = { + 'can_set_mount_point': True, + + # NOTE: as of Grizzly this is not yet supported in Nova so enabling this + # setting will not do anything useful + 'can_encrypt_volumes': False +} + +LOGGING['loggers']['openstack_dashboard'] = { + 'handlers': ['test'], + 'propagate': False, +} + +LOGGING['loggers']['selenium'] = { + 'handlers': ['test'], + 'propagate': False, +} + +LOGGING['loggers']['sahara-dashboard'] = { + 'handlers': ['test'], + 'propagate': False, +} + +SECURITY_GROUP_RULES = { + 'all_tcp': { + 'name': 'ALL TCP', + 'ip_protocol': 'tcp', + 'from_port': '1', + 'to_port': '65535', + }, + 'http': { + 'name': 'HTTP', + 'ip_protocol': 'tcp', + 'from_port': '80', + 'to_port': '80', + }, +} + +NOSE_ARGS = ['--nocapture', + '--nologcapture', + '--cover-package=openstack_dashboard', + '--cover-inclusive', + '--all-modules'] + +POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf") +POLICY_FILES = { + 'identity': 'keystone_policy.json', + 'compute': 'nova_policy.json' +} + +# The openstack_auth.user.Token object isn't JSON-serializable ATM +SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer' diff --git a/saharadashboard/tests/README.rst b/saharadashboard/tests/README.rst deleted file mode 100644 index 86af2e1b..00000000 --- a/saharadashboard/tests/README.rst +++ /dev/null @@ -1,54 +0,0 @@ -Sahara Dashboard Selenium Tests -===================================== - - -Main goal of Selenium Tests ----------- - -Selenium tests for Sahara Dashboard are designed to check the correctness of the Sahara Dashboard Horizon plug-in. - - -How to run UI tests: ----------- - -It's assumed that sahara and horizon are already installed and running. - -Information about installation and start of sahara and horizon can be found on the sahara site - http://docs.openstack.org/developer/sahara/#user-guide - in tabs Sahara Installation Guide and Sahara UI Installation Guide. - -1. Go to sahara dashboard path. -2. Create config file for selenium tests - `saharadashboard/tests/configs/config.py`. - You can take a look at the sample config file - `saharadashboard/tests/configs/config.py.sample`. - All values used in `saharadashboard/tests/configs/parameters.py` file are - defaults, so, if they are applicable for your environment then you can skip - config file creation. - -3. Install virtual framebuffer X server for X Version 11 (Xvfb): - sudo apt-get -y install xvfb - -4. Install Firefox: - sudo add-apt-repository ppa:ubuntu-mozilla-security/ppa - sudo apt-get update - sudo apt-get install firefox libstdc++5 - -5. To run ui tests you should use the corresponding tox env: `tox -e uitests`. - If need to run only one test module, use: - - tox -e uitests -- '' - - may be equal 'cluster', 'cluster_template', 'image_registry', 'node_group_template', 'image_registry', 'vanilla', 'hdp' - It's full list of actual modules. - - -Coverage: ----------- - --Clusters --Cluster templates --Node group templates --Image registry --Data sources --Job binaries --Jobs --Job executions diff --git a/saharadashboard/tests/base.py b/saharadashboard/tests/base.py deleted file mode 100644 index 692fe0ca..00000000 --- a/saharadashboard/tests/base.py +++ /dev/null @@ -1,970 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import logging -import os -import time -import traceback - -import selenium.common.exceptions as selenim_except -from selenium import webdriver -import selenium.webdriver.common.by as by -from swiftclient import client as swift_client -import unittest2 - -import saharadashboard.tests.configs.config as cfg - - -logger = logging.getLogger('swiftclient') -logger.setLevel(logging.WARNING) - - -class UITestCase(unittest2.TestCase): - - @classmethod - def setUpClass(cls): - try: - cls.ifFail = False - cls.driver = webdriver.Firefox() - cls.driver.get(cfg.common.base_url + "/") - cls.find_clear_send(by.By.ID, "id_username", cfg.common.user) - cls.find_clear_send(by.By.ID, "id_password", cfg.common.password) - cls.driver.find_element_by_xpath( - "//button[@type='submit']").click() - except Exception: - traceback.print_exc() - cls.ifFail = True - pass - - def setUp(self): - if self.ifFail: - self.fail("setUpClass method is fail") - self.await_element(by.By.CLASS_NAME, 'clearfix', - 'authorization failed') - - def image_registry(self, image_name, user_name=None, description=None, - tags_to_add=None, tags_to_remove=None, positive=True, - close_window=True, message=''): - if positive: - message = 'Success: Successfully updated image.' - self.image_registry_helper(image_name, user_name, description, - tags_to_add, tags_to_remove, positive, - close_window, message, 'Registry') - - def edit_tags_by_image_name(self, image_name, user_name=None, - description=None, tags_to_add=None, - positive=True, message=None, close_window=True, - tags_to_remove=None): - if positive: - message = 'Success: Successfully updated image.' - self.image_registry_helper(image_name, user_name, description, - tags_to_add, tags_to_remove, positive, - close_window, message, 'Edit') - - def create_node_group_template( - self, name, list_processes, plugin, flavor=None, params=None, - storage={'type': 'Ephemeral Drive'}, description=None, - positive=True, message=None, close_window=True): - driver = self.driver - if not flavor: - flavor = cfg.common.flavor - driver.get(cfg.common.base_url + - "/project/data_processing/nodegroup_templates/") - self.await_element(by.By.ID, "nodegroup_templates__action_create") - driver.find_element_by_id("nodegroup_templates__action_create").click() - self.choose_plugin_name(plugin.plugin_name, plugin.hadoop_version, - name, description, "id_nodegroup_name") - self.driver.find_element_by_xpath( - "//select[@id='id_flavor']/option[text()='%s']" % flavor).click() - self.driver.find_element_by_xpath( - "//*[@id='id_storage']/option[text()='%s']" - % storage['type']).click() - if storage['type'] == "Cinder Volume": - self.find_clear_send(by.By.ID, "id_volumes_per_node", - storage['volume_per_node']) - self.find_clear_send(by.By.ID, "id_volumes_size", - storage['volume_size']) - if cfg.common.floating_ip_pool: - self.driver.find_element_by_xpath( - "//*[@id='id_floating_ip_pool']/option[text()='%s']" - % cfg.common.floating_ip_pool).click() - if cfg.common.auto_security_groups != driver.find_element_by_id( - "id_autogroup").is_selected(): - driver.find_element_by_id("id_autogroup").click() - if cfg.common.security_groups: - # create dictionary with existing security groups - actual_groups = {} - for sec_group in driver.find_elements_by_xpath( - "//label[contains(@for, 'id_groups_')]"): - actual_groups[sec_group.text] = sec_group - # search specified in config file security groups of existing - for sec_group in cfg.common.security_groups: - if sec_group not in actual_groups: - self.fail("Security group with name %s not " - "found. Aborting." % sec_group) - if not actual_groups[sec_group].is_selected(): - actual_groups[sec_group].click() - processes = [] - for process in list_processes: - number_pr = self.search_id_processes(process, plugin) - driver.find_element_by_id( - "id_processes_%s" % str(number_pr)).click() - processes.append(driver.find_element_by_id( - "id_processes_%s" % str(number_pr)). - find_element_by_xpath('..').text) - if params: - self.config_helper(params) - self.click_visible_key("//input[@value='Create']") - if not message: - message = "Success: Created Node Group Template %s" % name - if close_window: - self.check_create_object( - name, positive, message, - [{2: [name]}, - {3: [plugin.plugin_overview_name]}, - {4: [plugin.hadoop_version]}, {5: processes}]) - else: - self.error_helper(message) - - def create_cluster_template( - self, name, node_groups, plugin, description=None, - close_window=True, anti_affinity_groups=None, positive=True, - message=None, params=None): - driver = self.driver - driver.get(cfg.common.base_url + - "/project/data_processing/cluster_templates/") - self.await_element(by.By.ID, "cluster_templates__action_create") - driver.find_element_by_id("cluster_templates__action_create").click() - self.choose_plugin_name(plugin.plugin_name, plugin.hadoop_version, - name, description, "id_cluster_template_name") - if anti_affinity_groups: - for group in anti_affinity_groups: - driver.find_element_by_id( - "id_anti_affinity_%s" % self.search_id_processes( - group, plugin)).click() - driver.find_element_by_link_text("Node Groups").click() - number_to_add = 0 - node_groups_list = [] - for node_group, count in node_groups.items(): - driver.find_element_by_xpath( - "//select[@id='template_id']/option[text()='%s']" - % node_group).click() - driver.find_element_by_id("add_group_button").click() - self.find_clear_send(by.By.ID, "count_%d" % number_to_add, count) - node_groups_list.append("%s: %d" % (node_group, count)) - number_to_add += 1 - if params: - self.config_helper(params) - self.click_visible_key("//input[@value='Create']") - if not message: - message = "Success: Created Cluster Template %s" % name - if close_window: - self.check_create_object( - name, positive, message, - [{2: [name]}, - {3: [plugin.plugin_overview_name]}, - {4: [plugin.hadoop_version]}, {5: node_groups_list}, - {6: [description if description else '']}]) - else: - self.error_helper(message) - - def create_cluster(self, name, cluster_template, plugin, keypair=None, - close_window=True, description=None, positive=True, - await_run=True, message=None): - driver = self.driver - driver.get(cfg.common.base_url + "/project/data_processing/clusters/") - self.await_element(by.By.ID, "clusters__action_create") - driver.find_element_by_id("clusters__action_create").click() - self.choose_plugin_name(plugin.plugin_name, plugin.hadoop_version, - name, description, "id_cluster_name") - driver.find_element_by_xpath("//select[@id='id_cluster_template']/" - "option[text()='%s']" % - cluster_template).click() - driver.find_element_by_xpath("//select[@id='id_image']/option" - "[text()='%s']" % - plugin.base_image).click() - if not keypair: - keypair = cfg.common.keypair - driver.find_element_by_xpath("//select[@id='id_keypair']" - "/option[text()='%s']" % keypair).click() - if cfg.common.neutron_management_network: - driver.find_element_by_xpath( - "//select[@id='id_neutron_management_network']/option[text()=" - "'%s']" % cfg.common.neutron_management_network).click() - self.click_visible_key("//input[@value='Create']") - if not message: - message = 'Success: Created Cluster %s' % name - if close_window: - self.check_create_object(name, positive, message) - else: - self.error_helper(message) - if await_run: - self.await_cluster_active(name) - - def create_data_source(self, name, url, close_window=True, - description=None, positive=True, message=None): - - driver = self.driver - driver.get(cfg.common.base_url + - "/project/data_processing/data_sources/") - self.await_element(by.By.ID, "data_sources__action_create data source") - driver.find_element_by_id( - "data_sources__action_create data source").click() - - self.await_element(by.By.ID, "id_data_source_name") - - self.find_clear_send(by.By.ID, "id_data_source_name", name) - self.find_clear_send(by.By.ID, "id_data_source_url", url) - self.find_clear_send(by.By.ID, "id_data_source_credential_user", - cfg.common.user) - self.find_clear_send(by.By.ID, "id_data_source_credential_pass", - cfg.common.password) - if description: - self.find_clear_send(by.By.ID, "id_data_source_description", - description) - - driver.find_element_by_xpath("//input[@value='Create']").click() - - if not message: - message = 'Success: Data source created' - if close_window: - self.check_create_object(name, positive, message) - else: - self.error_helper(message) - - def create_job_binary(self, name, parameters_of_storage, description=None, - positive=True, message=None, close_window=True): - - driver = self.driver - storage_type = parameters_of_storage['storage_type'] - driver.get(cfg.common.base_url + - "/project/data_processing/job_binaries/") - self.await_element(by.By.ID, "job_binaries__action_create job binary") - driver.find_element_by_id( - "job_binaries__action_create job binary").click() - - self.await_element(by.By.ID, "id_job_binary_name") - - self.find_clear_send(by.By.ID, "id_job_binary_name", name) - driver.find_element_by_xpath("//select[@id='id_job_binary_type']/optio" - "n[text()='%s']" % storage_type).click() - - if storage_type == 'Swift': - self.find_clear_send(by.By.ID, "id_job_binary_url", - parameters_of_storage['url']) - self.find_clear_send(by.By.ID, "id_job_binary_username", - cfg.common.user) - self.find_clear_send(by.By.ID, "id_job_binary_password", - cfg.common.password) - - elif storage_type == 'Internal database': - internal_binary = parameters_of_storage['Internal binary'] - driver.find_element_by_xpath( - "//select[@id='id_job_binary_internal']/option[text()" - "='%s']" % internal_binary).click() - if internal_binary == '*Upload a new file': - file = '%s/saharadashboard/tests/resources/%s' % ( - os.getcwd(), parameters_of_storage['filename']) - driver.find_element_by_id('id_job_binary_file').send_keys(file) - - elif internal_binary == '*Create a script': - self.find_clear_send(by.By.ID, "id_job_binary_script_name", - parameters_of_storage['script_name']) - self.find_clear_send(by.By.ID, "id_job_binary_script", - parameters_of_storage['script_text']) - - if description: - self.find_clear_send(by.By.ID, "id_job_binary_description", - description) - - driver.find_element_by_xpath("//input[@value='Create']").click() - - if not message: - message = 'Success: Successfully created job binary' - if close_window: - self.check_create_object(name, positive, message) - else: - self.error_helper(message) - - def create_job(self, name, job_type, main=None, libs=None, - close_window=True, description=None, positive=True, - message=None): - - driver = self.driver - driver.get(cfg.common.base_url + "/project/data_processing/jobs/") - self.await_element(by.By.ID, "jobs__action_create job") - driver.find_element_by_id("jobs__action_create job").click() - - self.await_element(by.By.ID, "id_job_name") - self.find_clear_send(by.By.ID, "id_job_name", name) - driver.find_element_by_xpath( - "//select[@id='id_job_type']/option[text()='%s']" - % job_type).click() - if main: - driver.find_element_by_xpath( - "//select[@id='id_main_binary']/option[text()='%s']" - % main).click() - if description: - self.find_clear_send(by.By.ID, "id_job_description", description) - if libs: - driver.find_element_by_link_text('Libs').click() - self.await_element(by.By.ID, "id_lib_binaries") - for lib in libs: - driver.find_element_by_xpath( - "//select[@id='id_lib_binaries']/option[text()='%s']" - % lib).click() - driver.find_element_by_id('add_lib_button').click() - - driver.find_element_by_xpath("//input[@value='Create']").click() - - if not message: - message = 'Success: Job created' - if close_window: - self.check_create_object(name, positive, message) - else: - self.error_helper(message) - - def launch_job_on_existing_cluster(self, name, input, output, cluster, - configure=None, positive=True, - message=None, close_window=True, - await_launch=True): - - driver = self.driver - driver.get(cfg.common.base_url + "/project/data_processing/jobs/") - self.await_element(by.By.ID, "jobs__action_create job") - - action_column = driver.find_element_by_link_text( - name).find_element_by_xpath('../../td[4]') - action_column.find_element_by_class_name('dropdown-toggle').click() - action_column.find_element_by_link_text( - 'Launch On Existing Cluster').click() - - self.await_element(by.By.ID, "id_job_input") - driver.find_element_by_xpath( - "//select[@id='id_job_input']/option[text()='%s']" % input).click() - driver.find_element_by_xpath( - "//select[@id='id_job_output']/option[text()='%s']" % - output).click() - driver.find_element_by_xpath( - "//select[@id='id_cluster']/option[text()='%s']" % cluster).click() - - if configure: - driver.find_element_by_link_text('Configure').click() - for config_part, values in configure.items(): - config_number = 1 - for config, value in values.items(): - driver.find_element_by_id( - config_part).find_element_by_link_text('Add').click() - driver.find_element_by_xpath( - '//*[@id="%s"]/table/tbody/tr[%i]/td[1]/input' % ( - config_part, config_number)).send_keys(config) - driver.find_element_by_xpath( - '//*[@id="%s"]/table/tbody/tr[%i]/td[2]/input' % ( - config_part, config_number)).send_keys(value) - config_number += 1 - - driver.find_element_by_xpath("//input[@value='Launch']").click() - - if not message: - message = 'Success: Job launched' - if close_window: - self.check_create_object(name, positive, message, - check_create_element=False) - if await_launch: - self.await_launch_job(name) - - else: - self.error_helper(message) - - def delete_node_group_templates(self, names, undelete_names=None, - finally_delete=False): - url = "/project/data_processing/nodegroup_templates/" - delete_button_id = 'nodegroup_templates__action_' \ - 'delete_nodegroup_template' - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete) - - def delete_cluster_templates(self, names, undelete_names=None, - finally_delete=False): - url = "/project/data_processing/cluster_templates/" - delete_button_id = "cluster_templates__action_delete_cluster_template" - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete) - - def delete_clusters(self, names, undelete_names=None, - finally_delete=False, await_delete=False): - url = "/project/data_processing/clusters/" - delete_button_id = "clusters__action_delete" - msg = "Success: Deleted Cluster" - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, succes_msg=msg, - await_delete=await_delete) - - def delete_data_sources(self, names, undelete_names=None, - finally_delete=False): - url = "/project/data_processing/data_sources/" - delete_button_id = "data_sources__action_delete" - msg = "Success: Deleted Data source" - err_msg = 'Error: Unable to delete data source' - info_msg = 'Info: Deleted Data source' - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, msg, err_msg, info_msg) - - def delete_job_binaries(self, names, undelete_names=None, - finally_delete=False): - - url = "/project/data_processing/job_binaries/" - delete_button_id = "job_binaries__action_delete" - - msg = "Success: Deleted Job binary" - err_msg = 'Error: Unable to delete job binary' - info_msg = 'Info: Deleted Job binary' - - if not undelete_names and len(names) > 1: - msg = "Success: Deleted Job binarie" - - if undelete_names and len(names) - len(undelete_names) > 1: - info_msg = 'Info: Deleted Job binarie' - - if undelete_names and len(undelete_names) > 1: - err_msg = 'Error: Unable to delete job binarie' - - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, msg, err_msg, info_msg) - - def delete_jobs(self, names, undelete_names=None, finally_delete=False): - url = "/project/data_processing/jobs/" - delete_button_id = "jobs__action_delete" - msg = "Success: Deleted Job" - err_msg = 'Error: Unable to delete job' - info_msg = 'Info: Deleted Job' - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, msg, err_msg, info_msg) - - def delete_job_executions(self, names, undelete_names=None, - finally_delete=False, await_delete=False): - url = "/project/data_processing/job_executions/" - delete_button_id = 'job_executions__action_delete' - msg = "Success: Deleted Job execution" - err_msg = "Error: Unable to delete job execution" - info_msg = "Info: Deleted Job execution" - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, msg, err_msg, info_msg, - await_delete) - - def unregister_images(self, names, undelete_names=None, - finally_delete=False): - url = '/project/data_processing/data_image_registry/' - delete_button_id = "image_registry__action_Unregister" - msg = "Success: Unregistered Image" - self.delete_and_validate(url, delete_button_id, names, undelete_names, - finally_delete, succes_msg=msg,) - -# -------------------------helpers_methods------------------------------------- - - @staticmethod - def connect_to_swift(): - return swift_client.Connection( - authurl=cfg.common.keystone_url, - user=cfg.common.user, - key=cfg.common.password, - tenant_name=cfg.common.tenant, - auth_version=2 - ) - - @staticmethod - def delete_swift_container(swift, container): - - try: - objects = [obj['name'] for obj - in swift.get_container(container)[1]] - except Exception: - return - - for obj in objects: - - swift.delete_object(container, obj) - - try: - swift.delete_container(container) - except Exception: - return - - @classmethod - def find_clear_send(cls, by_find, find_element, send): - cls.driver.find_element(by=by_find, value=find_element).clear() - cls.driver.find_element(by=by_find, value=find_element).send_keys(send) - - def click_visible_key(self, xpath): - keys = self.driver.find_elements_by_xpath(xpath) - for key in keys: - if key.is_displayed(): - key.click() - - def delete_and_validate(self, url, delete_button_id, names, undelete_names, - finally_delete, - succes_msg='Success: Deleted Template', - error_msg='Error: Unable to delete template', - info_msg='Info: Deleted Template', - await_delete=False,): - driver = self.driver - driver.refresh() - driver.get(cfg.common.base_url + url) - - if finally_delete: - try: - self.await_element(by.By.ID, delete_button_id, await_count=3) - except selenim_except.NoSuchElementException: - return - else: - self.await_element(by.By.ID, delete_button_id) - - for name in names: - # choose checkbox for this element - checkbox = None - retry_count = 0 - while not checkbox: - if retry_count > 10: - self.fail("id of job execution didn't obtained") - try: - checkbox = driver.find_element_by_link_text( - name).find_element_by_xpath( - "../../td[1]/input") - except selenim_except.StaleElementReferenceException: - time.sleep(1) - retry_count += 1 - except selenim_except.NoSuchElementException: - if not finally_delete: - print ("element with name %s not found " - "for delete" % name) - raise - if not checkbox.is_selected(): - checkbox.click() - # click deletebutton - driver.find_element_by_id(delete_button_id).click() - # wait window to confirm the deletion - self.await_element(by.By.CLASS_NAME, "btn-primary") - # confirm the deletion - driver.find_element_by_class_name("btn-primary").click() - if finally_delete: - return - exp_del_obj = list(set(names).symmetric_difference(set( - undelete_names if undelete_names else []))) - if not undelete_names: - if len(names) > 1: - succes_msg += "s" - succes_msg += ": " - self.check_alert("alert-success", succes_msg, names, deleted=True, - await_delete=await_delete) - elif not exp_del_obj: - if len(undelete_names) > 1: - error_msg += "s" - error_msg += ": " - self.check_alert("alert-danger", error_msg, undelete_names, - deleted=False) - else: - if len(undelete_names) > 1: - error_msg += "s" - error_msg += ": " - if len(exp_del_obj) > 1: - info_msg += "s" - info_msg += ": " - self.check_alert("alert-danger", error_msg, undelete_names, - deleted=False) - self.check_alert("alert-info", info_msg, exp_del_obj, deleted=True, - await_delete=await_delete) - driver.refresh() - - def error_helper(self, message): - driver = self.driver - messages = message.split(", ") - self.await_element(by.By.CLASS_NAME, "error") - errors = driver.find_elements_by_class_name("error") - for message in messages: - mes = message.split(":") - if len(mes) > 1: - # if word count for error mesage > 1, then error message - # can be on the open tab or on another - if len(mes) > 2: - # if word count for error mesage > 2, then error message - # on another tab - # Click the tab indicated in the message - driver.find_element_by_link_text(mes.pop(0)).click() - error = errors.pop(0).text.split("\n") - self.assertEqual(mes[0], error[0]) - self.assertEqual(mes[1], error[1]) - else: - self.assertEqual(mes[0], errors.pop(0).text) - self.assertEqual(errors, []) - driver.refresh() - - def config_helper(self, config_list): - driver = self.driver - for pair in config_list: - for par, value in pair.iteritems(): - if len(par.split(":")) > 1: - config_blog = driver.find_element_by_link_text( - par.split(":")[0]) - config_blog.click() - - # Find class for config blog for for unambiguous - # finding buttons - config_class = driver.find_element_by_id( - config_blog.get_attribute('data-target').lstrip("#")) - - config_id = "id_CONF:%s" % par.split(":")[0].split(" ")[0] - if config_id == "id_CONF:General": - config_id = "id_CONF:general" - par = par.split(":")[1] - if par == "Show_param": - show_button = config_class.find_element_by_class_name( - "full-config-show") - hide_button = config_class.find_element_by_class_name( - "full-config-hide") - if value: - self.waiting_element_in_visible_state( - button=show_button) - show_button.click() - self.waiting_element_in_visible_state( - button=hide_button) - else: - self.waiting_element_in_visible_state( - button=hide_button) - hide_button.click() - self.waiting_element_in_visible_state( - button=show_button) - elif par == "Filter": - filter_button = config_class.find_element_by_css_selector( - "input.form-control.field-filter") - filter_button.clear() - filter_button.send_keys(value) - - else: - self.waiting_element_in_visible_state( - by.By.ID, "%s:%s" % (config_id, par)) - if isinstance(value, bool): - if driver.find_element_by_id( - "%s:%s" % (config_id, - par)).is_selected() != value: - driver.find_element_by_id( - "%s:%s" % (config_id, par)).click() - else: - self.find_clear_send( - by.By.ID, "%s:%s" % (config_id, par), value) - - def image_registry_helper(self, image_name, user_name, description, - tags_to_add, tags_to_remove, positive, - close_window, message, operation): - driver = self.driver - list_for_check_tags = [] - driver.get(cfg.common.base_url + - "/project/data_processing/data_image_registry/") - self.await_element(by.By.ID, "image_registry__action_register") - if operation == 'Registry': - driver.find_element_by_id( - "image_registry__action_register").click() - else: - # Add existing tags in the list - list_for_check_tags = driver.\ - find_element(by=by.By.LINK_TEXT, value=image_name).\ - find_element_by_xpath('../../td[3]').text.split('\n') - # Click "Edit Tags" - driver.find_element(by=by.By.LINK_TEXT, value=image_name).\ - find_element_by_xpath('../../td[4]').\ - find_element(by=by.By.LINK_TEXT, value='Edit Tags').click() - self.await_element(by.By.ID, 'id_user_name') - if operation == 'Registry': - driver.find_element_by_xpath("//select[@id='id_image_id']" - "/option[text()='%s']" - % image_name).click() - if user_name: - self.find_clear_send(by.By.ID, 'id_user_name', user_name) - if description: - self.find_clear_send(by.By.ID, 'id_description', user_name) - if tags_to_add: - for tag in tags_to_add: - for first, second in tag.iteritems(): - if first in ["vanilla", 'hdp']: - driver.find_element_by_xpath( - "//select[@id='plugin_select']/option[text()='%s']" - % first).click() - driver.find_element_by_xpath( - "//select[@id='data_processing_version_%s']" - "/option[text()='%s']" % (first, second)).click() - driver.find_element_by_id('add_all_btn').click() - if first not in list_for_check_tags: - list_for_check_tags.append(first) - if second not in list_for_check_tags: - list_for_check_tags.append(second) - elif first == 'custom_tag': - self.find_clear_send(by.By.ID, '_sahara_image_tag', - second) - driver.find_element_by_id('add_tag_btn').click() - if second not in list_for_check_tags: - list_for_check_tags.append(second) - else: - self.fail("Tag:%s, %s is unknown" % (first, second)) - if tags_to_remove: - for tag in tags_to_remove: - # click "x" in tag - driver.find_element_by_xpath( - "//div[@id='image_tags_list']//span[contains(.,'%s')]//i" - % tag).click() - if tag in list_for_check_tags: - list_for_check_tags.remove(tag) - driver.find_element_by_id('edit_image_tags_btn').click() - if positive: - self.check_create_object(image_name, positive, message, - [{3: list_for_check_tags}]) - else: - if not close_window: - self.error_helper(message) - else: - self.check_create_object(image_name, positive, message) - - def choose_plugin_name(self, plugin_name, hadoop_version, name, - description, id_name): - self.await_element(by.By.ID, "id_plugin_name") - self.driver.find_element_by_xpath( - "//select[@id='id_plugin_name']/option[text()='%s']" % - plugin_name).click() - if plugin_name == "Hortonworks Data Platform": - version_id = "id_hdp_version" - elif plugin_name == "Vanilla Apache Hadoop": - version_id = "id_vanilla_version" - else: - self.fail("plugin_name:%s is wrong" % plugin_name) - self.driver.find_element_by_id(version_id).find_element_by_xpath( - "option[text()='%s']" % hadoop_version).click() - self.driver.find_element_by_xpath("//input[@value='Create']").click() - self.await_element(by.By.ID, id_name) - self.find_clear_send(by.By.ID, id_name, name) - if description: - self.find_clear_send(by.By.ID, "id_description", description) - - def check_alert(self, alert, expected_message, list_obj, deleted=True, - await_delete=False): - self.await_element(by.By.CLASS_NAME, alert) - actual_message = self.find_alert_message( - alert, first_character=2, last_character=len(expected_message) + 2) - self.assertEqual(actual_message, expected_message) - not_expected_objs = list(set(self.find_alert_message( - alert, first_character=len(expected_message) + 2).split( - ", ")).symmetric_difference(set(list_obj))) - if not_expected_objs: - self.fail("have deleted objects: %s" % not_expected_objs) - if deleted: - errmsg = "object with name:{} is not deleted" - else: - errmsg = "object with name:{} is deleted" - for name in list_obj: - if await_delete: - await_count = 0 - while self.does_element_present(by.By.LINK_TEXT, - name) == deleted: - self.driver.refresh() - time.sleep(5) - await_count += 1 - if await_count > 12: - self.fail(errmsg.format(name)) - return - if self.does_element_present(by.By.LINK_TEXT, name) == deleted: - self.fail(errmsg.format(name)) - delete_attempts_count = 0 - for name in list_obj: - while self.does_element_present(by.By.LINK_TEXT, name) == deleted: - if delete_attempts_count > cfg.common.await_element: - if deleted: - errmsg = "object with name:%s is not deleted" % name - else: - errmsg = "object with name:%s is deleted" % name - self.fail(errmsg) - time.sleep(1) - delete_attempts_count += 1 - - def find_alert_message(self, name, first_character=None, - last_character=None): - driver = self.driver - return str(driver.find_element_by_class_name("%s" % name).text[ - first_character:last_character]) - - def search_id_processes(self, process, plugin): - return plugin.processes[process] - - def waiting_element_in_visible_state(self, how=None, what=None, - button=None): - if not button: - button = self.driver.find_element(by=how, value=what) - for i in range(cfg.common.await_element): - if button.is_displayed(): - break - time.sleep(1) - else: - self.fail("time out for await visible: %s , %s" % (how, what)) - - def does_element_present(self, how, what): - try: - self.driver.find_element(by=how, value=what) - except Exception as e: - print(e.message) - return False - return True - - def await_element(self, by, value, message="", - await_count=cfg.common.await_element): - for i in range(await_count): - if self.does_element_present(by, value): - break - time.sleep(1) - else: - if not message: - message = "time out for await: %s , %s" % (by, value) - print(message) - raise selenim_except.NoSuchElementException - - def check_create_object(self, name, positive, expected_message, - check_columns=None, check_create_element=True): - driver = self.driver - expected_alert = "alert-danger" - unexpected_alert = "alert-success" - if positive: - expected_alert = "alert-success" - unexpected_alert = "alert-danger" - for i in range(cfg.common.await_element): - if self.does_element_present(by.By.CLASS_NAME, expected_alert): - break - elif self.does_element_present(by.By.CLASS_NAME, unexpected_alert): - fail_mesg = self.driver.find_element( - by=by.By.CLASS_NAME, value=unexpected_alert).text[2:] - self.fail("Result of creation %s is not expected: %s != %s" - % (name, expected_message, fail_mesg)) - time.sleep(1) - else: - self.fail("alert check:%s time out" % expected_alert) - actual_message = self.driver.find_element( - by=by.By.CLASS_NAME, value=expected_alert).text[2:] - if check_create_element and positive: - self.assertEqual(expected_message, str(actual_message)) - if not self.does_element_present(by.By.LINK_TEXT, name): - self.fail("object with name:%s not found" % name) - if check_columns: - for column in check_columns: - for column_number, expected_values in column.iteritems(): - actual_values = driver.\ - find_element_by_link_text(name).\ - find_element_by_xpath( - '../../td[%d]' % column_number).\ - text.split('\n') - self.assertItemsEqual(actual_values, expected_values) - else: - if expected_message: - self.assertEqual(expected_message, str(actual_message)) - self.driver.refresh() - - def await_cluster_active(self, name): - driver = self.driver - i = 1 - while True: - - if i > cfg.common.cluster_creation_timeout * 60: - self.fail( - 'cluster is not getting status \'Active\', ' - 'passed %d minutes' % cfg.common.cluster_creation_timeout) - - try: - status = driver.find_element_by_link_text( - "selenium-cl").find_element_by_xpath("../../td[3]").text - except selenim_except.StaleElementReferenceException: - status = 'unknown' - - if str(status) == 'Error': - self.fail('Cluster state == \'Error\'.') - - if str(status) == 'Active': - break - - time.sleep(5) - i += 5 - - def await_launch_job(self, job_name): - driver = self.driver - driver.get(cfg.common.base_url + - "/project/data_processing/job_executions/") - self.await_element(by.By.ID, 'job_executions') - - job_id = None - retry_count = 0 - while not job_id: - if retry_count > 10: - self.fail("id of job execution didn't obtained") - try: - job_id = driver.find_element_by_id( - 'job_executions').find_elements_by_class_name( - 'ajax-update')[0].get_attribute('id') - self.job_id = job_id.split("_")[-1] - # TODO(vrovachev): replace find job_id on commented code - # after resolve bug 1391469 - # job_id = driver.find_element_by_id( - # 'job_executions').find_element_by_link_text( - # job_name).find_element_by_xpath( - # '../..').get_attribute('id') - except selenim_except.StaleElementReferenceException: - time.sleep(1) - retry_count += 1 - - status = None - retry_count = 0 - while not status: - if retry_count > 10: - self.fail("id of job execution didn't obtained") - try: - status = driver.find_element_by_id( - job_id).find_element_by_xpath( - "td[contains(@class, 'status_')]").text - except selenim_except.StaleElementReferenceException: - time.sleep(1) - retry_count += 1 - - timeout = cfg.common.job_launch_timeout * 60 - - while str(status) != 'SUCCEEDED': - - if timeout <= 0: - self.fail( - 'Job did not return to \'SUCCEEDED\' status within ' - '%d minute(s).' % cfg.common.job_launch_timeout) - - if status == 'KILLED': - self.fail('Job status == \'KILLED\'.') - - status = None - retry_count = 0 - while not status: - if retry_count > 10: - self.fail("id of job execution didn't obtained") - try: - status = driver.find_element_by_id( - job_id).find_element_by_xpath( - "td[contains(@class, 'status_')]").text - except selenim_except.StaleElementReferenceException: - time.sleep(1) - retry_count += 1 - - time.sleep(1) - timeout -= 1 - - @classmethod - def tearDownClass(cls): - cls.driver.quit() diff --git a/saharadashboard/tests/cluster_template_tests/negative_tests.py b/saharadashboard/tests/cluster_template_tests/negative_tests.py deleted file mode 100644 index 602f55e5..00000000 --- a/saharadashboard/tests/cluster_template_tests/negative_tests.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from testtools import testcase -import unittest2 - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UINegativeCreateClusterTemplateTest(base.UITestCase): - - @testcase.attr('cluster_template', 'vanilla') - @unittest2.skip - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_vanilla_cluster_template_with_wrong_fields(self): - self.create_node_group_template('selenium-master', ["NN", "JT"], - cfg.vanilla) - self.create_node_group_template('selenium-worker', ["DN", "TT"], - cfg.vanilla) - self.create_cluster_template( - "", {'selenium-master': 1, 'selenium-worker': 2}, cfg.vanilla, - anti_affinity_groups=["NN", "DN", "TT"], - params=[{"General Parameters:Enable Swift": False}, - {"HDFS Parameters:io.file.buffer.size": "str"}, - {"MapReduce Parameters:mapreduce.job.counters.max": - "str"}], - positive=False, close_window=False, - message='Details, HDFS Parameters, MapReduce Parameters, ' - 'Template Name:This field is required., ' - 'HDFS Parameters:io.file.buffer.size:Enter a whole number., ' - 'MapReduce Parameters:mapreduce.job.counters.max:' - 'Enter a whole number.') - self.delete_node_group_templates(["selenium-master", - "selenium-worker"]) diff --git a/saharadashboard/tests/cluster_template_tests/test_create_cluster_template.py b/saharadashboard/tests/cluster_template_tests/test_create_cluster_template.py deleted file mode 100644 index f15185fe..00000000 --- a/saharadashboard/tests/cluster_template_tests/test_create_cluster_template.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from testtools import testcase -import unittest2 - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UICreateClusterTemplate(base.UITestCase): - - @testcase.attr('cluster_template', 'vanilla') - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_cluster_template_for_vanilla(self): - self.create_node_group_template('selenium-master', ["NN", "JT"], - cfg.vanilla) - self.create_node_group_template('selenium-worker', ["DN", "TT"], - cfg.vanilla) - self.create_node_group_template('selenium-delete', ["NN", "OZ"], - cfg.vanilla) - self.create_cluster_template( - "selenium-clstr-tmpl", {'selenium-master': 1, - 'selenium-worker': 2}, - cfg.vanilla, anti_affinity_groups=["NN", "DN", "TT"], - params=[{"General Parameters:Enable Swift": False}, - {"HDFS Parameters:dfs.replication": 2}, - {"MapReduce Parameters:mapred.output.compress": False}]) - msg = 'Error: Cluster template with name \'selenium-clstr-tmpl\'' \ - ' already exists' - self.create_cluster_template('selenium-clstr-tmpl', - {'selenium-delete': 1, - 'selenium-worker': 2}, - cfg.vanilla, positive=False, message=msg) - self.delete_node_group_templates(["selenium-master", "selenium-worker", - "selenium-delete"], - undelete_names=["selenium-master", - "selenium-worker"]) - self.delete_cluster_templates(['selenium-clstr-tmpl']) - self.delete_node_group_templates(["selenium-master", - "selenium-worker"]) - - @testcase.attr('cluster_template', 'hdp') - @unittest2.skipIf(cfg.hdp.skip_plugin_tests, - 'tests for hdp plugin skipped') - def test_create_cluster_template_for_hdp(self): - self.create_node_group_template( - 'selenium-hdp-master', - ["NN", "JT", "SNN", "GANGLIA_SERVER", "NAGIOS_SERVER", - "AMBARI_SERVER"], cfg.hdp) - self.create_node_group_template( - 'selenium-hdp-worker', - ["TT", "DN", "HDFS_CLIENT", "MAPREDUCE_CLIENT"], cfg.hdp) - self.create_cluster_template( - "selenium-hdp", {'selenium-hdp-master': 1, - 'selenium-hdp-worker': 2}, cfg.hdp, - description="hdp plugin", anti_affinity_groups=["NN", "DN", "TT"], - params=[{"General Parameters:Show_param": True}, - {"hadoop_heapsize": 512}, - {"HDFS Parameters:Show_param": True}, - {"HDFS Parameters:dfs.replication": 2}]) - self.delete_cluster_templates(['selenium-hdp']) - self.delete_node_group_templates(["selenium-hdp-master", - "selenium-hdp-worker"]) diff --git a/saharadashboard/tests/cluster_tests/__init__.py b/saharadashboard/tests/cluster_tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/tests/cluster_tests/test_clusters.py b/saharadashboard/tests/cluster_tests/test_clusters.py deleted file mode 100644 index f6f782be..00000000 --- a/saharadashboard/tests/cluster_tests/test_clusters.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import random -import string - -from testtools import testcase -import unittest2 - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UICreateCluster(base.UITestCase): - - def setUp(self): - super(UICreateCluster, self).setUp() - self.pass_test = False - self.processes = ["NN", "JT"] - self.await_run = False - self.master_storage = {'type': 'Ephemeral Drive'} - self.anty_affinity = [] - if not cfg.vanilla.skip_edp_test: - self.swift = self.connect_to_swift() - self.processes = ["NN", "JT", "OZ"] - self.await_run = True - if cfg.common.cinder: - self.master_storage = {"type": "Cinder Volume", - "volume_per_node": 1, - "volume_size": 5} - if cfg.common.anty_affinity: - self.anty_affinity = "NN", "DN", "TT" - - @testcase.attr('cluster', 'vanilla') - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_vanilla_cluster(self): - - self.create_node_group_template('selenium-master', self.processes, - cfg.vanilla, - storage=self.master_storage) - self.create_node_group_template('selenium-worker', ["DN", "TT"], - cfg.vanilla) - self.create_node_group_template('selenium-del1', ["NN", "JT", - "DN", "TT"], - cfg.vanilla) - self.create_node_group_template('selenium-del2', - ["DN", "TT", "OZ"], - cfg.vanilla) - self.create_cluster_template("selenium-cl-tmpl", - {'selenium-master': 1, - 'selenium-worker': 1}, cfg.vanilla, - anti_affinity_groups=self.anty_affinity) - self.create_cluster_template("selenium-cl-tmpl2", - {'selenium-master': 1, - 'selenium-del2': 2}, - cfg.vanilla, - anti_affinity_groups=["NN", "DN", - "TT", "JT"]) - self.create_cluster(cfg.vanilla.cluster_name, 'selenium-cl-tmpl', - cfg.vanilla, await_run=self.await_run) - if not cfg.vanilla.skip_edp_test: - self.edp_helper() - self.delete_node_group_templates(["selenium-master", - "selenium-worker", - "selenium-del1", - "selenium-del2"], - undelete_names=["selenium-master", - "selenium-worker", - "selenium-del2"]) - self.delete_cluster_templates(['selenium-cl-tmpl', - 'selenium-cl-tmpl2'], - undelete_names=["selenium-cl-tmpl"]) - self.delete_node_group_templates(["selenium-master", - "selenium-worker", - "selenium-del2"], - undelete_names=[ - "selenium-master", - "selenium-worker"]) - self.delete_clusters([cfg.vanilla.cluster_name], await_delete=True) - self.delete_cluster_templates(["selenium-cl-tmpl"]) - self.delete_node_group_templates(["selenium-master", - "selenium-worker"]) - self.pass_test = True - - def edp_helper(self): - self.swift.put_container('selenium-container') - self.swift.put_object( - 'selenium-container', 'input', ''.join(random.choice( - ':' + ' ' + '\n' + string.ascii_lowercase) - for x in range(10000))) - - self.create_data_source( - 'input', 'selenium-container.sahara/input') - self.create_data_source( - 'output', 'selenium-container.sahara/output') - - parameters_of_storage = { - 'storage_type': 'Internal database', - 'Internal binary': '*Upload a new file', - 'filename': 'edp-lib.jar'} - - self.create_job_binary('edp-lib.jar', parameters_of_storage) - - parameters_of_storage = { - 'storage_type': 'Internal database', - 'Internal binary': '*Create a script', - 'script_name': 'edp-job.pig', - 'script_text': open('saharadashboard/tests/resources/' - 'edp-job.pig').read()} - - self.create_job_binary('edp-job.pig', parameters_of_storage) - - self.create_job( - 'selenium-job', 'Pig', 'edp-job.pig', ['edp-lib.jar']) - self.launch_job_on_existing_cluster( - 'selenium-job', 'input', 'output', cfg.vanilla.cluster_name) - - self.delete_swift_container(self.swift, 'selenium-container') - if getattr(self, "job_id", None): - self.delete_job_executions([self.job_id], await_delete=True) - self.delete_jobs(['selenium-job']) - self.delete_job_binaries(['edp-lib.jar', 'edp-job.pig']) - self.delete_data_sources(['input', 'output']) - - def cleanup(self): - if not cfg.vanilla.skip_edp_test: - self.delete_swift_container(self.swift, 'selenium-container') - if getattr(self, "job_id", None): - self.delete_job_executions([self.job_id], finally_delete=True) - self.delete_jobs(['selenium-job'], finally_delete=True) - self.delete_job_binaries(['edp-lib.jar', 'edp-job.pig'], - finally_delete=True) - self.delete_data_sources(['input', 'output'], finally_delete=True) - self.delete_clusters([cfg.vanilla.cluster_name], finally_delete=True) - self.delete_cluster_templates(['selenium-cl-tmpl', - 'selenium-cl-tmpl2'], - finally_delete=True) - self.delete_node_group_templates(["selenium-master", "selenium-worker", - "selenium-del1", "selenium-del2"], - finally_delete=True) - - def tearDown(self): - if not self.pass_test: - self.cleanup() - super(UICreateCluster, self).tearDown() diff --git a/saharadashboard/tests/configs/__init__.py b/saharadashboard/tests/configs/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/tests/configs/config.conf.sample b/saharadashboard/tests/configs/config.conf.sample deleted file mode 100644 index 6d49da64..00000000 --- a/saharadashboard/tests/configs/config.conf.sample +++ /dev/null @@ -1,33 +0,0 @@ -[common] -base_url = "http://127.0.0.1:8080" -user = "admin" -password = "admin" -keypair = 'jenkins' -tenant = 'admin' -auto_security_groups = False -security_groups = default -flavor = 'm1.minniemouse' -# uncomment this parameters if quantum in OpenStack -# neutron_management_network = '' -# floating_ip_pool = '' -keystone_url = 'http://127.0.0.1:5000/v2.0' -# in minutes -cluster_creation_timeout = 10 -# in seconds -await_element = 10 -# in minutes -job_launch_timeout = 5 -image_name_for_register = 'image_name' -image_name_for_edit = 'image_name' -[vanilla] -skip_plugin_tests = False -plugin_name = "Vanilla Apache Hadoop" -plugin_overview_name = "vanilla" -hadoop_version = "1.2.1" -processes = NN: 0, DN: 1, SNN: 2, OZ: 3, TT: 4, JT: 5 -base_image = "image_name" -[hdp] -skip_plugin_tests = False -plugin_name = "Hortonworks Data Platform" -hadoop_version = "1.3.2" -base_image = "image_name" \ No newline at end of file diff --git a/saharadashboard/tests/configs/config.py b/saharadashboard/tests/configs/config.py deleted file mode 100644 index e65cf1ac..00000000 --- a/saharadashboard/tests/configs/config.py +++ /dev/null @@ -1,169 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import os - -from oslo_config import cfg - -common_group = cfg.OptGroup(name='common', title="common configs") - -CommonGroup = [ - cfg.StrOpt('base_url', - default='http://127.0.0.1:8080', - help="sahara url"), - cfg.StrOpt('user', - default='admin', - help="keystone user"), - cfg.StrOpt('password', - default='pass', - help="password for keystone user"), - cfg.StrOpt('keypair', - default='public-jenkins', - help='keypair for create cluster'), - cfg.StrOpt('tenant', - default='admin', - help='keystone tenant'), - cfg.BoolOpt('auto_security_groups', - default=False, - help="Security Groups for sahara cluster"), - cfg.ListOpt('security_groups', - default=None, - help="Security Groups for sahara cluster"), - cfg.StrOpt('flavor', - default='m1.minniemouse', - help='OpenStack flavor name for image.'), - cfg.StrOpt('neutron_management_network', - default=None, - help='Private network for quantum.' - 'Must be specified in create cluster tab'), - cfg.StrOpt('floating_ip_pool', - default=None, - help='Public network for quantum.' - 'Must be specified in create nodegroup template tab'), - cfg.StrOpt('keystone_url', - default='http://127.0.0.1:5000/v2.0', - help='url for keystone authentication'), - cfg.BoolOpt('anty_affinity', - default=False, - help="Parameter for enable/disable Anty Affinity " - "Groups for Sahara cluster"), - cfg.BoolOpt('cinder', - default=False, - help="Parameter for enable/disable attach volume disk " - "to node for Sahara cluster"), - cfg.IntOpt('cluster_creation_timeout', - default=10, - help="cluster timeout in minutes"), - cfg.IntOpt('await_element', - default=15, - help="await each web element in seconds"), - cfg.StrOpt('image_name_for_register', - default='fedora_19', - help='Image name for register to Sahara'), - cfg.StrOpt('image_name_for_edit', - default='latest-ci-image', - help='Image name for edit in image registry in Sahara'), - cfg.IntOpt('job_launch_timeout', - default=5, - help='Timeout for job launch (in minutes); ' - 'minimal value is 1.'), -] - -vanilla_group = cfg.OptGroup(name='vanilla', title="vanilla configs") - -VanillaGroup = [ - cfg.BoolOpt('skip_plugin_tests', - default=False, - help=""" - If this variable is True then - tests for vanilla will be skipped - """), - cfg.BoolOpt('skip_edp_test', default=True), - cfg.StrOpt('plugin_name', - default='Vanilla Apache Hadoop', - help="plugin title, default: Vanilla Apache Hadoop"), - cfg.StrOpt('plugin_overview_name', - default='vanilla', - help="plugin name in overview"), - cfg.StrOpt('cluster_name', - default="selenium-cl", - help="Name of vanilla cluster"), - cfg.StrOpt('hadoop_version', - default='1.2.1', - help="hadoop version for plugin"), - cfg.DictOpt('processes', - default={"NN": 0, "DN": 1, "SNN": 2, - "OZ": 3, "TT": 4, "JT": 5, "hiveserver": 6}, - help='numbers of processes for vanilla in saharadashboard'), - cfg.StrOpt('base_image', - default='ubuntu_sahara_latest', - help="image name for start vanilla cluster") -] - -hdp_group = cfg.OptGroup(name='hdp', title="hdp configs") - -HdpGroup = [ - cfg.BoolOpt('skip_plugin_tests', - default=False, - help=""" - If this variable is True then - tests for hdp will be skipped - """), - cfg.StrOpt('plugin_name', - default='Hortonworks Data Platform', - help="plugin title, default: Hortonworks Data Platform"), - cfg.StrOpt('plugin_overview_name', - default='hdp', - help="plugin name in overview"), - cfg.StrOpt('hadoop_version', - default='1.3.2', - help="hadoop version for plugin"), - cfg.DictOpt('processes', - default={ - "NN": 0, "DN": 1, "SNN": 2, "HDFS_CLIENT": 3, - " ZOOKEEPER_SERVER": 4, "ZOOKEEPER_CLIENT": 5, - "AMBARI_SERVER": 6, "HCAT": 7, "SQOOP": 8, - "JT": 9, "TT": 10, "MAPREDUCE_CLIENT": 11, - "HIVE_SERVER": 12, "HIVE_METASTORE": 13, - "HIVE_CLIENT": 14, "MYSQL_SERVER": 15, - "PIG": 16, "WEBHCAT_SERVER": 17, "OOZIE_SERVER": 18, - "OOZIE_CLIENT": 19, "GANGLIA_SERVER": 20, - "NAGIOS_SERVER": 21, "HBASE_MASTER": 22, - "HBASE_REGIONSERVER": 23, "HBASE_CLIENT": 24 - }, help='numbers of processes for hdp in saharadashboard'), - cfg.StrOpt('base_image', - default='ib-centos-6-4-64-hdp-13', - help="image name for start hdp cluster") -] - - -def register_config(config, config_group, config_opts): - - config.register_group(config_group) - config.register_opts(config_opts, config_group) - -path = os.path.join("%s/saharadashboard/tests/configs/config.conf" - % os.getcwd()) - -if os.path.exists(path): - cfg.CONF([], project='saharadashboard', default_config_files=[path]) - -register_config(cfg.CONF, common_group, CommonGroup) -register_config(cfg.CONF, vanilla_group, VanillaGroup) -register_config(cfg.CONF, hdp_group, HdpGroup) - -common = cfg.CONF.common -vanilla = cfg.CONF.vanilla -hdp = cfg.CONF.hdp diff --git a/saharadashboard/tests/image_registry_tests/__init__.py b/saharadashboard/tests/image_registry_tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/tests/image_registry_tests/test_for_image_registry.py b/saharadashboard/tests/image_registry_tests/test_for_image_registry.py deleted file mode 100644 index 39aa68d9..00000000 --- a/saharadashboard/tests/image_registry_tests/test_for_image_registry.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from testtools import testcase - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UIImageRegistry(base.UITestCase): - - @testcase.attr('image_registry') - def test_edit_tags_for_image(self): - self.edit_tags_by_image_name(cfg.common.image_name_for_edit, - tags_to_add=[ - {cfg.hdp.plugin_overview_name: - cfg.hdp.hadoop_version}, - {'custom_tag': 'blabla'}]) - self.edit_tags_by_image_name(cfg.common.image_name_for_edit, - tags_to_add=[{'custom_tag': 'qweqwe'}], - tags_to_remove=['qweqwe', 'blabla']) - - @testcase.attr('image_registry') - def test_registry_vanilla_image(self): - self.image_registry(cfg.common.image_name_for_register, - user_name='cloud_user', - tags_to_add=[{cfg.vanilla.plugin_overview_name: - cfg.vanilla.hadoop_version}, - {'custom_tag': 'blabla'}]) - self.unregister_images([cfg.common.image_name_for_register]) diff --git a/saharadashboard/tests/node_group_template_tests/__init__.py b/saharadashboard/tests/node_group_template_tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/tests/node_group_template_tests/negative_tests.py b/saharadashboard/tests/node_group_template_tests/negative_tests.py deleted file mode 100644 index cb0eb975..00000000 --- a/saharadashboard/tests/node_group_template_tests/negative_tests.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from testtools import testcase -import unittest2 - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UINegativeCreateNodeGroupTemplate(base.UITestCase): - - @testcase.attr('node_group_template', 'vanilla') - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_vanilla_node_group_template_with_wrong_parameters(self): - self.create_node_group_template( - "", ["NN", "JT"], cfg.vanilla, flavor="m1.small", - params=[{"HDFS Parameters:dfs.datanode.handler.count": "str"}, - {"MapReduce Parameters:io.sort.mb": "str"}], - positive=False, close_window=False, - message='Configure Node Group Template, ' - 'HDFS Parameters, MapReduce Parameters, ' - 'Template Name:This field is required., ' - 'HDFS Parameters:dfs.datanode.handler.count:' - 'Enter a whole number., ' - 'MapReduce Parameters:io.sort.mb:' - 'Enter a whole number.') - - @testcase.attr('node_group_template', 'vanilla') - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_vanilla_node_group_template_with_missing_parameters(self): - self.create_node_group_template( - "", [], cfg.vanilla, positive=False, close_window=False, - message='Configure Node Group Template, ' - 'Template Name:This field is required., ' - 'Processes:This field is required.') diff --git a/saharadashboard/tests/node_group_template_tests/test_create_node_group_template.py b/saharadashboard/tests/node_group_template_tests/test_create_node_group_template.py deleted file mode 100644 index c83ad6db..00000000 --- a/saharadashboard/tests/node_group_template_tests/test_create_node_group_template.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from testtools import testcase -import unittest2 - -from saharadashboard.tests import base -import saharadashboard.tests.configs.config as cfg - - -class UICreateNodeGroupTemplate(base.UITestCase): - - @testcase.attr('node_group_template', 'vanilla') - @unittest2.skipIf(cfg.vanilla.skip_plugin_tests, - 'tests for vanilla plugin skipped') - def test_create_node_group_template_vanilla(self): - self.create_node_group_template( - "selenium-vanilla", ["NN", "JT"], cfg.vanilla, flavor="m1.small", - storage={'type': "Cinder Volume", 'volume_per_node': '2', - 'volume_size': '6'}, description='selenium-test', - params=[{"HDFS Parameters:Show_param": True}, - {"hadoop.native.lib": False}, {"Filter": "heap"}, - {"Name Node Heap Size": 512}, - {"Data Node Heap Size": 512}, - {"Show_param": False}, {"Filter": ""}, - {"dfs.datanode.max.xcievers": 3555}, - {"MapReduce Parameters:io.sort.mb": 200}, - {"mapred.child.java.opts": "-Xmx300m"}]) - msg = "Error: NodeGroup template with name 'selenium-vanilla'" \ - " already exists" - self.create_node_group_template("selenium-vanilla", ["NN", "JT"], - cfg.vanilla, positive=False, - message=msg) - self.delete_node_group_templates(['selenium-vanilla']) - - @testcase.attr('node_group_template', 'hdp') - @unittest2.skipIf(cfg.hdp.skip_plugin_tests, - 'tests for hdp plugin skipped') - def test_create_node_group_template_hdp(self): - self.create_node_group_template( - "sel-hdp", ["NN", "JT", "HDFS_CLIENT", "AMBARI_SERVER"], cfg.hdp, - flavor="m1.small", storage={'type': "Cinder Volume", - 'volume_per_node': '2', - 'volume_size': '6'}, - description='selenium-test') - msg = "Error: NodeGroup template with name 'sel-hdp' already exists" - self.create_node_group_template("sel-hdp", ["NN", "JT"], cfg.hdp, - positive=False, message=msg) - self.delete_node_group_templates(['sel-hdp']) diff --git a/saharadashboard/tests/resources/README.rst b/saharadashboard/tests/resources/README.rst deleted file mode 100644 index e849207c..00000000 --- a/saharadashboard/tests/resources/README.rst +++ /dev/null @@ -1,82 +0,0 @@ -README for resources -===================================== - -Resources in this directory using for check EDP for Sahara. -For this purpose the cluster with oozie by process is created. -With these resources created and launched jobs. -Success of performance of jobs is checked. - -Pig job -------------------------------------- - -Description. ------------- - -Resources 'edp-job.pig' and 'edp-lib.jar' used for create oozie job -that deletes all symbols in line after ":". - -Example: --------- - -input file: -""" -qweqwe -qweqweqwe: -qweqweqwe:qwe -:ertertert -asd -""" - -output file: -""" -qweqwe -qweqweqwe -asd -""" - -Sources. --------- - -Link for 'edp-job.pig': -https://github.com/apache/oozie/blob/branch-4.0/examples/src/main/apps/pig/id.pig - -Source for 'edp-lib.jar': -https://github.com/apache/oozie/blob/branch-4.0/examples/src/main/java/org/apache/oozie/example/DateList.java - - -MapReduce job -------------------------------------- - -Description. ------------- - -Resource 'edp-job.jar' used for create oozie job -which counts the characters in file and displays values ​​at end of each line. - -Example: --------- - -input file: -""" -qweqwe -qweqweqwe: -qweqweqwe:qwe -:ertertert -asd -""" - -output file: -""" -qweqwe 6 -qweqweqwe: 16 -qweqweqwe:qwe 29 -:ertertert 39 -asd 42 -""" - -Sources. --------- - -Sources for 'edp-job.jar': -https://github.com/apache/oozie/blob/branch-4.0/examples/src/main/java/org/apache/oozie/example/SampleMapper.java -https://github.com/apache/oozie/blob/branch-4.0/examples/src/main/java/org/apache/oozie/example/SampleReducer.java \ No newline at end of file diff --git a/saharadashboard/tests/resources/edp-job.jar b/saharadashboard/tests/resources/edp-job.jar deleted file mode 100644 index 04388a95..00000000 Binary files a/saharadashboard/tests/resources/edp-job.jar and /dev/null differ diff --git a/saharadashboard/tests/resources/edp-job.pig b/saharadashboard/tests/resources/edp-job.pig deleted file mode 100644 index 4141906e..00000000 --- a/saharadashboard/tests/resources/edp-job.pig +++ /dev/null @@ -1,3 +0,0 @@ -A = load '$INPUT' using PigStorage(':') as (fruit: chararray); -B = foreach A generate com.hadoopbook.pig.Trim(fruit); -store B into '$OUTPUT' USING PigStorage(); diff --git a/saharadashboard/tests/resources/edp-lib.jar b/saharadashboard/tests/resources/edp-lib.jar deleted file mode 100644 index 2eba7023..00000000 Binary files a/saharadashboard/tests/resources/edp-lib.jar and /dev/null differ diff --git a/saharadashboard/utils/__init__.py b/saharadashboard/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/utils/hacking/__init__.py b/saharadashboard/utils/hacking/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/saharadashboard/utils/hacking/checks.py b/saharadashboard/utils/hacking/checks.py deleted file mode 100644 index fc0daea0..00000000 --- a/saharadashboard/utils/hacking/checks.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import tokenize - - -def hacking_no_assert_equals(logical_line, tokens): - r"""assertEquals() is deprecated, use assertEqual instead. - - Copied from https://review.openstack.org/#/c/35962/ - - Okay: self.assertEqual(0, 0) - S362: self.assertEquals(0, 0) - """ - - for token_type, text, start_index, _, _ in tokens: - - if token_type == tokenize.NAME and text == "assertEquals": - yield ( - start_index[1], - "S362: assertEquals is deprecated, use assertEqual") - - -def hacking_no_author_attr(logical_line, tokens): - """__author__ should not be used. - - S363: __author__ = slukjanov - """ - for token_type, text, start_index, _, _ in tokens: - if token_type == tokenize.NAME and text == "__author__": - yield (start_index[1], - "S363: __author__ should not be used") - - -def factory(register): - register(hacking_no_assert_equals) - register(hacking_no_author_attr) diff --git a/saharadashboard/version.py b/saharadashboard/version.py deleted file mode 100644 index 76ea5f47..00000000 --- a/saharadashboard/version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2013 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from pbr import version - -version_info = version.VersionInfo('sahara-dashboard') diff --git a/setup.cfg b/setup.cfg index 66da8837..e62b72ce 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,25 +1,47 @@ [metadata] name = sahara-dashboard -version = 2015.1 -summary = Sahara dashboard -description-file = README.rst -license = Apache Software License -classifiers = - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 +summary = Sahara Management Dashboard +description-file = + README.rst +author = OpenStack +author-email = openstack-dev@lists.openstack.org +home-page = http://www.openstack.org/ +classifier = Environment :: OpenStack Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://docs.openstack.org/developer/sahara - -[global] -setup-hooks = pbr.hooks.setup_hook + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 2.6 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.3 + Programming Language :: Python :: 3.4 [files] packages = - saharadashboard + sahara-dashboard + +[build_sphinx] +source-dir = doc/source +build-dir = doc/build +all_files = 1 + +[upload_sphinx] +upload-dir = doc/build/html + +[compile_catalog] +directory = sahara-dashboard/locale +domain = sahara-dashboard + +[update_catalog] +domain = manila-ui +output_dir = manila_ui/locale +input_file = manila_ui/locale/manila-ui.pot + +[extract_messages] +keywords = _ gettext ngettext l_ lazy_gettext +mapping_file = babel.cfg +output_file = manila_ui/locale/manila-ui.pot diff --git a/test-requirements.txt b/test-requirements.txt index 335dea8c..658c596b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,16 +2,18 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking<0.11,>=0.10.0 +-e git://github.com/openstack/horizon.git#egg=horizon +hacking<0.11,>=0.10.0 coverage>=3.6 +ddt>=0.7.0 +django-nose>=1.2 discover mock>=1.2 -oslo.config>=2.6.0 # Apache-2.0 -pylint==1.4.4 # GNU GPL v2 -python-keystoneclient!=1.8.0,>=1.6.0 -python-swiftclient>=2.2.0 -selenium +mox3>=0.7.0 +python-subunit>=0.0.18 +sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 +oslosphinx>=2.5.0 # Apache-2.0 testrepository>=0.0.18 +testscenarios>=0.4 testtools>=1.4.0 -unittest2 diff --git a/tox.ini b/tox.ini index 3eb627c9..61f61517 100644 --- a/tox.ini +++ b/tox.ini @@ -1,25 +1,19 @@ [tox] minversion = 1.6 +envlist = py27,pep8,py27dj17 skipsdist = True -envlist = py26,py27,pep8 [testenv] usedevelop = True install_command = pip install -U {opts} {packages} setenv = - VIRTUAL_ENV={envdir} -deps = - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt + VIRTUAL_ENV={envdir} +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt +commands = /bin/bash run_tests.sh -N --no-pep8 {posargs} -[testenv:uitests] -commands = python setup.py testr --slowest --testr-args="--concurrency 1 {posargs}" - -[testenv:cover] -commands = python setup.py testr --coverage --testr-args='--concurrency 1 {posargs}' - -[tox:jenkins] -downloadcache = ~/cache/pip +[testenv:py27] +setenv = DJANGO_SETTINGS_MODULE=manila_ui.test.settings [testenv:pep8] commands = flake8 @@ -27,12 +21,30 @@ commands = flake8 [testenv:venv] commands = {posargs} -[flake8] -# H904 Wrap long lines in parentheses instead of a backslash -ignore = H904 -show-source = true -builtins = _ -exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,tools,horizon +[testenv:py27dj17] +basepython = python2.7 +commands = pip install django>=1.7,<1.8 + /bin/bash run_tests.sh -N --no-pep8 {posargs} -[hacking] -local-check-factory = saharadashboard.utils.hacking.checks.factory +# Django-1.8 is LTS +[testenv:py27dj18] +basepython = python2.7 +commands = pip install django>=1.8,<1.9 + /bin/bash run_tests.sh -N --no-pep8 {posargs} + +[testenv:cover] +commands = python setup.py testr --coverage --testr-args='{posargs}' + +[testenv:docs] +commands = python setup.py build_sphinx + +[testenv:debug] +commands = oslo_debug_helper {posargs} + +[flake8] +show-source = True +# E123, E125 skipped as they are invalid PEP-8. +# H405 multi line docstring summary not separated with an empty line +ignore = E123,E125,H405 +builtins = _ +exclude=.venv,.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg,build,.ropeproject,tools