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