4 +--------------------------------------------------------------------+
5 | CiviCRM version 4.5 |
6 +--------------------------------------------------------------------+
7 | Copyright CiviCRM LLC (c) 2004-2014 |
8 +--------------------------------------------------------------------+
9 | This file is a part of CiviCRM. |
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. |
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. |
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 +--------------------------------------------------------------------+
30 require_once 'CiviTest/CiviUnitTestCase.php';
31 class CRM_Core_CommunityMessagesTest
extends CiviUnitTestCase
{
33 * @var CRM_Utils_Cache_Interface
38 * @var array list of possible web responses
40 protected static $webResponses = NULL;
42 public static function initWebResponses() {
43 if (self
::$webResponses === NULL) {
44 self
::$webResponses = array(
45 'http-error' => array(
46 CRM_Utils_HttpClient
::STATUS_DL_ERROR
,
50 CRM_Utils_HttpClient
::STATUS_OK
,
51 '<html>this is not json!</html>'
53 'invalid-ttl-document' => array(
54 CRM_Utils_HttpClient
::STATUS_OK
,
56 'ttl' => 'z', // not an integer!
57 'retry' => 'z', // not an integer!
60 'markup' => '<h1>Invalid document</h1>',
65 'first-valid-response' => array(
66 CRM_Utils_HttpClient
::STATUS_OK
,
72 'markup' => '<h1>First valid response</h1>',
77 'second-valid-response' => array(
78 CRM_Utils_HttpClient
::STATUS_OK
,
84 'markup' => '<h1>Second valid response</h1>',
89 'two-messages' => array(
90 CRM_Utils_HttpClient
::STATUS_OK
,
96 'markup' => '<h1>One</h1>',
97 'components' => array('CiviMail'),
100 'markup' => '<h1>Two</h1>',
101 'components' => array('CiviMail'),
106 'two-messages-halfbadcomp' => array(
107 CRM_Utils_HttpClient
::STATUS_OK
,
113 'markup' => '<h1>One</h1>',
114 'components' => array('NotARealComponent'),
117 'markup' => '<h1>Two</h1>',
118 'components' => array('CiviMail'),
125 return self
::$webResponses;
128 public function setUp() {
130 $this->cache
= new CRM_Utils_Cache_Arraycache(array());
131 self
::initWebResponses();
134 public function tearDown() {
136 CRM_Utils_Time
::resetTime();
140 * A list of bad web-responses; in general, whenever the downloader
141 * encounters one of these bad responses, it should ignore the
142 * document, retain the old data, and retry again later.
146 public function badWebResponses() {
147 self
::initWebResponses();
149 array(self
::$webResponses['http-error']),
150 array(self
::$webResponses['bad-json']),
151 array(self
::$webResponses['invalid-ttl-document']),
156 public function testIsEnabled() {
157 $communityMessages = new CRM_Core_CommunityMessages(
159 $this->expectNoHttpRequest()
161 $this->assertTrue($communityMessages->isEnabled());
164 public function testIsEnabled_false() {
165 $communityMessages = new CRM_Core_CommunityMessages(
167 $this->expectNoHttpRequest(),
170 $this->assertFalse($communityMessages->isEnabled());
174 * Download a document; after the set expiration period, download again.
176 public function testGetDocument_NewOK_CacheOK_UpdateOK() {
177 // first try, good response
178 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
179 $communityMessages = new CRM_Core_CommunityMessages(
181 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
183 $doc1 = $communityMessages->getDocument();
184 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
185 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires']);
187 // second try, $doc1 hasn't expired yet, so still use it
188 CRM_Utils_Time
::setTime('2013-03-01 10:09:00');
189 $communityMessages = new CRM_Core_CommunityMessages(
191 $this->expectNoHttpRequest()
193 $doc2 = $communityMessages->getDocument();
194 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
195 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc2['expires']);
197 // third try, $doc1 expired, update it
198 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
199 $communityMessages = new CRM_Core_CommunityMessages(
201 $this->expectOneHttpRequest(self
::$webResponses['second-valid-response'])
203 $doc3 = $communityMessages->getDocument();
204 $this->assertEquals('<h1>Second valid response</h1>', $doc3['messages'][0]['markup']);
205 $this->assertEquals(strtotime('2013-03-01 12:10:02'), $doc3['expires']);
209 * First download attempt fails (due to some bad web request).
210 * Store the NACK and retry after the default time period (DEFAULT_RETRY).
212 * @dataProvider badWebResponses
213 * @param array $badWebResponse Description of a web request that returns some kind of failure
215 public function testGetDocument_NewFailure_CacheOK_UpdateOK($badWebResponse) {
216 $this->assertNotEmpty($badWebResponse);
218 // first try, bad response
219 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
220 $communityMessages = new CRM_Core_CommunityMessages(
222 $this->expectOneHttpRequest($badWebResponse)
224 $doc1 = $communityMessages->getDocument();
225 $this->assertEquals(array(), $doc1['messages']);
226 $this->assertTrue($doc1['expires'] > CRM_Utils_Time
::getTimeRaw());
228 // second try, $doc1 hasn't expired yet, so still use it
229 CRM_Utils_Time
::setTime('2013-03-01 10:09:00');
230 $communityMessages = new CRM_Core_CommunityMessages(
232 $this->expectNoHttpRequest()
234 $doc2 = $communityMessages->getDocument();
235 $this->assertEquals(array(), $doc2['messages']);
236 $this->assertEquals($doc1['expires'], $doc2['expires']);
238 // third try, $doc1 expired, try again, get a good response
239 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
240 $communityMessages = new CRM_Core_CommunityMessages(
242 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
244 $doc3 = $communityMessages->getDocument();
245 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
246 $this->assertTrue($doc3['expires'] > CRM_Utils_Time
::getTimeRaw());
250 * First download of new doc is OK.
251 * The update fails (due to some bad web response).
252 * The old data is retained in the cache.
253 * The failure eventually expires.
254 * A new update succeeds.
256 * @dataProvider badWebResponses
257 * @param array $badWebResponse Description of a web request that returns some kind of failure
259 public function testGetDocument_NewOK_UpdateFailure_CacheOK_UpdateOK($badWebResponse) {
260 $this->assertNotEmpty($badWebResponse);
262 // first try, good response
263 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
264 $communityMessages = new CRM_Core_CommunityMessages(
266 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
268 $doc1 = $communityMessages->getDocument();
269 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
270 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires']);
272 // second try, $doc1 has expired; bad response; keep old data
273 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
274 $communityMessages = new CRM_Core_CommunityMessages(
276 $this->expectOneHttpRequest($badWebResponse)
278 $doc2 = $communityMessages->getDocument();
279 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
280 $this->assertTrue($doc2['expires'] > CRM_Utils_Time
::getTimeRaw());
282 // third try, $doc2 hasn't expired yet; no request; keep old data
283 CRM_Utils_Time
::setTime('2013-03-01 12:09:00');
284 $communityMessages = new CRM_Core_CommunityMessages(
286 $this->expectNoHttpRequest()
288 $doc3 = $communityMessages->getDocument();
289 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
290 $this->assertEquals($doc2['expires'], $doc3['expires']);
292 // fourth try, $doc2 has expired yet; new request; replace data
293 CRM_Utils_Time
::setTime('2013-03-01 12:10:02');
294 $communityMessages = new CRM_Core_CommunityMessages(
296 $this->expectOneHttpRequest(self
::$webResponses['second-valid-response'])
298 $doc4 = $communityMessages->getDocument();
299 $this->assertEquals('<h1>Second valid response</h1>', $doc4['messages'][0]['markup']);
300 $this->assertEquals(strtotime('2013-03-01 12:20:02'), $doc4['expires']);
304 * Randomly pick among two options
306 public function testPick_rand() {
307 $communityMessages = new CRM_Core_CommunityMessages(
309 $this->expectOneHttpRequest(self
::$webResponses['two-messages'])
311 $doc1 = $communityMessages->getDocument();
312 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
313 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
315 // randomly pick many times
317 $freq = array(); // array($message => $count)
318 for ($i = 0; $i < $trials; $i++
) {
319 $message = $communityMessages->pick();
320 $freq[$message['markup']] = CRM_Utils_Array
::value($message['markup'], $freq, 0) +
1;
323 // assert the probabilities
324 $this->assertApproxEquals(0.5, $freq['<h1>One</h1>'] / $trials, 0.3);
325 $this->assertApproxEquals(0.5, $freq['<h1>Two</h1>'] / $trials, 0.3);
326 $this->assertEquals($trials, $freq['<h1>One</h1>'] +
$freq['<h1>Two</h1>']);
330 * When presented with two options using component filters, always
331 * choose the one which references an active component.
333 public function testPick_componentFilter() {
334 $communityMessages = new CRM_Core_CommunityMessages(
336 $this->expectOneHttpRequest(self
::$webResponses['two-messages-halfbadcomp'])
338 $doc1 = $communityMessages->getDocument();
339 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
340 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
342 // randomly pick many times
344 $freq = array(); // array($message => $count)
345 for ($i = 0; $i < $trials; $i++
) {
346 $message = $communityMessages->pick();
347 $freq[$message['markup']] = CRM_Utils_Array
::value($message['markup'], $freq, 0) +
1;
350 $this->assertEquals($trials, $freq['<h1>Two</h1>']);
353 function testEvalMarkup() {
354 $communityMessages = new CRM_Core_CommunityMessages(
356 $this->expectNoHttpRequest()
358 $this->assertEquals('cms=UnitTests cms=UnitTests', $communityMessages->evalMarkup('cms=%%uf%% cms={{uf}}'));
362 * Generate a mock HTTP client with the expectation that it is never called.
364 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
366 protected function expectNoHttpRequest() {
367 $client = $this->getMock('CRM_Utils_HttpClient');
368 $client->expects($this->never())
374 * Generate a mock HTTP client with the expectation that it is called once.
376 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
378 protected function expectOneHttpRequest($response) {
379 $client = $this->getMock('CRM_Utils_HttpClient');
380 $client->expects($this->once())
382 ->will($this->returnValue($response));