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