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