Merge pull request #13289 from mfb/pear-mail
[civicrm-core.git] / tests / phpunit / E2E / Cache / TieredTest.php
1 <?php
2 /*
3 +--------------------------------------------------------------------+
4 | CiviCRM version 5 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2019 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
9 | |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
13 | |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU Affero General Public |
20 | License along with this program; if not, contact CiviCRM LLC |
21 | at info[AT]civicrm[DOT]org. If you have questions about the |
22 | GNU Affero General Public License or the licensing of CiviCRM, |
23 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
24 +--------------------------------------------------------------------+
25 */
26
27 /**
28 * Verify that CRM_Utils_Cache_Tiered complies with PSR-16.
29 *
30 * @group e2e
31 */
32 class E2E_Cache_TieredTest extends E2E_Cache_CacheTestCase {
33 const TOLERANCE = 5;
34
35 /**
36 * @var CRM_Utils_Cache_ArrayCache
37 */
38 protected $a, $b;
39
40 protected function tearDown() {
41 if (function_exists('timecop_return')) {
42 timecop_return();
43 }
44 parent::tearDown();
45 }
46
47 public function createSimpleCache($maxTimeouts = [86400]) {
48 return new CRM_Utils_Cache_Tiered([
49 $this->a = CRM_Utils_Cache::create([
50 'name' => 'e2e tiered test a',
51 'type' => ['ArrayCache'],
52 ]),
53 $this->b = CRM_Utils_Cache::create([
54 'name' => 'e2e tiered test b',
55 'type' => ['ArrayCache'],
56 ])
57 ], $maxTimeouts);
58 }
59
60 public function testDoubleLifeWithDelete() {
61 $this->assertFalse($this->a->has('foo'));
62 $this->assertFalse($this->b->has('foo'));
63 $this->assertEquals('dfl-1', $this->a->get('foo', 'dfl-1'));
64 $this->assertEquals('dfl-2', $this->b->get('foo', 'dfl-2'));
65
66 $this->cache->set('foo', 100);
67
68 $this->assertTrue($this->a->has('foo'));
69 $this->assertTrue($this->b->has('foo'));
70 $this->assertEquals(100, $this->a->get('foo', 'dfl-1')[1]);
71 $this->assertEquals(100, $this->b->get('foo', 'dfl-2')[1]);
72 $this->assertEquals($this->a->get('foo'), $this->b->get('foo'));
73
74 $this->cache->set('foo', 200);
75
76 $this->assertTrue($this->a->has('foo'));
77 $this->assertTrue($this->b->has('foo'));
78 $this->assertEquals(200, $this->a->get('foo', 'dfl-1')[1]);
79 $this->assertEquals(200, $this->b->get('foo', 'dfl-2')[1]);
80 $this->assertEquals($this->a->get('foo'), $this->b->get('foo'));
81
82 $this->cache->delete('foo');
83
84 $this->assertFalse($this->a->has('foo'));
85 $this->assertFalse($this->b->has('foo'));
86 $this->assertEquals('dfl-1', $this->a->get('foo', 'dfl-1'));
87 $this->assertEquals('dfl-2', $this->b->get('foo', 'dfl-2'));
88 }
89
90 public function testDoubleLifeWithClear() {
91 $this->assertFalse($this->a->has('foo'));
92 $this->assertFalse($this->b->has('foo'));
93 $this->assertEquals('dfl-1', $this->a->get('foo', 'dfl-1'));
94 $this->assertEquals('dfl-2', $this->b->get('foo', 'dfl-2'));
95
96 $this->cache->set('foo', 100);
97
98 $this->assertTrue($this->a->has('foo'));
99 $this->assertTrue($this->b->has('foo'));
100 $this->assertEquals(100, $this->a->get('foo', 'dfl-1')[1]);
101 $this->assertEquals(100, $this->b->get('foo', 'dfl-2')[1]);
102 $this->assertEquals($this->a->get('foo'), $this->b->get('foo'));
103
104 $this->cache->clear();
105
106 $this->assertFalse($this->a->has('foo'));
107 $this->assertFalse($this->b->has('foo'));
108 $this->assertEquals('dfl-1', $this->a->get('foo', 'dfl-1'));
109 $this->assertEquals('dfl-2', $this->b->get('foo', 'dfl-2'));
110 }
111
112 public function testTieredTimeout_default() {
113 $start = CRM_Utils_Time::getTimeRaw();
114 $this->cache = $this->createSimpleCache([100, 1000]);
115
116 $this->cache->set('foo', 'bar');
117 $this->assertApproxEquals($start + 100, $this->a->getExpires('foo'), self::TOLERANCE);
118 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
119
120 // Simulate expiration & repopulation in nearest tier.
121
122 $this->a->clear();
123 $this->assertApproxEquals(NULL, $this->a->getExpires('foo'), self::TOLERANCE);
124 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
125
126 $this->assertEquals('bar', $this->cache->get('foo'));
127 $this->assertApproxEquals($start + 100, $this->a->getExpires('foo'), self::TOLERANCE);
128 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
129 }
130
131 public function testTieredTimeout_explicitLow() {
132 $start = CRM_Utils_Time::getTimeRaw();
133 $this->cache = $this->createSimpleCache([100, 1000]);
134
135 $this->cache->set('foo', 'bar', 50);
136 $this->assertApproxEquals($start + 50, $this->a->getExpires('foo'), self::TOLERANCE);
137 $this->assertApproxEquals($start + 50, $this->b->getExpires('foo'), self::TOLERANCE);
138
139 // Simulate expiration & repopulation in nearest tier.
140
141 $this->a->clear();
142 $this->assertApproxEquals(NULL, $this->a->getExpires('foo'), self::TOLERANCE);
143 $this->assertApproxEquals($start + 50, $this->b->getExpires('foo'), self::TOLERANCE);
144
145 $this->assertEquals('bar', $this->cache->get('foo'));
146 $this->assertApproxEquals($start + 50, $this->a->getExpires('foo'), self::TOLERANCE);
147 $this->assertApproxEquals($start + 50, $this->b->getExpires('foo'), self::TOLERANCE);
148 }
149
150 public function testTieredTimeout_explicitMedium() {
151 $start = CRM_Utils_Time::getTimeRaw();
152 $this->cache = $this->createSimpleCache([100, 1000]);
153
154 $this->cache->set('foo', 'bar', 500);
155 $this->assertApproxEquals($start + 100, $this->a->getExpires('foo'), self::TOLERANCE);
156 $this->assertApproxEquals($start + 500, $this->b->getExpires('foo'), self::TOLERANCE);
157
158 // Simulate expiration & repopulation in nearest tier.
159
160 $this->a->clear();
161 $this->assertApproxEquals(NULL, $this->a->getExpires('foo'), self::TOLERANCE);
162 $this->assertApproxEquals($start + 500, $this->b->getExpires('foo'), self::TOLERANCE);
163
164 $this->assertEquals('bar', $this->cache->get('foo'));
165 $this->assertApproxEquals($start + 100, $this->a->getExpires('foo'), self::TOLERANCE);
166 $this->assertApproxEquals($start + 500, $this->b->getExpires('foo'), self::TOLERANCE);
167 }
168
169 public function testTieredTimeout_explicitHigh_lateReoad() {
170 $start = CRM_Utils_Time::getTimeRaw();
171 $this->cache = $this->createSimpleCache([100, 1000]);
172
173 $this->cache->set('foo', 'bar', 5000);
174 $this->assertApproxEquals($start + 100, $this->a->getExpires('foo'), self::TOLERANCE);
175 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
176
177 // Simulate expiration & repopulation in nearest tier.
178
179 $this->a->clear();
180 $this->assertApproxEquals(NULL, $this->a->getExpires('foo'), self::TOLERANCE);
181 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
182
183 function_exists('timecop_return') ? timecop_travel(time() + self::TOLERANCE) : sleep(self::TOLERANCE);
184
185 $this->assertEquals('bar', $this->cache->get('foo'));
186 $this->assertApproxEquals($start + 100 + self::TOLERANCE, $this->a->getExpires('foo'), self::TOLERANCE);
187 $this->assertApproxEquals($start + 1000, $this->b->getExpires('foo'), self::TOLERANCE);
188 }
189
190 /**
191 * Assert that two numbers are approximately equal.
192 *
193 * @param int|float $expected
194 * @param int|float $actual
195 * @param int|float $tolerance
196 * @param string $message
197 */
198 public function assertApproxEquals($expected, $actual, $tolerance, $message = NULL) {
199 if ($message === NULL) {
200 $message = sprintf("approx-equals: expected=[%.3f] actual=[%.3f] tolerance=[%.3f]", $expected, $actual, $tolerance);
201 }
202 $this->assertTrue(abs($actual - $expected) < $tolerance, $message);
203 }
204
205 }