Security update for Core, with self-updated composer
[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         // defining the timeout before the actual method call
100         // allows to test for "greater than" values in the $criteria
101         $testTimeout = time() + 1;
102
103         $collection->expects($this->once())
104             ->method('findOne')
105             ->will($this->returnCallback(function ($criteria) use ($testTimeout) {
106                 $this->assertArrayHasKey($this->options['id_field'], $criteria);
107                 $this->assertEquals($criteria[$this->options['id_field']], 'foo');
108
109                 $this->assertArrayHasKey($this->options['expiry_field'], $criteria);
110                 $this->assertArrayHasKey('$gte', $criteria[$this->options['expiry_field']]);
111
112                 if (phpversion('mongodb')) {
113                     $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$gte']);
114                     $this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout);
115                 } else {
116                     $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$gte']);
117                     $this->assertGreaterThanOrEqual($criteria[$this->options['expiry_field']]['$gte']->sec, $testTimeout);
118                 }
119
120                 $fields = array(
121                     $this->options['id_field'] => 'foo',
122                 );
123
124                 if (phpversion('mongodb')) {
125                     $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY);
126                     $fields[$this->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000);
127                 } else {
128                     $fields[$this->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY);
129                     $fields[$this->options['id_field']] = new \MongoDate();
130                 }
131
132                 return $fields;
133             }));
134
135         $this->assertEquals('bar', $this->storage->read('foo'));
136     }
137
138     public function testWrite()
139     {
140         $collection = $this->createMongoCollectionMock();
141
142         $this->mongo->expects($this->once())
143             ->method('selectCollection')
144             ->with($this->options['database'], $this->options['collection'])
145             ->will($this->returnValue($collection));
146
147         $data = array();
148
149         $methodName = phpversion('mongodb') ? 'updateOne' : 'update';
150
151         $collection->expects($this->once())
152             ->method($methodName)
153             ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) {
154                 $this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria);
155
156                 if (phpversion('mongodb')) {
157                     $this->assertEquals(array('upsert' => true), $options);
158                 } else {
159                     $this->assertEquals(array('upsert' => true, 'multiple' => false), $options);
160                 }
161
162                 $data = $updateData['$set'];
163             }));
164
165         $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime');
166         $this->assertTrue($this->storage->write('foo', 'bar'));
167
168         if (phpversion('mongodb')) {
169             $this->assertEquals('bar', $data[$this->options['data_field']]->getData());
170             $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]);
171             $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]);
172             $this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000));
173         } else {
174             $this->assertEquals('bar', $data[$this->options['data_field']]->bin);
175             $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
176             $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]);
177             $this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec);
178         }
179     }
180
181     public function testWriteWhenUsingExpiresField()
182     {
183         $this->options = array(
184             'id_field' => '_id',
185             'data_field' => 'data',
186             'time_field' => 'time',
187             'database' => 'sf2-test',
188             'collection' => 'session-test',
189             'expiry_field' => 'expiresAt',
190         );
191
192         $this->storage = new MongoDbSessionHandler($this->mongo, $this->options);
193
194         $collection = $this->createMongoCollectionMock();
195
196         $this->mongo->expects($this->once())
197             ->method('selectCollection')
198             ->with($this->options['database'], $this->options['collection'])
199             ->will($this->returnValue($collection));
200
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 (&$data) {
208                 $this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria);
209
210                 if (phpversion('mongodb')) {
211                     $this->assertEquals(array('upsert' => true), $options);
212                 } else {
213                     $this->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             $this->assertEquals('bar', $data[$this->options['data_field']]->getData());
223             $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]);
224             $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]);
225         } else {
226             $this->assertEquals('bar', $data[$this->options['data_field']]->bin);
227             $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]);
228             $this->assertInstanceOf('MongoDate', $data[$this->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         $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove';
289
290         $collection->expects($this->once())
291             ->method($methodName)
292             ->will($this->returnCallback(function ($criteria) {
293                 if (phpversion('mongodb')) {
294                     $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$lt']);
295                     $this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000));
296                 } else {
297                     $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$lt']);
298                     $this->assertGreaterThanOrEqual(time() - 1, $criteria[$this->options['expiry_field']]['$lt']->sec);
299                 }
300             }));
301
302         $this->assertTrue($this->storage->gc(1));
303     }
304
305     public function testGetConnection()
306     {
307         $method = new \ReflectionMethod($this->storage, 'getMongo');
308         $method->setAccessible(true);
309
310         if (phpversion('mongodb')) {
311             $mongoClass = 'MongoDB\Client';
312         } else {
313             $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient';
314         }
315
316         $this->assertInstanceOf($mongoClass, $method->invoke($this->storage));
317     }
318
319     private function createMongoCollectionMock()
320     {
321         $collectionClass = 'MongoCollection';
322         if (phpversion('mongodb')) {
323             $collectionClass = 'MongoDB\Collection';
324         }
325
326         $collection = $this->getMockBuilder($collectionClass)
327             ->disableOriginalConstructor()
328             ->getMock();
329
330         return $collection;
331     }
332 }