summaryrefslogtreecommitdiff
path: root/modules/update/update.test
blob: a274e38642f6f52cd96b26b1b40cecdf13c4221a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
<?php
// $Id$

/**
 * @file
 * This file contains tests for the update module. The overarching methodology
 * of these tests is we need to compare a given state of installed modules and
 * themes (e.g. version, project grouping, timestamps, etc) vs. a current
 * state of what the release history XML files we fetch say is available.  We
 * have dummy XML files (in the 'tests' subdirectory) that describe various
 * scenarios of what's available for different test projects, and we have
 * dummy .info file data (specified via hook_system_info_alter() in the
 * update_test helper module) describing what's currently installed.  Each
 * test case defines a set of projects to install, their current state (via
 * the 'update_test_system_info' variable) and the desired availabile update
 * data (via the 'update_test_xml_map' variable), and then performs a series
 * of assertions that the report matches our expectations given the specific
 * initial state and availability scenario.
 */

/**
 * Base class to define some shared functions used by all update tests.
 */
class UpdateTestHelper extends DrupalWebTestCase {
  /**
   * Refresh the update status based on the desired available update scenario.
   *
   * @param $xml_map
   *   Array that maps project names to availability scenarios to fetch.
   *   The key '#all' is used if a project-specific mapping is not defined.
   *
   * @see update_test_mock_page()
   */
  protected function refreshUpdateStatus($xml_map) {
    // Tell update module to fetch from the URL provided by update_test module.
    variable_set('update_fetch_url', url('update-test', array('absolute' => TRUE)));
    // Save the map for update_test_mock_page() to use.
    variable_set('update_test_xml_map', $xml_map);
    // Manually check the update status.
    $this->drupalGet('admin/reports/updates/check');
  }

  /**
   * Run a series of assertions that are applicable for all update statuses.
   */
  protected function standardTests() {
    $this->assertRaw('<h3>' . t('Drupal core') . '</h3>');
    $this->assertRaw(l(t('Check manually'), 'admin/reports/updates/check'), t('Link to check available updates manually appears.'));
    $this->assertRaw(l(t('Drupal'), 'http://example.com/project/drupal'), t('Link to the Drupal project appears.'));
    $this->assertNoText(t('No available releases found'));
  }

}

class UpdateCoreTestCase extends UpdateTestHelper {

  public static function getInfo() {
    return array(
      'name' => 'Update core functionality',
      'description' => 'Tests the update module through a series of functional tests using mock XML data.',
      'group' => 'Update',
    );
  }

  function setUp() {
    parent::setUp('update_test', 'update');
    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
    $this->drupalLogin($admin_user);
  }

  /**
   * Tests the update module when no updates are available.
   */
  function testNoUpdatesAvailable() {
    $this->setSystemInfo7_0();
    $this->refreshUpdateStatus(array('drupal' => '0'));
    $this->drupalGet('admin/reports/updates');
    $this->standardTests();
    $this->assertText(t('Up to date'));
    $this->assertNoText(t('Update available'));
    $this->assertNoText(t('Security update required!'));
  }

  /**
   * Tests the update module when one normal update ("7.1") is available.
   */
  function testNormalUpdateAvailable() {
    $this->setSystemInfo7_0();
    $this->refreshUpdateStatus(array('drupal' => '1'));
    $this->drupalGet('admin/reports/updates');
    $this->standardTests();
    $this->assertNoText(t('Up to date'));
    $this->assertText(t('Update available'));
    $this->assertNoText(t('Security update required!'));
    $this->assertRaw(l('7.1', 'http://example.com/drupal-7-1-release'), t('Link to release appears.'));
    $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-1.tar.gz'), t('Link to download appears.'));
    $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-1-release'), t('Link to release notes appears.'));
  }

  /**
   * Tests the update module when a security update ("7.2") is available.
   */
  function testSecurityUpdateAvailable() {
    $this->setSystemInfo7_0();
    $this->refreshUpdateStatus(array('drupal' => '2-sec'));
    $this->drupalGet('admin/reports/updates');
    $this->standardTests();
    $this->assertNoText(t('Up to date'));
    $this->assertNoText(t('Update available'));
    $this->assertText(t('Security update required!'));
    $this->assertRaw(l('7.2', 'http://example.com/drupal-7-2-release'), t('Link to release appears.'));
    $this->assertRaw(l(t('Download'), 'http://example.com/drupal-7-2.tar.gz'), t('Link to download appears.'));
    $this->assertRaw(l(t('Release notes'), 'http://example.com/drupal-7-2-release'), t('Link to release notes appears.'));
  }

  /**
   * Ensure proper results where there are date mismatches among modules.
   */
  function testDatestampMismatch() {
    $system_info = array(
      '#all' => array(
        // We need to think we're running a -dev snapshot to see dates.
        'version' => '7.0-dev',
        'datestamp' => time(),
      ),
      'block' => array(
        // This is 2001-09-09 01:46:40 GMT, so test for "2001-Sep-".
        'datestamp' => '1000000000',
      ),
    );
    variable_set('update_test_system_info', $system_info);
    $this->refreshUpdateStatus(array('drupal' => 'dev'));
    $this->drupalGet('admin/reports/updates');
    $this->assertNoText(t('2001-Sep-'));
    $this->assertText(t('Up to date'));
    $this->assertNoText(t('Update available'));
    $this->assertNoText(t('Security update required!'));
  }

  protected function setSystemInfo7_0() {
    $setting = array(
      '#all' => array(
        'version' => '7.0',
      ),
    );
    variable_set('update_test_system_info', $setting);
  }

}

class UpdateTestContribCase extends UpdateTestHelper {

  public static function getInfo() {
    return array(
      'name' => 'Update contrib functionality',
      'description' => 'Tests how the update module handles contributed modules and themes in a series of functional tests using mock XML data.',
      'group' => 'Update',
    );
  }

  function setUp() {
    parent::setUp('update_test', 'update', 'aaa_update_test', 'bbb_update_test', 'ccc_update_test');
    $admin_user = $this->drupalCreateUser(array('administer site configuration'));
    $this->drupalLogin($admin_user);
  }

  /**
   * Test the basic functionality of a contrib module on the status report.
   */
  function testUpdateContribBasic() {
    $system_info = array(
      '#all' => array(
        'version' => '7.0',
      ),
      'aaa_update_test' => array(
        'project' => 'aaa_update_test',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),
    );
    variable_set('update_test_system_info', $system_info);
    $this->refreshUpdateStatus(
      array(
        'drupal' => '0',
        'aaa_update_test' => '1_0',
      )
    );
    $this->drupalGet('admin/reports/updates');
    $this->standardTests();
    $this->assertText(t('Up to date'));
    $this->assertRaw('<h3>' . t('Modules') . '</h3>');
    $this->assertNoText(t('Update available'));
    $this->assertRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), t('Link to aaa_update_test project appears.'));
  }

  /**
   * Test that contrib projects are ordered by project name.
   *
   * If a project contains multiple modules, we want to make sure that the
   * available updates report is sorted by the parent project names, not by
   * the names of the modules included in each project. In this test case, we
   * have 2 contrib projects, "BBB Update test" and "CCC Update test".
   * However, we have a module called "aaa_update_test" that's part of the
   * "CCC Update test" project. We need to make sure that we see the "BBB"
   * project before the "CCC" project, even though "CCC" includes a module
   * that's processed first if you sort alphabetically by module name (which
   * is the order we see things inside system_get_module_data() for example).
   */
  function testUpdateContribOrder() {
    // We want core to be version 7.0.
    $system_info = array(
      '#all' => array(
        'version' => '7.0',
      ),
      // All the rest should be visible as contrib modules at version 7.x-1.0.

      // aaa_update_test needs to be part of the "CCC Update test" project,
      // which would throw off the report if we weren't properly sorting by
      // the project names.
      'aaa_update_test' => array(
        'project' => 'ccc_update_test',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),

      // This should be its own project, and listed first on the report.
      'bbb_update_test' => array(
        'project' => 'bbb_update_test',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),

      // This will contain both aaa_update_test and ccc_update_test, and
      // should come after the bbb_update_test project.
      'ccc_update_test' => array(
        'project' => 'ccc_update_test',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),
    );
    variable_set('update_test_system_info', $system_info);
    $this->refreshUpdateStatus(array('drupal' => '0', '#all' => '1_0'));
    $this->drupalGet('admin/reports/updates');
    $this->standardTests();
    // We're expecting the report to say all projects are up to date.
    $this->assertText(t('Up to date'));
    $this->assertNoText(t('Update available'));
    // We want to see all 3 module names listed, since they'll show up either
    // as project names or as modules under the "Includes" listing.
    $this->assertText(t('AAA Update test'));
    $this->assertText(t('BBB Update test'));
    $this->assertText(t('CCC Update test'));
    // We want aaa_update_test included in the ccc_update_test project, not as
    // its own project on the report.
    $this->assertNoRaw(l(t('AAA Update test'), 'http://example.com/project/aaa_update_test'), t('Link to aaa_update_test project does not appear.'));
    // The other two should be listed as projects.
    $this->assertRaw(l(t('BBB Update test'), 'http://example.com/project/bbb_update_test'), t('Link to bbb_update_test project appears.'));
    $this->assertRaw(l(t('CCC Update test'), 'http://example.com/project/ccc_update_test'), t('Link to bbb_update_test project appears.'));

    // We want to make sure we see the BBB project before the CCC project.
    // Instead of just searching for 'BBB Update test' or something, we want
    // to use the full markup that starts the project entry itself, so that
    // we're really testing that the project listings are in the right order.
    $bbb_project_link = '<div class="project"><a href="http://example.com/project/bbb_update_test">BBB Update test</a>';
    $ccc_project_link = '<div class="project"><a href="http://example.com/project/ccc_update_test">CCC Update test</a>';
    $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");
  }

  /**
   * Test that subthemes are notified about security updates for base themes.
   */
  function testUpdateBaseThemeSecurityUpdate() {
    // Only enable the subtheme, not the base theme.
    db_update('system')
      ->fields(array('status' => 1))
      ->condition('type', 'theme')
      ->condition('name', 'update_test_subtheme')
      ->execute();

    // Define the initial state for core and the subtheme.
    $system_info = array(
      // We want core to be version 7.0.    
      '#all' => array(
        'version' => '7.0',
      ),
      // Show the update_test_basetheme
      'update_test_basetheme' => array(
        'project' => 'update_test_basetheme',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),
      // Show the update_test_subtheme
      'update_test_subtheme' => array(
        'project' => 'update_test_subtheme',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),
    );
    variable_set('update_test_system_info', $system_info);
    $xml_mapping = array(
      'drupal' => '0',
      'update_test_subtheme' => '1_0',
      'update_test_basetheme' => '1_1-sec',
    );
    $this->refreshUpdateStatus($xml_mapping);
    $this->drupalGet('admin/reports/updates');
    $this->assertText(t('Security update required!'));
    $this->assertRaw(l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme'), t('Link to the Update test base theme project appears.'));
  }

  /**
   * Test that disabled themes are only shown when desired.
   */
  function testUpdateShowDisabledThemes() {
    // Make sure all the update_test_* themes are disabled.
    db_update('system')
      ->fields(array('status' => 0))
      ->condition('type', 'theme')
      ->condition('name', 'update_test_%', 'LIKE')
      ->execute();

    // Define the initial state for core and the test contrib themes.
    $system_info = array(
      // We want core to be version 7.0.    
      '#all' => array(
        'version' => '7.0',
      ),
      // The update_test_basetheme should be visible and up to date.
      'update_test_basetheme' => array(
        'project' => 'update_test_basetheme',
        'version' => '7.x-1.1',
        'hidden' => FALSE,
      ),
      // The update_test_subtheme should be visible and up to date.
      'update_test_subtheme' => array(
        'project' => 'update_test_subtheme',
        'version' => '7.x-1.0',
        'hidden' => FALSE,
      ),
    );
    variable_set('update_test_system_info', $system_info);
    $xml_mapping = array(
      'drupal' => '0',
      'update_test_subtheme' => '1_0',
      'update_test_basetheme' => '1_1-sec',
    );
    $base_theme_project_link = l(t('Update test base theme'), 'http://example.com/project/update_test_basetheme');
    $sub_theme_project_link = l(t('Update test subtheme'), 'http://example.com/project/update_test_subtheme');
    foreach (array(TRUE, FALSE) as $check_disabled) {
      variable_set('update_check_disabled', $check_disabled);
      $this->refreshUpdateStatus($xml_mapping);
      $this->drupalGet('admin/reports/updates');
      // In neither case should we see the "Themes" heading for enabled themes.
      $this->assertNoText(t('Themes'));
      if ($check_disabled) {
        $this->assertText(t('Disabled themes'));
        $this->assertRaw($base_theme_project_link, t('Link to the Update test base theme project appears.'));
        $this->assertRaw($sub_theme_project_link, t('Link to the Update test subtheme project appears.'));
      }
      else {
        $this->assertNoText(t('Disabled themes'));
        $this->assertNoRaw($base_theme_project_link, t('Link to the Update test base theme project does not appear.'));
        $this->assertNoRaw($sub_theme_project_link, t('Link to the Update test subtheme project does not appear.'));
      }
    }
  }

}