8687.15.45
by Karl Fogel
Add license header block to files brought in in the r8731 merge. |
1 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
3 |
|
4 |
"""Basic ShipIt usage test."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
__all__ = [] |
|
8 |
||
9 |
import re |
|
8911.2.12
by Stuart Bishop
Use a lock to prevent race where multiple threads attempt to open the database connection |
10 |
import threading |
8911.2.4
by Stuart Bishop
ShipIt load tester |
11 |
import unittest |
12 |
||
13 |
from funkload.FunkLoadTestCase import FunkLoadTestCase |
|
14 |
from funkload.Lipsum import Lipsum |
|
15 |
import psycopg2 |
|
16 |
||
17 |
||
18 |
class ShipIt(FunkLoadTestCase): |
|
19 |
||
20 |
db_connection = None |
|
8911.2.12
by Stuart Bishop
Use a lock to prevent race where multiple threads attempt to open the database connection |
21 |
db_connection_lock = threading.Lock() |
8911.2.4
by Stuart Bishop
ShipIt load tester |
22 |
|
23 |
def setUp(self): |
|
24 |
"""Setting up test."""
|
|
25 |
self.logd("setUp") |
|
26 |
||
27 |
self.server_url = self.conf_get('main', 'url') |
|
28 |
self.database_conninfo = self.conf_get('main', 'database_conninfo') |
|
29 |
||
30 |
self.lipsum = Lipsum() |
|
31 |
||
32 |
if ShipIt.db_connection is None: |
|
8911.2.5
by Stuart Bishop
Review feedback |
33 |
# We use a class variable for the database connection so the
|
34 |
# same connection is shared between threads. This is important
|
|
35 |
# for when we are running with hundreds of threads.
|
|
8911.2.12
by Stuart Bishop
Use a lock to prevent race where multiple threads attempt to open the database connection |
36 |
ShipIt.db_connection_lock.acquire() |
37 |
try: |
|
38 |
if ShipIt.db_connection is None: |
|
39 |
assert psycopg2.threadsafety >= 2, ( |
|
40 |
"psycopg2 cannot share connections between threads") |
|
41 |
self.logi( |
|
42 |
'Opening database connection "%s".' |
|
43 |
% self.database_conninfo) |
|
44 |
ShipIt.db_connection = psycopg2.connect( |
|
45 |
self.database_conninfo) |
|
46 |
ShipIt.db_connection.set_isolation_level(0) |
|
47 |
finally: |
|
48 |
ShipIt.db_connection_lock.release() |
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
49 |
|
50 |
def cursor(self): |
|
51 |
return ShipIt.db_connection.cursor() |
|
52 |
||
53 |
def get_email_validation_token(self, email): |
|
54 |
cur = self.cursor() |
|
55 |
cur.execute(""" |
|
56 |
SELECT token FROM AuthToken
|
|
57 |
WHERE date_consumed IS NULL AND token_type=12 AND email=%s |
|
58 |
""", (email,)) |
|
59 |
row = cur.fetchone() |
|
60 |
if row is None: |
|
61 |
return None |
|
62 |
return row[0] |
|
63 |
||
64 |
_error_re = re.compile('(?s)class="error">.*?class="message">(.*?)</') |
|
65 |
||
66 |
def assertNoFormErrors(self, response): |
|
67 |
self.assertEquals(response.code, 200) |
|
68 |
match = self._error_re.search(response.body) |
|
69 |
if match is not None: |
|
70 |
self.fail('Form contained error "%s"' % match.group(1)) |
|
71 |
||
72 |
def test_shipit(self): |
|
73 |
server_url = self.server_url |
|
74 |
||
75 |
self.get(server_url + "/", description="GET /") |
|
76 |
||
77 |
response = self.get(server_url + "/login", description="Get /login") |
|
78 |
response = response.postForm( |
|
79 |
0, self.post, {'submit': 'Continue'}, |
|
80 |
'Post /+openid - OpenID authentication request') |
|
81 |
self.assertNoFormErrors(response) |
|
82 |
||
83 |
# User is not logged on
|
|
84 |
email = 'user_%s@lp%s.example.com' % ( |
|
85 |
self.lipsum.getUniqWord(), self.lipsum.getUniqWord()) |
|
86 |
# response.postForm fails here - looks like a bug. The action
|
|
87 |
# on the form is a relative URL and response.postForm tries
|
|
88 |
# to retrieve it from localhost.
|
|
89 |
params = response.extractForm(include_submit=True) |
|
90 |
params['field.email'] = email |
|
91 |
params['field.action'] = 'createaccount' |
|
92 |
response = self.post( |
|
8911.2.5
by Stuart Bishop
Review feedback |
93 |
self.absolute_url(response, '/+login-register'), |
8911.2.4
by Stuart Bishop
ShipIt load tester |
94 |
params, "Post /+login-register - Create account") |
95 |
self.assertNoFormErrors(response) |
|
96 |
||
97 |
# Pull the email validation token from the database and
|
|
98 |
# validate it.
|
|
99 |
token = self.get_email_validation_token(email) |
|
8911.2.7
by Stuart Bishop
Ensure email validation token was found |
100 |
self.assert_(token is not None, "No login token created") |
8911.2.8
by Stuart Bishop
Cope with Bug #400610 |
101 |
newaccount_url = self.absolute_url( |
102 |
response, '/token/%s/+newaccount' % token) |
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
103 |
response = self.get( |
8911.2.8
by Stuart Bishop
Cope with Bug #400610 |
104 |
newaccount_url, description="Get /token/[...]/+newaccount") |
8911.2.4
by Stuart Bishop
ShipIt load tester |
105 |
|
106 |
# Complete the registration process.
|
|
107 |
displayname = self.lipsum.getSubject(2) |
|
108 |
password = self.lipsum.getWord() |
|
8911.2.8
by Stuart Bishop
Cope with Bug #400610 |
109 |
params = response.extractForm(include_submit=True) |
110 |
||
111 |
params.update({ |
|
112 |
'field.displayname': displayname, |
|
113 |
'field.hide_email_addresses': 'on', |
|
114 |
'field.password': password, |
|
115 |
'field.password_dupe': password, |
|
116 |
'field.actions.continue': 'Continue'}) |
|
117 |
# At the moment, creating your account doesn't log you in
|
|
118 |
# immidiately so you might end up at a 403 page - Bug #400610
|
|
119 |
response = self.post( |
|
8911.2.9
by Stuart Bishop
Cope with Bug #400610 |
120 |
newaccount_url, params, ok_codes=[200, 302, 303, 403], |
8911.2.8
by Stuart Bishop
Cope with Bug #400610 |
121 |
description="Post /token/[...]/+newaccount") |
122 |
# Keep hitting the /login link until it works.
|
|
8911.2.9
by Stuart Bishop
Cope with Bug #400610 |
123 |
while response.code == 403: |
8911.2.8
by Stuart Bishop
Cope with Bug #400610 |
124 |
login_url = self.absolute_url(response, '/login') |
125 |
response = self.get(login_url, description="Get /login") |
|
8911.2.10
by Stuart Bishop
More login race conditions, and ensure CD order fields are allowed lengths |
126 |
if response.get_base_url() == '/myrequest': |
127 |
break
|
|
8911.2.9
by Stuart Bishop
Cope with Bug #400610 |
128 |
response = response.postForm( |
129 |
0, self.post, {}, "Post /+openid") |
|
130 |
if response.get_base_url() == '/+openid': |
|
131 |
params = response.extractForm() |
|
132 |
params['field.actions.auth'] = 'Sign In' |
|
133 |
response = self.post( |
|
134 |
self.absolute_url(response, '/+decide'), params, |
|
135 |
description = "Post /+decide", |
|
136 |
ok_codes=[200, 302, 303, 403]) |
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
137 |
|
138 |
# Registration succeeded - should be on the order details page now.
|
|
139 |
self.assertEquals(response.get_base_url(), '/myrequest') |
|
140 |
||
141 |
# Request some CDs.
|
|
142 |
params = response.extractForm(include_submit=True) |
|
143 |
params.update({ |
|
8911.2.11
by Stuart Bishop
Ensure CD order fields are allowed lengths better |
144 |
'field.recipientdisplayname': displayname[:20], |
145 |
'field.addressline1': self.lipsum.getSubject(3)[:30], |
|
146 |
'field.addressline2': self.lipsum.getSubject(3)[:30], |
|
147 |
'field.city': self.lipsum.getSubject(1)[:30], |
|
148 |
'field.province': self.lipsum.getSubject(2)[:30], |
|
149 |
'field.postcode': self.lipsum.getSubject(1)[:20], |
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
150 |
'field.country': '212', |
151 |
'field.country-empty-marker': '1', |
|
8911.2.11
by Stuart Bishop
Ensure CD order fields are allowed lengths better |
152 |
'field.phone': self.lipsum.getPhoneNumber()[:16], |
8911.2.4
by Stuart Bishop
ShipIt load tester |
153 |
'field.actions.continue': 'Submit Request'}) |
154 |
response = self.post( |
|
8911.2.5
by Stuart Bishop
Review feedback |
155 |
self.absolute_url(response, '/myrequest'), |
8911.2.4
by Stuart Bishop
ShipIt load tester |
156 |
params, "Post /myrequest - Request CDs") |
157 |
self.assertNoFormErrors(response) |
|
158 |
||
8911.2.11
by Stuart Bishop
Ensure CD order fields are allowed lengths better |
159 |
if response.body.find('Cancel Request') == -1: |
160 |
open('dud.html', 'w').write(response.body) |
|
161 |
||
8911.2.4
by Stuart Bishop
ShipIt load tester |
162 |
# Confirm the request worked.
|
163 |
self.assert_( |
|
164 |
response.body.find('Cancel Request') != -1, |
|
165 |
"Cancel button not found.") |
|
166 |
||
167 |
# Logout.
|
|
168 |
response = self.post( |
|
169 |
server_url + "/+logout", description="Post /+logout") |
|
170 |
self.assert_( |
|
171 |
response.body.find('You have been logged out') != -1, |
|
172 |
"No logged out notification.") |
|
173 |
||
174 |
# Attempt to login again, bringing up the login form.
|
|
175 |
response = self.get(server_url, description="Get /") |
|
176 |
response = self.get( |
|
177 |
server_url + "/login", description="Get /login") |
|
178 |
response = response.postForm( |
|
179 |
0, self.post, {'submit': 'Continue'}, |
|
180 |
'Post /+openid - OpenID authentication request') |
|
181 |
self.assertNoFormErrors(response) |
|
182 |
||
183 |
# Submit the login form.
|
|
184 |
params = response.extractForm(include_submit=True) |
|
185 |
params['field.email'] = email |
|
186 |
params['field.password'] = password |
|
187 |
params['field.action'] = 'login' |
|
188 |
response = self.post( |
|
8911.2.5
by Stuart Bishop
Review feedback |
189 |
self.absolute_url(response, '/+login-register'), |
8911.2.4
by Stuart Bishop
ShipIt load tester |
190 |
params, "Post /+login-register - Login to existing account") |
191 |
self.assertNoFormErrors(response) |
|
192 |
self.assertEquals(response.url, '/myrequest') |
|
193 |
||
194 |
# Cancel the CD request.
|
|
195 |
params = response.extractForm([('form', 1)], include_submit=True) |
|
196 |
response = self.post( |
|
8911.2.5
by Stuart Bishop
Review feedback |
197 |
self.absolute_url(response, '/myrequest'), |
8911.2.4
by Stuart Bishop
ShipIt load tester |
198 |
params, description="Post /myrequest - Cancel CD order.") |
199 |
self.assertNoFormErrors(response) |
|
200 |
self.assert_( |
|
201 |
response.body.find('Cancel Request') == -1, |
|
202 |
"Cancel button found.") |
|
203 |
||
204 |
# Don't log out - leave the session dangling like most real users
|
|
205 |
# do.
|
|
206 |
||
8911.2.5
by Stuart Bishop
Review feedback |
207 |
def absolute_url(self, response, path): |
208 |
"""Calculate an absolute URL using the response and the path."""
|
|
8911.2.4
by Stuart Bishop
ShipIt load tester |
209 |
return '%s://%s:%s%s' % ( |
210 |
response.protocol, response.server, response.port, path) |
|
211 |
||
212 |
def tearDown(self): |
|
213 |
"""Setting up test."""
|
|
214 |
self.logd("tearDown.\n") |
|
215 |
||
216 |
||
217 |
||
218 |
if __name__ in ('main', '__main__'): |
|
219 |
unittest.main() |