No Description

MongoDbSessionHandlerTest.php 12KB

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