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