f23161c10b0762ed28654f13609e1c9acbf2797b
[yaffs-website] / vendor / symfony / http-foundation / Tests / Session / Storage / Handler / MongoDbSessionHandlerTest.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler;
16
17 /**
18  * @author Markus Bachmann <markus.bachmann@bachi.biz>
19  * @group time-sensitive
20  */
21 class MongoDbSessionHandlerTest extends TestCase
22 {
23     /**
24      * @var \PHPUnit_Framework_MockObject_MockObject
25      */
26     private $mongo;
27     private $storage;
28     public $options;
29
30     protected function setUp()
31     {
32         parent::setUp();
33
34         if (!extension_loaded('mongo') && !extension_loaded('mongodb')) {
35             $this->markTestSkipped('The Mongo or MongoDB extension is required.');
36         }
37
38         if (phpversion('mongodb')) {
39             $mongoClass = 'MongoDB\Client';
40         } else {
41             $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient';
42         }
43
44         $this->mongo = $this->getMockBuilder($mongoClass)
45             ->disableOriginalConstructor()
46             ->getMock();
47
48         $this->options = array(
49             'id_field' => '_id',
50             'data_field' => 'data',
51             'time_field' => 'time',
52             'expiry_field' => 'expires_at',
53             'database' => 'sf2-test',
54             'collection' => 'session-test',
55         );
56
57         $this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
58     }
59
60     /**
61      * @expectedException \InvalidArgumentException
62      */
63     public function testConstructorShouldThrowExceptionForInvalidMongo()
64     {
65         new MongoDbSessionHandler(new \stdClass(), $this->options);
66     }
67
68     /**
69      * @expectedException \InvalidArgumentException
70      */
71     public function testConstructorShouldThrowExceptionForMissingOptions()
72     {
73         new MongoDbSessionHandler($this->mongo, array());
74     }
75
76     public function testOpenMethodAlwaysReturnTrue()
77     {
78         $this->assertTrue($this->storage->open('test', 'test'), 'The "open" method should always return true');
79     }
80
81     public function testCloseMethodAlwaysReturnTrue()
82     {
83         $this->assertTrue($this->storage->close(), 'The "close" method should always return true');
84     }
85
86     public function testRead()
87     {
88         $collection = $this->createMongoCollectionMock();
89
90         $this->mongo->expects($this->once())
91             ->method('selectCollection')
92             ->with($this->options['database'], $this->options['collection'])
93             ->will($this->returnValue($collection));
94
95         $that = $this;
96
97         // defining the timeout before the actual method call
98         // allows to test for "greater than" values in the $criteria
99         $testTimeout = time() + 1;
100
101         $collection->expects($this->once())
102             ->method('findOne')
103             ->will($this->returnCallback(function ($criteria) use ($that, $testTimeout) {
104                 $that->assertArrayHasKey($that->options['id_field'], $criteria);
105                 $that->assertEquals($criteria[$that->options['id_field']], 'foo');
106
107                 $that->assertArrayHasKey($that->options['expiry_field'], $criteria);
108                 $that->assertArrayHasKey('$gte', $criteria[$that->options['expiry_field']]);
109
110                 if (phpversion('mongodb')) {
111                     $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$that->options['expiry_field']]['$gte']);
112                     $that->assertGreaterThanOrEqual(round(((int) $criteria[$that->options['expiry_field']]['$gte']) / 1000), $testTimeout);
113                 } else {
114                     $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$gte']);
115                     $that->assertGreaterThanOrEqual($criteria[$that->options['expiry_field']]['$gte']->sec, $testTimeout);
116                 }
117
118                 $fields = array(
119                     $that->options['id_field'] => 'foo',
120                 );
121
122                 if (phpversion('mongodb')) {
123                     $fields[$that->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
124                     $fields[$that->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000);
125                 } else {
126                     $fields[$that->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY);
127                     $fields[$that->options['id_field']] = new \MongoDate();
128                 }
129
130                 return $fields;
131             }));
132
133         $this->assertEquals('bar', $this->storage->read('foo'));
134     }
135
136     public function testWrite()
137     {
138         $collection = $this->createMongoCollectionMock();
139
140         $this->mongo->expects($this->once())
141             ->method('selectCollection')
142             ->with($this->options['database'], $this->options['collection'])
143             ->will($this->returnValue($collection));
144
145         $that = $this;
146         $data = array();
147
148         $methodName = phpversion('mongodb') ? 'updateOne' : 'update';
149
150         $collection->expects($this->once())
151             ->method($methodName)
152             ->will($this->returnCallback(function ($criteria, $updateData, $options) use ($that, &$data) {
153                 $that->assertEquals(array($that->options['id_field'] => 'foo'), $criteria);
154
155                 if (phpversion('mongodb')) {
156                     $that->assertEquals(array('upsert' => true), $options);
157                 } else {
158                     $that->assertEquals(array('upsert' => true, 'multiple' => false), $options);
159                 }
160
161                 $data = $updateData['$set'];
162             }));
163
164         $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime');
165         $this->assertTrue($this->storage->write('foo', 'bar'));
166
167         if (phpversion('mongodb')) {
168             $that->assertEquals('bar', $data[$that->options['data_field']]->getData());
169             $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['time_field']]);
170             $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['expiry_field']]);
171             $that->assertGreaterThanOrEqual($expectedExpiry, round(((int) $data[$that->options['expiry_field']]) / 1000));
172         } else {
173             $that->assertEquals('bar', $data[$that->options['data_field']]->bin);
174             $that->assertInstanceOf('MongoDate', $data[$that->options['time_field']]);
175             $that->assertInstanceOf('MongoDate', $data[$that->options['expiry_field']]);
176             $that->assertGreaterThanOrEqual($expectedExpiry, $data[$that->options['expiry_field']]->sec);
177         }
178     }
179
180     public function testWriteWhenUsingExpiresField()
181     {
182         $this->options = array(
183             'id_field' => '_id',
184             'data_field' => 'data',
185             'time_field' => 'time',
186             'database' => 'sf2-test',
187             'collection' => 'session-test',
188             'expiry_field' => 'expiresAt',
189         );
190
191         $this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
192
193         $collection = $this->createMongoCollectionMock();
194
195         $this->mongo->expects($this->once())
196             ->method('selectCollection')
197             ->with($this->options['database'], $this->options['collection'])
198             ->will($this->returnValue($collection));
199
200         $that = $this;
201         $data = array();
202
203         $methodName = phpversion('mongodb') ? 'updateOne' : 'update';
204
205         $collection->expects($this->once())
206             ->method($methodName)
207             ->will($this->returnCallback(function ($criteria, $updateData, $options) use ($that, &$data) {
208                 $that->assertEquals(array($that->options['id_field'] => 'foo'), $criteria);
209
210                 if (phpversion('mongodb')) {
211                     $that->assertEquals(array('upsert' => true), $options);
212                 } else {
213                     $that->assertEquals(array('upsert' => true, 'multiple' => false), $options);
214                 }
215
216                 $data = $updateData['$set'];
217             }));
218
219         $this->assertTrue($this->storage->write('foo', 'bar'));
220
221         if (phpversion('mongodb')) {
222             $that->assertEquals('bar', $data[$that->options['data_field']]->getData());
223             $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['time_field']]);
224             $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['expiry_field']]);
225         } else {
226             $that->assertEquals('bar', $data[$that->options['data_field']]->bin);
227             $that->assertInstanceOf('MongoDate', $data[$that->options['time_field']]);
228             $that->assertInstanceOf('MongoDate', $data[$that->options['expiry_field']]);
229         }
230     }
231
232     public function testReplaceSessionData()
233     {
234         $collection = $this->createMongoCollectionMock();
235
236         $this->mongo->expects($this->once())
237             ->method('selectCollection')
238             ->with($this->options['database'], $this->options['collection'])
239             ->will($this->returnValue($collection));
240
241         $data = array();
242
243         $methodName = phpversion('mongodb') ? 'updateOne' : 'update';
244
245         $collection->expects($this->exactly(2))
246             ->method($methodName)
247             ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) {
248                 $data = $updateData;
249             }));
250
251         $this->storage->write('foo', 'bar');
252         $this->storage->write('foo', 'foobar');
253
254         if (phpversion('mongodb')) {
255             $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData());
256         } else {
257             $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin);
258         }
259     }
260
261     public function testDestroy()
262     {
263         $collection = $this->createMongoCollectionMock();
264
265         $this->mongo->expects($this->once())
266             ->method('selectCollection')
267             ->with($this->options['database'], $this->options['collection'])
268             ->will($this->returnValue($collection));
269
270         $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove';
271
272         $collection->expects($this->once())
273             ->method($methodName)
274             ->with(array($this->options['id_field'] => 'foo'));
275
276         $this->assertTrue($this->storage->destroy('foo'));
277     }
278
279     public function testGc()
280     {
281         $collection = $this->createMongoCollectionMock();
282
283         $this->mongo->expects($this->once())
284             ->method('selectCollection')
285             ->with($this->options['database'], $this->options['collection'])
286             ->will($this->returnValue($collection));
287
288         $that = $this;
289
290         $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove';
291
292         $collection->expects($this->once())
293             ->method($methodName)
294             ->will($this->returnCallback(function ($criteria) use ($that) {
295                 if (phpversion('mongodb')) {
296                     $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$that->options['expiry_field']]['$lt']);
297                     $that->assertGreaterThanOrEqual(time() - 1, round(((int) $criteria[$that->options['expiry_field']]['$lt']) / 1000));
298                 } else {
299                     $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$lt']);
300                     $that->assertGreaterThanOrEqual(time() - 1, $criteria[$that->options['expiry_field']]['$lt']->sec);
301                 }
302             }));
303
304         $this->assertTrue($this->storage->gc(1));
305     }
306
307     public function testGetConnection()
308     {
309         $method = new \ReflectionMethod($this->storage, 'getMongo');
310         $method->setAccessible(true);
311
312         if (phpversion('mongodb')) {
313             $mongoClass = 'MongoDB\Client';
314         } else {
315             $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient';
316         }
317
318         $this->assertInstanceOf($mongoClass, $method->invoke($this->storage));
319     }
320
321     private function createMongoCollectionMock()
322     {
323         $collectionClass = 'MongoCollection';
324         if (phpversion('mongodb')) {
325             $collectionClass = 'MongoDB\Collection';
326         }
327
328         $collection = $this->getMockBuilder($collectionClass)
329             ->disableOriginalConstructor()
330             ->getMock();
331
332         return $collection;
333     }
334 }