Merge pull request #10988 from jmcclelland/CRM-21194
[civicrm-core.git] / tests / phpunit / CRM / Utils / versionCheckTest.php
1 <?php
2
3 /**
4 * Class CRM_Utils_versionCheckTest
5 * @group headless
6 */
7 class CRM_Utils_versionCheckTest extends CiviUnitTestCase {
8
9 /**
10 * @return array
11 */
12 public function get_info() {
13 return array(
14 'name' => 'VersionCheck Test',
15 'description' => 'Test versionCheck functionality',
16 'group' => 'CiviCRM BAO Tests',
17 );
18 }
19
20 public function setUp() {
21 parent::setUp();
22 }
23
24 /**
25 * @var array
26 */
27 protected $sampleVersionInfo = array(
28 '4.2' => array(
29 'status' => 'eol',
30 'releases' => array(
31 array('version' => '4.2.0', 'date' => '2012-08-20'),
32 array('version' => '4.2.1', 'date' => '2012-09-12'),
33 array('version' => '4.2.2', 'date' => '2012-09-27'),
34 array('version' => '4.2.4', 'date' => '2012-10-18'),
35 array('version' => '4.2.6', 'date' => '2012-11-01', 'security' => TRUE),
36 array('version' => '4.2.7', 'date' => '2013-01-02', 'security' => TRUE),
37 array('version' => '4.2.8', 'date' => '2013-02-20'),
38 array('version' => '4.2.9', 'date' => '2013-04-03'),
39 array('version' => '4.2.10', 'date' => '2013-07-29', 'security' => TRUE),
40 array('version' => '4.2.11', 'date' => '2013-09-25'),
41 array('version' => '4.2.12', 'date' => '2013-10-02', 'security' => TRUE),
42 array('version' => '4.2.13', 'date' => '2013-11-06', 'security' => TRUE),
43 array('version' => '4.2.14', 'date' => '2013-11-20'),
44 array('version' => '4.2.15', 'date' => '2014-02-07', 'security' => TRUE),
45 array('version' => '4.2.16', 'date' => '2014-02-18'),
46 array('version' => '4.2.17', 'date' => '2014-07-01', 'security' => TRUE),
47 array('version' => '4.2.18', 'date' => '2014-08-06'),
48 array('version' => '4.2.19', 'date' => '2014-09-17', 'security' => TRUE),
49 ),
50 ),
51 '4.3' => array(
52 'status' => 'lts',
53 'releases' => array(
54 array('version' => '4.3.0', 'date' => '2013-04-10'),
55 array('version' => '4.3.1', 'date' => '2013-04-18'),
56 array('version' => '4.3.2', 'date' => '2013-05-02'),
57 array('version' => '4.3.3', 'date' => '2013-05-08'),
58 array('version' => '4.3.4', 'date' => '2013-06-10', 'security' => TRUE),
59 array('version' => '4.3.5', 'date' => '2013-07-08', 'security' => TRUE),
60 array('version' => '4.3.6', 'date' => '2013-09-25'),
61 array('version' => '4.3.7', 'date' => '2013-10-02', 'security' => TRUE),
62 array('version' => '4.3.8', 'date' => '2013-11-06', 'security' => TRUE),
63 array('version' => '4.3.9', 'date' => '2014-09-07', 'security' => TRUE),
64 ),
65 ),
66 '4.4' => array(
67 'status' => 'lts',
68 'releases' => array(
69 array('version' => '4.4.0', 'date' => '2013-10-23'),
70 array('version' => '4.4.1', 'date' => '2013-11-06', 'security' => TRUE),
71 array('version' => '4.4.2', 'date' => '2013-11-20'),
72 array('version' => '4.4.3', 'date' => '2013-12-05'),
73 array('version' => '4.4.4', 'date' => '2014-02-07', 'security' => TRUE),
74 array('version' => '4.4.5', 'date' => '2014-04-17'),
75 array('version' => '4.4.6', 'date' => '2014-07-01', 'security' => TRUE),
76 array('version' => '4.4.7', 'date' => '2014-09-17', 'security' => TRUE),
77 array('version' => '4.4.8', 'date' => '2014-10-14'),
78 array('version' => '4.4.9', 'date' => '2014-11-05'),
79 array('version' => '4.4.10', 'date' => '2014-11-19'),
80 array('version' => '4.4.11', 'date' => '2014-12-17', 'security' => TRUE),
81 ),
82 ),
83 '4.5' => array(
84 'status' => 'stable',
85 'releases' => array(
86 array('version' => '4.5.0', 'date' => '2014-09-18'),
87 array('version' => '4.5.1', 'date' => '2014-10-09'),
88 array('version' => '4.5.2', 'date' => '2014-10-14'),
89 array('version' => '4.5.3', 'date' => '2014-11-05'),
90 array('version' => '4.5.4', 'date' => '2014-11-19'),
91 array('version' => '4.5.5', 'date' => '2014-12-17', 'security' => TRUE),
92 ),
93 ),
94 '4.6' => array(
95 'status' => 'testing',
96 'releases' => array(
97 array('version' => '4.6.alpha1', 'date' => '2015-02-01'),
98 array('version' => '4.6.beta1', 'date' => '2015-03-01'),
99 ),
100 ),
101 );
102
103 /**
104 * @dataProvider newerVersionDataProvider
105 * @param string $localVersion
106 * @param array $versionInfo
107 * @param mixed $expectedResult
108 */
109 public function testNewerVersion($localVersion, $versionInfo, $expectedResult) {
110 $vc = new CRM_Utils_VersionCheck();
111 // These values are set by the constructor but for testing we override them
112 $vc->localVersion = $localVersion;
113 $vc->localMajorVersion = $vc->getMajorVersion($localVersion);
114 $vc->setVersionInfo($versionInfo);
115 $available = $vc->isNewerVersionAvailable();
116 $this->assertEquals($available['version'], $expectedResult);
117 }
118
119 /**
120 * @return array
121 * (localVersion, versionInfo, expectedResult)
122 */
123 public function newerVersionDataProvider() {
124 $data = array();
125
126 // Make sure we do not get unstable release updates for a stable localVersion
127 $data[] = array('4.5.5', $this->sampleVersionInfo, NULL);
128
129 // Make sure we do get unstable release updates for unstable localVersion
130 $data[] = array('4.6.alpha1', $this->sampleVersionInfo, '4.6.beta1');
131
132 // Make sure we get nothing (and no errors) if no versionInfo available
133 $data[] = array('4.7.beta1', array(), NULL);
134
135 // Make sure alerts prioritize the localMajorVersion
136 $data[] = array('4.4.1', $this->sampleVersionInfo, '4.4.11');
137
138 // Make sure new security release on newest version doesn't trigger security
139 // notice on site running LTS version that doesn't have a security release
140 $data[] = array('4.3.9', $this->sampleVersionInfo, NULL);
141
142 // Make sure new security release on newest version DOES trigger security
143 // notice on site running EOL version that doesn't have a security release
144 $data[] = array('4.2.19', $this->sampleVersionInfo, '4.5.5');
145
146 return $data;
147 }
148
149 /**
150 * @dataProvider securityUpdateDataProvider
151 * @param string $localVersion
152 * @param array $versionInfo
153 * @param bool $expectedResult
154 */
155 public function testSecurityUpdate($localVersion, $versionInfo, $expectedResult) {
156 $vc = new CRM_Utils_VersionCheck();
157 // These values are set by the constructor but for testing we override them
158 $vc->localVersion = $localVersion;
159 $vc->localMajorVersion = $vc->getMajorVersion($localVersion);
160 $vc->setVersionInfo($versionInfo);
161 $available = $vc->isNewerVersionAvailable();
162 $this->assertEquals($available['upgrade'], $expectedResult);
163 }
164
165 /**
166 * @return array
167 * (localVersion, versionInfo, expectedResult)
168 */
169 public function securityUpdateDataProvider() {
170 $data = array();
171
172 // Make sure we get alerted if a security release is available
173 $data[] = array('4.5.1', $this->sampleVersionInfo, 'security');
174
175 // Make sure we do not get alerted if a security release is not available
176 $data[] = array('4.5.5', $this->sampleVersionInfo, NULL);
177
178 // Make sure we get false (and no errors) if no versionInfo available (this will be the case for pre-alphas)
179 $data[] = array('4.7.alpha1', array(), NULL);
180
181 // If there are 2 security updates on the same day (e.g. lts and stable majorVersions)
182 // we should not get alerted to one if we are using the other
183 $data[] = array('4.4.11', $this->sampleVersionInfo, FALSE);
184
185 // This version predates the ones in the info array, it should be assumed to be EOL and insecure
186 $data[] = array('4.0.1', $this->sampleVersionInfo, 'security');
187
188 // Make sure new security release on newest version doesn't trigger security
189 // notice on site running LTS version that doesn't have a security release
190 $data[] = array('4.3.9', $this->sampleVersionInfo, NULL);
191
192 // Make sure new security release on newest version DOES trigger security
193 // notice on site running EOL version that doesn't have a security release
194 $data[] = array('4.2.19', $this->sampleVersionInfo, 'security');
195
196 return $data;
197 }
198
199 public function testCronFallback() {
200 // Fake "remote" source data
201 $tmpSrc = '/tmp/versionCheckTestFile.json';
202 file_put_contents($tmpSrc, json_encode($this->sampleVersionInfo));
203
204 $vc = new CRM_Utils_VersionCheck();
205 $vc->pingbackUrl = $tmpSrc;
206
207 // If the cachefile doesn't exist, fallback should kick in
208 if (file_exists($vc->cacheFile)) {
209 unlink($vc->cacheFile);
210 }
211 $vc->initialize();
212 $this->assertEquals($this->sampleVersionInfo, $vc->versionInfo);
213 unset($vc);
214
215 // Update "remote" source data
216 $remoteData = array('4.3' => $this->sampleVersionInfo['4.3']);
217 file_put_contents($tmpSrc, json_encode($remoteData));
218
219 // Cache was just updated, so fallback should not happen - assert we are still using cached data
220 $vc = new CRM_Utils_VersionCheck();
221 $vc->pingbackUrl = $tmpSrc;
222 $vc->initialize();
223 $this->assertEquals($this->sampleVersionInfo, $vc->versionInfo);
224 unset($vc);
225
226 // Ensure fallback happens if file is too old
227 $vc = new CRM_Utils_VersionCheck();
228 $vc->pingbackUrl = $tmpSrc;
229 // Set cachefile to be 1 minute older than expire time
230 touch($vc->cacheFile, time() - 60 - $vc::CACHEFILE_EXPIRE);
231 clearstatcache();
232 $vc->initialize();
233 $this->assertEquals($remoteData, $vc->versionInfo);
234 }
235
236 public function testGetSiteStats() {
237 // Create domain address so the domain country will come up in the stats.
238 $country_params = array(
239 'sequential' => 1,
240 'options' => array(
241 'limit' => 1,
242 ),
243 );
244 $country_result = civicrm_api3('country', 'get', $country_params);
245 $country = $country_result['values'][0];
246
247 $domain_params = array(
248 'id' => CRM_Core_Config::domainID(),
249 );
250 CRM_Core_BAO_Domain::retrieve($domain_params, $domain_defaults);
251 $location_type = CRM_Core_BAO_LocationType::getDefault();
252 $address_params = array(
253 'contact_id' => $domain_defaults['contact_id'],
254 'location_type_id' => $location_type->id,
255 'is_primary' => '1',
256 'is_billing' => '0',
257 'street_address' => '1 Main St.',
258 'city' => 'Anywhere',
259 'postal_code' => '99999',
260 'country_id' => $country['id'],
261 );
262 $address_result = civicrm_api3('address', 'create', $address_params);
263
264 // Build stats and test them.
265 $vc = new ReflectionClass('CRM_Utils_VersionCheck');
266 $vc_instance = $vc->newInstance();
267
268 $statsBuilder = $vc->getMethod('getSiteStats');
269 $statsBuilder->setAccessible(TRUE);
270 $statsBuilder->invoke($vc_instance, NULL);
271
272 $statsProperty = $vc->getProperty('stats');
273 $statsProperty->setAccessible(TRUE);
274 $stats = $statsProperty->getValue($vc_instance);
275
276 // Stats array should have correct elements.
277 $this->assertArrayHasKey('version', $stats);
278
279 // See CRM_Utils_VersionCheck::getSiteStats where alpha versions don't get
280 // full stats generated
281 if (array_key_exists('version', $stats) && strpos($stats['version'], 'alpha') === FALSE) {
282 $this->assertArrayHasKey('hash', $stats);
283 $this->assertArrayHasKey('uf', $stats);
284 $this->assertArrayHasKey('lang', $stats);
285 $this->assertArrayHasKey('co', $stats);
286 $this->assertArrayHasKey('ufv', $stats);
287 $this->assertArrayHasKey('PHP', $stats);
288 $this->assertArrayHasKey('MySQL', $stats);
289 $this->assertArrayHasKey('communityMessagesUrl', $stats);
290 $this->assertArrayHasKey('domain_isoCode', $stats);
291 $this->assertArrayHasKey('PPTypes', $stats);
292 $this->assertArrayHasKey('entities', $stats);
293 $this->assertArrayHasKey('extensions', $stats);
294 $this->assertType('array', $stats['entities']);
295 $this->assertType('array', $stats['extensions']);
296
297 // Assert $stats['domain_isoCode'] is correct.
298 $this->assertEquals($country['iso_code'], $stats['domain_isoCode']);
299
300 $entity_names = array();
301 foreach ($stats['entities'] as $entity) {
302 $entity_names[] = $entity['name'];
303 $this->assertType('int', $entity['size'], "Stats entity {$entity['name']} has integer size?");
304 }
305
306 $expected_entity_names = array(
307 'Activity',
308 'Case',
309 'Contact',
310 'Relationship',
311 'Campaign',
312 'Contribution',
313 'ContributionPage',
314 'ContributionProduct',
315 'Widget',
316 'Discount',
317 'PriceSetEntity',
318 'UFGroup',
319 'Event',
320 'Participant',
321 'Friend',
322 'Grant',
323 'Mailing',
324 'Membership',
325 'MembershipBlock',
326 'Pledge',
327 'PledgeBlock',
328 'Delivered',
329 );
330 sort($entity_names);
331 sort($expected_entity_names);
332 $this->assertEquals($expected_entity_names, $entity_names);
333
334 // TODO: Also test for enabled extensions.
335 }
336 }
337
338 }