Fixed/enabled selenium tests.

Moved the tests to the horizon portion since they test core functionality.
This also required moving some of the templates, etc. that belong in horizon
to their proper homes.

Change-Id: I7d9758845b81e4b8bcf1ffaaff4f6e237b4fe9f8
This commit is contained in:
Gabriel Hurley 2012-07-25 14:03:52 -07:00
parent 6c766326b5
commit 6f838a09b8
62 changed files with 112 additions and 172 deletions

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -30,10 +30,12 @@ from django.contrib.messages.storage import default_storage
from django.contrib.auth.middleware import AuthenticationMiddleware from django.contrib.auth.middleware import AuthenticationMiddleware
from django.core.handlers import wsgi from django.core.handlers import wsgi
from django.test.client import RequestFactory from django.test.client import RequestFactory
from django.utils import unittest
from glanceclient.v1 import client as glance_client from glanceclient.v1 import client as glance_client
from keystoneclient.v2_0 import client as keystone_client from keystoneclient.v2_0 import client as keystone_client
from novaclient.v1_1 import client as nova_client from novaclient.v1_1 import client as nova_client
from selenium.webdriver.firefox.webdriver import WebDriver
import httplib2 import httplib2
import mox import mox
@ -325,3 +327,19 @@ class APITestCase(TestCase):
.AndReturn(self.swiftclient) .AndReturn(self.swiftclient)
expected_calls -= 1 expected_calls -= 1
return self.swiftclient return self.swiftclient
@unittest.skipUnless(os.environ.get('WITH_SELENIUM', False),
"The WITH_SELENIUM env variable is not set.")
class SeleniumTestCase(django_test.LiveServerTestCase):
@classmethod
def setUpClass(cls):
if os.environ.get('WITH_SELENIUM', False):
cls.selenium = WebDriver()
super(SeleniumTestCase, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(SeleniumTestCase, cls).tearDownClass()
if os.environ.get('WITH_SELENIUM', False):
cls.selenium.quit()

View File

@ -49,14 +49,14 @@ class MyPanel(horizon.Panel):
name = _("My Panel") name = _("My Panel")
slug = "myslug" slug = "myslug"
permissions = ("openstack.services.compute",) permissions = ("openstack.services.compute",)
urls = 'horizon.tests.test_panel_urls' urls = 'horizon.tests.test_dashboards.cats.kittens.urls'
class AdminPanel(horizon.Panel): class AdminPanel(horizon.Panel):
name = _("Admin Panel") name = _("Admin Panel")
slug = "admin_panel" slug = "admin_panel"
permissions = ("openstack.roles.admin",) permissions = ("openstack.roles.admin",)
urls = 'horizon.tests.test_panel_urls' urls = 'horizon.tests.test_dashboards.cats.kittens.urls'
class BaseHorizonTests(test.TestCase): class BaseHorizonTests(test.TestCase):
@ -256,6 +256,13 @@ class HorizonTests(BaseHorizonTests):
panel = dash.get_panel('myslug') panel = dash.get_panel('myslug')
self._reload_urls() self._reload_urls()
# Set roles for admin user
self.setActiveUser(token=self.token,
username=self.user.name,
tenant_id=self.tenant.id,
service_catalog=self.request.user.service_catalog,
roles=[{'name': 'admin'}])
# With the required service, the page returns fine. # With the required service, the page returns fine.
resp = self.client.get(panel.get_absolute_url()) resp = self.client.get(panel.get_absolute_url())
self.assertEqual(resp.status_code, 200) self.assertEqual(resp.status_code, 200)

View File

@ -0,0 +1,38 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 Nebula, 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 horizon import test
import selenium.webdriver.support.ui as ui
class BrowserTests(test.SeleniumTestCase):
def test_splash(self):
self.selenium.get(self.live_server_url)
button = self.selenium.find_element_by_tag_name("button")
self.assertEqual(button.text, "Sign In")
def test_qunit(self):
self.selenium.get("%s%s" % (self.live_server_url, "/qunit/"))
wait = ui.WebDriverWait(self.selenium, 10)
def qunit_done(driver):
text = driver.find_element_by_id("qunit-testresult").text
return "Tests completed" in text
wait.until(qunit_done)
failed = self.selenium.find_element_by_class_name("failed")
self.assertEqual(int(failed.text), 0)

View File

@ -1,34 +0,0 @@
{% load branding i18n %}
<!DOCTYPE html>
<html>
<head>
<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
<title>{% block title %}{% endblock %} - {% site_branding %}</title>
{% include "horizon/_conf.html" %}
{% include "horizon/client_side/_script_loader.html" %}
</head>
<body id="{% block body_id %}{% endblock %}">
{% block content %}
<div id="container">
{% block sidebar %}
{% include 'horizon/common/_sidebar.html' %}
{% endblock %}
<div id='main_content'>
<div class='topbar'>
{% include "_header.html" %}
{% block page_header %}{% endblock %}
</div>
{% include "horizon/_messages.html" %}
{% block main %}{% endblock %}
</div>
</div>
{% endblock %}
<div id="footer">
{% block footer %}{% endblock %}
</div>
{% block js %}
{% include "horizon/_scripts.html" %}
{% endblock %}
<div id="modal_wrapper" />
</body>
</html>

View File

@ -1,21 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Nebula, 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 django.conf.urls.defaults import *
urlpatterns = patterns('',
url(r'^$', 'horizon.tests.views.fakeView', name='index'),
)

View File

@ -44,10 +44,12 @@ DEFAULT_EXCEPTION_REPORTER_FILTER = 'horizon.exceptions.HorizonReporterFilter'
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.staticfiles',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.humanize', 'django.contrib.humanize',
'django_nose', 'django_nose',
'openstack_auth', 'openstack_auth',
'compressor',
'horizon', 'horizon',
'horizon.tests', 'horizon.tests',
'horizon.dashboards.nova', 'horizon.dashboards.nova',
@ -116,6 +118,16 @@ HORIZON_CONFIG = {
'user_home': None 'user_home': None
} }
COMPRESS_ENABLED = False
COMPRESS_OFFLINE = False
COMPRESS_ROOT = "/tmp/"
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'compressor.finders.CompressorFinder',
)
AVAILABLE_REGIONS = [ AVAILABLE_REGIONS = [
('http://localhost:5000/v2.0', 'local'), ('http://localhost:5000/v2.0', 'local'),
('http://remote:5000/v2.0', 'remote'), ('http://remote:5000/v2.0', 'remote'),

View File

@ -23,12 +23,19 @@ URL patterns for testing Horizon views.
""" """
from django.conf.urls.defaults import patterns, url, include from django.conf.urls.defaults import patterns, url, include
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic import TemplateView
import horizon import horizon
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', 'horizon.tests.views.fakeView', name='splash'), url(r'^$', 'horizon.views.splash', name='splash'),
url(r'^auth/', include('openstack_auth.urls')), url(r'^auth/', include('openstack_auth.urls')),
url(r'', include(horizon.urls)), url(r'', include(horizon.urls)),
url(r'^qunit/$',
TemplateView.as_view(template_name="horizon/qunit.html"),
name='qunit_tests')
) )
urlpatterns += staticfiles_urlpatterns()

View File

@ -1,30 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, 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 django import http
def fakeView(request):
resp = http.HttpResponse()
resp.write('<html><body><p>'
'This is a fake httpresponse from a fake view for testing '
' purposes only'
'</p></body></html>')
return resp

View File

@ -14,4 +14,4 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from .base import APIView, user_home from .base import APIView, user_home, splash

View File

@ -16,6 +16,9 @@
from django import shortcuts from django import shortcuts
from django.views import generic from django.views import generic
from django.views.decorators import vary
from openstack_auth.views import Login
import horizon import horizon
from horizon import exceptions from horizon import exceptions
@ -26,6 +29,22 @@ def user_home(request):
return shortcuts.redirect(horizon.get_user_home(request.user)) return shortcuts.redirect(horizon.get_user_home(request.user))
def get_user_home(user):
if user.is_superuser:
return horizon.get_dashboard('syspanel').get_absolute_url()
return horizon.get_dashboard('nova').get_absolute_url()
@vary.vary_on_cookie
def splash(request):
if request.user.is_authenticated():
return shortcuts.redirect(get_user_home(request.user))
form = Login(request)
request.session.clear()
request.session.set_test_cookie()
return shortcuts.render(request, 'splash.html', {'form': form})
class APIView(generic.TemplateView): class APIView(generic.TemplateView):
""" A quick class-based view for putting API data into a template. """ A quick class-based view for putting API data into a template.

View File

@ -51,7 +51,7 @@ ROOT_URLCONF = 'openstack_dashboard.urls'
HORIZON_CONFIG = { HORIZON_CONFIG = {
'dashboards': ('nova', 'syspanel', 'settings',), 'dashboards': ('nova', 'syspanel', 'settings',),
'default_dashboard': 'nova', 'default_dashboard': 'nova',
'user_home': 'openstack_dashboard.views.user_home', 'user_home': 'horizon.views.user_home',
'ajax_queue_limit': 10 'ajax_queue_limit': 10
} }

View File

@ -1,4 +1,4 @@
@import "../../bootstrap/less/bootstrap.less"; @import "../../../../horizon/static/bootstrap/less/bootstrap.less";
/* new clearfix */ /* new clearfix */
.clearfix:after { .clearfix:after {

View File

@ -1,33 +0,0 @@
import os
from django import test
from django.utils import unittest
from selenium.webdriver.firefox.webdriver import WebDriver
@unittest.skipUnless(os.environ.get('WITH_SELENIUM', False),
"The WITH_SELENIUM env variable is not set.")
class SeleniumTests(test.LiveServerTestCase):
@classmethod
def setUpClass(cls):
if os.environ.get('WITH_SELENIUM', False):
cls.selenium = WebDriver()
super(SeleniumTests, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(SeleniumTests, cls).tearDownClass()
if os.environ.get('WITH_SELENIUM', False):
cls.selenium.quit()
def test_splash(self):
self.selenium.get(self.live_server_url)
button = self.selenium.find_element_by_tag_name("button")
self.assertEqual(button.text, "Sign In")
def test_qunit(self):
self.selenium.get("%s%s" % (self.live_server_url, "/qunit/")),
self.selenium.implicitly_wait("1000")
failed = self.selenium.find_element_by_class_name("failed")
self.assertEqual(int(failed.text), 0)

View File

@ -31,7 +31,7 @@ import horizon
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', 'openstack_dashboard.views.splash', name='splash'), url(r'^$', 'horizon.views.splash', name='splash'),
url(r'^auth/', include('openstack_auth.urls')), url(r'^auth/', include('openstack_auth.urls')),
url(r'', include(horizon.urls))) url(r'', include(horizon.urls)))

View File

@ -1,44 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2012 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Copyright 2012 Nebula, 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.
"""
Views for home page.
"""
from django import shortcuts
from django.views.decorators import vary
import horizon
from openstack_auth.views import Login
def user_home(user):
if user.is_superuser:
return horizon.get_dashboard('syspanel').get_absolute_url()
return horizon.get_dashboard('nova').get_absolute_url()
@vary.vary_on_cookie
def splash(request):
if request.user.is_authenticated():
return shortcuts.redirect(user_home(request.user))
form = Login(request)
request.session.clear()
request.session.set_test_cookie()
return shortcuts.render(request, 'splash.html', {'form': form})

View File

@ -259,6 +259,10 @@ function install_venv {
function run_tests { function run_tests {
sanity_check sanity_check
if [ $selenium -eq 1 ]; then
export WITH_SELENIUM=1
fi
echo "Running Horizon application tests" echo "Running Horizon application tests"
export NOSE_XUNIT_FILE=horizon/nosetests.xml export NOSE_XUNIT_FILE=horizon/nosetests.xml
${command_wrapper} coverage erase ${command_wrapper} coverage erase
@ -267,9 +271,6 @@ function run_tests {
HORIZON_RESULT=$? HORIZON_RESULT=$?
echo "Running openstack_dashboard tests" echo "Running openstack_dashboard tests"
if [ $selenium -eq 1 ]; then
export WITH_SELENIUM=1
fi
export NOSE_XUNIT_FILE=openstack_dashboard/nosetests.xml export NOSE_XUNIT_FILE=openstack_dashboard/nosetests.xml
${command_wrapper} coverage run -p $root/manage.py test openstack_dashboard --settings=openstack_dashboard.test.settings $testargs ${command_wrapper} coverage run -p $root/manage.py test openstack_dashboard --settings=openstack_dashboard.test.settings $testargs
# get results of the openstack_dashboard tests # get results of the openstack_dashboard tests