(NFC) Change getMock to createMock in tests to fix deprecated warning on getMock...
[civicrm-core.git] / tests / phpunit / CRM / Core / CommunityMessagesTest.php
CommitLineData
ecbe1139 1<?php
ecbe1139
TO
2/*
3 +--------------------------------------------------------------------+
2fe49090 4 | CiviCRM version 5 |
ecbe1139 5 +--------------------------------------------------------------------+
8c9251b3 6 | Copyright CiviCRM LLC (c) 2004-2018 |
ecbe1139
TO
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
d25dd0ee 26 */
ecbe1139 27
e9479dcf
EM
28/**
29 * Class CRM_Core_CommunityMessagesTest
acb109b7 30 * @group headless
e9479dcf 31 */
ecbe1139 32class CRM_Core_CommunityMessagesTest extends CiviUnitTestCase {
6a522e8b
TO
33
34 /**
35 * The max difference between two times such that they should be
36 * treated as equals (expressed in seconds).
37 */
38 const APPROX_TIME_EQUALITY = 2;
39
ecbe1139
TO
40 /**
41 * @var CRM_Utils_Cache_Interface
42 */
43 protected $cache;
44
45 /**
46 * @var array list of possible web responses
47 */
376d8353 48 protected static $webResponses = NULL;
ecbe1139 49
4cbe18b8
EM
50 /**
51 * @return array
52 */
376d8353
TO
53 public static function initWebResponses() {
54 if (self::$webResponses === NULL) {
55 self::$webResponses = array(
56 'http-error' => array(
57 CRM_Utils_HttpClient::STATUS_DL_ERROR,
21dfd5f5 58 NULL,
376d8353
TO
59 ),
60 'bad-json' => array(
61 CRM_Utils_HttpClient::STATUS_OK,
21dfd5f5 62 '<html>this is not json!</html>',
376d8353
TO
63 ),
64 'invalid-ttl-document' => array(
65 CRM_Utils_HttpClient::STATUS_OK,
66 json_encode(array(
67 'ttl' => 'z', // not an integer!
68 'retry' => 'z', // not an integer!
69 'messages' => array(
70 array(
71 'markup' => '<h1>Invalid document</h1>',
72 ),
8bfc3cb1 73 ),
21dfd5f5 74 )),
376d8353 75 ),
3dcd50d8 76 'first-valid-response' => array(
376d8353
TO
77 CRM_Utils_HttpClient::STATUS_OK,
78 json_encode(array(
79 'ttl' => 600,
80 'retry' => 600,
81 'messages' => array(
82 array(
3dcd50d8 83 'markup' => '<h1>First valid response</h1>',
376d8353 84 ),
ecbe1139 85 ),
21dfd5f5 86 )),
376d8353 87 ),
3dcd50d8 88 'second-valid-response' => array(
376d8353
TO
89 CRM_Utils_HttpClient::STATUS_OK,
90 json_encode(array(
91 'ttl' => 600,
92 'retry' => 600,
93 'messages' => array(
94 array(
3dcd50d8 95 'markup' => '<h1>Second valid response</h1>',
376d8353 96 ),
ecbe1139 97 ),
21dfd5f5 98 )),
376d8353 99 ),
dc92f2f8
TO
100 'two-messages' => array(
101 CRM_Utils_HttpClient::STATUS_OK,
102 json_encode(array(
103 'ttl' => 600,
104 'retry' => 600,
105 'messages' => array(
106 array(
107 'markup' => '<h1>One</h1>',
108 'components' => array('CiviMail'),
109 ),
110 array(
111 'markup' => '<h1>Two</h1>',
112 'components' => array('CiviMail'),
113 ),
114 ),
21dfd5f5 115 )),
dc92f2f8
TO
116 ),
117 'two-messages-halfbadcomp' => array(
118 CRM_Utils_HttpClient::STATUS_OK,
119 json_encode(array(
120 'ttl' => 600,
121 'retry' => 600,
122 'messages' => array(
123 array(
124 'markup' => '<h1>One</h1>',
125 'components' => array('NotARealComponent'),
126 ),
127 array(
128 'markup' => '<h1>Two</h1>',
129 'components' => array('CiviMail'),
130 ),
131 ),
21dfd5f5 132 )),
dc92f2f8 133 ),
376d8353
TO
134 );
135 }
136 return self::$webResponses;
137 }
138
139 public function setUp() {
140 parent::setUp();
141 $this->cache = new CRM_Utils_Cache_Arraycache(array());
142 self::initWebResponses();
ecbe1139
TO
143 }
144
145 public function tearDown() {
146 parent::tearDown();
147 CRM_Utils_Time::resetTime();
148 }
149
acdf9ae2
TO
150 /**
151 * A list of bad web-responses; in general, whenever the downloader
152 * encounters one of these bad responses, it should ignore the
153 * document, retain the old data, and retry again later.
154 *
155 * @return array
156 */
157 public function badWebResponses() {
376d8353
TO
158 self::initWebResponses();
159 $result = array(
160 array(self::$webResponses['http-error']),
161 array(self::$webResponses['bad-json']),
162 array(self::$webResponses['invalid-ttl-document']),
163 );
164 return $result;
165 }
166
847c93ac
TO
167 public function testIsEnabled() {
168 $communityMessages = new CRM_Core_CommunityMessages(
169 $this->cache,
170 $this->expectNoHttpRequest()
171 );
172 $this->assertTrue($communityMessages->isEnabled());
173 }
174
175 public function testIsEnabled_false() {
e8977170
TO
176 $communityMessages = new CRM_Core_CommunityMessages(
177 $this->cache,
178 $this->expectNoHttpRequest(),
179 FALSE
180 );
847c93ac 181 $this->assertFalse($communityMessages->isEnabled());
e8977170
TO
182 }
183
ecbe1139
TO
184 /**
185 * Download a document; after the set expiration period, download again.
186 */
e8977170 187 public function testGetDocument_NewOK_CacheOK_UpdateOK() {
ecbe1139
TO
188 // first try, good response
189 CRM_Utils_Time::setTime('2013-03-01 10:00:00');
190 $communityMessages = new CRM_Core_CommunityMessages(
191 $this->cache,
3dcd50d8 192 $this->expectOneHttpRequest(self::$webResponses['first-valid-response'])
ecbe1139
TO
193 );
194 $doc1 = $communityMessages->getDocument();
3dcd50d8 195 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
6a522e8b 196 $this->assertApproxEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires'], self::APPROX_TIME_EQUALITY);
ecbe1139
TO
197
198 // second try, $doc1 hasn't expired yet, so still use it
199 CRM_Utils_Time::setTime('2013-03-01 10:09:00');
200 $communityMessages = new CRM_Core_CommunityMessages(
201 $this->cache,
202 $this->expectNoHttpRequest()
203 );
204 $doc2 = $communityMessages->getDocument();
3dcd50d8 205 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
6a522e8b 206 $this->assertApproxEquals(strtotime('2013-03-01 10:10:00'), $doc2['expires'], self::APPROX_TIME_EQUALITY);
ecbe1139
TO
207
208 // third try, $doc1 expired, update it
209 CRM_Utils_Time::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
210 $communityMessages = new CRM_Core_CommunityMessages(
211 $this->cache,
3dcd50d8 212 $this->expectOneHttpRequest(self::$webResponses['second-valid-response'])
ecbe1139
TO
213 );
214 $doc3 = $communityMessages->getDocument();
3dcd50d8 215 $this->assertEquals('<h1>Second valid response</h1>', $doc3['messages'][0]['markup']);
6a522e8b 216 $this->assertApproxEquals(strtotime('2013-03-01 12:10:02'), $doc3['expires'], self::APPROX_TIME_EQUALITY);
ecbe1139
TO
217 }
218
219 /**
376d8353
TO
220 * First download attempt fails (due to some bad web request).
221 * Store the NACK and retry after the default time period (DEFAULT_RETRY).
222 *
acdf9ae2 223 * @dataProvider badWebResponses
e16033b4
TO
224 * @param array $badWebResponse
225 * Description of a web request that returns some kind of failure.
ecbe1139 226 */
acdf9ae2
TO
227 public function testGetDocument_NewFailure_CacheOK_UpdateOK($badWebResponse) {
228 $this->assertNotEmpty($badWebResponse);
376d8353 229
ecbe1139
TO
230 // first try, bad response
231 CRM_Utils_Time::setTime('2013-03-01 10:00:00');
232 $communityMessages = new CRM_Core_CommunityMessages(
233 $this->cache,
acdf9ae2 234 $this->expectOneHttpRequest($badWebResponse)
ecbe1139
TO
235 );
236 $doc1 = $communityMessages->getDocument();
237 $this->assertEquals(array(), $doc1['messages']);
238 $this->assertTrue($doc1['expires'] > CRM_Utils_Time::getTimeRaw());
239
240 // second try, $doc1 hasn't expired yet, so still use it
241 CRM_Utils_Time::setTime('2013-03-01 10:09:00');
242 $communityMessages = new CRM_Core_CommunityMessages(
243 $this->cache,
244 $this->expectNoHttpRequest()
245 );
246 $doc2 = $communityMessages->getDocument();
247 $this->assertEquals(array(), $doc2['messages']);
248 $this->assertEquals($doc1['expires'], $doc2['expires']);
249
250 // third try, $doc1 expired, try again, get a good response
251 CRM_Utils_Time::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
252 $communityMessages = new CRM_Core_CommunityMessages(
253 $this->cache,
3dcd50d8 254 $this->expectOneHttpRequest(self::$webResponses['first-valid-response'])
ecbe1139
TO
255 );
256 $doc3 = $communityMessages->getDocument();
3dcd50d8 257 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
ecbe1139
TO
258 $this->assertTrue($doc3['expires'] > CRM_Utils_Time::getTimeRaw());
259 }
260
261 /**
262 * First download of new doc is OK.
acdf9ae2
TO
263 * The update fails (due to some bad web response).
264 * The old data is retained in the cache.
265 * The failure eventually expires.
266 * A new update succeeds.
376d8353 267 *
acdf9ae2 268 * @dataProvider badWebResponses
e16033b4
TO
269 * @param array $badWebResponse
270 * Description of a web request that returns some kind of failure.
ecbe1139 271 */
acdf9ae2
TO
272 public function testGetDocument_NewOK_UpdateFailure_CacheOK_UpdateOK($badWebResponse) {
273 $this->assertNotEmpty($badWebResponse);
376d8353 274
ecbe1139
TO
275 // first try, good response
276 CRM_Utils_Time::setTime('2013-03-01 10:00:00');
277 $communityMessages = new CRM_Core_CommunityMessages(
278 $this->cache,
3dcd50d8 279 $this->expectOneHttpRequest(self::$webResponses['first-valid-response'])
ecbe1139
TO
280 );
281 $doc1 = $communityMessages->getDocument();
3dcd50d8 282 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
6a522e8b 283 $this->assertApproxEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires'], self::APPROX_TIME_EQUALITY);
ecbe1139
TO
284
285 // second try, $doc1 has expired; bad response; keep old data
286 CRM_Utils_Time::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
287 $communityMessages = new CRM_Core_CommunityMessages(
288 $this->cache,
acdf9ae2 289 $this->expectOneHttpRequest($badWebResponse)
ecbe1139
TO
290 );
291 $doc2 = $communityMessages->getDocument();
3dcd50d8 292 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
ecbe1139
TO
293 $this->assertTrue($doc2['expires'] > CRM_Utils_Time::getTimeRaw());
294
295 // third try, $doc2 hasn't expired yet; no request; keep old data
296 CRM_Utils_Time::setTime('2013-03-01 12:09:00');
297 $communityMessages = new CRM_Core_CommunityMessages(
298 $this->cache,
299 $this->expectNoHttpRequest()
300 );
301 $doc3 = $communityMessages->getDocument();
3dcd50d8 302 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
ecbe1139
TO
303 $this->assertEquals($doc2['expires'], $doc3['expires']);
304
305 // fourth try, $doc2 has expired yet; new request; replace data
306 CRM_Utils_Time::setTime('2013-03-01 12:10:02');
307 $communityMessages = new CRM_Core_CommunityMessages(
308 $this->cache,
3dcd50d8 309 $this->expectOneHttpRequest(self::$webResponses['second-valid-response'])
ecbe1139
TO
310 );
311 $doc4 = $communityMessages->getDocument();
3dcd50d8 312 $this->assertEquals('<h1>Second valid response</h1>', $doc4['messages'][0]['markup']);
6a522e8b 313 $this->assertApproxEquals(strtotime('2013-03-01 12:20:02'), $doc4['expires'], self::APPROX_TIME_EQUALITY);
ecbe1139
TO
314 }
315
dc92f2f8 316 /**
eceb18cc 317 * Randomly pick among two options.
dc92f2f8
TO
318 */
319 public function testPick_rand() {
320 $communityMessages = new CRM_Core_CommunityMessages(
321 $this->cache,
322 $this->expectOneHttpRequest(self::$webResponses['two-messages'])
323 );
324 $doc1 = $communityMessages->getDocument();
325 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
326 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
327
328 // randomly pick many times
2e794830 329 $trials = 80;
dc92f2f8
TO
330 $freq = array(); // array($message => $count)
331 for ($i = 0; $i < $trials; $i++) {
332 $message = $communityMessages->pick();
af2dfa5c 333 $freq[$message['markup']] = CRM_Utils_Array::value($message['markup'], $freq, 0) + 1;
dc92f2f8
TO
334 }
335
336 // assert the probabilities
2e794830
TO
337 $this->assertApproxEquals(0.5, $freq['<h1>One</h1>'] / $trials, 0.3);
338 $this->assertApproxEquals(0.5, $freq['<h1>Two</h1>'] / $trials, 0.3);
dc92f2f8
TO
339 $this->assertEquals($trials, $freq['<h1>One</h1>'] + $freq['<h1>Two</h1>']);
340 }
341
342 /**
343 * When presented with two options using component filters, always
344 * choose the one which references an active component.
345 */
346 public function testPick_componentFilter() {
347 $communityMessages = new CRM_Core_CommunityMessages(
348 $this->cache,
349 $this->expectOneHttpRequest(self::$webResponses['two-messages-halfbadcomp'])
350 );
351 $doc1 = $communityMessages->getDocument();
352 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
353 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
354
355 // randomly pick many times
356 $trials = 10;
357 $freq = array(); // array($message => $count)
358 for ($i = 0; $i < $trials; $i++) {
359 $message = $communityMessages->pick();
af2dfa5c 360 $freq[$message['markup']] = CRM_Utils_Array::value($message['markup'], $freq, 0) + 1;
dc92f2f8
TO
361 }
362
363 $this->assertEquals($trials, $freq['<h1>Two</h1>']);
364 }
365
00be9182 366 public function testEvalMarkup() {
d1b65097
TO
367 $communityMessages = new CRM_Core_CommunityMessages(
368 $this->cache,
369 $this->expectNoHttpRequest()
370 );
371 $this->assertEquals('cms=UnitTests cms=UnitTests', $communityMessages->evalMarkup('cms=%%uf%% cms={{uf}}'));
372 }
373
ecbe1139
TO
374 /**
375 * Generate a mock HTTP client with the expectation that it is never called.
376 *
377 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
378 */
379 protected function expectNoHttpRequest() {
eee950be 380 $client = $this->createMock('CRM_Utils_HttpClient');
ecbe1139
TO
381 $client->expects($this->never())
382 ->method('get');
383 return $client;
384 }
385
386 /**
387 * Generate a mock HTTP client with the expectation that it is called once.
388 *
2a6da8d7
EM
389 * @param $response
390 *
ecbe1139
TO
391 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
392 */
393 protected function expectOneHttpRequest($response) {
eee950be 394 $client = $this->createMock('CRM_Utils_HttpClient');
ecbe1139
TO
395 $client->expects($this->once())
396 ->method('get')
397 ->will($this->returnValue($response));
398 return $client;
399 }
96025800 400
ecbe1139 401}