|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * Tests for user.module. |
|
6 */ |
|
7 |
|
8 class UserRegistrationTestCase extends DrupalWebTestCase { |
|
9 public static function getInfo() { |
|
10 return array( |
|
11 'name' => 'User registration', |
|
12 'description' => 'Test registration of user under different configurations.', |
|
13 'group' => 'User' |
|
14 ); |
|
15 } |
|
16 |
|
17 function setUp() { |
|
18 parent::setUp('field_test'); |
|
19 } |
|
20 |
|
21 function testRegistrationWithEmailVerification() { |
|
22 // Require e-mail verification. |
|
23 variable_set('user_email_verification', TRUE); |
|
24 |
|
25 // Set registration to administrator only. |
|
26 variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY); |
|
27 $this->drupalGet('user/register'); |
|
28 $this->assertResponse(403, 'Registration page is inaccessible when only administrators can create accounts.'); |
|
29 |
|
30 // Allow registration by site visitors without administrator approval. |
|
31 variable_set('user_register', USER_REGISTER_VISITORS); |
|
32 $edit = array(); |
|
33 $edit['name'] = $name = $this->randomName(); |
|
34 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
35 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
36 $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), 'User registered successfully.'); |
|
37 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
38 $new_user = reset($accounts); |
|
39 $this->assertTrue($new_user->status, 'New account is active after registration.'); |
|
40 |
|
41 // Allow registration by site visitors, but require administrator approval. |
|
42 variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL); |
|
43 $edit = array(); |
|
44 $edit['name'] = $name = $this->randomName(); |
|
45 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
46 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
47 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
48 $new_user = reset($accounts); |
|
49 $this->assertFalse($new_user->status, 'New account is blocked until approved by an administrator.'); |
|
50 } |
|
51 |
|
52 function testRegistrationWithoutEmailVerification() { |
|
53 // Don't require e-mail verification. |
|
54 variable_set('user_email_verification', FALSE); |
|
55 |
|
56 // Allow registration by site visitors without administrator approval. |
|
57 variable_set('user_register', USER_REGISTER_VISITORS); |
|
58 $edit = array(); |
|
59 $edit['name'] = $name = $this->randomName(); |
|
60 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
61 |
|
62 // Try entering a mismatching password. |
|
63 $edit['pass[pass1]'] = '99999.0'; |
|
64 $edit['pass[pass2]'] = '99999'; |
|
65 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
66 $this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.'); |
|
67 |
|
68 // Enter a correct password. |
|
69 $edit['pass[pass1]'] = $new_pass = $this->randomName(); |
|
70 $edit['pass[pass2]'] = $new_pass; |
|
71 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
72 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
73 $new_user = reset($accounts); |
|
74 $this->assertText(t('Registration successful. You are now logged in.'), 'Users are logged in after registering.'); |
|
75 $this->drupalLogout(); |
|
76 |
|
77 // Allow registration by site visitors, but require administrator approval. |
|
78 variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL); |
|
79 $edit = array(); |
|
80 $edit['name'] = $name = $this->randomName(); |
|
81 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
82 $edit['pass[pass1]'] = $pass = $this->randomName(); |
|
83 $edit['pass[pass2]'] = $pass; |
|
84 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
85 $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval'); |
|
86 |
|
87 // Try to login before administrator approval. |
|
88 $auth = array( |
|
89 'name' => $name, |
|
90 'pass' => $pass, |
|
91 ); |
|
92 $this->drupalPost('user/login', $auth, t('Log in')); |
|
93 $this->assertText(t('The username @name has not been activated or is blocked.', array('@name' => $name)), 'User cannot login yet.'); |
|
94 |
|
95 // Activate the new account. |
|
96 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
97 $new_user = reset($accounts); |
|
98 $admin_user = $this->drupalCreateUser(array('administer users')); |
|
99 $this->drupalLogin($admin_user); |
|
100 $edit = array( |
|
101 'status' => 1, |
|
102 ); |
|
103 $this->drupalPost('user/' . $new_user->uid . '/edit', $edit, t('Save')); |
|
104 $this->drupalLogout(); |
|
105 |
|
106 // Login after administrator approval. |
|
107 $this->drupalPost('user/login', $auth, t('Log in')); |
|
108 $this->assertText(t('Member for'), 'User can log in after administrator approval.'); |
|
109 } |
|
110 |
|
111 function testRegistrationEmailDuplicates() { |
|
112 // Don't require e-mail verification. |
|
113 variable_set('user_email_verification', FALSE); |
|
114 |
|
115 // Allow registration by site visitors without administrator approval. |
|
116 variable_set('user_register', USER_REGISTER_VISITORS); |
|
117 |
|
118 // Set up a user to check for duplicates. |
|
119 $duplicate_user = $this->drupalCreateUser(); |
|
120 |
|
121 $edit = array(); |
|
122 $edit['name'] = $this->randomName(); |
|
123 $edit['mail'] = $duplicate_user->mail; |
|
124 |
|
125 // Attempt to create a new account using an existing e-mail address. |
|
126 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
127 $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying an exact duplicate email address displays an error message'); |
|
128 |
|
129 // Attempt to bypass duplicate email registration validation by adding spaces. |
|
130 $edit['mail'] = ' ' . $duplicate_user->mail . ' '; |
|
131 |
|
132 $this->drupalPost('user/register', $edit, t('Create new account')); |
|
133 $this->assertText(t('The e-mail address @email is already registered.', array('@email' => $duplicate_user->mail)), 'Supplying a duplicate email address with added whitespace displays an error message'); |
|
134 } |
|
135 |
|
136 function testRegistrationDefaultValues() { |
|
137 // Allow registration by site visitors without administrator approval. |
|
138 variable_set('user_register', USER_REGISTER_VISITORS); |
|
139 |
|
140 // Don't require e-mail verification. |
|
141 variable_set('user_email_verification', FALSE); |
|
142 |
|
143 // Set the default timezone to Brussels. |
|
144 variable_set('configurable_timezones', 1); |
|
145 variable_set('date_default_timezone', 'Europe/Brussels'); |
|
146 |
|
147 // Check that the account information fieldset's options are not displayed |
|
148 // is a fieldset if there is not more than one fieldset in the form. |
|
149 $this->drupalGet('user/register'); |
|
150 $this->assertNoRaw('<fieldset id="edit-account"><legend>Account information</legend>', 'Account settings fieldset was hidden.'); |
|
151 |
|
152 $edit = array(); |
|
153 $edit['name'] = $name = $this->randomName(); |
|
154 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
155 $edit['pass[pass1]'] = $new_pass = $this->randomName(); |
|
156 $edit['pass[pass2]'] = $new_pass; |
|
157 $this->drupalPost(NULL, $edit, t('Create new account')); |
|
158 |
|
159 // Check user fields. |
|
160 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
161 $new_user = reset($accounts); |
|
162 $this->assertEqual($new_user->name, $name, 'Username matches.'); |
|
163 $this->assertEqual($new_user->mail, $mail, 'E-mail address matches.'); |
|
164 $this->assertEqual($new_user->theme, '', 'Correct theme field.'); |
|
165 $this->assertEqual($new_user->signature, '', 'Correct signature field.'); |
|
166 $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), 'Correct creation time.'); |
|
167 $this->assertEqual($new_user->status, variable_get('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL) == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.'); |
|
168 $this->assertEqual($new_user->timezone, variable_get('date_default_timezone'), 'Correct time zone field.'); |
|
169 $this->assertEqual($new_user->language, '', 'Correct language field.'); |
|
170 $this->assertEqual($new_user->picture, '', 'Correct picture field.'); |
|
171 $this->assertEqual($new_user->init, $mail, 'Correct init field.'); |
|
172 } |
|
173 |
|
174 /** |
|
175 * Tests Field API fields on user registration forms. |
|
176 */ |
|
177 function testRegistrationWithUserFields() { |
|
178 // Create a field, and an instance on 'user' entity type. |
|
179 $field = array( |
|
180 'type' => 'test_field', |
|
181 'field_name' => 'test_user_field', |
|
182 'cardinality' => 1, |
|
183 ); |
|
184 field_create_field($field); |
|
185 $instance = array( |
|
186 'field_name' => 'test_user_field', |
|
187 'entity_type' => 'user', |
|
188 'label' => 'Some user field', |
|
189 'bundle' => 'user', |
|
190 'required' => TRUE, |
|
191 'settings' => array('user_register_form' => FALSE), |
|
192 ); |
|
193 field_create_instance($instance); |
|
194 |
|
195 // Check that the field does not appear on the registration form. |
|
196 $this->drupalGet('user/register'); |
|
197 $this->assertNoText($instance['label'], 'The field does not appear on user registration form'); |
|
198 |
|
199 // Have the field appear on the registration form. |
|
200 $instance['settings']['user_register_form'] = TRUE; |
|
201 field_update_instance($instance); |
|
202 $this->drupalGet('user/register'); |
|
203 $this->assertText($instance['label'], 'The field appears on user registration form'); |
|
204 |
|
205 // Check that validation errors are correctly reported. |
|
206 $edit = array(); |
|
207 $edit['name'] = $name = $this->randomName(); |
|
208 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
209 // Missing input in required field. |
|
210 $edit['test_user_field[und][0][value]'] = ''; |
|
211 $this->drupalPost(NULL, $edit, t('Create new account')); |
|
212 $this->assertRaw(t('@name field is required.', array('@name' => $instance['label'])), 'Field validation error was correctly reported.'); |
|
213 // Invalid input. |
|
214 $edit['test_user_field[und][0][value]'] = '-1'; |
|
215 $this->drupalPost(NULL, $edit, t('Create new account')); |
|
216 $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $instance['label'])), 'Field validation error was correctly reported.'); |
|
217 |
|
218 // Submit with valid data. |
|
219 $value = rand(1, 255); |
|
220 $edit['test_user_field[und][0][value]'] = $value; |
|
221 $this->drupalPost(NULL, $edit, t('Create new account')); |
|
222 // Check user fields. |
|
223 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
224 $new_user = reset($accounts); |
|
225 $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, 'The field value was correctly saved.'); |
|
226 |
|
227 // Check that the 'add more' button works. |
|
228 $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED; |
|
229 field_update_field($field); |
|
230 foreach (array('js', 'nojs') as $js) { |
|
231 $this->drupalGet('user/register'); |
|
232 // Add two inputs. |
|
233 $value = rand(1, 255); |
|
234 $edit = array(); |
|
235 $edit['test_user_field[und][0][value]'] = $value; |
|
236 if ($js == 'js') { |
|
237 $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more'); |
|
238 $this->drupalPostAJAX(NULL, $edit, 'test_user_field_add_more'); |
|
239 } |
|
240 else { |
|
241 $this->drupalPost(NULL, $edit, t('Add another item')); |
|
242 $this->drupalPost(NULL, $edit, t('Add another item')); |
|
243 } |
|
244 // Submit with three values. |
|
245 $edit['test_user_field[und][1][value]'] = $value + 1; |
|
246 $edit['test_user_field[und][2][value]'] = $value + 2; |
|
247 $edit['name'] = $name = $this->randomName(); |
|
248 $edit['mail'] = $mail = $edit['name'] . '@example.com'; |
|
249 $this->drupalPost(NULL, $edit, t('Create new account')); |
|
250 // Check user fields. |
|
251 $accounts = user_load_multiple(array(), array('name' => $name, 'mail' => $mail)); |
|
252 $new_user = reset($accounts); |
|
253 $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][0]['value'], $value, format_string('@js : The field value was correclty saved.', array('@js' => $js))); |
|
254 $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][1]['value'], $value + 1, format_string('@js : The field value was correclty saved.', array('@js' => $js))); |
|
255 $this->assertEqual($new_user->test_user_field[LANGUAGE_NONE][2]['value'], $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js))); |
|
256 } |
|
257 } |
|
258 } |
|
259 |
|
260 class UserValidationTestCase extends DrupalWebTestCase { |
|
261 public static function getInfo() { |
|
262 return array( |
|
263 'name' => 'Username/e-mail validation', |
|
264 'description' => 'Verify that username/email validity checks behave as designed.', |
|
265 'group' => 'User' |
|
266 ); |
|
267 } |
|
268 |
|
269 // Username validation. |
|
270 function testUsernames() { |
|
271 $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'), |
|
272 'foo' => array('Valid username', 'assertNull'), |
|
273 'FOO' => array('Valid username', 'assertNull'), |
|
274 'Foo O\'Bar' => array('Valid username', 'assertNull'), |
|
275 'foo@bar' => array('Valid username', 'assertNull'), |
|
276 'foo@example.com' => array('Valid username', 'assertNull'), |
|
277 'foo@-example.com' => array('Valid username', 'assertNull'), // invalid domains are allowed in usernames |
|
278 'þòøÇߪř€' => array('Valid username', 'assertNull'), |
|
279 'ᚠᛇᚻ᛫ᛒᛦᚦ' => array('Valid UTF8 username', 'assertNull'), // runes |
|
280 ' foo' => array('Invalid username that starts with a space', 'assertNotNull'), |
|
281 'foo ' => array('Invalid username that ends with a space', 'assertNotNull'), |
|
282 'foo bar' => array('Invalid username that contains 2 spaces \' \'', 'assertNotNull'), |
|
283 '' => array('Invalid empty username', 'assertNotNull'), |
|
284 'foo/' => array('Invalid username containing invalid chars', 'assertNotNull'), |
|
285 'foo' . chr(0) . 'bar' => array('Invalid username containing chr(0)', 'assertNotNull'), // NULL |
|
286 'foo' . chr(13) . 'bar' => array('Invalid username containing chr(13)', 'assertNotNull'), // CR |
|
287 str_repeat('x', USERNAME_MAX_LENGTH + 1) => array('Invalid excessively long username', 'assertNotNull'), |
|
288 ); |
|
289 foreach ($test_cases as $name => $test_case) { |
|
290 list($description, $test) = $test_case; |
|
291 $result = user_validate_name($name); |
|
292 $this->$test($result, $description . ' (' . $name . ')'); |
|
293 } |
|
294 } |
|
295 |
|
296 // Mail validation. More extensive tests can be found at common.test |
|
297 function testMailAddresses() { |
|
298 $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'), |
|
299 '' => array('Empty mail address', 'assertNotNull'), |
|
300 'foo' => array('Invalid mail address', 'assertNotNull'), |
|
301 'foo@example.com' => array('Valid mail address', 'assertNull'), |
|
302 ); |
|
303 foreach ($test_cases as $name => $test_case) { |
|
304 list($description, $test) = $test_case; |
|
305 $result = user_validate_mail($name); |
|
306 $this->$test($result, $description . ' (' . $name . ')'); |
|
307 } |
|
308 } |
|
309 } |
|
310 |
|
311 /** |
|
312 * Functional tests for user logins, including rate limiting of login attempts. |
|
313 */ |
|
314 class UserLoginTestCase extends DrupalWebTestCase { |
|
315 public static function getInfo() { |
|
316 return array( |
|
317 'name' => 'User login', |
|
318 'description' => 'Ensure that login works as expected.', |
|
319 'group' => 'User', |
|
320 ); |
|
321 } |
|
322 |
|
323 /** |
|
324 * Test the global login flood control. |
|
325 */ |
|
326 function testGlobalLoginFloodControl() { |
|
327 // Set the global login limit. |
|
328 variable_set('user_failed_login_ip_limit', 10); |
|
329 // Set a high per-user limit out so that it is not relevant in the test. |
|
330 variable_set('user_failed_login_user_limit', 4000); |
|
331 |
|
332 $user1 = $this->drupalCreateUser(array()); |
|
333 $incorrect_user1 = clone $user1; |
|
334 $incorrect_user1->pass_raw .= 'incorrect'; |
|
335 |
|
336 // Try 2 failed logins. |
|
337 for ($i = 0; $i < 2; $i++) { |
|
338 $this->assertFailedLogin($incorrect_user1); |
|
339 } |
|
340 |
|
341 // A successful login will not reset the IP-based flood control count. |
|
342 $this->drupalLogin($user1); |
|
343 $this->drupalLogout(); |
|
344 |
|
345 // Try 8 more failed logins, they should not trigger the flood control |
|
346 // mechanism. |
|
347 for ($i = 0; $i < 8; $i++) { |
|
348 $this->assertFailedLogin($incorrect_user1); |
|
349 } |
|
350 |
|
351 // The next login trial should result in an IP-based flood error message. |
|
352 $this->assertFailedLogin($incorrect_user1, 'ip'); |
|
353 |
|
354 // A login with the correct password should also result in a flood error |
|
355 // message. |
|
356 $this->assertFailedLogin($user1, 'ip'); |
|
357 } |
|
358 |
|
359 /** |
|
360 * Test the per-user login flood control. |
|
361 */ |
|
362 function testPerUserLoginFloodControl() { |
|
363 // Set a high global limit out so that it is not relevant in the test. |
|
364 variable_set('user_failed_login_ip_limit', 4000); |
|
365 // Set the per-user login limit. |
|
366 variable_set('user_failed_login_user_limit', 3); |
|
367 |
|
368 $user1 = $this->drupalCreateUser(array()); |
|
369 $incorrect_user1 = clone $user1; |
|
370 $incorrect_user1->pass_raw .= 'incorrect'; |
|
371 |
|
372 $user2 = $this->drupalCreateUser(array()); |
|
373 |
|
374 // Try 2 failed logins. |
|
375 for ($i = 0; $i < 2; $i++) { |
|
376 $this->assertFailedLogin($incorrect_user1); |
|
377 } |
|
378 |
|
379 // A successful login will reset the per-user flood control count. |
|
380 $this->drupalLogin($user1); |
|
381 $this->drupalLogout(); |
|
382 |
|
383 // Try 3 failed logins for user 1, they will not trigger flood control. |
|
384 for ($i = 0; $i < 3; $i++) { |
|
385 $this->assertFailedLogin($incorrect_user1); |
|
386 } |
|
387 |
|
388 // Try one successful attempt for user 2, it should not trigger any |
|
389 // flood control. |
|
390 $this->drupalLogin($user2); |
|
391 $this->drupalLogout(); |
|
392 |
|
393 // Try one more attempt for user 1, it should be rejected, even if the |
|
394 // correct password has been used. |
|
395 $this->assertFailedLogin($user1, 'user'); |
|
396 } |
|
397 |
|
398 /** |
|
399 * Test that user password is re-hashed upon login after changing $count_log2. |
|
400 */ |
|
401 function testPasswordRehashOnLogin() { |
|
402 // Load password hashing API. |
|
403 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
404 // Set initial $count_log2 to the default, DRUPAL_HASH_COUNT. |
|
405 variable_set('password_count_log2', DRUPAL_HASH_COUNT); |
|
406 // Create a new user and authenticate. |
|
407 $account = $this->drupalCreateUser(array()); |
|
408 $password = $account->pass_raw; |
|
409 $this->drupalLogin($account); |
|
410 $this->drupalLogout(); |
|
411 // Load the stored user. The password hash should reflect $count_log2. |
|
412 $account = user_load($account->uid); |
|
413 $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT); |
|
414 // Change $count_log2 and log in again. |
|
415 variable_set('password_count_log2', DRUPAL_HASH_COUNT + 1); |
|
416 $account->pass_raw = $password; |
|
417 $this->drupalLogin($account); |
|
418 // Load the stored user, which should have a different password hash now. |
|
419 $account = user_load($account->uid, TRUE); |
|
420 $this->assertIdentical(_password_get_count_log2($account->pass), DRUPAL_HASH_COUNT + 1); |
|
421 } |
|
422 |
|
423 /** |
|
424 * Make an unsuccessful login attempt. |
|
425 * |
|
426 * @param $account |
|
427 * A user object with name and pass_raw attributes for the login attempt. |
|
428 * @param $flood_trigger |
|
429 * Whether or not to expect that the flood control mechanism will be |
|
430 * triggered. |
|
431 */ |
|
432 function assertFailedLogin($account, $flood_trigger = NULL) { |
|
433 $edit = array( |
|
434 'name' => $account->name, |
|
435 'pass' => $account->pass_raw, |
|
436 ); |
|
437 $this->drupalPost('user', $edit, t('Log in')); |
|
438 $this->assertNoFieldByXPath("//input[@name='pass' and @value!='']", NULL, 'Password value attribute is blank.'); |
|
439 if (isset($flood_trigger)) { |
|
440 if ($flood_trigger == 'user') { |
|
441 $this->assertRaw(format_plural(variable_get('user_failed_login_user_limit', 5), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password')))); |
|
442 } |
|
443 else { |
|
444 // No uid, so the limit is IP-based. |
|
445 $this->assertRaw(t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password')))); |
|
446 } |
|
447 } |
|
448 else { |
|
449 $this->assertText(t('Sorry, unrecognized username or password. Have you forgotten your password?')); |
|
450 } |
|
451 } |
|
452 } |
|
453 |
|
454 /** |
|
455 * Tests resetting a user password. |
|
456 */ |
|
457 class UserPasswordResetTestCase extends DrupalWebTestCase { |
|
458 protected $profile = 'standard'; |
|
459 |
|
460 public static function getInfo() { |
|
461 return array( |
|
462 'name' => 'Reset password', |
|
463 'description' => 'Ensure that password reset methods work as expected.', |
|
464 'group' => 'User', |
|
465 ); |
|
466 } |
|
467 |
|
468 /** |
|
469 * Retrieves password reset email and extracts the login link. |
|
470 */ |
|
471 public function getResetURL() { |
|
472 // Assume the most recent email. |
|
473 $_emails = $this->drupalGetMails(); |
|
474 $email = end($_emails); |
|
475 $urls = array(); |
|
476 preg_match('#.+user/reset/.+#', $email['body'], $urls); |
|
477 |
|
478 return $urls[0]; |
|
479 } |
|
480 |
|
481 /** |
|
482 * Tests password reset functionality. |
|
483 */ |
|
484 function testUserPasswordReset() { |
|
485 // Create a user. |
|
486 $account = $this->drupalCreateUser(); |
|
487 $this->drupalLogin($account); |
|
488 $this->drupalLogout(); |
|
489 // Attempt to reset password. |
|
490 $edit = array('name' => $account->name); |
|
491 $this->drupalPost('user/password', $edit, t('E-mail new password')); |
|
492 // Confirm the password reset. |
|
493 $this->assertText(t('Further instructions have been sent to your e-mail address.'), 'Password reset instructions mailed message displayed.'); |
|
494 |
|
495 // Create an image field to enable an Ajax request on the user profile page. |
|
496 $field = array( |
|
497 'field_name' => 'field_avatar', |
|
498 'type' => 'image', |
|
499 'settings' => array(), |
|
500 'cardinality' => 1, |
|
501 ); |
|
502 field_create_field($field); |
|
503 |
|
504 $instance = array( |
|
505 'field_name' => $field['field_name'], |
|
506 'entity_type' => 'user', |
|
507 'label' => 'Avatar', |
|
508 'bundle' => 'user', |
|
509 'required' => FALSE, |
|
510 'settings' => array(), |
|
511 'widget' => array( |
|
512 'type' => 'image_image', |
|
513 'settings' => array(), |
|
514 ), |
|
515 ); |
|
516 field_create_instance($instance); |
|
517 |
|
518 $resetURL = $this->getResetURL(); |
|
519 $this->drupalGet($resetURL); |
|
520 |
|
521 // Check successful login. |
|
522 $this->drupalPost(NULL, NULL, t('Log in')); |
|
523 |
|
524 // Make sure the Ajax request from uploading a file does not invalidate the |
|
525 // reset token. |
|
526 $image = current($this->drupalGetTestFiles('image')); |
|
527 $edit = array( |
|
528 'files[field_avatar_und_0]' => drupal_realpath($image->uri), |
|
529 ); |
|
530 $this->drupalPostAJAX(NULL, $edit, 'field_avatar_und_0_upload_button'); |
|
531 |
|
532 // Change the forgotten password. |
|
533 $password = user_password(); |
|
534 $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password); |
|
535 $this->drupalPost(NULL, $edit, t('Save')); |
|
536 $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.'); |
|
537 } |
|
538 |
|
539 /** |
|
540 * Test user password reset while logged in. |
|
541 */ |
|
542 function testUserPasswordResetLoggedIn() { |
|
543 $account = $this->drupalCreateUser(); |
|
544 $this->drupalLogin($account); |
|
545 // Make sure the test account has a valid password. |
|
546 user_save($account, array('pass' => user_password())); |
|
547 |
|
548 // Generate one time login link. |
|
549 $reset_url = user_pass_reset_url($account); |
|
550 $this->drupalGet($reset_url); |
|
551 |
|
552 $this->assertText('Reset password'); |
|
553 $this->drupalPost(NULL, NULL, t('Log in')); |
|
554 |
|
555 $this->assertText('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'); |
|
556 |
|
557 $pass = user_password(); |
|
558 $edit = array( |
|
559 'pass[pass1]' => $pass, |
|
560 'pass[pass2]' => $pass, |
|
561 ); |
|
562 $this->drupalPost(NULL, $edit, t('Save')); |
|
563 |
|
564 $this->assertText('The changes have been saved.'); |
|
565 } |
|
566 |
|
567 /** |
|
568 * Attempts login using an expired password reset link. |
|
569 */ |
|
570 function testUserPasswordResetExpired() { |
|
571 // Set password reset timeout variable to 43200 seconds = 12 hours. |
|
572 $timeout = 43200; |
|
573 variable_set('user_password_reset_timeout', $timeout); |
|
574 |
|
575 // Create a user. |
|
576 $account = $this->drupalCreateUser(); |
|
577 $this->drupalLogin($account); |
|
578 // Load real user object. |
|
579 $account = user_load($account->uid, TRUE); |
|
580 $this->drupalLogout(); |
|
581 |
|
582 // To attempt an expired password reset, create a password reset link as if |
|
583 // its request time was 60 seconds older than the allowed limit of timeout. |
|
584 $bogus_timestamp = REQUEST_TIME - variable_get('user_password_reset_timeout', 86400) - 60; |
|
585 $this->drupalGet("user/reset/$account->uid/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid)); |
|
586 $this->assertText(t('You have tried to use a one-time login link that has expired. Please request a new one using the form below.'), 'Expired password reset request rejected.'); |
|
587 } |
|
588 |
|
589 /** |
|
590 * Prefill the text box on incorrect login via link to password reset page. |
|
591 */ |
|
592 function testUserPasswordTextboxFilled() { |
|
593 $this->drupalGet('user/login'); |
|
594 $edit = array( |
|
595 'name' => $this->randomName(), |
|
596 'pass' => $this->randomName(), |
|
597 ); |
|
598 $this->drupalPost('user', $edit, t('Log in')); |
|
599 $this->assertRaw(t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', |
|
600 array('@password' => url('user/password', array('query' => array('name' => $edit['name'])))))); |
|
601 unset($edit['pass']); |
|
602 $this->drupalGet('user/password', array('query' => array('name' => $edit['name']))); |
|
603 $this->assertFieldByName('name', $edit['name'], 'User name found.'); |
|
604 } |
|
605 |
|
606 /** |
|
607 * Make sure that users cannot forge password reset URLs of other users. |
|
608 */ |
|
609 function testResetImpersonation() { |
|
610 // Make sure user 1 has a valid password, so it does not interfere with the |
|
611 // test user accounts that are created below. |
|
612 $account = user_load(1); |
|
613 user_save($account, array('pass' => user_password())); |
|
614 |
|
615 // Create two identical user accounts except for the user name. They must |
|
616 // have the same empty password, so we can't use $this->drupalCreateUser(). |
|
617 $edit = array(); |
|
618 $edit['name'] = $this->randomName(); |
|
619 $edit['mail'] = $edit['name'] . '@example.com'; |
|
620 $edit['status'] = 1; |
|
621 |
|
622 $user1 = user_save(drupal_anonymous_user(), $edit); |
|
623 |
|
624 $edit['name'] = $this->randomName(); |
|
625 $user2 = user_save(drupal_anonymous_user(), $edit); |
|
626 |
|
627 // The password reset URL must not be valid for the second user when only |
|
628 // the user ID is changed in the URL. |
|
629 $reset_url = user_pass_reset_url($user1); |
|
630 $attack_reset_url = str_replace("user/reset/$user1->uid", "user/reset/$user2->uid", $reset_url); |
|
631 $this->drupalGet($attack_reset_url); |
|
632 $this->assertNoText($user2->name, 'The invalid password reset page does not show the user name.'); |
|
633 $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.'); |
|
634 $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'); |
|
635 |
|
636 // When legacy code calls user_pass_rehash() without providing the $uid |
|
637 // parameter, neither password reset URL should be valid since it is |
|
638 // impossible for the system to determine which user account the token was |
|
639 // intended for. |
|
640 $timestamp = REQUEST_TIME; |
|
641 // Pass an explicit NULL for the $uid parameter of user_pass_rehash() |
|
642 // rather than not passing it at all, to avoid triggering PHP warnings in |
|
643 // the test. |
|
644 $reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL); |
|
645 $reset_url = url("user/reset/$user1->uid/$timestamp/$reset_url_token", array('absolute' => TRUE)); |
|
646 $this->drupalGet($reset_url); |
|
647 $this->assertNoText($user1->name, 'The invalid password reset page does not show the user name.'); |
|
648 $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.'); |
|
649 $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'); |
|
650 $attack_reset_url = str_replace("user/reset/$user1->uid", "user/reset/$user2->uid", $reset_url); |
|
651 $this->drupalGet($attack_reset_url); |
|
652 $this->assertNoText($user2->name, 'The invalid password reset page does not show the user name.'); |
|
653 $this->assertUrl('user/password', array(), 'The user is redirected to the password reset request page.'); |
|
654 $this->assertText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'); |
|
655 |
|
656 // To verify that user_pass_rehash() never returns a valid result in the |
|
657 // above situation (even if legacy code also called it to attempt to |
|
658 // validate the token, rather than just to generate the URL), check that a |
|
659 // second call with the same parameters produces a different result. |
|
660 $new_reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL); |
|
661 $this->assertNotEqual($reset_url_token, $new_reset_url_token); |
|
662 |
|
663 // However, when the duplicate account is removed, the password reset URL |
|
664 // should be valid. |
|
665 user_delete($user2->uid); |
|
666 $reset_url_token = user_pass_rehash($user1->pass, $timestamp, $user1->login, NULL); |
|
667 $reset_url = url("user/reset/$user1->uid/$timestamp/$reset_url_token", array('absolute' => TRUE)); |
|
668 $this->drupalGet($reset_url); |
|
669 $this->assertText($user1->name, 'The valid password reset page shows the user name.'); |
|
670 $this->assertUrl($reset_url, array(), 'The user remains on the password reset login page.'); |
|
671 $this->assertNoText('You have tried to use a one-time login link that has either been used or is no longer valid. Please request a new one using the form below.'); |
|
672 } |
|
673 |
|
674 } |
|
675 |
|
676 /** |
|
677 * Test cancelling a user. |
|
678 */ |
|
679 class UserCancelTestCase extends DrupalWebTestCase { |
|
680 public static function getInfo() { |
|
681 return array( |
|
682 'name' => 'Cancel account', |
|
683 'description' => 'Ensure that account cancellation methods work as expected.', |
|
684 'group' => 'User', |
|
685 ); |
|
686 } |
|
687 |
|
688 function setUp() { |
|
689 parent::setUp('comment'); |
|
690 } |
|
691 |
|
692 /** |
|
693 * Attempt to cancel account without permission. |
|
694 */ |
|
695 function testUserCancelWithoutPermission() { |
|
696 variable_set('user_cancel_method', 'user_cancel_reassign'); |
|
697 |
|
698 // Create a user. |
|
699 $account = $this->drupalCreateUser(array()); |
|
700 $this->drupalLogin($account); |
|
701 // Load real user object. |
|
702 $account = user_load($account->uid, TRUE); |
|
703 |
|
704 // Create a node. |
|
705 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
706 |
|
707 // Attempt to cancel account. |
|
708 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
709 $this->assertNoRaw(t('Cancel account'), 'No cancel account button displayed.'); |
|
710 |
|
711 // Attempt bogus account cancellation request confirmation. |
|
712 $timestamp = $account->login; |
|
713 $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)); |
|
714 $this->assertResponse(403, 'Bogus cancelling request rejected.'); |
|
715 $account = user_load($account->uid); |
|
716 $this->assertTrue($account->status == 1, 'User account was not canceled.'); |
|
717 |
|
718 // Confirm user's content has not been altered. |
|
719 $test_node = node_load($node->nid, NULL, TRUE); |
|
720 $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.'); |
|
721 } |
|
722 |
|
723 /** |
|
724 * Tests that user account for uid 1 cannot be cancelled. |
|
725 * |
|
726 * This should never be possible, or the site owner would become unable to |
|
727 * administer the site. |
|
728 */ |
|
729 function testUserCancelUid1() { |
|
730 // Update uid 1's name and password to we know it. |
|
731 $password = user_password(); |
|
732 require_once DRUPAL_ROOT . '/' . variable_get('password_inc', 'includes/password.inc'); |
|
733 $account = array( |
|
734 'name' => 'user1', |
|
735 'pass' => user_hash_password(trim($password)), |
|
736 ); |
|
737 // We cannot use user_save() here or the password would be hashed again. |
|
738 db_update('users') |
|
739 ->fields($account) |
|
740 ->condition('uid', 1) |
|
741 ->execute(); |
|
742 |
|
743 // Reload and log in uid 1. |
|
744 $user1 = user_load(1, TRUE); |
|
745 $user1->pass_raw = $password; |
|
746 |
|
747 // Try to cancel uid 1's account with a different user. |
|
748 $this->admin_user = $this->drupalCreateUser(array('administer users')); |
|
749 $this->drupalLogin($this->admin_user); |
|
750 $edit = array( |
|
751 'operation' => 'cancel', |
|
752 'accounts[1]' => TRUE, |
|
753 ); |
|
754 $this->drupalPost('admin/people', $edit, t('Update')); |
|
755 |
|
756 // Verify that uid 1's account was not cancelled. |
|
757 $user1 = user_load(1, TRUE); |
|
758 $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.'); |
|
759 } |
|
760 |
|
761 /** |
|
762 * Attempt invalid account cancellations. |
|
763 */ |
|
764 function testUserCancelInvalid() { |
|
765 variable_set('user_cancel_method', 'user_cancel_reassign'); |
|
766 |
|
767 // Create a user. |
|
768 $account = $this->drupalCreateUser(array('cancel account')); |
|
769 $this->drupalLogin($account); |
|
770 // Load real user object. |
|
771 $account = user_load($account->uid, TRUE); |
|
772 |
|
773 // Create a node. |
|
774 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
775 |
|
776 // Attempt to cancel account. |
|
777 $this->drupalPost('user/' . $account->uid . '/edit', NULL, t('Cancel account')); |
|
778 |
|
779 // Confirm account cancellation. |
|
780 $timestamp = time(); |
|
781 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
782 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
783 |
|
784 // Attempt bogus account cancellation request confirmation. |
|
785 $bogus_timestamp = $timestamp + 60; |
|
786 $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid)); |
|
787 $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Bogus cancelling request rejected.'); |
|
788 $account = user_load($account->uid); |
|
789 $this->assertTrue($account->status == 1, 'User account was not canceled.'); |
|
790 |
|
791 // Attempt expired account cancellation request confirmation. |
|
792 $bogus_timestamp = $timestamp - 86400 - 60; |
|
793 $this->drupalGet("user/$account->uid/cancel/confirm/$bogus_timestamp/" . user_pass_rehash($account->pass, $bogus_timestamp, $account->login, $account->uid)); |
|
794 $this->assertText(t('You have tried to use an account cancellation link that has expired. Please request a new one using the form below.'), 'Expired cancel account request rejected.'); |
|
795 $accounts = user_load_multiple(array($account->uid), array('status' => 1)); |
|
796 $this->assertTrue(reset($accounts), 'User account was not canceled.'); |
|
797 |
|
798 // Confirm user's content has not been altered. |
|
799 $test_node = node_load($node->nid, NULL, TRUE); |
|
800 $this->assertTrue(($test_node->uid == $account->uid && $test_node->status == 1), 'Node of the user has not been altered.'); |
|
801 } |
|
802 |
|
803 /** |
|
804 * Disable account and keep all content. |
|
805 */ |
|
806 function testUserBlock() { |
|
807 variable_set('user_cancel_method', 'user_cancel_block'); |
|
808 |
|
809 // Create a user. |
|
810 $web_user = $this->drupalCreateUser(array('cancel account')); |
|
811 $this->drupalLogin($web_user); |
|
812 |
|
813 // Load real user object. |
|
814 $account = user_load($web_user->uid, TRUE); |
|
815 |
|
816 // Attempt to cancel account. |
|
817 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
818 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
819 $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.'); |
|
820 $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will remain attributed to your user name.'), 'Informs that all content will be remain as is.'); |
|
821 $this->assertNoText(t('Select the method to cancel the account above.'), 'Does not allow user to select account cancellation method.'); |
|
822 |
|
823 // Confirm account cancellation. |
|
824 $timestamp = time(); |
|
825 |
|
826 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
827 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
828 |
|
829 // Confirm account cancellation request. |
|
830 $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)); |
|
831 $account = user_load($account->uid, TRUE); |
|
832 $this->assertTrue($account->status == 0, 'User has been blocked.'); |
|
833 |
|
834 // Confirm that the confirmation message made it through to the end user. |
|
835 $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user."); |
|
836 } |
|
837 |
|
838 /** |
|
839 * Disable account and unpublish all content. |
|
840 */ |
|
841 function testUserBlockUnpublish() { |
|
842 variable_set('user_cancel_method', 'user_cancel_block_unpublish'); |
|
843 |
|
844 // Create a user. |
|
845 $account = $this->drupalCreateUser(array('cancel account')); |
|
846 $this->drupalLogin($account); |
|
847 // Load real user object. |
|
848 $account = user_load($account->uid, TRUE); |
|
849 |
|
850 // Create a node with two revisions. |
|
851 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
852 $settings = get_object_vars($node); |
|
853 $settings['revision'] = 1; |
|
854 $node = $this->drupalCreateNode($settings); |
|
855 |
|
856 // Attempt to cancel account. |
|
857 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
858 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
859 $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.'); |
|
860 $this->assertText(t('Your account will be blocked and you will no longer be able to log in. All of your content will be hidden from everyone but administrators.'), 'Informs that all content will be unpublished.'); |
|
861 |
|
862 // Confirm account cancellation. |
|
863 $timestamp = time(); |
|
864 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
865 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
866 |
|
867 // Confirm account cancellation request. |
|
868 $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)); |
|
869 $account = user_load($account->uid, TRUE); |
|
870 $this->assertTrue($account->status == 0, 'User has been blocked.'); |
|
871 |
|
872 // Confirm user's content has been unpublished. |
|
873 $test_node = node_load($node->nid, NULL, TRUE); |
|
874 $this->assertTrue($test_node->status == 0, 'Node of the user has been unpublished.'); |
|
875 $test_node = node_load($node->nid, $node->vid, TRUE); |
|
876 $this->assertTrue($test_node->status == 0, 'Node revision of the user has been unpublished.'); |
|
877 |
|
878 // Confirm that the confirmation message made it through to the end user. |
|
879 $this->assertRaw(t('%name has been disabled.', array('%name' => $account->name)), "Confirmation message displayed to user."); |
|
880 } |
|
881 |
|
882 /** |
|
883 * Delete account and anonymize all content. |
|
884 */ |
|
885 function testUserAnonymize() { |
|
886 variable_set('user_cancel_method', 'user_cancel_reassign'); |
|
887 |
|
888 // Create a user. |
|
889 $account = $this->drupalCreateUser(array('cancel account')); |
|
890 $this->drupalLogin($account); |
|
891 // Load real user object. |
|
892 $account = user_load($account->uid, TRUE); |
|
893 |
|
894 // Create a simple node. |
|
895 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
896 |
|
897 // Create a node with two revisions, the initial one belonging to the |
|
898 // cancelling user. |
|
899 $revision_node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
900 $revision = $revision_node->vid; |
|
901 $settings = get_object_vars($revision_node); |
|
902 $settings['revision'] = 1; |
|
903 $settings['uid'] = 1; // Set new/current revision to someone else. |
|
904 $revision_node = $this->drupalCreateNode($settings); |
|
905 |
|
906 // Attempt to cancel account. |
|
907 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
908 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
909 $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.'); |
|
910 $this->assertRaw(t('Your account will be removed and all account information deleted. All of your content will be assigned to the %anonymous-name user.', array('%anonymous-name' => variable_get('anonymous', t('Anonymous')))), 'Informs that all content will be attributed to anonymous account.'); |
|
911 |
|
912 // Confirm account cancellation. |
|
913 $timestamp = time(); |
|
914 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
915 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
916 |
|
917 // Confirm account cancellation request. |
|
918 $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)); |
|
919 $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.'); |
|
920 |
|
921 // Confirm that user's content has been attributed to anonymous user. |
|
922 $test_node = node_load($node->nid, NULL, TRUE); |
|
923 $this->assertTrue(($test_node->uid == 0 && $test_node->status == 1), 'Node of the user has been attributed to anonymous user.'); |
|
924 $test_node = node_load($revision_node->nid, $revision, TRUE); |
|
925 $this->assertTrue(($test_node->revision_uid == 0 && $test_node->status == 1), 'Node revision of the user has been attributed to anonymous user.'); |
|
926 $test_node = node_load($revision_node->nid, NULL, TRUE); |
|
927 $this->assertTrue(($test_node->uid != 0 && $test_node->status == 1), "Current revision of the user's node was not attributed to anonymous user."); |
|
928 |
|
929 // Confirm that the confirmation message made it through to the end user. |
|
930 $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user."); |
|
931 } |
|
932 |
|
933 /** |
|
934 * Delete account and remove all content. |
|
935 */ |
|
936 function testUserDelete() { |
|
937 variable_set('user_cancel_method', 'user_cancel_delete'); |
|
938 |
|
939 // Create a user. |
|
940 $account = $this->drupalCreateUser(array('cancel account', 'post comments', 'skip comment approval')); |
|
941 $this->drupalLogin($account); |
|
942 // Load real user object. |
|
943 $account = user_load($account->uid, TRUE); |
|
944 |
|
945 // Create a simple node. |
|
946 $node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
947 |
|
948 // Create comment. |
|
949 $langcode = LANGUAGE_NONE; |
|
950 $edit = array(); |
|
951 $edit['subject'] = $this->randomName(8); |
|
952 $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16); |
|
953 |
|
954 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); |
|
955 $this->drupalPost(NULL, array(), t('Save')); |
|
956 $this->assertText(t('Your comment has been posted.')); |
|
957 $comments = comment_load_multiple(array(), array('subject' => $edit['subject'])); |
|
958 $comment = reset($comments); |
|
959 $this->assertTrue($comment->cid, 'Comment found.'); |
|
960 |
|
961 // Create a node with two revisions, the initial one belonging to the |
|
962 // cancelling user. |
|
963 $revision_node = $this->drupalCreateNode(array('uid' => $account->uid)); |
|
964 $revision = $revision_node->vid; |
|
965 $settings = get_object_vars($revision_node); |
|
966 $settings['revision'] = 1; |
|
967 $settings['uid'] = 1; // Set new/current revision to someone else. |
|
968 $revision_node = $this->drupalCreateNode($settings); |
|
969 |
|
970 // Attempt to cancel account. |
|
971 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
972 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
973 $this->assertText(t('Are you sure you want to cancel your account?'), 'Confirmation form to cancel account displayed.'); |
|
974 $this->assertText(t('Your account will be removed and all account information deleted. All of your content will also be deleted.'), 'Informs that all content will be deleted.'); |
|
975 |
|
976 // Confirm account cancellation. |
|
977 $timestamp = time(); |
|
978 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
979 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
980 |
|
981 // Confirm account cancellation request. |
|
982 $this->drupalGet("user/$account->uid/cancel/confirm/$timestamp/" . user_pass_rehash($account->pass, $timestamp, $account->login, $account->uid)); |
|
983 $this->assertFalse(user_load($account->uid, TRUE), 'User is not found in the database.'); |
|
984 |
|
985 // Confirm that user's content has been deleted. |
|
986 $this->assertFalse(node_load($node->nid, NULL, TRUE), 'Node of the user has been deleted.'); |
|
987 $this->assertFalse(node_load($node->nid, $revision, TRUE), 'Node revision of the user has been deleted.'); |
|
988 $this->assertTrue(node_load($revision_node->nid, NULL, TRUE), "Current revision of the user's node was not deleted."); |
|
989 $this->assertFalse(comment_load($comment->cid), 'Comment of the user has been deleted.'); |
|
990 |
|
991 // Confirm that the confirmation message made it through to the end user. |
|
992 $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), "Confirmation message displayed to user."); |
|
993 } |
|
994 |
|
995 /** |
|
996 * Create an administrative user and delete another user. |
|
997 */ |
|
998 function testUserCancelByAdmin() { |
|
999 variable_set('user_cancel_method', 'user_cancel_reassign'); |
|
1000 |
|
1001 // Create a regular user. |
|
1002 $account = $this->drupalCreateUser(array()); |
|
1003 |
|
1004 // Create administrative user. |
|
1005 $admin_user = $this->drupalCreateUser(array('administer users')); |
|
1006 $this->drupalLogin($admin_user); |
|
1007 |
|
1008 // Delete regular user. |
|
1009 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
1010 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
1011 $this->assertRaw(t('Are you sure you want to cancel the account %name?', array('%name' => $account->name)), 'Confirmation form to cancel account displayed.'); |
|
1012 $this->assertText(t('Select the method to cancel the account above.'), 'Allows to select account cancellation method.'); |
|
1013 |
|
1014 // Confirm deletion. |
|
1015 $this->drupalPost(NULL, NULL, t('Cancel account')); |
|
1016 $this->assertRaw(t('%name has been deleted.', array('%name' => $account->name)), 'User deleted.'); |
|
1017 $this->assertFalse(user_load($account->uid), 'User is not found in the database.'); |
|
1018 } |
|
1019 |
|
1020 /** |
|
1021 * Create an administrative user and mass-delete other users. |
|
1022 */ |
|
1023 function testMassUserCancelByAdmin() { |
|
1024 variable_set('user_cancel_method', 'user_cancel_reassign'); |
|
1025 // Enable account cancellation notification. |
|
1026 variable_set('user_mail_status_canceled_notify', TRUE); |
|
1027 |
|
1028 // Create administrative user. |
|
1029 $admin_user = $this->drupalCreateUser(array('administer users')); |
|
1030 $this->drupalLogin($admin_user); |
|
1031 |
|
1032 // Create some users. |
|
1033 $users = array(); |
|
1034 for ($i = 0; $i < 3; $i++) { |
|
1035 $account = $this->drupalCreateUser(array()); |
|
1036 $users[$account->uid] = $account; |
|
1037 } |
|
1038 |
|
1039 // Cancel user accounts, including own one. |
|
1040 $edit = array(); |
|
1041 $edit['operation'] = 'cancel'; |
|
1042 foreach ($users as $uid => $account) { |
|
1043 $edit['accounts[' . $uid . ']'] = TRUE; |
|
1044 } |
|
1045 $edit['accounts[' . $admin_user->uid . ']'] = TRUE; |
|
1046 // Also try to cancel uid 1. |
|
1047 $edit['accounts[1]'] = TRUE; |
|
1048 $this->drupalPost('admin/people', $edit, t('Update')); |
|
1049 $this->assertText(t('Are you sure you want to cancel these user accounts?'), 'Confirmation form to cancel accounts displayed.'); |
|
1050 $this->assertText(t('When cancelling these accounts'), 'Allows to select account cancellation method.'); |
|
1051 $this->assertText(t('Require e-mail confirmation to cancel account.'), 'Allows to send confirmation mail.'); |
|
1052 $this->assertText(t('Notify user when account is canceled.'), 'Allows to send notification mail.'); |
|
1053 |
|
1054 // Confirm deletion. |
|
1055 $this->drupalPost(NULL, NULL, t('Cancel accounts')); |
|
1056 $status = TRUE; |
|
1057 foreach ($users as $account) { |
|
1058 $status = $status && (strpos($this->content, t('%name has been deleted.', array('%name' => $account->name))) !== FALSE); |
|
1059 $status = $status && !user_load($account->uid, TRUE); |
|
1060 } |
|
1061 $this->assertTrue($status, 'Users deleted and not found in the database.'); |
|
1062 |
|
1063 // Ensure that admin account was not cancelled. |
|
1064 $this->assertText(t('A confirmation request to cancel your account has been sent to your e-mail address.'), 'Account cancellation request mailed message displayed.'); |
|
1065 $admin_user = user_load($admin_user->uid); |
|
1066 $this->assertTrue($admin_user->status == 1, 'Administrative user is found in the database and enabled.'); |
|
1067 |
|
1068 // Verify that uid 1's account was not cancelled. |
|
1069 $user1 = user_load(1, TRUE); |
|
1070 $this->assertEqual($user1->status, 1, 'User #1 still exists and is not blocked.'); |
|
1071 } |
|
1072 } |
|
1073 |
|
1074 class UserPictureTestCase extends DrupalWebTestCase { |
|
1075 protected $user; |
|
1076 protected $_directory_test; |
|
1077 |
|
1078 public static function getInfo() { |
|
1079 return array( |
|
1080 'name' => 'Upload user picture', |
|
1081 'description' => 'Assure that dimension check, extension check and image scaling work as designed.', |
|
1082 'group' => 'User' |
|
1083 ); |
|
1084 } |
|
1085 |
|
1086 function setUp() { |
|
1087 parent::setUp(); |
|
1088 // Enable user pictures. |
|
1089 variable_set('user_pictures', 1); |
|
1090 |
|
1091 $this->user = $this->drupalCreateUser(); |
|
1092 |
|
1093 // Test if directories specified in settings exist in filesystem. |
|
1094 $file_dir = 'public://'; |
|
1095 $file_check = file_prepare_directory($file_dir, FILE_CREATE_DIRECTORY); |
|
1096 // TODO: Test public and private methods? |
|
1097 |
|
1098 $picture_dir = variable_get('user_picture_path', 'pictures'); |
|
1099 $picture_path = $file_dir . $picture_dir; |
|
1100 |
|
1101 $pic_check = file_prepare_directory($picture_path, FILE_CREATE_DIRECTORY); |
|
1102 $this->_directory_test = is_writable($picture_path); |
|
1103 $this->assertTrue($this->_directory_test, "The directory $picture_path doesn't exist or is not writable. Further tests won't be made."); |
|
1104 } |
|
1105 |
|
1106 function testNoPicture() { |
|
1107 $this->drupalLogin($this->user); |
|
1108 |
|
1109 // Try to upload a file that is not an image for the user picture. |
|
1110 $not_an_image = current($this->drupalGetTestFiles('html')); |
|
1111 $this->saveUserPicture($not_an_image); |
|
1112 $this->assertRaw(t('Only JPEG, PNG and GIF images are allowed.'), 'Non-image files are not accepted.'); |
|
1113 } |
|
1114 |
|
1115 /** |
|
1116 * Do the test: |
|
1117 * GD Toolkit is installed |
|
1118 * Picture has invalid dimension |
|
1119 * |
|
1120 * results: The image should be uploaded because ImageGDToolkit resizes the picture |
|
1121 */ |
|
1122 function testWithGDinvalidDimension() { |
|
1123 if ($this->_directory_test && image_get_toolkit()) { |
|
1124 $this->drupalLogin($this->user); |
|
1125 |
|
1126 $image = current($this->drupalGetTestFiles('image')); |
|
1127 $info = image_get_info($image->uri); |
|
1128 |
|
1129 // Set new variables: invalid dimensions, valid filesize (0 = no limit). |
|
1130 $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10); |
|
1131 variable_set('user_picture_dimensions', $test_dim); |
|
1132 variable_set('user_picture_file_size', 0); |
|
1133 |
|
1134 $pic_path = $this->saveUserPicture($image); |
|
1135 // Check that the image was resized and is being displayed on the |
|
1136 // user's profile page. |
|
1137 $text = t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $test_dim)); |
|
1138 $this->assertRaw($text, 'Image was resized.'); |
|
1139 $alt = t("@user's picture", array('@user' => format_username($this->user))); |
|
1140 $style = variable_get('user_picture_style', ''); |
|
1141 $this->assertRaw(check_plain(image_style_url($style, $pic_path)), "Image is displayed in user's edit page"); |
|
1142 |
|
1143 // Check if file is located in proper directory. |
|
1144 $this->assertTrue(is_file($pic_path), "File is located in proper directory"); |
|
1145 } |
|
1146 } |
|
1147 |
|
1148 /** |
|
1149 * Do the test: |
|
1150 * GD Toolkit is installed |
|
1151 * Picture has invalid size |
|
1152 * |
|
1153 * results: The image should be uploaded because ImageGDToolkit resizes the picture |
|
1154 */ |
|
1155 function testWithGDinvalidSize() { |
|
1156 if ($this->_directory_test && image_get_toolkit()) { |
|
1157 $this->drupalLogin($this->user); |
|
1158 |
|
1159 // Images are sorted first by size then by name. We need an image |
|
1160 // bigger than 1 KB so we'll grab the last one. |
|
1161 $files = $this->drupalGetTestFiles('image'); |
|
1162 $image = end($files); |
|
1163 $info = image_get_info($image->uri); |
|
1164 |
|
1165 // Set new variables: valid dimensions, invalid filesize. |
|
1166 $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10); |
|
1167 $test_size = 1; |
|
1168 variable_set('user_picture_dimensions', $test_dim); |
|
1169 variable_set('user_picture_file_size', $test_size); |
|
1170 |
|
1171 $pic_path = $this->saveUserPicture($image); |
|
1172 |
|
1173 // Test that the upload failed and that the correct reason was cited. |
|
1174 $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename)); |
|
1175 $this->assertRaw($text, 'Upload failed.'); |
|
1176 $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024))); |
|
1177 $this->assertRaw($text, 'File size cited as reason for failure.'); |
|
1178 |
|
1179 // Check if file is not uploaded. |
|
1180 $this->assertFalse(is_file($pic_path), 'File was not uploaded.'); |
|
1181 } |
|
1182 } |
|
1183 |
|
1184 /** |
|
1185 * Do the test: |
|
1186 * GD Toolkit is not installed |
|
1187 * Picture has invalid size |
|
1188 * |
|
1189 * results: The image shouldn't be uploaded |
|
1190 */ |
|
1191 function testWithoutGDinvalidDimension() { |
|
1192 if ($this->_directory_test && !image_get_toolkit()) { |
|
1193 $this->drupalLogin($this->user); |
|
1194 |
|
1195 $image = current($this->drupalGetTestFiles('image')); |
|
1196 $info = image_get_info($image->uri); |
|
1197 |
|
1198 // Set new variables: invalid dimensions, valid filesize (0 = no limit). |
|
1199 $test_dim = ($info['width'] - 10) . 'x' . ($info['height'] - 10); |
|
1200 variable_set('user_picture_dimensions', $test_dim); |
|
1201 variable_set('user_picture_file_size', 0); |
|
1202 |
|
1203 $pic_path = $this->saveUserPicture($image); |
|
1204 |
|
1205 // Test that the upload failed and that the correct reason was cited. |
|
1206 $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename)); |
|
1207 $this->assertRaw($text, 'Upload failed.'); |
|
1208 $text = t('The image is too large; the maximum dimensions are %dimensions pixels.', array('%dimensions' => $test_dim)); |
|
1209 $this->assertRaw($text, 'Checking response on invalid image (dimensions).'); |
|
1210 |
|
1211 // Check if file is not uploaded. |
|
1212 $this->assertFalse(is_file($pic_path), 'File was not uploaded.'); |
|
1213 } |
|
1214 } |
|
1215 |
|
1216 /** |
|
1217 * Do the test: |
|
1218 * GD Toolkit is not installed |
|
1219 * Picture has invalid size |
|
1220 * |
|
1221 * results: The image shouldn't be uploaded |
|
1222 */ |
|
1223 function testWithoutGDinvalidSize() { |
|
1224 if ($this->_directory_test && !image_get_toolkit()) { |
|
1225 $this->drupalLogin($this->user); |
|
1226 |
|
1227 $image = current($this->drupalGetTestFiles('image')); |
|
1228 $info = image_get_info($image->uri); |
|
1229 |
|
1230 // Set new variables: valid dimensions, invalid filesize. |
|
1231 $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10); |
|
1232 $test_size = 1; |
|
1233 variable_set('user_picture_dimensions', $test_dim); |
|
1234 variable_set('user_picture_file_size', $test_size); |
|
1235 |
|
1236 $pic_path = $this->saveUserPicture($image); |
|
1237 |
|
1238 // Test that the upload failed and that the correct reason was cited. |
|
1239 $text = t('The specified file %filename could not be uploaded.', array('%filename' => $image->filename)); |
|
1240 $this->assertRaw($text, 'Upload failed.'); |
|
1241 $text = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size(filesize($image->uri)), '%maxsize' => format_size($test_size * 1024))); |
|
1242 $this->assertRaw($text, 'File size cited as reason for failure.'); |
|
1243 |
|
1244 // Check if file is not uploaded. |
|
1245 $this->assertFalse(is_file($pic_path), 'File was not uploaded.'); |
|
1246 } |
|
1247 } |
|
1248 |
|
1249 /** |
|
1250 * Do the test: |
|
1251 * Picture is valid (proper size and dimension) |
|
1252 * |
|
1253 * results: The image should be uploaded |
|
1254 */ |
|
1255 function testPictureIsValid() { |
|
1256 if ($this->_directory_test) { |
|
1257 $this->drupalLogin($this->user); |
|
1258 |
|
1259 $image = current($this->drupalGetTestFiles('image')); |
|
1260 $info = image_get_info($image->uri); |
|
1261 |
|
1262 // Set new variables: valid dimensions, valid filesize (0 = no limit). |
|
1263 $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10); |
|
1264 variable_set('user_picture_dimensions', $test_dim); |
|
1265 variable_set('user_picture_file_size', 0); |
|
1266 |
|
1267 $pic_path = $this->saveUserPicture($image); |
|
1268 |
|
1269 // Check if image is displayed in user's profile page. |
|
1270 $this->drupalGet('user'); |
|
1271 $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page"); |
|
1272 |
|
1273 // Check if file is located in proper directory. |
|
1274 $this->assertTrue(is_file($pic_path), 'File is located in proper directory'); |
|
1275 |
|
1276 // Set new picture dimensions. |
|
1277 $test_dim = ($info['width'] + 5) . 'x' . ($info['height'] + 5); |
|
1278 variable_set('user_picture_dimensions', $test_dim); |
|
1279 |
|
1280 $pic_path2 = $this->saveUserPicture($image); |
|
1281 $this->assertNotEqual($pic_path, $pic_path2, 'Filename of second picture is different.'); |
|
1282 |
|
1283 // Check if user picture has a valid file ID after saving the user. |
|
1284 $account = user_load($this->user->uid, TRUE); |
|
1285 $this->assertTrue(is_object($account->picture), 'User picture object is valid after user load.'); |
|
1286 $this->assertNotNull($account->picture->fid, 'User picture object has a FID after user load.'); |
|
1287 $this->assertTrue(is_file($account->picture->uri), 'File is located in proper directory after user load.'); |
|
1288 user_save($account); |
|
1289 // Verify that the user save does not destroy the user picture object. |
|
1290 $this->assertTrue(is_object($account->picture), 'User picture object is valid after user save.'); |
|
1291 $this->assertNotNull($account->picture->fid, 'User picture object has a FID after user save.'); |
|
1292 $this->assertTrue(is_file($account->picture->uri), 'File is located in proper directory after user save.'); |
|
1293 } |
|
1294 } |
|
1295 |
|
1296 /** |
|
1297 * Test HTTP schema working with user pictures. |
|
1298 */ |
|
1299 function testExternalPicture() { |
|
1300 $this->drupalLogin($this->user); |
|
1301 // Set the default picture to an URI with a HTTP schema. |
|
1302 $images = $this->drupalGetTestFiles('image'); |
|
1303 $image = $images[0]; |
|
1304 $pic_path = file_create_url($image->uri); |
|
1305 variable_set('user_picture_default', $pic_path); |
|
1306 |
|
1307 // Check if image is displayed in user's profile page. |
|
1308 $this->drupalGet('user'); |
|
1309 |
|
1310 // Get the user picture image via xpath. |
|
1311 $elements = $this->xpath('//div[@class="user-picture"]/img'); |
|
1312 $this->assertEqual(count($elements), 1, "There is exactly one user picture on the user's profile page"); |
|
1313 $this->assertEqual($pic_path, (string) $elements[0]['src'], "User picture source is correct."); |
|
1314 } |
|
1315 |
|
1316 /** |
|
1317 * Tests deletion of user pictures. |
|
1318 */ |
|
1319 function testDeletePicture() { |
|
1320 $this->drupalLogin($this->user); |
|
1321 |
|
1322 $image = current($this->drupalGetTestFiles('image')); |
|
1323 $info = image_get_info($image->uri); |
|
1324 |
|
1325 // Set new variables: valid dimensions, valid filesize (0 = no limit). |
|
1326 $test_dim = ($info['width'] + 10) . 'x' . ($info['height'] + 10); |
|
1327 variable_set('user_picture_dimensions', $test_dim); |
|
1328 variable_set('user_picture_file_size', 0); |
|
1329 |
|
1330 // Save a new picture. |
|
1331 $edit = array('files[picture_upload]' => drupal_realpath($image->uri)); |
|
1332 $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save')); |
|
1333 |
|
1334 // Load actual user data from database. |
|
1335 $account = user_load($this->user->uid, TRUE); |
|
1336 $pic_path = isset($account->picture) ? $account->picture->uri : NULL; |
|
1337 |
|
1338 // Check if image is displayed in user's profile page. |
|
1339 $this->drupalGet('user'); |
|
1340 $this->assertRaw(file_uri_target($pic_path), "Image is displayed in user's profile page"); |
|
1341 |
|
1342 // Check if file is located in proper directory. |
|
1343 $this->assertTrue(is_file($pic_path), 'File is located in proper directory'); |
|
1344 |
|
1345 $edit = array('picture_delete' => 1); |
|
1346 $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save')); |
|
1347 |
|
1348 // Load actual user data from database. |
|
1349 $account1 = user_load($this->user->uid, TRUE); |
|
1350 $this->assertNull($account1->picture, 'User object has no picture'); |
|
1351 |
|
1352 $file = file_load($account->picture->fid); |
|
1353 $this->assertFalse($file, 'File is removed from database'); |
|
1354 |
|
1355 // Clear out PHP's file stat cache so we see the current value. |
|
1356 clearstatcache(); |
|
1357 $this->assertFalse(is_file($pic_path), 'File is removed from file system'); |
|
1358 } |
|
1359 |
|
1360 function saveUserPicture($image) { |
|
1361 $edit = array('files[picture_upload]' => drupal_realpath($image->uri)); |
|
1362 $this->drupalPost('user/' . $this->user->uid . '/edit', $edit, t('Save')); |
|
1363 |
|
1364 // Load actual user data from database. |
|
1365 $account = user_load($this->user->uid, TRUE); |
|
1366 return isset($account->picture) ? $account->picture->uri : NULL; |
|
1367 } |
|
1368 |
|
1369 /** |
|
1370 * Tests the admin form validates user picture settings. |
|
1371 */ |
|
1372 function testUserPictureAdminFormValidation() { |
|
1373 $this->drupalLogin($this->drupalCreateUser(array('administer users'))); |
|
1374 |
|
1375 // The default values are valid. |
|
1376 $this->drupalPost('admin/config/people/accounts', array(), t('Save configuration')); |
|
1377 $this->assertText(t('The configuration options have been saved.'), 'The default values are valid.'); |
|
1378 |
|
1379 // The form does not save with an invalid file size. |
|
1380 $edit = array( |
|
1381 'user_picture_file_size' => $this->randomName(), |
|
1382 ); |
|
1383 $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration')); |
|
1384 $this->assertNoText(t('The configuration options have been saved.'), 'The form does not save with an invalid file size.'); |
|
1385 } |
|
1386 } |
|
1387 |
|
1388 |
|
1389 class UserPermissionsTestCase extends DrupalWebTestCase { |
|
1390 protected $admin_user; |
|
1391 protected $rid; |
|
1392 |
|
1393 public static function getInfo() { |
|
1394 return array( |
|
1395 'name' => 'Role permissions', |
|
1396 'description' => 'Verify that role permissions can be added and removed via the permissions page.', |
|
1397 'group' => 'User' |
|
1398 ); |
|
1399 } |
|
1400 |
|
1401 function setUp() { |
|
1402 parent::setUp(); |
|
1403 |
|
1404 $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users')); |
|
1405 |
|
1406 // Find the new role ID - it must be the maximum. |
|
1407 $all_rids = array_keys($this->admin_user->roles); |
|
1408 sort($all_rids); |
|
1409 $this->rid = array_pop($all_rids); |
|
1410 } |
|
1411 |
|
1412 /** |
|
1413 * Change user permissions and check user_access(). |
|
1414 */ |
|
1415 function testUserPermissionChanges() { |
|
1416 $this->drupalLogin($this->admin_user); |
|
1417 $rid = $this->rid; |
|
1418 $account = $this->admin_user; |
|
1419 |
|
1420 // Add a permission. |
|
1421 $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.'); |
|
1422 $edit = array(); |
|
1423 $edit[$rid . '[administer nodes]'] = TRUE; |
|
1424 $this->drupalPost('admin/people/permissions', $edit, t('Save permissions')); |
|
1425 $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.'); |
|
1426 drupal_static_reset('user_access'); |
|
1427 drupal_static_reset('user_role_permissions'); |
|
1428 $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.'); |
|
1429 |
|
1430 // Remove a permission. |
|
1431 $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.'); |
|
1432 $edit = array(); |
|
1433 $edit[$rid . '[access user profiles]'] = FALSE; |
|
1434 $this->drupalPost('admin/people/permissions', $edit, t('Save permissions')); |
|
1435 $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.'); |
|
1436 drupal_static_reset('user_access'); |
|
1437 drupal_static_reset('user_role_permissions'); |
|
1438 $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.'); |
|
1439 } |
|
1440 |
|
1441 /** |
|
1442 * Test assigning of permissions for the administrator role. |
|
1443 */ |
|
1444 function testAdministratorRole() { |
|
1445 $this->drupalLogin($this->admin_user); |
|
1446 $this->drupalGet('admin/config/people/accounts'); |
|
1447 |
|
1448 // Set the user's role to be the administrator role. |
|
1449 $edit = array(); |
|
1450 $edit['user_admin_role'] = $this->rid; |
|
1451 $this->drupalPost('admin/config/people/accounts', $edit, t('Save configuration')); |
|
1452 |
|
1453 // Enable aggregator module and ensure the 'administer news feeds' |
|
1454 // permission is assigned by default. |
|
1455 $edit = array(); |
|
1456 $edit['modules[Core][aggregator][enable]'] = TRUE; |
|
1457 $this->drupalPost('admin/modules', $edit, t('Save configuration')); |
|
1458 $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role'); |
|
1459 } |
|
1460 |
|
1461 /** |
|
1462 * Verify proper permission changes by user_role_change_permissions(). |
|
1463 */ |
|
1464 function testUserRoleChangePermissions() { |
|
1465 $rid = $this->rid; |
|
1466 $account = $this->admin_user; |
|
1467 |
|
1468 // Verify current permissions. |
|
1469 $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.'); |
|
1470 $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.'); |
|
1471 $this->assertTrue(user_access('administer site configuration', $account), 'User has "administer site configuration" permission.'); |
|
1472 |
|
1473 // Change permissions. |
|
1474 $permissions = array( |
|
1475 'administer nodes' => 1, |
|
1476 'access user profiles' => 0, |
|
1477 ); |
|
1478 user_role_change_permissions($rid, $permissions); |
|
1479 |
|
1480 // Verify proper permission changes. |
|
1481 $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.'); |
|
1482 $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.'); |
|
1483 $this->assertTrue(user_access('administer site configuration', $account), 'User still has "administer site configuration" permission.'); |
|
1484 } |
|
1485 } |
|
1486 |
|
1487 class UserAdminTestCase extends DrupalWebTestCase { |
|
1488 public static function getInfo() { |
|
1489 return array( |
|
1490 'name' => 'User administration', |
|
1491 'description' => 'Test user administration page functionality.', |
|
1492 'group' => 'User' |
|
1493 ); |
|
1494 } |
|
1495 |
|
1496 /** |
|
1497 * Registers a user and deletes it. |
|
1498 */ |
|
1499 function testUserAdmin() { |
|
1500 |
|
1501 $user_a = $this->drupalCreateUser(array()); |
|
1502 $user_b = $this->drupalCreateUser(array('administer taxonomy')); |
|
1503 $user_c = $this->drupalCreateUser(array('administer taxonomy')); |
|
1504 |
|
1505 // Create admin user to delete registered user. |
|
1506 $admin_user = $this->drupalCreateUser(array('administer users')); |
|
1507 $this->drupalLogin($admin_user); |
|
1508 $this->drupalGet('admin/people'); |
|
1509 $this->assertText($user_a->name, 'Found user A on admin users page'); |
|
1510 $this->assertText($user_b->name, 'Found user B on admin users page'); |
|
1511 $this->assertText($user_c->name, 'Found user C on admin users page'); |
|
1512 $this->assertText($admin_user->name, 'Found Admin user on admin users page'); |
|
1513 |
|
1514 // Test for existence of edit link in table. |
|
1515 $link = l(t('edit'), "user/$user_a->uid/edit", array('query' => array('destination' => 'admin/people'))); |
|
1516 $this->assertRaw($link, 'Found user A edit link on admin users page'); |
|
1517 |
|
1518 // Filter the users by permission 'administer taxonomy'. |
|
1519 $edit = array(); |
|
1520 $edit['permission'] = 'administer taxonomy'; |
|
1521 $this->drupalPost('admin/people', $edit, t('Filter')); |
|
1522 |
|
1523 // Check if the correct users show up. |
|
1524 $this->assertNoText($user_a->name, 'User A not on filtered by perm admin users page'); |
|
1525 $this->assertText($user_b->name, 'Found user B on filtered by perm admin users page'); |
|
1526 $this->assertText($user_c->name, 'Found user C on filtered by perm admin users page'); |
|
1527 |
|
1528 // Filter the users by role. Grab the system-generated role name for User C. |
|
1529 $edit['role'] = max(array_flip($user_c->roles)); |
|
1530 $this->drupalPost('admin/people', $edit, t('Refine')); |
|
1531 |
|
1532 // Check if the correct users show up when filtered by role. |
|
1533 $this->assertNoText($user_a->name, 'User A not on filtered by role on admin users page'); |
|
1534 $this->assertNoText($user_b->name, 'User B not on filtered by role on admin users page'); |
|
1535 $this->assertText($user_c->name, 'User C on filtered by role on admin users page'); |
|
1536 |
|
1537 // Test blocking of a user. |
|
1538 $account = user_load($user_c->uid); |
|
1539 $this->assertEqual($account->status, 1, 'User C not blocked'); |
|
1540 $edit = array(); |
|
1541 $edit['operation'] = 'block'; |
|
1542 $edit['accounts[' . $account->uid . ']'] = TRUE; |
|
1543 $this->drupalPost('admin/people', $edit, t('Update')); |
|
1544 $account = user_load($user_c->uid, TRUE); |
|
1545 $this->assertEqual($account->status, 0, 'User C blocked'); |
|
1546 |
|
1547 // Test unblocking of a user from /admin/people page and sending of activation mail |
|
1548 $editunblock = array(); |
|
1549 $editunblock['operation'] = 'unblock'; |
|
1550 $editunblock['accounts[' . $account->uid . ']'] = TRUE; |
|
1551 $this->drupalPost('admin/people', $editunblock, t('Update')); |
|
1552 $account = user_load($user_c->uid, TRUE); |
|
1553 $this->assertEqual($account->status, 1, 'User C unblocked'); |
|
1554 $this->assertMail("to", $account->mail, "Activation mail sent to user C"); |
|
1555 |
|
1556 // Test blocking and unblocking another user from /user/[uid]/edit form and sending of activation mail |
|
1557 $user_d = $this->drupalCreateUser(array()); |
|
1558 $account1 = user_load($user_d->uid, TRUE); |
|
1559 $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => 0), t('Save')); |
|
1560 $account1 = user_load($user_d->uid, TRUE); |
|
1561 $this->assertEqual($account1->status, 0, 'User D blocked'); |
|
1562 $this->drupalPost('user/' . $account1->uid . '/edit', array('status' => TRUE), t('Save')); |
|
1563 $account1 = user_load($user_d->uid, TRUE); |
|
1564 $this->assertEqual($account1->status, 1, 'User D unblocked'); |
|
1565 $this->assertMail("to", $account1->mail, "Activation mail sent to user D"); |
|
1566 } |
|
1567 } |
|
1568 |
|
1569 /** |
|
1570 * Tests for user-configurable time zones. |
|
1571 */ |
|
1572 class UserTimeZoneFunctionalTest extends DrupalWebTestCase { |
|
1573 public static function getInfo() { |
|
1574 return array( |
|
1575 'name' => 'User time zones', |
|
1576 'description' => 'Set a user time zone and verify that dates are displayed in local time.', |
|
1577 'group' => 'User', |
|
1578 ); |
|
1579 } |
|
1580 |
|
1581 /** |
|
1582 * Tests the display of dates and time when user-configurable time zones are set. |
|
1583 */ |
|
1584 function testUserTimeZone() { |
|
1585 // Setup date/time settings for Los Angeles time. |
|
1586 variable_set('date_default_timezone', 'America/Los_Angeles'); |
|
1587 variable_set('configurable_timezones', 1); |
|
1588 |
|
1589 // Override the 'medium' date format, which is the default for node |
|
1590 // creation time. Since we are testing time zones with Daylight Saving |
|
1591 // Time, and need to future proof against changes to the zoneinfo database, |
|
1592 // we choose the 'I' format placeholder instead of a human-readable zone |
|
1593 // name. With 'I', a 1 means the date is in DST, and 0 if not. |
|
1594 variable_set('date_format_medium', 'Y-m-d H:i I'); |
|
1595 |
|
1596 // Create a user account and login. |
|
1597 $web_user = $this->drupalCreateUser(); |
|
1598 $this->drupalLogin($web_user); |
|
1599 |
|
1600 // Create some nodes with different authored-on dates. |
|
1601 // Two dates in PST (winter time): |
|
1602 $date1 = '2007-03-09 21:00:00 -0800'; |
|
1603 $date2 = '2007-03-11 01:00:00 -0800'; |
|
1604 // One date in PDT (summer time): |
|
1605 $date3 = '2007-03-20 21:00:00 -0700'; |
|
1606 $node1 = $this->drupalCreateNode(array('created' => strtotime($date1), 'type' => 'article')); |
|
1607 $node2 = $this->drupalCreateNode(array('created' => strtotime($date2), 'type' => 'article')); |
|
1608 $node3 = $this->drupalCreateNode(array('created' => strtotime($date3), 'type' => 'article')); |
|
1609 |
|
1610 // Confirm date format and time zone. |
|
1611 $this->drupalGet("node/$node1->nid"); |
|
1612 $this->assertText('2007-03-09 21:00 0', 'Date should be PST.'); |
|
1613 $this->drupalGet("node/$node2->nid"); |
|
1614 $this->assertText('2007-03-11 01:00 0', 'Date should be PST.'); |
|
1615 $this->drupalGet("node/$node3->nid"); |
|
1616 $this->assertText('2007-03-20 21:00 1', 'Date should be PDT.'); |
|
1617 |
|
1618 // Change user time zone to Santiago time. |
|
1619 $edit = array(); |
|
1620 $edit['mail'] = $web_user->mail; |
|
1621 $edit['timezone'] = 'America/Santiago'; |
|
1622 $this->drupalPost("user/$web_user->uid/edit", $edit, t('Save')); |
|
1623 $this->assertText(t('The changes have been saved.'), 'Time zone changed to Santiago time.'); |
|
1624 |
|
1625 // Confirm date format and time zone. |
|
1626 $this->drupalGet("node/$node1->nid"); |
|
1627 $this->assertText('2007-03-10 02:00 1', 'Date should be Chile summer time; five hours ahead of PST.'); |
|
1628 $this->drupalGet("node/$node2->nid"); |
|
1629 $this->assertText('2007-03-11 05:00 0', 'Date should be Chile time; four hours ahead of PST'); |
|
1630 $this->drupalGet("node/$node3->nid"); |
|
1631 $this->assertText('2007-03-21 00:00 0', 'Date should be Chile time; three hours ahead of PDT.'); |
|
1632 } |
|
1633 } |
|
1634 |
|
1635 /** |
|
1636 * Test user autocompletion. |
|
1637 */ |
|
1638 class UserAutocompleteTestCase extends DrupalWebTestCase { |
|
1639 public static function getInfo() { |
|
1640 return array( |
|
1641 'name' => 'User autocompletion', |
|
1642 'description' => 'Test user autocompletion functionality.', |
|
1643 'group' => 'User' |
|
1644 ); |
|
1645 } |
|
1646 |
|
1647 function setUp() { |
|
1648 parent::setUp(); |
|
1649 |
|
1650 // Set up two users with different permissions to test access. |
|
1651 $this->unprivileged_user = $this->drupalCreateUser(); |
|
1652 $this->privileged_user = $this->drupalCreateUser(array('access user profiles')); |
|
1653 } |
|
1654 |
|
1655 /** |
|
1656 * Tests access to user autocompletion and verify the correct results. |
|
1657 */ |
|
1658 function testUserAutocomplete() { |
|
1659 // Check access from unprivileged user, should be denied. |
|
1660 $this->drupalLogin($this->unprivileged_user); |
|
1661 $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]); |
|
1662 $this->assertResponse(403, 'Autocompletion access denied to user without permission.'); |
|
1663 |
|
1664 // Check access from privileged user. |
|
1665 $this->drupalLogout(); |
|
1666 $this->drupalLogin($this->privileged_user); |
|
1667 $this->drupalGet('user/autocomplete/' . $this->unprivileged_user->name[0]); |
|
1668 $this->assertResponse(200, 'Autocompletion access allowed.'); |
|
1669 |
|
1670 // Using first letter of the user's name, make sure the user's full name is in the results. |
|
1671 $this->assertRaw($this->unprivileged_user->name, 'User name found in autocompletion results.'); |
|
1672 } |
|
1673 } |
|
1674 |
|
1675 |
|
1676 /** |
|
1677 * Tests user links in the secondary menu. |
|
1678 */ |
|
1679 class UserAccountLinksUnitTests extends DrupalWebTestCase { |
|
1680 public static function getInfo() { |
|
1681 return array( |
|
1682 'name' => 'User account links', |
|
1683 'description' => 'Test user-account links.', |
|
1684 'group' => 'User' |
|
1685 ); |
|
1686 } |
|
1687 |
|
1688 function setUp() { |
|
1689 parent::setUp('menu'); |
|
1690 } |
|
1691 |
|
1692 /** |
|
1693 * Tests the secondary menu. |
|
1694 */ |
|
1695 function testSecondaryMenu() { |
|
1696 // Create a regular user. |
|
1697 $user = $this->drupalCreateUser(array()); |
|
1698 |
|
1699 // Log in and get the homepage. |
|
1700 $this->drupalLogin($user); |
|
1701 $this->drupalGet('<front>'); |
|
1702 |
|
1703 // For a logged-in user, expect the secondary menu to have links for "My |
|
1704 // account" and "Log out". |
|
1705 $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array( |
|
1706 ':menu_id' => 'secondary-menu-links', |
|
1707 ':href' => 'user', |
|
1708 ':text' => 'My account', |
|
1709 )); |
|
1710 $this->assertEqual(count($link), 1, 'My account link is in secondary menu.'); |
|
1711 |
|
1712 $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array( |
|
1713 ':menu_id' => 'secondary-menu-links', |
|
1714 ':href' => 'user/logout', |
|
1715 ':text' => 'Log out', |
|
1716 )); |
|
1717 $this->assertEqual(count($link), 1, 'Log out link is in secondary menu.'); |
|
1718 |
|
1719 // Log out and get the homepage. |
|
1720 $this->drupalLogout(); |
|
1721 $this->drupalGet('<front>'); |
|
1722 |
|
1723 // For a logged-out user, expect no secondary links. |
|
1724 $element = $this->xpath('//ul[@id=:menu_id]', array(':menu_id' => 'secondary-menu-links')); |
|
1725 $this->assertEqual(count($element), 0, 'No secondary-menu for logged-out users.'); |
|
1726 } |
|
1727 |
|
1728 /** |
|
1729 * Tests disabling the 'My account' link. |
|
1730 */ |
|
1731 function testDisabledAccountLink() { |
|
1732 // Create an admin user and log in. |
|
1733 $this->drupalLogin($this->drupalCreateUser(array('access administration pages', 'administer menu'))); |
|
1734 |
|
1735 // Verify that the 'My account' link is enabled. |
|
1736 $this->drupalGet('admin/structure/menu/manage/user-menu'); |
|
1737 $label = $this->xpath('//label[contains(.,:text)]/@for', array(':text' => 'Enable My account menu link')); |
|
1738 $this->assertFieldChecked((string) $label[0], "The 'My account' link is enabled by default."); |
|
1739 |
|
1740 // Disable the 'My account' link. |
|
1741 $input = $this->xpath('//input[@id=:field_id]/@name', array(':field_id' => (string)$label[0])); |
|
1742 $edit = array( |
|
1743 (string) $input[0] => FALSE, |
|
1744 ); |
|
1745 $this->drupalPost('admin/structure/menu/manage/user-menu', $edit, t('Save configuration')); |
|
1746 |
|
1747 // Get the homepage. |
|
1748 $this->drupalGet('<front>'); |
|
1749 |
|
1750 // Verify that the 'My account' link does not appear when disabled. |
|
1751 $link = $this->xpath('//ul[@id=:menu_id]/li/a[contains(@href, :href) and text()=:text]', array( |
|
1752 ':menu_id' => 'secondary-menu-links', |
|
1753 ':href' => 'user', |
|
1754 ':text' => 'My account', |
|
1755 )); |
|
1756 $this->assertEqual(count($link), 0, 'My account link is not in the secondary menu.'); |
|
1757 } |
|
1758 |
|
1759 } |
|
1760 |
|
1761 /** |
|
1762 * Test user blocks. |
|
1763 */ |
|
1764 class UserBlocksUnitTests extends DrupalWebTestCase { |
|
1765 public static function getInfo() { |
|
1766 return array( |
|
1767 'name' => 'User blocks', |
|
1768 'description' => 'Test user blocks.', |
|
1769 'group' => 'User' |
|
1770 ); |
|
1771 } |
|
1772 |
|
1773 /** |
|
1774 * Test the user login block. |
|
1775 */ |
|
1776 function testUserLoginBlock() { |
|
1777 // Create a user with some permission that anonymous users lack. |
|
1778 $user = $this->drupalCreateUser(array('administer permissions')); |
|
1779 |
|
1780 // Log in using the block. |
|
1781 $edit = array(); |
|
1782 $edit['name'] = $user->name; |
|
1783 $edit['pass'] = $user->pass_raw; |
|
1784 $this->drupalPost('admin/people/permissions', $edit, t('Log in')); |
|
1785 $this->assertNoText(t('User login'), 'Logged in.'); |
|
1786 |
|
1787 // Check that we are still on the same page. |
|
1788 $this->assertEqual(url('admin/people/permissions', array('absolute' => TRUE)), $this->getUrl(), 'Still on the same page after login for access denied page'); |
|
1789 |
|
1790 // Now, log out and repeat with a non-403 page. |
|
1791 $this->drupalLogout(); |
|
1792 $this->drupalPost('filter/tips', $edit, t('Log in')); |
|
1793 $this->assertNoText(t('User login'), 'Logged in.'); |
|
1794 $this->assertPattern('!<title.*?' . t('Compose tips') . '.*?</title>!', 'Still on the same page after login for allowed page'); |
|
1795 |
|
1796 // Check that the user login block is not vulnerable to information |
|
1797 // disclosure to third party sites. |
|
1798 $this->drupalLogout(); |
|
1799 $this->drupalPost('http://example.com/', $edit, t('Log in'), array('external' => FALSE)); |
|
1800 // Check that we remain on the site after login. |
|
1801 $this->assertEqual(url('user/' . $user->uid, array('absolute' => TRUE)), $this->getUrl(), 'Redirected to user profile page after login from the frontpage'); |
|
1802 } |
|
1803 |
|
1804 /** |
|
1805 * Test the Who's Online block. |
|
1806 */ |
|
1807 function testWhosOnlineBlock() { |
|
1808 // Generate users and make sure there are no current user sessions. |
|
1809 $user1 = $this->drupalCreateUser(array()); |
|
1810 $user2 = $this->drupalCreateUser(array()); |
|
1811 $user3 = $this->drupalCreateUser(array()); |
|
1812 $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions}")->fetchField(), 0, 'Sessions table is empty.'); |
|
1813 |
|
1814 // Insert a user with two sessions. |
|
1815 $this->insertSession(array('uid' => $user1->uid)); |
|
1816 $this->insertSession(array('uid' => $user1->uid)); |
|
1817 $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid", array(':uid' => $user1->uid))->fetchField(), 2, 'Duplicate user session has been inserted.'); |
|
1818 |
|
1819 // Insert a user with only one session. |
|
1820 $this->insertSession(array('uid' => $user2->uid, 'timestamp' => REQUEST_TIME + 1)); |
|
1821 |
|
1822 // Insert an inactive logged-in user who should not be seen in the block. |
|
1823 $this->insertSession(array('uid' => $user3->uid, 'timestamp' => (REQUEST_TIME - variable_get('user_block_seconds_online', 900) - 1))); |
|
1824 |
|
1825 // Insert two anonymous user sessions. |
|
1826 $this->insertSession(); |
|
1827 $this->insertSession(); |
|
1828 |
|
1829 // Test block output. |
|
1830 $block = user_block_view('online'); |
|
1831 $this->drupalSetContent($block['content']); |
|
1832 $this->assertRaw(t('2 users'), 'Correct number of online users (2 users).'); |
|
1833 $this->assertText($user1->name, 'Active user 1 found in online list.'); |
|
1834 $this->assertText($user2->name, 'Active user 2 found in online list.'); |
|
1835 $this->assertNoText($user3->name, "Inactive user not found in online list."); |
|
1836 $this->assertTrue(strpos($this->drupalGetContent(), $user1->name) > strpos($this->drupalGetContent(), $user2->name), 'Online users are ordered correctly.'); |
|
1837 } |
|
1838 |
|
1839 /** |
|
1840 * Insert a user session into the {sessions} table. This function is used |
|
1841 * since we cannot log in more than one user at the same time in tests. |
|
1842 */ |
|
1843 private function insertSession(array $fields = array()) { |
|
1844 $fields += array( |
|
1845 'uid' => 0, |
|
1846 'sid' => drupal_hash_base64(uniqid(mt_rand(), TRUE)), |
|
1847 'timestamp' => REQUEST_TIME, |
|
1848 ); |
|
1849 db_insert('sessions') |
|
1850 ->fields($fields) |
|
1851 ->execute(); |
|
1852 $this->assertEqual(db_query("SELECT COUNT(*) FROM {sessions} WHERE uid = :uid AND sid = :sid AND timestamp = :timestamp", array(':uid' => $fields['uid'], ':sid' => $fields['sid'], ':timestamp' => $fields['timestamp']))->fetchField(), 1, 'Session record inserted.'); |
|
1853 } |
|
1854 } |
|
1855 |
|
1856 /** |
|
1857 * Tests saving a user account. |
|
1858 */ |
|
1859 class UserSaveTestCase extends DrupalWebTestCase { |
|
1860 |
|
1861 public static function getInfo() { |
|
1862 return array( |
|
1863 'name' => 'User save test', |
|
1864 'description' => 'Test user_save() for arbitrary new uid.', |
|
1865 'group' => 'User', |
|
1866 ); |
|
1867 } |
|
1868 |
|
1869 /** |
|
1870 * Test creating a user with arbitrary uid. |
|
1871 */ |
|
1872 function testUserImport() { |
|
1873 // User ID must be a number that is not in the database. |
|
1874 $max_uid = db_query('SELECT MAX(uid) FROM {users}')->fetchField(); |
|
1875 $test_uid = $max_uid + mt_rand(1000, 1000000); |
|
1876 $test_name = $this->randomName(); |
|
1877 |
|
1878 // Create the base user, based on drupalCreateUser(). |
|
1879 $user = array( |
|
1880 'name' => $test_name, |
|
1881 'uid' => $test_uid, |
|
1882 'mail' => $test_name . '@example.com', |
|
1883 'is_new' => TRUE, |
|
1884 'pass' => user_password(), |
|
1885 'status' => 1, |
|
1886 ); |
|
1887 $user_by_return = user_save(drupal_anonymous_user(), $user); |
|
1888 $this->assertTrue($user_by_return, 'Loading user by return of user_save().'); |
|
1889 |
|
1890 // Test if created user exists. |
|
1891 $user_by_uid = user_load($test_uid); |
|
1892 $this->assertTrue($user_by_uid, 'Loading user by uid.'); |
|
1893 |
|
1894 $user_by_name = user_load_by_name($test_name); |
|
1895 $this->assertTrue($user_by_name, 'Loading user by name.'); |
|
1896 } |
|
1897 } |
|
1898 |
|
1899 /** |
|
1900 * Test the create user administration page. |
|
1901 */ |
|
1902 class UserCreateTestCase extends DrupalWebTestCase { |
|
1903 |
|
1904 public static function getInfo() { |
|
1905 return array( |
|
1906 'name' => 'User create', |
|
1907 'description' => 'Test the create user administration page.', |
|
1908 'group' => 'User', |
|
1909 ); |
|
1910 } |
|
1911 |
|
1912 /** |
|
1913 * Create a user through the administration interface and ensure that it |
|
1914 * displays in the user list. |
|
1915 */ |
|
1916 protected function testUserAdd() { |
|
1917 $user = $this->drupalCreateUser(array('administer users')); |
|
1918 $this->drupalLogin($user); |
|
1919 |
|
1920 foreach (array(FALSE, TRUE) as $notify) { |
|
1921 $edit = array( |
|
1922 'name' => $this->randomName(), |
|
1923 'mail' => $this->randomName() . '@example.com', |
|
1924 'pass[pass1]' => $pass = $this->randomString(), |
|
1925 'pass[pass2]' => $pass, |
|
1926 'notify' => $notify, |
|
1927 ); |
|
1928 $this->drupalPost('admin/people/create', $edit, t('Create new account')); |
|
1929 |
|
1930 if ($notify) { |
|
1931 $this->assertText(t('A welcome message with further instructions has been e-mailed to the new user @name.', array('@name' => $edit['name'])), 'User created'); |
|
1932 $this->assertEqual(count($this->drupalGetMails()), 1, 'Notification e-mail sent'); |
|
1933 } |
|
1934 else { |
|
1935 $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created'); |
|
1936 $this->assertEqual(count($this->drupalGetMails()), 0, 'Notification e-mail not sent'); |
|
1937 } |
|
1938 |
|
1939 $this->drupalGet('admin/people'); |
|
1940 $this->assertText($edit['name'], 'User found in list of users'); |
|
1941 } |
|
1942 |
|
1943 // Test that the password '0' is considered a password. |
|
1944 $name = $this->randomName(); |
|
1945 $edit = array( |
|
1946 'name' => $name, |
|
1947 'mail' => $name . '@example.com', |
|
1948 'pass[pass1]' => 0, |
|
1949 'pass[pass2]' => 0, |
|
1950 'notify' => FALSE, |
|
1951 ); |
|
1952 $this->drupalPost('admin/people/create', $edit, t('Create new account')); |
|
1953 $this->assertText(t('Created a new user account for @name. No e-mail has been sent.', array('@name' => $edit['name'])), 'User created with password 0'); |
|
1954 $this->assertNoText('Password field is required'); |
|
1955 } |
|
1956 } |
|
1957 |
|
1958 /** |
|
1959 * Tests editing a user account. |
|
1960 */ |
|
1961 class UserEditTestCase extends DrupalWebTestCase { |
|
1962 |
|
1963 public static function getInfo() { |
|
1964 return array( |
|
1965 'name' => 'User edit', |
|
1966 'description' => 'Test user edit page.', |
|
1967 'group' => 'User', |
|
1968 ); |
|
1969 } |
|
1970 |
|
1971 /** |
|
1972 * Test user edit page. |
|
1973 */ |
|
1974 function testUserEdit() { |
|
1975 // Test user edit functionality with user pictures disabled. |
|
1976 variable_set('user_pictures', 0); |
|
1977 $user1 = $this->drupalCreateUser(array('change own username')); |
|
1978 $user2 = $this->drupalCreateUser(array()); |
|
1979 $this->drupalLogin($user1); |
|
1980 |
|
1981 // Test that error message appears when attempting to use a non-unique user name. |
|
1982 $edit['name'] = $user2->name; |
|
1983 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
1984 $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name']))); |
|
1985 |
|
1986 // Repeat the test with user pictures enabled, which modifies the form. |
|
1987 variable_set('user_pictures', 1); |
|
1988 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
1989 $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name']))); |
|
1990 |
|
1991 // Check that filling out a single password field does not validate. |
|
1992 $edit = array(); |
|
1993 $edit['pass[pass1]'] = ''; |
|
1994 $edit['pass[pass2]'] = $this->randomName(); |
|
1995 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
1996 $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.'); |
|
1997 |
|
1998 $edit['pass[pass1]'] = $this->randomName(); |
|
1999 $edit['pass[pass2]'] = ''; |
|
2000 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2001 $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.'); |
|
2002 |
|
2003 // Test that the error message appears when attempting to change the mail or |
|
2004 // pass without the current password. |
|
2005 $edit = array(); |
|
2006 $edit['mail'] = $this->randomName() . '@new.example.com'; |
|
2007 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2008 $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('E-mail address')))); |
|
2009 |
|
2010 $edit['current_pass'] = $user1->pass_raw; |
|
2011 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2012 $this->assertRaw(t("The changes have been saved.")); |
|
2013 |
|
2014 // Test that the user must enter current password before changing passwords. |
|
2015 $edit = array(); |
|
2016 $edit['pass[pass1]'] = $new_pass = $this->randomName(); |
|
2017 $edit['pass[pass2]'] = $new_pass; |
|
2018 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2019 $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password')))); |
|
2020 |
|
2021 // Try again with the current password. |
|
2022 $edit['current_pass'] = $user1->pass_raw; |
|
2023 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2024 $this->assertRaw(t("The changes have been saved.")); |
|
2025 |
|
2026 // Make sure the user can log in with their new password. |
|
2027 $this->drupalLogout(); |
|
2028 $user1->pass_raw = $new_pass; |
|
2029 $this->drupalLogin($user1); |
|
2030 $this->drupalLogout(); |
|
2031 } |
|
2032 |
|
2033 /** |
|
2034 * Tests setting the password to "0". |
|
2035 */ |
|
2036 public function testUserWith0Password() { |
|
2037 $admin = $this->drupalCreateUser(array('administer users')); |
|
2038 $this->drupalLogin($admin); |
|
2039 // Create a regular user. |
|
2040 $user1 = $this->drupalCreateUser(array()); |
|
2041 |
|
2042 $edit = array('pass[pass1]' => '0', 'pass[pass2]' => '0'); |
|
2043 $this->drupalPost("user/" . $user1->uid . "/edit", $edit, t('Save')); |
|
2044 $this->assertRaw(t("The changes have been saved.")); |
|
2045 |
|
2046 $this->drupalLogout(); |
|
2047 $user1->pass_raw = '0'; |
|
2048 $this->drupalLogin($user1); |
|
2049 $this->drupalLogout(); |
|
2050 } |
|
2051 } |
|
2052 |
|
2053 /** |
|
2054 * Tests editing a user account with and without a form rebuild. |
|
2055 */ |
|
2056 class UserEditRebuildTestCase extends DrupalWebTestCase { |
|
2057 |
|
2058 public static function getInfo() { |
|
2059 return array( |
|
2060 'name' => 'User edit with form rebuild', |
|
2061 'description' => 'Test user edit page when a form rebuild is triggered.', |
|
2062 'group' => 'User', |
|
2063 ); |
|
2064 } |
|
2065 |
|
2066 function setUp() { |
|
2067 parent::setUp('user_form_test'); |
|
2068 } |
|
2069 |
|
2070 /** |
|
2071 * Test user edit page when the form is set to rebuild. |
|
2072 */ |
|
2073 function testUserEditFormRebuild() { |
|
2074 $user1 = $this->drupalCreateUser(array('change own username')); |
|
2075 $this->drupalLogin($user1); |
|
2076 |
|
2077 $roles = array_keys($user1->roles); |
|
2078 // Save the user form twice. |
|
2079 $edit = array(); |
|
2080 $edit['current_pass'] = $user1->pass_raw; |
|
2081 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2082 $this->assertRaw(t("The changes have been saved.")); |
|
2083 $this->drupalPost(NULL, $edit, t('Save')); |
|
2084 $this->assertRaw(t("The changes have been saved.")); |
|
2085 $saved_user1 = entity_load_unchanged('user', $user1->uid); |
|
2086 $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.'); |
|
2087 $diff = array_diff(array_keys($saved_user1->roles), $roles); |
|
2088 $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles)))); |
|
2089 // Set variable that causes the form to be rebuilt in user_form_test.module. |
|
2090 variable_set('user_form_test_user_profile_form_rebuild', TRUE); |
|
2091 $this->drupalPost("user/$user1->uid/edit", $edit, t('Save')); |
|
2092 $this->assertRaw(t("The changes have been saved.")); |
|
2093 $this->drupalPost(NULL, $edit, t('Save')); |
|
2094 $this->assertRaw(t("The changes have been saved.")); |
|
2095 $saved_user1 = entity_load_unchanged('user', $user1->uid); |
|
2096 $this->assertEqual(count($roles), count($saved_user1->roles), 'Count of user roles in database matches original count.'); |
|
2097 $diff = array_diff(array_keys($saved_user1->roles), $roles); |
|
2098 $this->assertTrue(empty($diff), format_string('User roles in database match original: @roles', array('@roles' => implode(', ', $saved_user1->roles)))); |
|
2099 } |
|
2100 } |
|
2101 |
|
2102 /** |
|
2103 * Test case for user signatures. |
|
2104 */ |
|
2105 class UserSignatureTestCase extends DrupalWebTestCase { |
|
2106 public static function getInfo() { |
|
2107 return array( |
|
2108 'name' => 'User signatures', |
|
2109 'description' => 'Test user signatures.', |
|
2110 'group' => 'User', |
|
2111 ); |
|
2112 } |
|
2113 |
|
2114 function setUp() { |
|
2115 parent::setUp('comment'); |
|
2116 |
|
2117 // Enable user signatures. |
|
2118 variable_set('user_signatures', 1); |
|
2119 |
|
2120 // Prefetch text formats. |
|
2121 $this->full_html_format = filter_format_load('full_html'); |
|
2122 $this->plain_text_format = filter_format_load('plain_text'); |
|
2123 |
|
2124 // Create regular and administrative users. |
|
2125 $this->web_user = $this->drupalCreateUser(array()); |
|
2126 $admin_permissions = array('administer comments'); |
|
2127 foreach (filter_formats() as $format) { |
|
2128 if ($permission = filter_permission_name($format)) { |
|
2129 $admin_permissions[] = $permission; |
|
2130 } |
|
2131 } |
|
2132 $this->admin_user = $this->drupalCreateUser($admin_permissions); |
|
2133 } |
|
2134 |
|
2135 /** |
|
2136 * Test that a user can change their signature format and that it is respected |
|
2137 * upon display. |
|
2138 */ |
|
2139 function testUserSignature() { |
|
2140 // Create a new node with comments on. |
|
2141 $node = $this->drupalCreateNode(array('comment' => COMMENT_NODE_OPEN)); |
|
2142 |
|
2143 // Verify that user signature field is not displayed on registration form. |
|
2144 $this->drupalGet('user/register'); |
|
2145 $this->assertNoText(t('Signature')); |
|
2146 |
|
2147 // Log in as a regular user and create a signature. |
|
2148 $this->drupalLogin($this->web_user); |
|
2149 $signature_text = "<h1>" . $this->randomName() . "</h1>"; |
|
2150 $edit = array( |
|
2151 'signature[value]' => $signature_text, |
|
2152 'signature[format]' => $this->plain_text_format->format, |
|
2153 ); |
|
2154 $this->drupalPost('user/' . $this->web_user->uid . '/edit', $edit, t('Save')); |
|
2155 |
|
2156 // Verify that values were stored. |
|
2157 $this->assertFieldByName('signature[value]', $edit['signature[value]'], 'Submitted signature text found.'); |
|
2158 $this->assertFieldByName('signature[format]', $edit['signature[format]'], 'Submitted signature format found.'); |
|
2159 |
|
2160 // Create a comment. |
|
2161 $langcode = LANGUAGE_NONE; |
|
2162 $edit = array(); |
|
2163 $edit['subject'] = $this->randomName(8); |
|
2164 $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16); |
|
2165 $this->drupalPost('comment/reply/' . $node->nid, $edit, t('Preview')); |
|
2166 $this->drupalPost(NULL, array(), t('Save')); |
|
2167 |
|
2168 // Get the comment ID. (This technique is the same one used in the Comment |
|
2169 // module's CommentHelperCase test case.) |
|
2170 preg_match('/#comment-([0-9]+)/', $this->getURL(), $match); |
|
2171 $comment_id = $match[1]; |
|
2172 |
|
2173 // Log in as an administrator and edit the comment to use Full HTML, so |
|
2174 // that the comment text itself is not filtered at all. |
|
2175 $this->drupalLogin($this->admin_user); |
|
2176 $edit['comment_body[' . $langcode . '][0][format]'] = $this->full_html_format->format; |
|
2177 $this->drupalPost('comment/' . $comment_id . '/edit', $edit, t('Save')); |
|
2178 |
|
2179 // Assert that the signature did not make it through unfiltered. |
|
2180 $this->drupalGet('node/' . $node->nid); |
|
2181 $this->assertNoRaw($signature_text, 'Unfiltered signature text not found.'); |
|
2182 $this->assertRaw(check_markup($signature_text, $this->plain_text_format->format), 'Filtered signature text found.'); |
|
2183 } |
|
2184 } |
|
2185 |
|
2186 /* |
|
2187 * Test that a user, having editing their own account, can still log in. |
|
2188 */ |
|
2189 class UserEditedOwnAccountTestCase extends DrupalWebTestCase { |
|
2190 |
|
2191 public static function getInfo() { |
|
2192 return array( |
|
2193 'name' => 'User edited own account', |
|
2194 'description' => 'Test user edited own account can still log in.', |
|
2195 'group' => 'User', |
|
2196 ); |
|
2197 } |
|
2198 |
|
2199 function testUserEditedOwnAccount() { |
|
2200 // Change account setting 'Who can register accounts?' to Administrators |
|
2201 // only. |
|
2202 variable_set('user_register', USER_REGISTER_ADMINISTRATORS_ONLY); |
|
2203 |
|
2204 // Create a new user account and log in. |
|
2205 $account = $this->drupalCreateUser(array('change own username')); |
|
2206 $this->drupalLogin($account); |
|
2207 |
|
2208 // Change own username. |
|
2209 $edit = array(); |
|
2210 $edit['name'] = $this->randomName(); |
|
2211 $this->drupalPost('user/' . $account->uid . '/edit', $edit, t('Save')); |
|
2212 |
|
2213 // Log out. |
|
2214 $this->drupalLogout(); |
|
2215 |
|
2216 // Set the new name on the user account and attempt to log back in. |
|
2217 $account->name = $edit['name']; |
|
2218 $this->drupalLogin($account); |
|
2219 } |
|
2220 } |
|
2221 |
|
2222 /** |
|
2223 * Test case to test adding, editing and deleting roles. |
|
2224 */ |
|
2225 class UserRoleAdminTestCase extends DrupalWebTestCase { |
|
2226 |
|
2227 public static function getInfo() { |
|
2228 return array( |
|
2229 'name' => 'User role administration', |
|
2230 'description' => 'Test adding, editing and deleting user roles and changing role weights.', |
|
2231 'group' => 'User', |
|
2232 ); |
|
2233 } |
|
2234 |
|
2235 function setUp() { |
|
2236 parent::setUp(); |
|
2237 $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users')); |
|
2238 } |
|
2239 |
|
2240 /** |
|
2241 * Test adding, renaming and deleting roles. |
|
2242 */ |
|
2243 function testRoleAdministration() { |
|
2244 $this->drupalLogin($this->admin_user); |
|
2245 |
|
2246 // Test adding a role. (In doing so, we use a role name that happens to |
|
2247 // correspond to an integer, to test that the role administration pages |
|
2248 // correctly distinguish between role names and IDs.) |
|
2249 $role_name = '123'; |
|
2250 $edit = array('name' => $role_name); |
|
2251 $this->drupalPost('admin/people/permissions/roles', $edit, t('Add role')); |
|
2252 $this->assertText(t('The role has been added.'), 'The role has been added.'); |
|
2253 $role = user_role_load_by_name($role_name); |
|
2254 $this->assertTrue(is_object($role), 'The role was successfully retrieved from the database.'); |
|
2255 |
|
2256 // Try adding a duplicate role. |
|
2257 $this->drupalPost(NULL, $edit, t('Add role')); |
|
2258 $this->assertRaw(t('The role name %name already exists. Choose another role name.', array('%name' => $role_name)), 'Duplicate role warning displayed.'); |
|
2259 |
|
2260 // Test renaming a role. |
|
2261 $old_name = $role_name; |
|
2262 $role_name = '456'; |
|
2263 $edit = array('name' => $role_name); |
|
2264 $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", $edit, t('Save role')); |
|
2265 $this->assertText(t('The role has been renamed.'), 'The role has been renamed.'); |
|
2266 $this->assertFalse(user_role_load_by_name($old_name), 'The role can no longer be retrieved from the database using its old name.'); |
|
2267 $this->assertTrue(is_object(user_role_load_by_name($role_name)), 'The role can be retrieved from the database using its new name.'); |
|
2268 |
|
2269 // Test deleting the default administrator role. |
|
2270 $role_name = 'administrator'; |
|
2271 $role = user_role_load_by_name($role_name); |
|
2272 $this->drupalPost("admin/people/permissions/roles/edit/{$role->rid}", NULL, t('Delete role')); |
|
2273 $this->drupalPost(NULL, NULL, t('Delete')); |
|
2274 $this->assertText(t('The role has been deleted.'), 'The role has been deleted'); |
|
2275 $this->assertNoLinkByHref("admin/people/permissions/roles/edit/{$role->rid}", 'Role edit link removed.'); |
|
2276 $this->assertFalse(user_role_load_by_name($role_name), 'A deleted role can no longer be loaded.'); |
|
2277 // Make sure this role is no longer configured as the administrator role. |
|
2278 $this->assertNull(variable_get('user_admin_role'), 'The administrator role is no longer configured as the administrator role.'); |
|
2279 |
|
2280 // Make sure that the system-defined roles cannot be edited via the user |
|
2281 // interface. |
|
2282 $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_ANONYMOUS_RID); |
|
2283 $this->assertResponse(403, 'Access denied when trying to edit the built-in anonymous role.'); |
|
2284 $this->drupalGet('admin/people/permissions/roles/edit/' . DRUPAL_AUTHENTICATED_RID); |
|
2285 $this->assertResponse(403, 'Access denied when trying to edit the built-in authenticated role.'); |
|
2286 } |
|
2287 |
|
2288 /** |
|
2289 * Test user role weight change operation. |
|
2290 */ |
|
2291 function testRoleWeightChange() { |
|
2292 $this->drupalLogin($this->admin_user); |
|
2293 |
|
2294 // Pick up a random role and get its weight. |
|
2295 $rid = array_rand(user_roles()); |
|
2296 $role = user_role_load($rid); |
|
2297 $old_weight = $role->weight; |
|
2298 |
|
2299 // Change the role weight and submit the form. |
|
2300 $edit = array('roles['. $rid .'][weight]' => $old_weight + 1); |
|
2301 $this->drupalPost('admin/people/permissions/roles', $edit, t('Save order')); |
|
2302 $this->assertText(t('The role settings have been updated.'), 'The role settings form submitted successfully.'); |
|
2303 |
|
2304 // Retrieve the saved role and compare its weight. |
|
2305 $role = user_role_load($rid); |
|
2306 $new_weight = $role->weight; |
|
2307 $this->assertTrue(($old_weight + 1) == $new_weight, 'Role weight updated successfully.'); |
|
2308 } |
|
2309 } |
|
2310 |
|
2311 /** |
|
2312 * Test user token replacement in strings. |
|
2313 */ |
|
2314 class UserTokenReplaceTestCase extends DrupalWebTestCase { |
|
2315 public static function getInfo() { |
|
2316 return array( |
|
2317 'name' => 'User token replacement', |
|
2318 'description' => 'Generates text using placeholders for dummy content to check user token replacement.', |
|
2319 'group' => 'User', |
|
2320 ); |
|
2321 } |
|
2322 |
|
2323 /** |
|
2324 * Creates a user, then tests the tokens generated from it. |
|
2325 */ |
|
2326 function testUserTokenReplacement() { |
|
2327 global $language; |
|
2328 $url_options = array( |
|
2329 'absolute' => TRUE, |
|
2330 'language' => $language, |
|
2331 ); |
|
2332 |
|
2333 // Create two users and log them in one after another. |
|
2334 $user1 = $this->drupalCreateUser(array()); |
|
2335 $user2 = $this->drupalCreateUser(array()); |
|
2336 $this->drupalLogin($user1); |
|
2337 $this->drupalLogout(); |
|
2338 $this->drupalLogin($user2); |
|
2339 |
|
2340 $account = user_load($user1->uid); |
|
2341 $global_account = user_load($GLOBALS['user']->uid); |
|
2342 |
|
2343 // Generate and test sanitized tokens. |
|
2344 $tests = array(); |
|
2345 $tests['[user:uid]'] = $account->uid; |
|
2346 $tests['[user:name]'] = check_plain(format_username($account)); |
|
2347 $tests['[user:mail]'] = check_plain($account->mail); |
|
2348 $tests['[user:url]'] = url("user/$account->uid", $url_options); |
|
2349 $tests['[user:edit-url]'] = url("user/$account->uid/edit", $url_options); |
|
2350 $tests['[user:last-login]'] = format_date($account->login, 'medium', '', NULL, $language->language); |
|
2351 $tests['[user:last-login:short]'] = format_date($account->login, 'short', '', NULL, $language->language); |
|
2352 $tests['[user:created]'] = format_date($account->created, 'medium', '', NULL, $language->language); |
|
2353 $tests['[user:created:short]'] = format_date($account->created, 'short', '', NULL, $language->language); |
|
2354 $tests['[current-user:name]'] = check_plain(format_username($global_account)); |
|
2355 |
|
2356 // Test to make sure that we generated something for each token. |
|
2357 $this->assertFalse(in_array(0, array_map('strlen', $tests)), 'No empty tokens generated.'); |
|
2358 |
|
2359 foreach ($tests as $input => $expected) { |
|
2360 $output = token_replace($input, array('user' => $account), array('language' => $language)); |
|
2361 $this->assertEqual($output, $expected, format_string('Sanitized user token %token replaced.', array('%token' => $input))); |
|
2362 } |
|
2363 |
|
2364 // Generate and test unsanitized tokens. |
|
2365 $tests['[user:name]'] = format_username($account); |
|
2366 $tests['[user:mail]'] = $account->mail; |
|
2367 $tests['[current-user:name]'] = format_username($global_account); |
|
2368 |
|
2369 foreach ($tests as $input => $expected) { |
|
2370 $output = token_replace($input, array('user' => $account), array('language' => $language, 'sanitize' => FALSE)); |
|
2371 $this->assertEqual($output, $expected, format_string('Unsanitized user token %token replaced.', array('%token' => $input))); |
|
2372 } |
|
2373 } |
|
2374 } |
|
2375 |
|
2376 /** |
|
2377 * Test user search. |
|
2378 */ |
|
2379 class UserUserSearchTestCase extends DrupalWebTestCase { |
|
2380 public static function getInfo() { |
|
2381 return array( |
|
2382 'name' => 'User search', |
|
2383 'description' => 'Tests the user search page and verifies that sensitive information is hidden from unauthorized users.', |
|
2384 'group' => 'User', |
|
2385 ); |
|
2386 } |
|
2387 |
|
2388 function testUserSearch() { |
|
2389 $user1 = $this->drupalCreateUser(array('access user profiles', 'search content', 'use advanced search')); |
|
2390 $this->drupalLogin($user1); |
|
2391 $keys = $user1->mail; |
|
2392 $edit = array('keys' => $keys); |
|
2393 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2394 $this->assertNoText($keys); |
|
2395 $this->drupalLogout(); |
|
2396 |
|
2397 $user2 = $this->drupalCreateUser(array('administer users', 'access user profiles', 'search content', 'use advanced search')); |
|
2398 $this->drupalLogin($user2); |
|
2399 $keys = $user2->mail; |
|
2400 $edit = array('keys' => $keys); |
|
2401 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2402 $this->assertText($keys); |
|
2403 |
|
2404 // Verify that wildcard search works. |
|
2405 $keys = $user1->name; |
|
2406 $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2); |
|
2407 $edit = array('keys' => $keys); |
|
2408 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2409 $this->assertText($user1->name, 'Search for username wildcard resulted in user name on page for administrative user.'); |
|
2410 |
|
2411 // Verify that wildcard search works for email. |
|
2412 $keys = $user1->mail; |
|
2413 $keys = substr($keys, 0, 2) . '*' . substr($keys, 4, 2); |
|
2414 $edit = array('keys' => $keys); |
|
2415 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2416 $this->assertText($user1->name, 'Search for email wildcard resulted in user name on page for administrative user.'); |
|
2417 |
|
2418 // Create a blocked user. |
|
2419 $blocked_user = $this->drupalCreateUser(); |
|
2420 $edit = array('status' => 0); |
|
2421 $blocked_user = user_save($blocked_user, $edit); |
|
2422 |
|
2423 // Verify that users with "administer users" permissions can see blocked |
|
2424 // accounts in search results. |
|
2425 $edit = array('keys' => $blocked_user->name); |
|
2426 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2427 $this->assertText($blocked_user->name, 'Blocked users are listed on the user search results for users with the "administer users" permission.'); |
|
2428 |
|
2429 // Verify that users without "administer users" permissions do not see |
|
2430 // blocked accounts in search results. |
|
2431 $this->drupalLogin($user1); |
|
2432 $edit = array('keys' => $blocked_user->name); |
|
2433 $this->drupalPost('search/user/', $edit, t('Search')); |
|
2434 $this->assertNoText($blocked_user->name, 'Blocked users are hidden from the user search results.'); |
|
2435 |
|
2436 $this->drupalLogout(); |
|
2437 } |
|
2438 } |
|
2439 |
|
2440 /** |
|
2441 * Test role assignment. |
|
2442 */ |
|
2443 class UserRolesAssignmentTestCase extends DrupalWebTestCase { |
|
2444 protected $admin_user; |
|
2445 |
|
2446 public static function getInfo() { |
|
2447 return array( |
|
2448 'name' => 'Role assignment', |
|
2449 'description' => 'Tests that users can be assigned and unassigned roles.', |
|
2450 'group' => 'User' |
|
2451 ); |
|
2452 } |
|
2453 |
|
2454 function setUp() { |
|
2455 parent::setUp(); |
|
2456 $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'administer users')); |
|
2457 $this->drupalLogin($this->admin_user); |
|
2458 } |
|
2459 |
|
2460 /** |
|
2461 * Tests that a user can be assigned a role and that the role can be removed |
|
2462 * again. |
|
2463 */ |
|
2464 function testAssignAndRemoveRole() { |
|
2465 $rid = $this->drupalCreateRole(array('administer content types')); |
|
2466 $account = $this->drupalCreateUser(); |
|
2467 |
|
2468 // Assign the role to the user. |
|
2469 $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => $rid), t('Save')); |
|
2470 $this->assertText(t('The changes have been saved.')); |
|
2471 $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.'); |
|
2472 $this->userLoadAndCheckRoleAssigned($account, $rid); |
|
2473 |
|
2474 // Remove the role from the user. |
|
2475 $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save')); |
|
2476 $this->assertText(t('The changes have been saved.')); |
|
2477 $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.'); |
|
2478 $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE); |
|
2479 } |
|
2480 |
|
2481 /** |
|
2482 * Tests that when creating a user the role can be assigned. And that it can |
|
2483 * be removed again. |
|
2484 */ |
|
2485 function testCreateUserWithRole() { |
|
2486 $rid = $this->drupalCreateRole(array('administer content types')); |
|
2487 // Create a new user and add the role at the same time. |
|
2488 $edit = array( |
|
2489 'name' => $this->randomName(), |
|
2490 'mail' => $this->randomName() . '@example.com', |
|
2491 'pass[pass1]' => $pass = $this->randomString(), |
|
2492 'pass[pass2]' => $pass, |
|
2493 "roles[$rid]" => $rid, |
|
2494 ); |
|
2495 $this->drupalPost('admin/people/create', $edit, t('Create new account')); |
|
2496 $this->assertText(t('Created a new user account for !name.', array('!name' => $edit['name']))); |
|
2497 // Get the newly added user. |
|
2498 $account = user_load_by_name($edit['name']); |
|
2499 |
|
2500 $this->drupalGet('user/' . $account->uid . '/edit'); |
|
2501 $this->assertFieldChecked('edit-roles-' . $rid, 'Role is assigned.'); |
|
2502 $this->userLoadAndCheckRoleAssigned($account, $rid); |
|
2503 |
|
2504 // Remove the role again. |
|
2505 $this->drupalPost('user/' . $account->uid . '/edit', array("roles[$rid]" => FALSE), t('Save')); |
|
2506 $this->assertText(t('The changes have been saved.')); |
|
2507 $this->assertNoFieldChecked('edit-roles-' . $rid, 'Role is removed from user.'); |
|
2508 $this->userLoadAndCheckRoleAssigned($account, $rid, FALSE); |
|
2509 } |
|
2510 |
|
2511 /** |
|
2512 * Check role on user object. |
|
2513 * |
|
2514 * @param object $account |
|
2515 * The user account to check. |
|
2516 * @param string $rid |
|
2517 * The role ID to search for. |
|
2518 * @param bool $is_assigned |
|
2519 * (optional) Whether to assert that $rid exists (TRUE) or not (FALSE). |
|
2520 * Defaults to TRUE. |
|
2521 */ |
|
2522 private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) { |
|
2523 $account = user_load($account->uid, TRUE); |
|
2524 if ($is_assigned) { |
|
2525 $this->assertTrue(array_key_exists($rid, $account->roles), 'The role is present in the user object.'); |
|
2526 } |
|
2527 else { |
|
2528 $this->assertFalse(array_key_exists($rid, $account->roles), 'The role is not present in the user object.'); |
|
2529 } |
|
2530 } |
|
2531 } |
|
2532 |
|
2533 |
|
2534 /** |
|
2535 * Unit test for authmap assignment. |
|
2536 */ |
|
2537 class UserAuthmapAssignmentTestCase extends DrupalWebTestCase { |
|
2538 public static function getInfo() { |
|
2539 return array( |
|
2540 'name' => 'Authmap assignment', |
|
2541 'description' => 'Tests that users can be assigned and unassigned authmaps.', |
|
2542 'group' => 'User' |
|
2543 ); |
|
2544 } |
|
2545 |
|
2546 /** |
|
2547 * Test authmap assignment and retrieval. |
|
2548 */ |
|
2549 function testAuthmapAssignment() { |
|
2550 $account = $this->drupalCreateUser(); |
|
2551 |
|
2552 // Assign authmaps to the user. |
|
2553 $authmaps = array( |
|
2554 'authname_poll' => 'external username one', |
|
2555 'authname_book' => 'external username two', |
|
2556 ); |
|
2557 user_set_authmaps($account, $authmaps); |
|
2558 |
|
2559 // Test for expected authmaps. |
|
2560 $expected_authmaps = array( |
|
2561 'external username one' => array( |
|
2562 'poll' => 'external username one', |
|
2563 ), |
|
2564 'external username two' => array( |
|
2565 'book' => 'external username two', |
|
2566 ), |
|
2567 ); |
|
2568 foreach ($expected_authmaps as $authname => $expected_output) { |
|
2569 $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname))); |
|
2570 } |
|
2571 |
|
2572 // Remove authmap for module poll, add authmap for module blog. |
|
2573 $authmaps = array( |
|
2574 'authname_poll' => NULL, |
|
2575 'authname_blog' => 'external username three', |
|
2576 ); |
|
2577 user_set_authmaps($account, $authmaps); |
|
2578 |
|
2579 // Assert that external username one does not have authmaps. |
|
2580 $remove_username = 'external username one'; |
|
2581 unset($expected_authmaps[$remove_username]); |
|
2582 $this->assertFalse(user_get_authmaps($remove_username), format_string('Authmap for %authname was removed.', array('%authname' => $remove_username))); |
|
2583 |
|
2584 // Assert that a new authmap was created for external username three, and |
|
2585 // existing authmaps for external username two were unchanged. |
|
2586 $expected_authmaps['external username three'] = array('blog' => 'external username three'); |
|
2587 foreach ($expected_authmaps as $authname => $expected_output) { |
|
2588 $this->assertIdentical(user_get_authmaps($authname), $expected_output, format_string('Authmap for authname %authname was set correctly.', array('%authname' => $authname))); |
|
2589 } |
|
2590 } |
|
2591 } |
|
2592 |
|
2593 /** |
|
2594 * Tests user_validate_current_pass on a custom form. |
|
2595 */ |
|
2596 class UserValidateCurrentPassCustomForm extends DrupalWebTestCase { |
|
2597 |
|
2598 public static function getInfo() { |
|
2599 return array( |
|
2600 'name' => 'User validate current pass custom form', |
|
2601 'description' => 'Test that user_validate_current_pass is usable on a custom form.', |
|
2602 'group' => 'User', |
|
2603 ); |
|
2604 } |
|
2605 |
|
2606 /** |
|
2607 * User with permission to view content. |
|
2608 */ |
|
2609 protected $accessUser; |
|
2610 |
|
2611 /** |
|
2612 * User permission to administer users. |
|
2613 */ |
|
2614 protected $adminUser; |
|
2615 |
|
2616 function setUp() { |
|
2617 parent::setUp('user_form_test'); |
|
2618 // Create two users |
|
2619 $this->accessUser = $this->drupalCreateUser(array('access content')); |
|
2620 $this->adminUser = $this->drupalCreateUser(array('administer users')); |
|
2621 } |
|
2622 |
|
2623 /** |
|
2624 * Tests that user_validate_current_pass can be reused on a custom form. |
|
2625 */ |
|
2626 function testUserValidateCurrentPassCustomForm() { |
|
2627 $this->drupalLogin($this->adminUser); |
|
2628 |
|
2629 // Submit the custom form with the admin user using the access user's password. |
|
2630 $edit = array(); |
|
2631 $edit['user_form_test_field'] = $this->accessUser->name; |
|
2632 $edit['current_pass'] = $this->accessUser->pass_raw; |
|
2633 $this->drupalPost('user_form_test_current_password/' . $this->accessUser->uid, $edit, t('Test')); |
|
2634 $this->assertText(t('The password has been validated and the form submitted successfully.')); |
|
2635 } |
|
2636 } |