You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
15 KiB

  1. <?php
  2. /*
  3. * @copyright NetMonsters <team@netmonsters.ru>
  4. * @link http://netmonsters.ru
  5. * @package Majestic
  6. * @subpackage UnitTests
  7. * @since 2011-11-7
  8. *
  9. * Unit tests for MongoModel class
  10. */
  11. require_once dirname(__FILE__) . '/../../Registry.php';
  12. require_once dirname(__FILE__) . '/../../Config.php';
  13. require_once dirname(__FILE__) . '/../../cache/Cacher.php';
  14. require_once dirname(__FILE__) . '/../../exception/GeneralException.php';
  15. require_once dirname(__FILE__) . '/../../model/DbExpr.php';
  16. require_once dirname(__FILE__) . '/../../model/Db.php';
  17. require_once dirname(__FILE__) . '/../../model/MongoDbCommand.php';
  18. require_once dirname(__FILE__) . '/../../model/DbStatement.php';
  19. require_once dirname(__FILE__) . '/../../model/MongoStatement.php';
  20. require_once dirname(__FILE__) . '/../../model/DbDriver.php';
  21. require_once dirname(__FILE__) . '/../../model/NoSqlDbDriver.php';
  22. require_once dirname(__FILE__) . '/../../model/MongoDriver.php';
  23. require_once dirname(__FILE__) . '/../../model/Model.php';
  24. require_once dirname(__FILE__) . '/../../model/MongoModel.php';
  25. class MongoModelTest extends PHPUnit_Framework_TestCase
  26. {
  27. /**
  28. * @var MongoModel
  29. */
  30. private $model;
  31. /**
  32. * @var ReflectionMethod
  33. */
  34. private $method_count;
  35. /**
  36. * @var ReflectionMethod
  37. */
  38. private $method_fetch;
  39. public function run(PHPUnit_Framework_TestResult $result = NULL)
  40. {
  41. $this->setPreserveGlobalState(false);
  42. return parent::run($result);
  43. }
  44. public function setUp()
  45. {
  46. $conf = array('default' => array('driver' => 'MongoDriver', 'hostname' => 'localhost', 'database' => 'test', 'username' => 'test', 'password' => '1234', 'port' => 27017));
  47. $this->dbSetUp($conf);
  48. Config::set('Db', $conf);
  49. if (!class_exists('MockModel')) {
  50. $this->model = $this->getMockForAbstractClass('MongoModel', array(), 'MongoMockModel');
  51. } else {
  52. $this->model = new MongoMockModel();
  53. }
  54. $model = new ReflectionClass('MongoModel');
  55. $this->method_count = $model->getMethod('count');
  56. $this->method_count->setAccessible(true);
  57. $this->method_fetch = $model->getMethod('fetch');
  58. $this->method_fetch->setAccessible(true);
  59. set_new_overload(array($this, 'newCallback'));
  60. }
  61. /**
  62. * @group Mongo
  63. */
  64. public function testModel()
  65. {
  66. $this->assertInstanceOf('MongoMockModel', $this->model);
  67. }
  68. /**
  69. * @runInSeparateProcess
  70. * @group Mongo
  71. */
  72. public function testFetch()
  73. {
  74. Config::set('DEBUG', false);
  75. $mock = $this->getMock('CacheKey', array('set', 'get'));
  76. $mock->expects($this->once())
  77. ->method('set')
  78. ->will($this->returnValue(true));
  79. $mock->expects($this->once())
  80. ->method('get')
  81. ->will($this->returnValue(false));
  82. $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => -1), 'limit' => 2), $mock);
  83. $this->assertInstanceOf('ArrayObject', $result);
  84. $this->assertEquals('milk', $result->name);
  85. $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name')));
  86. $this->assertSame('bread', $result->name);
  87. $result = $this->method_fetch->invoke($this->model, array());
  88. $this->setExpectedException('PHPUnit_Framework_Error');
  89. $this->assertNull($result->pounds);
  90. }
  91. /**
  92. * @runInSeparateProcess
  93. * @group Mongo
  94. */
  95. public function testFetchField()
  96. {
  97. Config::set('DEBUG', false);
  98. $mock = $this->getMock('CacheKey', array('set', 'get'));
  99. $mock->expects($this->exactly(2))
  100. ->method('set')
  101. ->will($this->returnValue(true));
  102. $mock->expects($this->exactly(2))
  103. ->method('get')
  104. ->will($this->returnValue(false));
  105. $model = new ReflectionClass('MongoModel');
  106. $method = $model->getMethod('fetchField');
  107. $method->setAccessible(true);
  108. $result = $method->invoke($this->model, array('name' => 'milk'), array(), 'quantity', $mock);
  109. $this->assertEquals(1, $result);
  110. $result = $method->invoke($this->model, array(), array('skip' => 2), 'quantity', $mock);
  111. $this->assertEquals($result, $this->method_fetch->invoke($this->model, array(), array('skip' => 2))->quantity);
  112. }
  113. /**
  114. * @runInSeparateProcess
  115. * @group Mongo
  116. */
  117. public function testFetchAll()
  118. {
  119. Config::set('DEBUG', false);
  120. $mock = $this->getMock('CacheKey', array('set', 'get'));
  121. $mock->expects($this->once())
  122. ->method('set')
  123. ->will($this->returnValue(true));
  124. $mock->expects($this->once())
  125. ->method('get')
  126. ->will($this->returnValue(false));
  127. $model = new ReflectionClass('MongoModel');
  128. $method = $model->getMethod('fetchAll');
  129. $method->setAccessible(true);
  130. $result = $method->invoke($this->model, array('name' => 'eggs'), array(), $mock);
  131. $this->assertEquals(2, count($result));
  132. $result = $method->invoke($this->model, array(), array('skip' => 2));
  133. $this->assertEquals(3, count($result));
  134. $this->assertEquals('fish', $result[0]->name);
  135. $this->assertEquals('milk', $result[1]->name);
  136. $this->assertEquals('eggs', $result[2]->name);
  137. }
  138. /**
  139. * @runInSeparateProcess
  140. * @group Mongo
  141. */
  142. public function testFetchOrderParam()
  143. {
  144. Config::set('DEBUG', false);
  145. $result = $this->method_fetch->invoke($this->model, array(), array('order' => 'name'));
  146. $this->assertSame('bread', $result->name);
  147. $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1, 'quantity' => -1), 'skip' => 1));
  148. $this->assertSame(2.1, $result->price);
  149. $this->setExpectedException('GeneralException', 'Wrong order parameter given to query.');
  150. $this->method_fetch->invoke($this->model, array(), array('order' => 1));
  151. }
  152. /**
  153. * @runInSeparateProcess
  154. * @group Mongo
  155. */
  156. public function testFetchSkipLimitParam()
  157. {
  158. Config::set('DEBUG', false);
  159. $result = $this->method_fetch->invoke($this->model, array(), array('order' => 'name'));
  160. $this->assertSame('bread', $result->name);
  161. $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1, 'quantity' => -1), 'skip' => 1, 'limit' => 1));
  162. $this->assertSame(2.1, $result->price);
  163. $model = new ReflectionClass('MongoModel');
  164. $method = $model->getMethod('fetchAll');
  165. $method->setAccessible(true);
  166. $this->assertCount(3, $method->invoke($this->model, array(), array('limit' => 3)));
  167. $this->assertCount(2, $method->invoke($this->model, array(), array('skip' => 3)));
  168. $this->assertCount(5, $method->invoke($this->model, array(), array()));
  169. }
  170. /**
  171. * @runInSeparateProcess
  172. * @group Mongo
  173. */
  174. public function testFetchFieldsParam()
  175. {
  176. Config::set('DEBUG', false);
  177. $result = $this->method_fetch->invoke($this->model, array(), array('fields' => 'name'));
  178. $this->assertTrue(!isset($result->quantity));
  179. $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name', 'price')));
  180. $this->assertTrue(!isset($result->quantity));
  181. $result = $this->method_fetch->invoke($this->model, array(), array('fields' => array('name' => 1, 'price' => 1)));
  182. $this->assertTrue(!isset($result->quantity));
  183. $this->setExpectedException('GeneralException', 'Wrong fields parameter given to query.');
  184. $this->method_fetch->invoke($this->model, array(), array('fields' => 1));
  185. }
  186. /**
  187. * @runInSeparateProcess
  188. * @group Mongo
  189. */
  190. public function testGet()
  191. {
  192. Config::set('DEBUG', false);
  193. $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1)));
  194. $this->assertEquals('bread', $result->name);
  195. $id = $result->_id;
  196. $this->assertEquals(10, $this->model->get($id)->quantity);
  197. }
  198. /**
  199. * @runInSeparateProcess
  200. * @group Mongo
  201. */
  202. public function testDelete()
  203. {
  204. Config::set('DEBUG', false);
  205. $result = $this->method_fetch->invoke($this->model, array(), array('order' => array('name' => 1)));
  206. $id = $result->_id;
  207. $this->assertEquals(1, $this->model->delete($id));
  208. $this->assertFalse($this->method_fetch->invoke($this->model, array('name' => 'bread')));
  209. }
  210. /**
  211. * @runInSeparateProcess
  212. * @group Mongo
  213. */
  214. public function testUpdate()
  215. {
  216. Config::set('DEBUG', false);
  217. $this->model->insert(array('name' => 'testbread', 'price' => 3.2, 'quantity' => 10));
  218. $result = $this->method_fetch->invoke($this->model, array('name' => 'testbread'));
  219. $this->assertEquals(10, $result->quantity);
  220. $this->model->update(array('$set' => array('quantity' => 3)), $result->_id);
  221. $this->assertEquals(3, $this->model->get($result->_id)->quantity);
  222. $this->model->update(array('$set' => array('quantity' => 13)), (string)$result->_id);
  223. $this->assertEquals(13, $this->model->get($result->_id)->quantity);
  224. }
  225. /**
  226. * @runInSeparateProcess
  227. * @group Mongo
  228. */
  229. public function testBatchInsert()
  230. {
  231. Config::set('DEBUG', false);
  232. $data = array(
  233. array('name' => 'first object'),
  234. array('name' => 'second object'),
  235. array('name' => 'equal object'),
  236. array('name' => 'equal object')
  237. );
  238. $this->model->batchInsert($data);
  239. $this->assertEquals(1, $this->method_count->invoke($this->model, array('name' => 'first object')));
  240. $this->assertEquals(2, $this->method_count->invoke($this->model, array('name' => 'equal object')));
  241. }
  242. /**
  243. * @runInSeparateProcess
  244. * @group Mongo
  245. */
  246. public function testCount()
  247. {
  248. Config::set('DEBUG', false);
  249. $this->assertEquals(5, $this->method_count->invoke($this->model));
  250. $this->assertEquals(2, $this->method_count->invoke($this->model, array('name' => 'eggs')));
  251. }
  252. /**
  253. * @runInSeparateProcess
  254. * @group Mongo
  255. */
  256. public function testUseMongoId()
  257. {
  258. Config::set('DEBUG', false);
  259. $this->assertAttributeEquals(true, 'useMongoId', $this->model);
  260. }
  261. /**
  262. * @runInSeparateProcess
  263. * @group Mongo
  264. */
  265. public function testId()
  266. {
  267. Config::set('DEBUG', false);
  268. $class = new ReflectionClass('MongoModel');
  269. $prop = $class->getProperty('useMongoId');
  270. $prop->setAccessible(true);
  271. $this->model->insert(array('_id' => 1, 'name' => 'testbread', 'price' => 3.2, 'quantity' => 10));
  272. $this->model->insert(array('_id' => 2, 'name' => 'testbread', 'price' => 12, 'quantity' => 2));
  273. $this->assertSame(2, $this->method_count->invoke($this->model, array('name' => 'testbread')));
  274. $prop->setValue($this->model, false);
  275. $this->model->delete(1);
  276. $this->assertSame(1, $this->method_count->invoke($this->model, array('name' => 'testbread')));
  277. }
  278. /**
  279. * @runInSeparateProcess
  280. * @group Mongo
  281. */
  282. public function testIdToMongoId()
  283. {
  284. Config::set('DEBUG', false);
  285. $this->model->insert(array('name' => 'testbread', 'price' => 3.2, 'quantity' => 10));
  286. $this->model->insert(array('name' => 'testbread', 'price' => 12, 'quantity' => 2));
  287. $this->assertSame(2, $this->method_count->invoke($this->model, array('name' => 'testbread')));
  288. $id = $this->method_fetch->invoke($this->model, array('name' => 'testbread'))->_id->__toString();
  289. $this->assertInternalType('string', $id);
  290. $item = $this->model->get($id);
  291. $this->assertSame('testbread', $item->name);
  292. $this->model->delete($id);
  293. $this->assertSame(1, $this->method_count->invoke($this->model, array('name' => 'testbread')));
  294. }
  295. /**
  296. * @runInSeparateProcess
  297. * @group Mongo
  298. */
  299. public function testAddCondition()
  300. {
  301. Config::set('DEBUG', false);
  302. $model = new ReflectionClass('MongoModel');
  303. $method = $model->getMethod('addCondition');
  304. $method->setAccessible(true);
  305. $query = array();
  306. $result = $method->invokeArgs($this->model, array(&$query, 'name', 'tony'));
  307. $this->assertSame(array('name' => 'tony'), $query);
  308. $this->assertSame($this->model, $result);
  309. }
  310. /**
  311. * @runInSeparateProcess
  312. * @group Mongo
  313. */
  314. public function testAddConditionEmptyValue()
  315. {
  316. Config::set('DEBUG', false);
  317. $model = new ReflectionClass('MongoModel');
  318. $method = $model->getMethod('addCondition');
  319. $method->setAccessible(true);
  320. $query = array();
  321. $method->invokeArgs($this->model, array(&$query, 'name', false));
  322. $this->assertEmpty($query);
  323. $method->invokeArgs($this->model, array(&$query, 'name', null));
  324. $this->assertEmpty($query);
  325. }
  326. public function tearDown()
  327. {
  328. $conf = array('driver' => 'MongoDriver', 'hostname' => 'localhost', 'database' => 'test', 'username' => 'test', 'password' => '1234', 'port' => 27017);
  329. $connection = new Mongo('mongodb://' . $conf['hostname'] . ':' . $conf['port']);
  330. $db = $connection->selectDB($conf['database']);
  331. $db->authenticate($conf['username'], $conf['password']);
  332. $collection = 'mongomock';
  333. $db->selectCollection($collection)->remove(array());
  334. }
  335. protected function newCallback($className)
  336. {
  337. switch ($className) {
  338. case 'CacheKey':
  339. return 'MockCacheKey';
  340. default:
  341. return $className;
  342. }
  343. }
  344. public function dbSetUp($conf)
  345. {
  346. $data = array(
  347. array(
  348. 'name' => 'bread',
  349. 'price' => 3.2,
  350. 'quantity' => 10
  351. ),
  352. array(
  353. 'name' => 'eggs',
  354. 'price' => 2.1,
  355. 'quantity' => 20
  356. ),
  357. array(
  358. 'name' => 'fish',
  359. 'price' => 13.2,
  360. 'quantity' => 2
  361. ),
  362. array(
  363. 'name' => 'milk',
  364. 'price' => 3.8,
  365. 'quantity' => 1
  366. ),
  367. array(
  368. 'name' => 'eggs',
  369. 'price' => 2.3,
  370. 'quantity' => 5
  371. )
  372. );
  373. $connection = new Mongo('mongodb://' . $conf['default']['hostname'] . ':' . $conf['default']['port']);
  374. $db = $connection->selectDB($conf['default']['database']);
  375. $db->authenticate($conf['default']['username'], $conf['default']['password']);
  376. $collection = 'mongomock';
  377. $db->dropCollection($collection);
  378. $collection = $db->selectCollection($collection);
  379. foreach ($data as $document) {
  380. $collection->insert($document);
  381. }
  382. }
  383. }