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';
33 * Class CRM_Core_CommunityMessagesTest
35 class CRM_Core_CommunityMessagesTest
extends CiviUnitTestCase
{
37 * @var CRM_Utils_Cache_Interface
42 * @var array list of possible web responses
44 protected static $webResponses = NULL;
49 public static function initWebResponses() {
50 if (self
::$webResponses === NULL) {
51 self
::$webResponses = array(
52 'http-error' => array(
53 CRM_Utils_HttpClient
::STATUS_DL_ERROR
,
57 CRM_Utils_HttpClient
::STATUS_OK
,
58 '<html>this is not json!</html>'
60 'invalid-ttl-document' => array(
61 CRM_Utils_HttpClient
::STATUS_OK
,
63 'ttl' => 'z', // not an integer!
64 'retry' => 'z', // not an integer!
67 'markup' => '<h1>Invalid document</h1>',
72 'first-valid-response' => array(
73 CRM_Utils_HttpClient
::STATUS_OK
,
79 'markup' => '<h1>First valid response</h1>',
84 'second-valid-response' => array(
85 CRM_Utils_HttpClient
::STATUS_OK
,
91 'markup' => '<h1>Second valid response</h1>',
96 'two-messages' => array(
97 CRM_Utils_HttpClient
::STATUS_OK
,
103 'markup' => '<h1>One</h1>',
104 'components' => array('CiviMail'),
107 'markup' => '<h1>Two</h1>',
108 'components' => array('CiviMail'),
113 'two-messages-halfbadcomp' => array(
114 CRM_Utils_HttpClient
::STATUS_OK
,
120 'markup' => '<h1>One</h1>',
121 'components' => array('NotARealComponent'),
124 'markup' => '<h1>Two</h1>',
125 'components' => array('CiviMail'),
132 return self
::$webResponses;
135 public function setUp() {
137 $this->cache
= new CRM_Utils_Cache_Arraycache(array());
138 self
::initWebResponses();
141 public function tearDown() {
143 CRM_Utils_Time
::resetTime();
147 * A list of bad web-responses; in general, whenever the downloader
148 * encounters one of these bad responses, it should ignore the
149 * document, retain the old data, and retry again later.
153 public function badWebResponses() {
154 self
::initWebResponses();
156 array(self
::$webResponses['http-error']),
157 array(self
::$webResponses['bad-json']),
158 array(self
::$webResponses['invalid-ttl-document']),
163 public function testIsEnabled() {
164 $communityMessages = new CRM_Core_CommunityMessages(
166 $this->expectNoHttpRequest()
168 $this->assertTrue($communityMessages->isEnabled());
171 public function testIsEnabled_false() {
172 $communityMessages = new CRM_Core_CommunityMessages(
174 $this->expectNoHttpRequest(),
177 $this->assertFalse($communityMessages->isEnabled());
181 * Download a document; after the set expiration period, download again.
183 public function testGetDocument_NewOK_CacheOK_UpdateOK() {
184 // first try, good response
185 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
186 $communityMessages = new CRM_Core_CommunityMessages(
188 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
190 $doc1 = $communityMessages->getDocument();
191 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
192 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires']);
194 // second try, $doc1 hasn't expired yet, so still use it
195 CRM_Utils_Time
::setTime('2013-03-01 10:09:00');
196 $communityMessages = new CRM_Core_CommunityMessages(
198 $this->expectNoHttpRequest()
200 $doc2 = $communityMessages->getDocument();
201 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
202 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc2['expires']);
204 // third try, $doc1 expired, update it
205 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
206 $communityMessages = new CRM_Core_CommunityMessages(
208 $this->expectOneHttpRequest(self
::$webResponses['second-valid-response'])
210 $doc3 = $communityMessages->getDocument();
211 $this->assertEquals('<h1>Second valid response</h1>', $doc3['messages'][0]['markup']);
212 $this->assertEquals(strtotime('2013-03-01 12:10:02'), $doc3['expires']);
216 * First download attempt fails (due to some bad web request).
217 * Store the NACK and retry after the default time period (DEFAULT_RETRY).
219 * @dataProvider badWebResponses
220 * @param array $badWebResponse Description of a web request that returns some kind of failure
222 public function testGetDocument_NewFailure_CacheOK_UpdateOK($badWebResponse) {
223 $this->assertNotEmpty($badWebResponse);
225 // first try, bad response
226 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
227 $communityMessages = new CRM_Core_CommunityMessages(
229 $this->expectOneHttpRequest($badWebResponse)
231 $doc1 = $communityMessages->getDocument();
232 $this->assertEquals(array(), $doc1['messages']);
233 $this->assertTrue($doc1['expires'] > CRM_Utils_Time
::getTimeRaw());
235 // second try, $doc1 hasn't expired yet, so still use it
236 CRM_Utils_Time
::setTime('2013-03-01 10:09:00');
237 $communityMessages = new CRM_Core_CommunityMessages(
239 $this->expectNoHttpRequest()
241 $doc2 = $communityMessages->getDocument();
242 $this->assertEquals(array(), $doc2['messages']);
243 $this->assertEquals($doc1['expires'], $doc2['expires']);
245 // third try, $doc1 expired, try again, get a good response
246 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
247 $communityMessages = new CRM_Core_CommunityMessages(
249 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
251 $doc3 = $communityMessages->getDocument();
252 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
253 $this->assertTrue($doc3['expires'] > CRM_Utils_Time
::getTimeRaw());
257 * First download of new doc is OK.
258 * The update fails (due to some bad web response).
259 * The old data is retained in the cache.
260 * The failure eventually expires.
261 * A new update succeeds.
263 * @dataProvider badWebResponses
264 * @param array $badWebResponse Description of a web request that returns some kind of failure
266 public function testGetDocument_NewOK_UpdateFailure_CacheOK_UpdateOK($badWebResponse) {
267 $this->assertNotEmpty($badWebResponse);
269 // first try, good response
270 CRM_Utils_Time
::setTime('2013-03-01 10:00:00');
271 $communityMessages = new CRM_Core_CommunityMessages(
273 $this->expectOneHttpRequest(self
::$webResponses['first-valid-response'])
275 $doc1 = $communityMessages->getDocument();
276 $this->assertEquals('<h1>First valid response</h1>', $doc1['messages'][0]['markup']);
277 $this->assertEquals(strtotime('2013-03-01 10:10:00'), $doc1['expires']);
279 // second try, $doc1 has expired; bad response; keep old data
280 CRM_Utils_Time
::setTime('2013-03-01 12:00:02'); // more than 2 hours later (DEFAULT_RETRY)
281 $communityMessages = new CRM_Core_CommunityMessages(
283 $this->expectOneHttpRequest($badWebResponse)
285 $doc2 = $communityMessages->getDocument();
286 $this->assertEquals('<h1>First valid response</h1>', $doc2['messages'][0]['markup']);
287 $this->assertTrue($doc2['expires'] > CRM_Utils_Time
::getTimeRaw());
289 // third try, $doc2 hasn't expired yet; no request; keep old data
290 CRM_Utils_Time
::setTime('2013-03-01 12:09:00');
291 $communityMessages = new CRM_Core_CommunityMessages(
293 $this->expectNoHttpRequest()
295 $doc3 = $communityMessages->getDocument();
296 $this->assertEquals('<h1>First valid response</h1>', $doc3['messages'][0]['markup']);
297 $this->assertEquals($doc2['expires'], $doc3['expires']);
299 // fourth try, $doc2 has expired yet; new request; replace data
300 CRM_Utils_Time
::setTime('2013-03-01 12:10:02');
301 $communityMessages = new CRM_Core_CommunityMessages(
303 $this->expectOneHttpRequest(self
::$webResponses['second-valid-response'])
305 $doc4 = $communityMessages->getDocument();
306 $this->assertEquals('<h1>Second valid response</h1>', $doc4['messages'][0]['markup']);
307 $this->assertEquals(strtotime('2013-03-01 12:20:02'), $doc4['expires']);
311 * Randomly pick among two options
313 public function testPick_rand() {
314 $communityMessages = new CRM_Core_CommunityMessages(
316 $this->expectOneHttpRequest(self
::$webResponses['two-messages'])
318 $doc1 = $communityMessages->getDocument();
319 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
320 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
322 // randomly pick many times
324 $freq = array(); // array($message => $count)
325 for ($i = 0; $i < $trials; $i++
) {
326 $message = $communityMessages->pick();
327 $freq[$message['markup']] = CRM_Utils_Array
::value($message['markup'], $freq, 0) +
1;
330 // assert the probabilities
331 $this->assertApproxEquals(0.5, $freq['<h1>One</h1>'] / $trials, 0.3);
332 $this->assertApproxEquals(0.5, $freq['<h1>Two</h1>'] / $trials, 0.3);
333 $this->assertEquals($trials, $freq['<h1>One</h1>'] +
$freq['<h1>Two</h1>']);
337 * When presented with two options using component filters, always
338 * choose the one which references an active component.
340 public function testPick_componentFilter() {
341 $communityMessages = new CRM_Core_CommunityMessages(
343 $this->expectOneHttpRequest(self
::$webResponses['two-messages-halfbadcomp'])
345 $doc1 = $communityMessages->getDocument();
346 $this->assertEquals('<h1>One</h1>', $doc1['messages'][0]['markup']);
347 $this->assertEquals('<h1>Two</h1>', $doc1['messages'][1]['markup']);
349 // randomly pick many times
351 $freq = array(); // array($message => $count)
352 for ($i = 0; $i < $trials; $i++
) {
353 $message = $communityMessages->pick();
354 $freq[$message['markup']] = CRM_Utils_Array
::value($message['markup'], $freq, 0) +
1;
357 $this->assertEquals($trials, $freq['<h1>Two</h1>']);
360 function testEvalMarkup() {
361 $communityMessages = new CRM_Core_CommunityMessages(
363 $this->expectNoHttpRequest()
365 $this->assertEquals('cms=UnitTests cms=UnitTests', $communityMessages->evalMarkup('cms=%%uf%% cms={{uf}}'));
369 * Generate a mock HTTP client with the expectation that it is never called.
371 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
373 protected function expectNoHttpRequest() {
374 $client = $this->getMock('CRM_Utils_HttpClient');
375 $client->expects($this->never())
381 * Generate a mock HTTP client with the expectation that it is called once.
385 * @return CRM_Utils_HttpClient|PHPUnit_Framework_MockObject_MockObject
387 protected function expectOneHttpRequest($response) {
388 $client = $this->getMock('CRM_Utils_HttpClient');
389 $client->expects($this->once())
391 ->will($this->returnValue($response));