455 lines
16 KiB
Python
455 lines
16 KiB
Python
# -*- coding: iso-8859-15 -*-
|
||
|
||
import httpsession
|
||
import re
|
||
import sgmllib
|
||
import sys
|
||
import time
|
||
import unittest
|
||
|
||
glasnostPythonDir = '/usr/local/lib/glasnost-tests'
|
||
sys.path.insert(0, glasnostPythonDir)
|
||
|
||
from GlasnostTestCase import MinimalTestCase, OneUserTestCase
|
||
|
||
httpsession.PostRequest.follow_redirects = 1
|
||
|
||
# The dict function is new in Python 2.2.
|
||
try:
|
||
dict
|
||
except NameError:
|
||
def dict(sequence):
|
||
mapping = {}
|
||
for key, value in sequence:
|
||
mapping[key] = value
|
||
return mapping
|
||
|
||
class Form:
|
||
def __init__(self, action = '', method = '', formId = '', **keywords):
|
||
self.actionUrl = action
|
||
self.method = method
|
||
self.id = formId
|
||
self.values = {}
|
||
self.buttons = []
|
||
self.selects = {}
|
||
|
||
def set(self, k, v):
|
||
if not self.values.has_key(k):
|
||
raise 'unknown key'
|
||
self.values[k] = v
|
||
|
||
def setOption(self, k, v):
|
||
if not k in self.selects.keys():
|
||
raise 'unknown key'
|
||
self.values[k] = self.selects[k][v]
|
||
|
||
def getKeywords(self, buttonClicked = None):
|
||
if not buttonClicked:
|
||
buttonClicked = self.buttons[0]
|
||
else:
|
||
buttonClicked = [x for x in self.buttons if x[0] == buttonClicked
|
||
or x[1] == buttonClicked][0]
|
||
self.values[buttonClicked[0]] = buttonClicked[1]
|
||
return self.values
|
||
|
||
|
||
class ParserForForms(sgmllib.SGMLParser):
|
||
inTextArea = None
|
||
inOption = None
|
||
|
||
def __init__(self, session, body):
|
||
sgmllib.SGMLParser.__init__(self)
|
||
self.forms = []
|
||
self.currentForm = None
|
||
self.session = session
|
||
self.feed(body)
|
||
|
||
def start_form(self, attrs):
|
||
attrs = dict(attrs) # require python >= 2.2
|
||
self.currentForm = Form(**attrs)
|
||
self.currentForm.session = self.session
|
||
|
||
def end_form(self):
|
||
if not self.currentForm:
|
||
raise 'end form while it never opened!'
|
||
self.forms.append(self.currentForm)
|
||
self.currentForm = None
|
||
|
||
def start_input(self, attrs):
|
||
attrs = dict(attrs)
|
||
if not self.currentForm:
|
||
return
|
||
if not attrs.has_key('name'):
|
||
attrs['name'] = 'undefined'
|
||
if attrs.has_key('type') and attrs['type'] == 'submit':
|
||
self.currentForm.buttons.append( (attrs['name'], attrs['value']) )
|
||
return
|
||
if attrs.has_key('type') and attrs['type'] == 'checkbox':
|
||
if attrs.has_key('checked') and attrs['checked'] == 'checked':
|
||
self.currentForm.values[attrs['name']] = 'checked'
|
||
return
|
||
self.currentForm.values[attrs['name']] = None
|
||
if attrs.has_key('value'):
|
||
self.currentForm.values[attrs['name']] = attrs['value']
|
||
|
||
def start_select(self, attrs):
|
||
attrs = dict(attrs)
|
||
if not self.currentForm:
|
||
return
|
||
self.currentForm.values[attrs['name']] = None
|
||
self.inSelect = attrs['name']
|
||
self.currentForm.selects[self.inSelect] = {}
|
||
|
||
def end_select(self):
|
||
self.inSelect = None
|
||
|
||
def start_textarea(self, attrs):
|
||
attrs = dict(attrs)
|
||
if not self.currentForm:
|
||
return
|
||
if not attrs.has_key('name'):
|
||
return
|
||
self.currentForm.values[attrs['name']] = None
|
||
self.inTextArea = attrs['name']
|
||
|
||
def end_textarea(self):
|
||
self.inTextArea = None
|
||
|
||
def handle_data(self, data):
|
||
if self.inTextArea is not None:
|
||
self.currentForm.values[self.inTextArea] = data
|
||
elif self.inOption is not None:
|
||
select = self.currentForm.selects[self.inSelect]
|
||
current = ''
|
||
if select.has_key(self.inOption):
|
||
current = select[self.inOption]
|
||
select[self.inOption] = current + ' ' + data.strip()
|
||
|
||
def start_option(self, attrs):
|
||
if self.inSelect is None:
|
||
return
|
||
attrs = dict(attrs)
|
||
if attrs.has_key('selected') or \
|
||
not self.currentForm.values[self.inSelect]:
|
||
self.currentForm.values[self.inSelect] = attrs['value']
|
||
self.inOption = attrs['value']
|
||
|
||
def end_option(self):
|
||
select = self.currentForm.selects[self.inSelect]
|
||
select[self.inOption] = select[self.inOption].strip()
|
||
select[ select[self.inOption] ] = self.inOption
|
||
del select[self.inOption]
|
||
self.inOption = None
|
||
|
||
class ParserForLinks(sgmllib.SGMLParser):
|
||
def __init__(self, body):
|
||
sgmllib.SGMLParser.__init__(self)
|
||
self.links = []
|
||
self.inLink = 0
|
||
self.feed(body)
|
||
|
||
def start_a(self, attrs):
|
||
attrs = dict(attrs) # require python >= 2.2
|
||
if not attrs.has_key('href'):
|
||
return
|
||
self.inLink = 1
|
||
self.links.append(attrs)
|
||
self.links[-1]['data'] = ''
|
||
|
||
def handle_data(self, data):
|
||
if not self.inLink:
|
||
return
|
||
self.links[-1]['data'] += data
|
||
|
||
def end_a(self):
|
||
try:
|
||
self.links[-1]['data'] = self.links[-1]['data'].strip()
|
||
except IndexError:
|
||
# when first link has not content
|
||
pass
|
||
self.inLink = 0
|
||
|
||
|
||
class WebTestCase(MinimalTestCase, httpsession.HTTPSession):
|
||
pageContent = None
|
||
path = None
|
||
replyCode = None
|
||
|
||
links = None
|
||
forms = None
|
||
|
||
def setUp(self):
|
||
MinimalTestCase.setUp(self)
|
||
httpsession.HTTPSession.__init__(self, use_cookies = 1)
|
||
self.add_header('User-Agent', 'Glasnost/0.0 (WebTesting)')
|
||
self.add_header('Accept-Language', 'fr')
|
||
self.setHost('localhost:9000')
|
||
|
||
def setHost(self, host):
|
||
self.protocol = 'http'
|
||
self.hostName = host
|
||
self.add_header('Host', self.hostName)
|
||
|
||
|
||
def get(self, path):
|
||
if path.startswith('http'):
|
||
url = path
|
||
else:
|
||
url = '%s://%s%s' % (self.protocol, self.hostName, path)
|
||
url = url.replace('&', '&') # TODO: everything
|
||
req = httpsession.HTTPSession.get(self, url)
|
||
self.handle_req(req)
|
||
|
||
def getLinkByLabel(self, label):
|
||
try:
|
||
return [x for x in self.links if x['data'] == label][0]['href']
|
||
except IndexError:
|
||
self.fail('No link with that label')
|
||
|
||
def post(self, path, keywords):
|
||
if path.startswith('http'):
|
||
url = path
|
||
else:
|
||
url = '%s://%s%s' % (self.protocol, self.hostName, path)
|
||
url = url.replace('&', '&') # TODO: everything
|
||
req = httpsession.HTTPSession.post(self, url)
|
||
for k, v in keywords.items():
|
||
req.add_param(k, v)
|
||
self.handle_req(req)
|
||
|
||
def handle_req(self, req):
|
||
req.getreply()
|
||
self.replyCode = int(req.replycode)
|
||
self.pageContent = req.getfile().read()
|
||
self.links = ParserForLinks(self.pageContent).links
|
||
self.forms = ParserForForms(self, self.pageContent).forms
|
||
self.path = req.path
|
||
|
||
|
||
|
||
class BasicTestCase(WebTestCase):
|
||
def test01_getHomepage(self):
|
||
'''Get homepage'''
|
||
self.get('/')
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('<h1>Home</h1>') > -1)
|
||
self.failUnless(self.pageContent.find('Login') > -1)
|
||
|
||
def test02_getVirtualHostsPage(self):
|
||
'''Get virtual hosts page'''
|
||
self.get('/virtualhosts')
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find(
|
||
'<h1>Virtual Hosts</h1>') > -1)
|
||
|
||
def test03_getTheVirtualHostPage(self):
|
||
'''Get the virtual host page'''
|
||
self.get('/virtualhosts')
|
||
try:
|
||
link = [x for x in self.links if
|
||
x['data'] == 'Glasnost' and
|
||
re.match('/virtualhosts/\d+', x['href'])] [0]
|
||
except IndexError:
|
||
self.fail('No link to a virtual host object')
|
||
self.get(link['href'])
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find(
|
||
'<h1>Virtual Host - Glasnost</h1>') > -1)
|
||
|
||
def test04_editTheVirtualHost(self):
|
||
'''Change the language of the virtual host'''
|
||
self.get('/virtualhosts')
|
||
link = [x for x in self.links if
|
||
x['data'] == 'Glasnost' and
|
||
re.match('/virtualhosts/\d+', x['href'])] [0]
|
||
self.get(link['href'])
|
||
|
||
self.get( self.getLinkByLabel('Edit') )
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find(
|
||
'<h1>Editing Virtual Host - Glasnost</h1>') > -1)
|
||
|
||
try:
|
||
form = [x for x in self.forms if
|
||
x.actionUrl == '/virtualhosts/submit'][0]
|
||
except IndexError:
|
||
self.fail('No form on this page')
|
||
|
||
form.setOption('language', 'French')
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Modify'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find(
|
||
'<h1>H<>te virtuel - Glasnost</h1>') > -1)
|
||
|
||
self.get( self.getLinkByLabel('Supprimer') )
|
||
self.failUnless(
|
||
re.match('/virtualhosts/\d+/confirmDelete', self.path) )
|
||
self.get( self.getLinkByLabel('Supprimer') )
|
||
|
||
def test05_applyEveryTemplates(self):
|
||
'''Apply every templates'''
|
||
self.get('/virtualhosts')
|
||
link = [x for x in self.links if
|
||
x['data'] == 'Glasnost' and
|
||
re.match('/virtualhosts/\d+', x['href'])] [0]
|
||
self.get(link['href'])
|
||
previousPageContent = self.pageContent
|
||
|
||
self.get( self.getLinkByLabel('Edit') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl == '/virtualhosts/submit'][0]
|
||
|
||
templateNames = form.selects['templateDirectoryName'].keys()
|
||
for templateName in templateNames + ['Glasnost 2']:
|
||
self.get(link['href'])
|
||
self.get( self.getLinkByLabel('Edit') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl == '/virtualhosts/submit'][0]
|
||
form.setOption('templateDirectoryName', templateName)
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Modify'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.path == link['href'])
|
||
self.failUnless(self.pageContent.find(
|
||
'<h1>Virtual Host - Glasnost</h1>') > -1)
|
||
self.failUnless(self.pageContent != previousPageContent)
|
||
previousPageContent = self.pageContent
|
||
|
||
|
||
class AccountManipulationTestCase(WebTestCase):
|
||
def test01_buttonPresence(self):
|
||
'''Look for "New Account" button'''
|
||
self.get('/')
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('New Account') > -1)
|
||
|
||
def test02_emptyForm(self):
|
||
'''Submit empty *new account* form'''
|
||
self.get('/')
|
||
self.get( self.getLinkByLabel('New Account') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl.endswith('/newAccountSubmit')][0]
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Create'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('Missing value!') > -1)
|
||
|
||
def test03_userButNotUsername(self):
|
||
'''Submit *new account* form filled except the username field'''
|
||
self.get('/')
|
||
self.get( self.getLinkByLabel('New Account') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl.endswith('/newAccountSubmit')][0]
|
||
form.set('userCard_firstName', 'Test')
|
||
form.set('userCard_lastName', 'User')
|
||
form.set('userCard_email', 'test@example.com')
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Create'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('Missing value!') > -1)
|
||
|
||
def test04_userNameButNotUser(self):
|
||
'''Submit *new account* form with just the username field'''
|
||
self.get('/')
|
||
self.get( self.getLinkByLabel('New Account') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl.endswith('/newAccountSubmit')][0]
|
||
form.set('login', 'test')
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Create'))
|
||
self.failUnless(self.replyCode == 200)
|
||
|
||
def test05_fullForm(self):
|
||
'''Submit a correctly filled *new account* form'''
|
||
self.get('/')
|
||
self.get( self.getLinkByLabel('New Account') )
|
||
form = [x for x in self.forms if
|
||
x.actionUrl.endswith('/newAccountSubmit')][0]
|
||
form.set('userCard_firstName', 'Test')
|
||
form.set('userCard_lastName', 'User')
|
||
form.set('userCard_email', 'test@example.com')
|
||
form.set('login', 'test')
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'Create'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(
|
||
re.match('/people/\d+$', self.path))
|
||
|
||
def test06_removeUserAndAccount(self):
|
||
'''Remove the account just created'''
|
||
self.get('/authentication')
|
||
form = [x for x in self.forms if
|
||
x.actionUrl.endswith('/delete')][0]
|
||
self.post(form.actionUrl, form.getKeywords(buttonClicked = 'OK'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('<h1>Delete Account</h1>') > -1)
|
||
self.get( self.getLinkByLabel('Remove Both') )
|
||
self.failUnless(self.pageContent.find('<h1>Success</h1>') > -1)
|
||
self.get( self.getLinkByLabel('OK') )
|
||
self.failUnless(self.path == '/authentication')
|
||
self.failUnless(self.pageContent.find('Delete Account') == -1)
|
||
self.get('/people')
|
||
self.failUnless(self.pageContent.find('>Test User</a>') == -1)
|
||
|
||
|
||
class LoginTestCase(WebTestCase, OneUserTestCase):
|
||
|
||
def setUp(self):
|
||
OneUserTestCase.setUp(self)
|
||
WebTestCase.setUp(self)
|
||
self.get('/')
|
||
self.get( self.getLinkByLabel('Login') )
|
||
self.failUnless(self.replyCode == 200)
|
||
self.loginForm = [x for x in self.forms if
|
||
x.actionUrl.endswith('/loginSubmit')][0]
|
||
|
||
def tearDown(self):
|
||
OneUserTestCase.tearDown(self)
|
||
WebTestCase.tearDown(self)
|
||
|
||
def test01_falseUserName(self):
|
||
'''Login with false username'''
|
||
self.loginForm.set('login', 'blah')
|
||
self.post(self.loginForm.actionUrl,
|
||
self.loginForm.getKeywords(buttonClicked = 'Login'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('Error!') > -1)
|
||
|
||
def test02_realUserNameNoPassword(self):
|
||
'''Login with real username but no password'''
|
||
self.loginForm.set('login', 'test-user')
|
||
self.post(self.loginForm.actionUrl,
|
||
self.loginForm.getKeywords(buttonClicked = 'Login'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('Error!') > -1)
|
||
|
||
def test03_realUserNameFalsePassword(self):
|
||
'''Login with real username but false password'''
|
||
self.loginForm.set('login', 'test-user')
|
||
self.loginForm.set('password', 'blah')
|
||
self.post(self.loginForm.actionUrl,
|
||
self.loginForm.getKeywords(buttonClicked = 'Login'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.pageContent.find('Error!') > -1)
|
||
|
||
def test04_realUserNameAndPassword(self):
|
||
'''Login with real username and real password'''
|
||
|
||
self.loginForm.set('login', 'test-user')
|
||
self.loginForm.set('password', 'test-user')
|
||
self.post(self.loginForm.actionUrl,
|
||
self.loginForm.getKeywords(buttonClicked = 'Login'))
|
||
self.failUnless(self.replyCode == 200)
|
||
self.failUnless(self.path == '/')
|
||
self.get('/authentication')
|
||
self.failUnless(self.pageContent.find('You are logged') > -1)
|
||
|
||
self.get( self.getLinkByLabel('Exit') )
|
||
self.get('/authentication')
|
||
self.failUnless(self.pageContent.find('You are not logged') > -1)
|
||
|
||
suite1 = unittest.makeSuite(BasicTestCase, 'test')
|
||
suite2 = unittest.makeSuite(AccountManipulationTestCase, 'test')
|
||
suite3 = unittest.makeSuite(LoginTestCase, 'test')
|
||
|
||
allTests = unittest.TestSuite((suite1, suite2))
|
||
|
||
if __name__ == '__main__':
|
||
unittest.TextTestRunner(verbosity=2).run(suite3)
|
||
|