|
1 <?php |
|
2 |
|
3 /** |
|
4 * @file |
|
5 * This file contains tests for the Update Manager module. |
|
6 * |
|
7 * The overarching methodology of these tests is we need to compare a given |
|
8 * state of installed modules and themes (e.g., version, project grouping, |
|
9 * timestamps, etc) against a current state of what the release history XML |
|
10 * files we fetch say is available. We have dummy XML files (in the |
|
11 * modules/update/tests directory) that describe various scenarios of what's |
|
12 * available for different test projects, and we have dummy .info file data |
|
13 * (specified via hook_system_info_alter() in the update_test helper module) |
|
14 * describing what's currently installed. Each test case defines a set of |
|
15 * projects to install, their current state (via the 'update_test_system_info' |
|
16 * variable) and the desired available update data (via the |
|
17 * 'update_test_xml_map' variable), and then performs a series of assertions |
|
18 * that the report matches our expectations given the specific initial state and |
|
19 * availability scenario. |
|
20 */ |
|
21 |
|
22 /** |
|
23 * Defines some shared functions used by all update tests. |
|
24 */ |
|
25 class UpdateTestHelper extends DrupalWebTestCase { |
|
26 |
|
27 /** |
|
28 * Refreshes the update status based on the desired available update scenario. |
|
29 * |
|
30 * @param $xml_map |
|
31 * Array that maps project names to availability scenarios to fetch. The key |
|
32 * '#all' is used if a project-specific mapping is not defined. |
|
33 * @param $url |
|
34 * (optional) A string containing the URL to fetch update data from. |
|
35 * Defaults to 'update-test'. |
|
36 * |
|
37 * @see update_test_mock_page() |
|
38 */ |
|
39 protected function refreshUpdateStatus($xml_map, $url = 'update-test') { |
|
40 // Tell the Update Manager module to fetch from the URL provided by |
|
41 // update_test module. |
|
42 variable_set('update_fetch_url', url($url, array('absolute' => TRUE))); |
|
43 // Save the map for update_test_mock_page() to use. |
|
44 variable_set('update_test_xml_map', $xml_map); |
|
45 // Manually check the update status. |
|
46 $this->drupalGet('admin/reports/updates/check'); |
|
47 } |
|
48 |
|
49 /** |
|
50 * Runs a series of assertions that are applicable to all update statuses. |
|
51 */ |
|
52 protected function standardTests() { |
|
53 $this->assertRaw('<h3>' . t('Drupal core') . '</h3>'); |
|
54 $this->assertRaw(l(t('Drupal'), 'http://example.com/project/drupal'), 'Link to the Drupal project appears.'); |
|
55 $this->assertNoText(t('No available releases found')); |
|
56 } |
|
57 |
|
58 } |
|
59 |
|
60 /** |
|
61 * Tests behavior related to discovering and listing updates to Drupal core. |
|
62 */ |
|
63 class UpdateCoreTestCase extends UpdateTestHelper { |
|
64 |
|
65 public static function getInfo() { |
|
66 return array( |
|
67 'name' => 'Update core functionality', |
|
68 'description' => 'Tests the Update Manager module through a series of functional tests using mock XML data.', |
|
69 'group' => 'Update', |
|
70 ); |
|
71 } |
|
72 |
|
73 function setUp() { |
|
74 parent::setUp('update_test', 'update'); |
|
75 $admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer modules')); |
|
76 $this->drupalLogin($admin_user); |
|
77 } |
|
78 |
|
79 /** |
|
80 * Tests the Update Manager module when no updates are available. |
|
81 */ |
|
82 function testNoUpdatesAvailable() { |
|
83 $this->setSystemInfo7_0(); |
|
84 $this->refreshUpdateStatus(array('drupal' => '0')); |
|
85 $this->standardTests(); |
|
86 $this->assertText(t('Up to date')); |
|
87 $this->assertNoText(t('Update available')); |
|
88 $this->assertNoText(t('Security update required!')); |
|
89 } |
|
90 |
|
91 /** |
|
92 * Tests the Update Manager module when one normal update is available. |
|
93 */ |
|
94 function testNormalUpdateAvailable() { |
|
95 $this->setSystemInfo7_0(); |
|
96 $this->refreshUpdateStatus(array('drupal' => '1')); |
|
97 $this->standardTests(); |
|
98 $this->assertNoText(t('Up to date')); |
|
99 $this->assertText(t('Update available')); |
|
100 $this->assertNoText(t('Security update required!')); |
|
101 $this->assertRaw(l('7.1', 'http://example.com/drupal-7-1-release'), 'Link to release appears.'); |
|
102 $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-1.tar.gz'), 'Link to download appears.'); |
|
103 $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-1-release'), 'Link to release notes appears.'); |
|
104 } |
|
105 |
|
106 /** |
|
107 * Tests the Update Manager module when a security update is available. |
|
108 */ |
|
109 function testSecurityUpdateAvailable() { |
|
110 $this->setSystemInfo7_0(); |
|
111 $this->refreshUpdateStatus(array('drupal' => '2-sec')); |
|
112 $this->standardTests(); |
|
113 $this->assertNoText(t('Up to date')); |
|
114 $this->assertNoText(t('Update available')); |
|
115 $this->assertText(t('Security update required!')); |
|
116 $this->assertRaw(l('7.2', 'http://example.com/drupal-7-2-release'), 'Link to release appears.'); |
|
117 $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-2.tar.gz'), 'Link to download appears.'); |
|
118 $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-2-release'), 'Link to release notes appears.'); |
|
119 } |
|
120 |
|
121 /** |
|
122 * Ensures proper results where there are date mismatches among modules. |
|
123 */ |
|
124 function testDatestampMismatch() { |
|
125 $system_info = array( |
|
126 '#all' => array( |
|
127 // We need to think we're running a -dev snapshot to see dates. |
|
128 'version' => '7.0-dev', |
|
129 'datestamp' => time(), |
|
130 ), |
|
131 'block' => array( |
|
132 // This is 2001-09-09 01:46:40 GMT, so test for "2001-Sep-". |
|
133 'datestamp' => '1000000000', |
|
134 ), |
|
135 ); |
|
136 variable_set('update_test_system_info', $system_info); |
|
137 $this->refreshUpdateStatus(array('drupal' => 'dev')); |
|
138 $this->assertNoText(t('2001-Sep-')); |
|
139 $this->assertText(t('Up to date')); |
|
140 $this->assertNoText(t('Update available')); |
|
141 $this->assertNoText(t('Security update required!')); |
|
142 } |
|
143 |
|
144 /** |
|
145 * Checks that running cron updates the list of available updates. |
|
146 */ |
|
147 function testModulePageRunCron() { |
|
148 $this->setSystemInfo7_0(); |
|
149 variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE))); |
|
150 variable_set('update_test_xml_map', array('drupal' => '0')); |
|
151 |
|
152 $this->cronRun(); |
|
153 $this->drupalGet('admin/modules'); |
|
154 $this->assertNoText(t('No update information available.')); |
|
155 } |
|
156 |
|
157 /** |
|
158 * Checks the messages at admin/modules when the site is up to date. |
|
159 */ |
|
160 function testModulePageUpToDate() { |
|
161 $this->setSystemInfo7_0(); |
|
162 // Instead of using refreshUpdateStatus(), set these manually. |
|
163 variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE))); |
|
164 variable_set('update_test_xml_map', array('drupal' => '0')); |
|
165 |
|
166 $this->drupalGet('admin/reports/updates'); |
|
167 $this->clickLink(t('Check manually')); |
|
168 $this->assertText(t('Checked available update data for one project.')); |
|
169 $this->drupalGet('admin/modules'); |
|
170 $this->assertNoText(t('There are updates available for your version of Drupal.')); |
|
171 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
172 } |
|
173 |
|
174 /** |
|
175 * Checks the messages at admin/modules when an update is missing. |
|
176 */ |
|
177 function testModulePageRegularUpdate() { |
|
178 $this->setSystemInfo7_0(); |
|
179 // Instead of using refreshUpdateStatus(), set these manually. |
|
180 variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE))); |
|
181 variable_set('update_test_xml_map', array('drupal' => '1')); |
|
182 |
|
183 $this->drupalGet('admin/reports/updates'); |
|
184 $this->clickLink(t('Check manually')); |
|
185 $this->assertText(t('Checked available update data for one project.')); |
|
186 $this->drupalGet('admin/modules'); |
|
187 $this->assertText(t('There are updates available for your version of Drupal.')); |
|
188 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
189 } |
|
190 |
|
191 /** |
|
192 * Checks the messages at admin/modules when a security update is missing. |
|
193 */ |
|
194 function testModulePageSecurityUpdate() { |
|
195 $this->setSystemInfo7_0(); |
|
196 // Instead of using refreshUpdateStatus(), set these manually. |
|
197 variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE))); |
|
198 variable_set('update_test_xml_map', array('drupal' => '2-sec')); |
|
199 |
|
200 $this->drupalGet('admin/reports/updates'); |
|
201 $this->clickLink(t('Check manually')); |
|
202 $this->assertText(t('Checked available update data for one project.')); |
|
203 $this->drupalGet('admin/modules'); |
|
204 $this->assertNoText(t('There are updates available for your version of Drupal.')); |
|
205 $this->assertText(t('There is a security update available for your version of Drupal.')); |
|
206 |
|
207 // Make sure admin/appearance warns you you're missing a security update. |
|
208 $this->drupalGet('admin/appearance'); |
|
209 $this->assertNoText(t('There are updates available for your version of Drupal.')); |
|
210 $this->assertText(t('There is a security update available for your version of Drupal.')); |
|
211 |
|
212 // Make sure duplicate messages don't appear on Update status pages. |
|
213 $this->drupalGet('admin/reports/status'); |
|
214 // We're expecting "There is a security update..." inside the status report |
|
215 // itself, but the drupal_set_message() appears as an li so we can prefix |
|
216 // with that and search for the raw HTML. |
|
217 $this->assertNoRaw('<li>' . t('There is a security update available for your version of Drupal.')); |
|
218 |
|
219 $this->drupalGet('admin/reports/updates'); |
|
220 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
221 |
|
222 $this->drupalGet('admin/reports/updates/settings'); |
|
223 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
224 } |
|
225 |
|
226 /** |
|
227 * Tests the Update Manager module when the update server returns 503 errors. |
|
228 */ |
|
229 function testServiceUnavailable() { |
|
230 $this->refreshUpdateStatus(array(), '503-error'); |
|
231 // Ensure that no "Warning: SimpleXMLElement..." parse errors are found. |
|
232 $this->assertNoText('SimpleXMLElement'); |
|
233 $this->assertUniqueText(t('Failed to get available update data for one project.')); |
|
234 } |
|
235 |
|
236 /** |
|
237 * Tests that exactly one fetch task per project is created and not more. |
|
238 */ |
|
239 function testFetchTasks() { |
|
240 $projecta = array( |
|
241 'name' => 'aaa_update_test', |
|
242 ); |
|
243 $projectb = array( |
|
244 'name' => 'bbb_update_test', |
|
245 ); |
|
246 $queue = DrupalQueue::get('update_fetch_tasks'); |
|
247 $this->assertEqual($queue->numberOfItems(), 0, 'Queue is empty'); |
|
248 update_create_fetch_task($projecta); |
|
249 $this->assertEqual($queue->numberOfItems(), 1, 'Queue contains one item'); |
|
250 update_create_fetch_task($projectb); |
|
251 $this->assertEqual($queue->numberOfItems(), 2, 'Queue contains two items'); |
|
252 // Try to add project a again. |
|
253 update_create_fetch_task($projecta); |
|
254 $this->assertEqual($queue->numberOfItems(), 2, 'Queue still contains two items'); |
|
255 |
|
256 // Clear cache and try again. |
|
257 _update_cache_clear(); |
|
258 drupal_static_reset('_update_create_fetch_task'); |
|
259 update_create_fetch_task($projecta); |
|
260 $this->assertEqual($queue->numberOfItems(), 2, 'Queue contains two items'); |
|
261 } |
|
262 |
|
263 /** |
|
264 * Sets the version to 7.0 when no project-specific mapping is defined. |
|
265 */ |
|
266 protected function setSystemInfo7_0() { |
|
267 $setting = array( |
|
268 '#all' => array( |
|
269 'version' => '7.0', |
|
270 ), |
|
271 ); |
|
272 variable_set('update_test_system_info', $setting); |
|
273 } |
|
274 |
|
275 } |
|
276 |
|
277 /** |
|
278 * Tests behavior related to handling updates to contributed modules and themes. |
|
279 */ |
|
280 class UpdateTestContribCase extends UpdateTestHelper { |
|
281 |
|
282 public static function getInfo() { |
|
283 return array( |
|
284 'name' => 'Update contrib functionality', |
|
285 'description' => 'Tests how the Update Manager module handles contributed modules and themes in a series of functional tests using mock XML data.', |
|
286 'group' => 'Update', |
|
287 ); |
|
288 } |
|
289 |
|
290 function setUp() { |
|
291 parent::setUp('update_test', 'update', 'aaa_update_test', 'bbb_update_test', 'ccc_update_test'); |
|
292 $admin_user = $this->drupalCreateUser(array('administer site configuration')); |
|
293 $this->drupalLogin($admin_user); |
|
294 } |
|
295 |
|
296 /** |
|
297 * Tests when there is no available release data for a contrib module. |
|
298 */ |
|
299 function testNoReleasesAvailable() { |
|
300 $system_info = array( |
|
301 '#all' => array( |
|
302 'version' => '7.0', |
|
303 ), |
|
304 'aaa_update_test' => array( |
|
305 'project' => 'aaa_update_test', |
|
306 'version' => '7.x-1.0', |
|
307 'hidden' => FALSE, |
|
308 ), |
|
309 ); |
|
310 variable_set('update_test_system_info', $system_info); |
|
311 $this->refreshUpdateStatus(array('drupal' => '0', 'aaa_update_test' => 'no-releases')); |
|
312 $this->drupalGet('admin/reports/updates'); |
|
313 // Cannot use $this->standardTests() because we need to check for the |
|
314 // 'No available releases found' string. |
|
315 $this->assertRaw('<h3>' . t('Drupal core') . '</h3>'); |
|
316 $this->assertRaw(l(t('Drupal'), 'http://example.com/project/drupal')); |
|
317 $this->assertText(t('Up to date')); |
|
318 $this->assertRaw('<h3>' . t('Modules') . '</h3>'); |
|
319 $this->assertNoText(t('Update available')); |
|
320 $this->assertText(t('No available releases found')); |
|
321 $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test')); |
|
322 } |
|
323 |
|
324 /** |
|
325 * Tests the basic functionality of a contrib module on the status report. |
|
326 */ |
|
327 function testUpdateContribBasic() { |
|
328 $system_info = array( |
|
329 '#all' => array( |
|
330 'version' => '7.0', |
|
331 ), |
|
332 'aaa_update_test' => array( |
|
333 'project' => 'aaa_update_test', |
|
334 'version' => '7.x-1.0', |
|
335 'hidden' => FALSE, |
|
336 ), |
|
337 ); |
|
338 variable_set('update_test_system_info', $system_info); |
|
339 $this->refreshUpdateStatus( |
|
340 array( |
|
341 'drupal' => '0', |
|
342 'aaa_update_test' => '1_0', |
|
343 ) |
|
344 ); |
|
345 $this->standardTests(); |
|
346 $this->assertText(t('Up to date')); |
|
347 $this->assertRaw('<h3>' . t('Modules') . '</h3>'); |
|
348 $this->assertNoText(t('Update available')); |
|
349 $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.'); |
|
350 } |
|
351 |
|
352 /** |
|
353 * Tests that contrib projects are ordered by project name. |
|
354 * |
|
355 * If a project contains multiple modules, we want to make sure that the |
|
356 * available updates report is sorted by the parent project names, not by the |
|
357 * names of the modules included in each project. In this test case, we have |
|
358 * two contrib projects, "BBB Update test" and "CCC Update test". However, we |
|
359 * have a module called "aaa_update_test" that's part of the "CCC Update test" |
|
360 * project. We need to make sure that we see the "BBB" project before the |
|
361 * "CCC" project, even though "CCC" includes a module that's processed first |
|
362 * if you sort alphabetically by module name (which is the order we see things |
|
363 * inside system_rebuild_module_data() for example). |
|
364 */ |
|
365 function testUpdateContribOrder() { |
|
366 // We want core to be version 7.0. |
|
367 $system_info = array( |
|
368 '#all' => array( |
|
369 'version' => '7.0', |
|
370 ), |
|
371 // All the rest should be visible as contrib modules at version 7.x-1.0. |
|
372 |
|
373 // aaa_update_test needs to be part of the "CCC Update test" project, |
|
374 // which would throw off the report if we weren't properly sorting by |
|
375 // the project names. |
|
376 'aaa_update_test' => array( |
|
377 'project' => 'ccc_update_test', |
|
378 'version' => '7.x-1.0', |
|
379 'hidden' => FALSE, |
|
380 ), |
|
381 |
|
382 // This should be its own project, and listed first on the report. |
|
383 'bbb_update_test' => array( |
|
384 'project' => 'bbb_update_test', |
|
385 'version' => '7.x-1.0', |
|
386 'hidden' => FALSE, |
|
387 ), |
|
388 |
|
389 // This will contain both aaa_update_test and ccc_update_test, and |
|
390 // should come after the bbb_update_test project. |
|
391 'ccc_update_test' => array( |
|
392 'project' => 'ccc_update_test', |
|
393 'version' => '7.x-1.0', |
|
394 'hidden' => FALSE, |
|
395 ), |
|
396 ); |
|
397 variable_set('update_test_system_info', $system_info); |
|
398 $this->refreshUpdateStatus(array('drupal' => '0', '#all' => '1_0')); |
|
399 $this->standardTests(); |
|
400 // We're expecting the report to say all projects are up to date. |
|
401 $this->assertText(t('Up to date')); |
|
402 $this->assertNoText(t('Update available')); |
|
403 // We want to see all 3 module names listed, since they'll show up either |
|
404 // as project names or as modules under the "Includes" listing. |
|
405 $this->assertText(t('AAA Update test')); |
|
406 $this->assertText(t('BBB Update test')); |
|
407 $this->assertText(t('CCC Update test')); |
|
408 // We want aaa_update_test included in the ccc_update_test project, not as |
|
409 // its own project on the report. |
|
410 $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project does not appear.'); |
|
411 // The other two should be listed as projects. |
|
412 $this->assertRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), 'Link to bbb_update_test project appears.'); |
|
413 $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), 'Link to bbb_update_test project appears.'); |
|
414 |
|
415 // We want to make sure we see the BBB project before the CCC project. |
|
416 // Instead of just searching for 'BBB Update test' or something, we want |
|
417 // to use the full markup that starts the project entry itself, so that |
|
418 // we're really testing that the project listings are in the right order. |
|
419 $bbb_project_link = '<div class="project"><a href="http://example.com/project/bbb_update_test">BBB Update test</a>'; |
|
420 $ccc_project_link = '<div class="project"><a href="http://example.com/project/ccc_update_test">CCC Update test</a>'; |
|
421 $this->assertTrue(strpos($this->drupalGetContent(), $bbb_project_link) < strpos($this->drupalGetContent(), $ccc_project_link), "'BBB Update test' project is listed before the 'CCC Update test' project"); |
|
422 } |
|
423 |
|
424 /** |
|
425 * Tests that subthemes are notified about security updates for base themes. |
|
426 */ |
|
427 function testUpdateBaseThemeSecurityUpdate() { |
|
428 // Only enable the subtheme, not the base theme. |
|
429 db_update('system') |
|
430 ->fields(array('status' => 1)) |
|
431 ->condition('type', 'theme') |
|
432 ->condition('name', 'update_test_subtheme') |
|
433 ->execute(); |
|
434 |
|
435 // Define the initial state for core and the subtheme. |
|
436 $system_info = array( |
|
437 // We want core to be version 7.0. |
|
438 '#all' => array( |
|
439 'version' => '7.0', |
|
440 ), |
|
441 // Show the update_test_basetheme |
|
442 'update_test_basetheme' => array( |
|
443 'project' => 'update_test_basetheme', |
|
444 'version' => '7.x-1.0', |
|
445 'hidden' => FALSE, |
|
446 ), |
|
447 // Show the update_test_subtheme |
|
448 'update_test_subtheme' => array( |
|
449 'project' => 'update_test_subtheme', |
|
450 'version' => '7.x-1.0', |
|
451 'hidden' => FALSE, |
|
452 ), |
|
453 ); |
|
454 variable_set('update_test_system_info', $system_info); |
|
455 $xml_mapping = array( |
|
456 'drupal' => '0', |
|
457 'update_test_subtheme' => '1_0', |
|
458 'update_test_basetheme' => '1_1-sec', |
|
459 ); |
|
460 $this->refreshUpdateStatus($xml_mapping); |
|
461 $this->assertText(t('Security update required!')); |
|
462 $this->assertRaw(l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'), 'Link to the Update test base theme project appears.'); |
|
463 } |
|
464 |
|
465 /** |
|
466 * Tests that the admin theme is always notified about security updates. |
|
467 */ |
|
468 function testUpdateAdminThemeSecurityUpdate() { |
|
469 // Disable the admin theme. |
|
470 db_update('system') |
|
471 ->fields(array('status' => 0)) |
|
472 ->condition('type', 'theme') |
|
473 ->condition('name', 'update_test_%', 'LIKE') |
|
474 ->execute(); |
|
475 |
|
476 variable_set('admin_theme', 'update_test_admintheme'); |
|
477 |
|
478 // Define the initial state for core and the themes. |
|
479 $system_info = array( |
|
480 '#all' => array( |
|
481 'version' => '7.0', |
|
482 ), |
|
483 'update_test_admintheme' => array( |
|
484 'project' => 'update_test_admintheme', |
|
485 'version' => '7.x-1.0', |
|
486 'hidden' => FALSE, |
|
487 ), |
|
488 'update_test_basetheme' => array( |
|
489 'project' => 'update_test_basetheme', |
|
490 'version' => '7.x-1.1', |
|
491 'hidden' => FALSE, |
|
492 ), |
|
493 'update_test_subtheme' => array( |
|
494 'project' => 'update_test_subtheme', |
|
495 'version' => '7.x-1.0', |
|
496 'hidden' => FALSE, |
|
497 ), |
|
498 ); |
|
499 variable_set('update_test_system_info', $system_info); |
|
500 variable_set('update_check_disabled', FALSE); |
|
501 $xml_mapping = array( |
|
502 // This is enough because we don't check the update status of the admin |
|
503 // theme. We want to check that the admin theme is included in the list. |
|
504 'drupal' => '0', |
|
505 ); |
|
506 $this->refreshUpdateStatus($xml_mapping); |
|
507 // The admin theme is displayed even if it's disabled. |
|
508 $this->assertText('update_test_admintheme', "The admin theme is checked for update even if it's disabled"); |
|
509 // The other disabled themes are not displayed. |
|
510 $this->assertNoText('update_test_basetheme', 'Disabled theme is not checked for update in the list.'); |
|
511 $this->assertNoText('update_test_subtheme', 'Disabled theme is not checked for update in the list.'); |
|
512 } |
|
513 |
|
514 /** |
|
515 * Tests that disabled themes are only shown when desired. |
|
516 */ |
|
517 function testUpdateShowDisabledThemes() { |
|
518 // Make sure all the update_test_* themes are disabled. |
|
519 db_update('system') |
|
520 ->fields(array('status' => 0)) |
|
521 ->condition('type', 'theme') |
|
522 ->condition('name', 'update_test_%', 'LIKE') |
|
523 ->execute(); |
|
524 |
|
525 // Define the initial state for core and the test contrib themes. |
|
526 $system_info = array( |
|
527 // We want core to be version 7.0. |
|
528 '#all' => array( |
|
529 'version' => '7.0', |
|
530 ), |
|
531 // The update_test_basetheme should be visible and up to date. |
|
532 'update_test_basetheme' => array( |
|
533 'project' => 'update_test_basetheme', |
|
534 'version' => '7.x-1.1', |
|
535 'hidden' => FALSE, |
|
536 ), |
|
537 // The update_test_subtheme should be visible and up to date. |
|
538 'update_test_subtheme' => array( |
|
539 'project' => 'update_test_subtheme', |
|
540 'version' => '7.x-1.0', |
|
541 'hidden' => FALSE, |
|
542 ), |
|
543 ); |
|
544 // When there are contributed modules in the site's file system, the |
|
545 // total number of attempts made in the test may exceed the default value |
|
546 // of update_max_fetch_attempts. Therefore this variable is set very high |
|
547 // to avoid test failures in those cases. |
|
548 variable_set('update_max_fetch_attempts', 99999); |
|
549 variable_set('update_test_system_info', $system_info); |
|
550 $xml_mapping = array( |
|
551 'drupal' => '0', |
|
552 'update_test_subtheme' => '1_0', |
|
553 'update_test_basetheme' => '1_1-sec', |
|
554 ); |
|
555 $base_theme_project_link = l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'); |
|
556 $sub_theme_project_link = l(t('Update test subtheme'), 'http://example.com/project/update_test_subtheme'); |
|
557 foreach (array(TRUE, FALSE) as $check_disabled) { |
|
558 variable_set('update_check_disabled', $check_disabled); |
|
559 $this->refreshUpdateStatus($xml_mapping); |
|
560 // In neither case should we see the "Themes" heading for enabled themes. |
|
561 $this->assertNoText(t('Themes')); |
|
562 if ($check_disabled) { |
|
563 $this->assertText(t('Disabled themes')); |
|
564 $this->assertRaw($base_theme_project_link, 'Link to the Update test base theme project appears.'); |
|
565 $this->assertRaw($sub_theme_project_link, 'Link to the Update test subtheme project appears.'); |
|
566 } |
|
567 else { |
|
568 $this->assertNoText(t('Disabled themes')); |
|
569 $this->assertNoRaw($base_theme_project_link, 'Link to the Update test base theme project does not appear.'); |
|
570 $this->assertNoRaw($sub_theme_project_link, 'Link to the Update test subtheme project does not appear.'); |
|
571 } |
|
572 } |
|
573 } |
|
574 |
|
575 /** |
|
576 * Makes sure that if we fetch from a broken URL, sane things happen. |
|
577 */ |
|
578 function testUpdateBrokenFetchURL() { |
|
579 $system_info = array( |
|
580 '#all' => array( |
|
581 'version' => '7.0', |
|
582 ), |
|
583 'aaa_update_test' => array( |
|
584 'project' => 'aaa_update_test', |
|
585 'version' => '7.x-1.0', |
|
586 'hidden' => FALSE, |
|
587 ), |
|
588 'bbb_update_test' => array( |
|
589 'project' => 'bbb_update_test', |
|
590 'version' => '7.x-1.0', |
|
591 'hidden' => FALSE, |
|
592 ), |
|
593 'ccc_update_test' => array( |
|
594 'project' => 'ccc_update_test', |
|
595 'version' => '7.x-1.0', |
|
596 'hidden' => FALSE, |
|
597 ), |
|
598 ); |
|
599 variable_set('update_test_system_info', $system_info); |
|
600 |
|
601 $xml_mapping = array( |
|
602 'drupal' => '0', |
|
603 'aaa_update_test' => '1_0', |
|
604 'bbb_update_test' => 'does-not-exist', |
|
605 'ccc_update_test' => '1_0', |
|
606 ); |
|
607 $this->refreshUpdateStatus($xml_mapping); |
|
608 |
|
609 $this->assertText(t('Up to date')); |
|
610 // We're expecting the report to say most projects are up to date, so we |
|
611 // hope that 'Up to date' is not unique. |
|
612 $this->assertNoUniqueText(t('Up to date')); |
|
613 // It should say we failed to get data, not that we're missing an update. |
|
614 $this->assertNoText(t('Update available')); |
|
615 |
|
616 // We need to check that this string is found as part of a project row, |
|
617 // not just in the "Failed to get available update data for ..." message |
|
618 // at the top of the page. |
|
619 $this->assertRaw('<div class="version-status">' . t('Failed to get available update data')); |
|
620 |
|
621 // We should see the output messages from fetching manually. |
|
622 $this->assertUniqueText(t('Checked available update data for 3 projects.')); |
|
623 $this->assertUniqueText(t('Failed to get available update data for one project.')); |
|
624 |
|
625 // The other two should be listed as projects. |
|
626 $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.'); |
|
627 $this->assertNoRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), 'Link to bbb_update_test project does not appear.'); |
|
628 $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), 'Link to bbb_update_test project appears.'); |
|
629 } |
|
630 |
|
631 /** |
|
632 * Checks that hook_update_status_alter() works to change a status. |
|
633 * |
|
634 * We provide the same external data as if aaa_update_test 7.x-1.0 were |
|
635 * installed and that was the latest release. Then we use |
|
636 * hook_update_status_alter() to try to mark this as missing a security |
|
637 * update, then assert if we see the appropriate warnings on the right pages. |
|
638 */ |
|
639 function testHookUpdateStatusAlter() { |
|
640 variable_set('allow_authorize_operations', TRUE); |
|
641 $update_admin_user = $this->drupalCreateUser(array('administer site configuration', 'administer software updates')); |
|
642 $this->drupalLogin($update_admin_user); |
|
643 |
|
644 $system_info = array( |
|
645 '#all' => array( |
|
646 'version' => '7.0', |
|
647 ), |
|
648 'aaa_update_test' => array( |
|
649 'project' => 'aaa_update_test', |
|
650 'version' => '7.x-1.0', |
|
651 'hidden' => FALSE, |
|
652 ), |
|
653 ); |
|
654 variable_set('update_test_system_info', $system_info); |
|
655 $update_status = array( |
|
656 'aaa_update_test' => array( |
|
657 'status' => UPDATE_NOT_SECURE, |
|
658 ), |
|
659 ); |
|
660 variable_set('update_test_update_status', $update_status); |
|
661 $this->refreshUpdateStatus( |
|
662 array( |
|
663 'drupal' => '0', |
|
664 'aaa_update_test' => '1_0', |
|
665 ) |
|
666 ); |
|
667 $this->drupalGet('admin/reports/updates'); |
|
668 $this->assertRaw('<h3>' . t('Modules') . '</h3>'); |
|
669 $this->assertText(t('Security update required!')); |
|
670 $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.'); |
|
671 |
|
672 // Visit the reports page again without the altering and make sure the |
|
673 // status is back to normal. |
|
674 variable_set('update_test_update_status', array()); |
|
675 $this->drupalGet('admin/reports/updates'); |
|
676 $this->assertRaw('<h3>' . t('Modules') . '</h3>'); |
|
677 $this->assertNoText(t('Security update required!')); |
|
678 $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), 'Link to aaa_update_test project appears.'); |
|
679 |
|
680 // Turn the altering back on and visit the Update manager UI. |
|
681 variable_set('update_test_update_status', $update_status); |
|
682 $this->drupalGet('admin/modules/update'); |
|
683 $this->assertText(t('Security update')); |
|
684 |
|
685 // Turn the altering back off and visit the Update manager UI. |
|
686 variable_set('update_test_update_status', array()); |
|
687 $this->drupalGet('admin/modules/update'); |
|
688 $this->assertNoText(t('Security update')); |
|
689 } |
|
690 |
|
691 } |
|
692 |
|
693 /** |
|
694 * Tests project upload and extract functionality. |
|
695 */ |
|
696 class UpdateTestUploadCase extends UpdateTestHelper { |
|
697 |
|
698 public static function getInfo() { |
|
699 return array( |
|
700 'name' => 'Upload and extract module functionality', |
|
701 'description' => 'Tests the Update Manager module\'s upload and extraction functionality.', |
|
702 'group' => 'Update', |
|
703 ); |
|
704 } |
|
705 |
|
706 public function setUp() { |
|
707 parent::setUp('update', 'update_test'); |
|
708 variable_set('allow_authorize_operations', TRUE); |
|
709 $admin_user = $this->drupalCreateUser(array('administer software updates', 'administer site configuration')); |
|
710 $this->drupalLogin($admin_user); |
|
711 } |
|
712 |
|
713 /** |
|
714 * Tests upload and extraction of a module. |
|
715 */ |
|
716 public function testUploadModule() { |
|
717 // Images are not valid archives, so get one and try to install it. We |
|
718 // need an extra variable to store the result of drupalGetTestFiles() |
|
719 // since reset() takes an argument by reference and passing in a constant |
|
720 // emits a notice in strict mode. |
|
721 $imageTestFiles = $this->drupalGetTestFiles('image'); |
|
722 $invalidArchiveFile = reset($imageTestFiles); |
|
723 $edit = array( |
|
724 'files[project_upload]' => $invalidArchiveFile->uri, |
|
725 ); |
|
726 // This also checks that the correct archive extensions are allowed. |
|
727 $this->drupalPost('admin/modules/install', $edit, t('Install')); |
|
728 $this->assertText(t('Only files with the following extensions are allowed: @archive_extensions.', array('@archive_extensions' => archiver_get_extensions())),'Only valid archives can be uploaded.'); |
|
729 |
|
730 // Check to ensure an existing module can't be reinstalled. Also checks that |
|
731 // the archive was extracted since we can't know if the module is already |
|
732 // installed until after extraction. |
|
733 $validArchiveFile = drupal_get_path('module', 'update') . '/tests/aaa_update_test.tar.gz'; |
|
734 $edit = array( |
|
735 'files[project_upload]' => $validArchiveFile, |
|
736 ); |
|
737 $this->drupalPost('admin/modules/install', $edit, t('Install')); |
|
738 $this->assertText(t('@module_name is already installed.', array('@module_name' => 'AAA Update test')), 'Existing module was extracted and not reinstalled.'); |
|
739 } |
|
740 |
|
741 /** |
|
742 * Ensures that archiver extensions are properly merged in the UI. |
|
743 */ |
|
744 function testFileNameExtensionMerging() { |
|
745 $this->drupalGet('admin/modules/install'); |
|
746 // Make sure the bogus extension supported by update_test.module is there. |
|
747 $this->assertPattern('/file extensions are supported:.*update-test-extension/', "Found 'update-test-extension' extension"); |
|
748 // Make sure it didn't clobber the first option from core. |
|
749 $this->assertPattern('/file extensions are supported:.*tar/', "Found 'tar' extension"); |
|
750 } |
|
751 |
|
752 /** |
|
753 * Checks the messages on update manager pages when missing a security update. |
|
754 */ |
|
755 function testUpdateManagerCoreSecurityUpdateMessages() { |
|
756 $setting = array( |
|
757 '#all' => array( |
|
758 'version' => '7.0', |
|
759 ), |
|
760 ); |
|
761 variable_set('update_test_system_info', $setting); |
|
762 variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE))); |
|
763 variable_set('update_test_xml_map', array('drupal' => '2-sec')); |
|
764 // Initialize the update status. |
|
765 $this->drupalGet('admin/reports/updates'); |
|
766 |
|
767 // Now, make sure none of the Update manager pages have duplicate messages |
|
768 // about core missing a security update. |
|
769 |
|
770 $this->drupalGet('admin/modules/install'); |
|
771 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
772 |
|
773 $this->drupalGet('admin/modules/update'); |
|
774 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
775 |
|
776 $this->drupalGet('admin/appearance/install'); |
|
777 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
778 |
|
779 $this->drupalGet('admin/appearance/update'); |
|
780 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
781 |
|
782 $this->drupalGet('admin/reports/updates/install'); |
|
783 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
784 |
|
785 $this->drupalGet('admin/reports/updates/update'); |
|
786 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
787 |
|
788 $this->drupalGet('admin/update/ready'); |
|
789 $this->assertNoText(t('There is a security update available for your version of Drupal.')); |
|
790 } |
|
791 |
|
792 } |
|
793 |
|
794 /** |
|
795 * Tests update functionality unrelated to the database. |
|
796 */ |
|
797 class UpdateCoreUnitTestCase extends DrupalUnitTestCase { |
|
798 |
|
799 public static function getInfo() { |
|
800 return array( |
|
801 'name' => "Unit tests", |
|
802 'description' => 'Test update funcionality unrelated to the database.', |
|
803 'group' => 'Update', |
|
804 ); |
|
805 } |
|
806 |
|
807 function setUp() { |
|
808 parent::setUp('update'); |
|
809 module_load_include('inc', 'update', 'update.fetch'); |
|
810 } |
|
811 |
|
812 /** |
|
813 * Tests that _update_build_fetch_url() builds the URL correctly. |
|
814 */ |
|
815 function testUpdateBuildFetchUrl() { |
|
816 //first test that we didn't break the trivial case |
|
817 $project['name'] = 'update_test'; |
|
818 $project['project_type'] = ''; |
|
819 $project['info']['version'] = ''; |
|
820 $project['info']['project status url'] = 'http://www.example.com'; |
|
821 $project['includes'] = array('module1' => 'Module 1', 'module2' => 'Module 2'); |
|
822 $site_key = ''; |
|
823 $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; |
|
824 $url = _update_build_fetch_url($project, $site_key); |
|
825 $this->assertEqual($url, $expected, "'$url' when no site_key provided should be '$expected'."); |
|
826 |
|
827 //For disabled projects it shouldn't add the site key either. |
|
828 $site_key = 'site_key'; |
|
829 $project['project_type'] = 'disabled'; |
|
830 $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; |
|
831 $url = _update_build_fetch_url($project, $site_key); |
|
832 $this->assertEqual($url, $expected, "'$url' should be '$expected' for disabled projects."); |
|
833 |
|
834 //for enabled projects, adding the site key |
|
835 $project['project_type'] = ''; |
|
836 $expected = 'http://www.example.com/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; |
|
837 $expected .= '?site_key=site_key'; |
|
838 $expected .= '&list=' . rawurlencode('module1,module2'); |
|
839 $url = _update_build_fetch_url($project, $site_key); |
|
840 $this->assertEqual($url, $expected, "When site_key provided, '$url' should be '$expected'."); |
|
841 |
|
842 // http://drupal.org/node/1481156 test incorrect logic when URL contains |
|
843 // a question mark. |
|
844 $project['info']['project status url'] = 'http://www.example.com/?project='; |
|
845 $expected = 'http://www.example.com/?project=/' . $project['name'] . '/' . DRUPAL_CORE_COMPATIBILITY; |
|
846 $expected .= '&site_key=site_key'; |
|
847 $expected .= '&list=' . rawurlencode('module1,module2'); |
|
848 $url = _update_build_fetch_url($project, $site_key); |
|
849 $this->assertEqual($url, $expected, "When ? is present, '$url' should be '$expected'."); |
|
850 |
|
851 } |
|
852 } |