Removing all code from previous dashboard incarnation

Clearing out all of the old code from the Sahara
dashboard repo in preparation for bringing the new
code back into the repo for the Mitaka release.

Change-Id: I83cb932c35987ea80ac9233bd355355398b9164b
This commit is contained in:
Chad Roberts 2015-10-29 21:47:36 -04:00
parent acefa0451d
commit 01d6e53630
37 changed files with 846 additions and 1891 deletions

View File

@ -1,4 +0,0 @@
# Format is:
# <preferred e-mail> <other e-mail 1>
# <preferred e-mail> <other e-mail 2>
Timur Nurlygayanov <tnurlygayanov@mirantis.com>

View File

@ -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

View File

@ -1,11 +0,0 @@
include AUTHORS
include README.rst
include ChangeLog
include LICENSE
include saharadashboard/templates/**.html
exclude .gitignore
exclude .gitreview
global-exclude *.pyc

View File

@ -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:
------

23
manage.py Executable file
View File

@ -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)

View File

@ -1,4 +0,0 @@
[DEFAULT]
modules=importutils
base=saharadashboard

View File

@ -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

548
run_tests.sh Normal file
View File

@ -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 [<basecommit>]"
echo " Just run PEP8 and HACKING compliance check"
echo " on files changed since HEAD~1 (or <basecommit>)"
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

View File

@ -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'

View File

@ -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 -- '<module_name>'
<module_name> 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

View File

@ -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()

View File

@ -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"])

View File

@ -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"])

View File

@ -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()

View File

@ -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"

View File

@ -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

View File

@ -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])

View File

@ -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.')

View File

@ -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'])

View File

@ -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

View File

@ -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();

View File

@ -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)

View File

@ -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')

View File

@ -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

View File

@ -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

54
tox.ini
View File

@ -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