DatabaseTest.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. <?php
  2. use PrivateBin\Controller;
  3. use PrivateBin\Data\Database;
  4. class DatabaseTest extends PHPUnit_Framework_TestCase
  5. {
  6. private $_model;
  7. private $_path;
  8. private $_options = array(
  9. 'dsn' => 'sqlite::memory:',
  10. 'usr' => null,
  11. 'pwd' => null,
  12. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  13. );
  14. public function setUp()
  15. {
  16. /* Setup Routine */
  17. $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
  18. $this->_model = Database::getInstance($this->_options);
  19. }
  20. public function tearDown()
  21. {
  22. /* Tear Down Routine */
  23. if (is_dir($this->_path)) {
  24. Helper::rmDir($this->_path);
  25. }
  26. }
  27. public function testDatabaseBasedDataStoreWorks()
  28. {
  29. $this->_model->delete(Helper::getPasteId());
  30. // storing pastes
  31. $paste = Helper::getPaste();
  32. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
  33. $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
  34. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
  35. $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
  36. $this->assertEquals(json_decode(json_encode($paste)), $this->_model->read(Helper::getPasteId()));
  37. // storing comments
  38. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist');
  39. $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment(1)) !== false, 'store v1 comment');
  40. $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment exists after storing it');
  41. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment does not yet exist');
  42. $this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment(2)) !== false, 'store v2 comment');
  43. $this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment exists after storing it');
  44. $comment1 = json_decode(json_encode(Helper::getComment(1)));
  45. $comment1->id = Helper::getCommentId();
  46. $comment1->parentid = Helper::getPasteId();
  47. $comment2 = json_decode(json_encode(Helper::getComment(2)));
  48. $comment2->id = Helper::getPasteId();
  49. $comment2->parentid = Helper::getPasteId();
  50. $this->assertEquals(
  51. array(
  52. $comment1->meta->postdate => $comment1,
  53. $comment2->meta->created . '.1' => $comment2,
  54. ),
  55. $this->_model->readComments(Helper::getPasteId())
  56. );
  57. // deleting pastes
  58. $this->_model->delete(Helper::getPasteId());
  59. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste successfully deleted');
  60. $this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment was deleted with paste');
  61. $this->assertFalse($this->_model->read(Helper::getPasteId()), 'paste can no longer be found');
  62. }
  63. public function testDatabaseBasedAttachmentStoreWorks()
  64. {
  65. // this assumes a version 1 formatted paste
  66. $this->_model->delete(Helper::getPasteId());
  67. $original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
  68. $paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true;
  69. $paste['meta']['attachment'] = $paste['attachment'];
  70. $paste['meta']['attachmentname'] = $paste['attachmentname'];
  71. unset($paste['attachment'], $paste['attachmentname']);
  72. $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
  73. $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
  74. $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
  75. $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store the same paste twice');
  76. $this->assertEquals(json_decode(json_encode($original)), $this->_model->read(Helper::getPasteId()));
  77. }
  78. /**
  79. * pastes a-g are expired and should get deleted, x never expires and y-z expire in an hour
  80. */
  81. public function testPurge()
  82. {
  83. $this->_model->delete(Helper::getPasteId());
  84. $expired = Helper::getPaste(2, array('expire_date' => 1344803344));
  85. $paste = Helper::getPaste(2, array('expire_date' => time() + 3600));
  86. $keys = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
  87. $ids = array();
  88. foreach ($keys as $key) {
  89. $ids[$key] = hash('fnv1a64', $key);
  90. $this->_model->delete($ids[$key]);
  91. $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
  92. if (in_array($key, array('y', 'z'))) {
  93. $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
  94. } elseif ($key === 'x') {
  95. $this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste");
  96. } else {
  97. $this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste");
  98. }
  99. $this->assertTrue($this->_model->exists($ids[$key]), "paste $key exists after storing it");
  100. }
  101. $this->_model->purge(10);
  102. foreach ($ids as $key => $id) {
  103. if (in_array($key, array('x', 'y', 'z'))) {
  104. $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
  105. $this->_model->delete($id);
  106. } else {
  107. $this->assertFalse($this->_model->exists($id), "paste $key was purged");
  108. }
  109. }
  110. }
  111. /**
  112. * @expectedException PDOException
  113. */
  114. public function testGetIbmInstance()
  115. {
  116. Database::getInstance(array(
  117. 'dsn' => 'ibm:', 'usr' => null, 'pwd' => null,
  118. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  119. ));
  120. }
  121. /**
  122. * @expectedException PDOException
  123. */
  124. public function testGetInformixInstance()
  125. {
  126. Database::getInstance(array(
  127. 'dsn' => 'informix:', 'usr' => null, 'pwd' => null,
  128. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  129. ));
  130. }
  131. /**
  132. * @expectedException PDOException
  133. */
  134. public function testGetMssqlInstance()
  135. {
  136. Database::getInstance(array(
  137. 'dsn' => 'mssql:', 'usr' => null, 'pwd' => null,
  138. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  139. ));
  140. }
  141. /**
  142. * @expectedException PDOException
  143. */
  144. public function testGetMysqlInstance()
  145. {
  146. Database::getInstance(array(
  147. 'dsn' => 'mysql:', 'usr' => null, 'pwd' => null,
  148. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  149. ));
  150. }
  151. /**
  152. * @expectedException PDOException
  153. */
  154. public function testGetOciInstance()
  155. {
  156. Database::getInstance(array(
  157. 'dsn' => 'oci:', 'usr' => null, 'pwd' => null,
  158. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  159. ));
  160. }
  161. /**
  162. * @expectedException PDOException
  163. */
  164. public function testGetPgsqlInstance()
  165. {
  166. Database::getInstance(array(
  167. 'dsn' => 'pgsql:', 'usr' => null, 'pwd' => null,
  168. 'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
  169. ));
  170. }
  171. /**
  172. * @expectedException Exception
  173. * @expectedExceptionCode 5
  174. */
  175. public function testGetFooInstance()
  176. {
  177. Database::getInstance(array(
  178. 'dsn' => 'foo:', 'usr' => null, 'pwd' => null, 'opt' => null,
  179. ));
  180. }
  181. /**
  182. * @expectedException Exception
  183. * @expectedExceptionCode 6
  184. */
  185. public function testMissingDsn()
  186. {
  187. $options = $this->_options;
  188. unset($options['dsn']);
  189. Database::getInstance($options);
  190. }
  191. /**
  192. * @expectedException Exception
  193. * @expectedExceptionCode 6
  194. */
  195. public function testMissingUsr()
  196. {
  197. $options = $this->_options;
  198. unset($options['usr']);
  199. Database::getInstance($options);
  200. }
  201. /**
  202. * @expectedException Exception
  203. * @expectedExceptionCode 6
  204. */
  205. public function testMissingPwd()
  206. {
  207. $options = $this->_options;
  208. unset($options['pwd']);
  209. Database::getInstance($options);
  210. }
  211. /**
  212. * @expectedException Exception
  213. * @expectedExceptionCode 6
  214. */
  215. public function testMissingOpt()
  216. {
  217. $options = $this->_options;
  218. unset($options['opt']);
  219. Database::getInstance($options);
  220. }
  221. public function testOldAttachments()
  222. {
  223. mkdir($this->_path);
  224. $path = $this->_path . DIRECTORY_SEPARATOR . 'attachement-test.sq3';
  225. if (is_file($path)) {
  226. unlink($path);
  227. }
  228. $this->_options['dsn'] = 'sqlite:' . $path;
  229. $this->_options['tbl'] = 'bar_';
  230. $model = Database::getInstance($this->_options);
  231. $original = $paste = Helper::getPasteWithAttachment(1, array('expire_date' => 1344803344));
  232. $meta = $paste['meta'];
  233. $meta['attachment'] = $paste['attachment'];
  234. $meta['attachmentname'] = $paste['attachmentname'];
  235. unset($paste['attachment'], $paste['attachmentname']);
  236. $db = new PDO(
  237. $this->_options['dsn'],
  238. $this->_options['usr'],
  239. $this->_options['pwd'],
  240. $this->_options['opt']
  241. );
  242. $statement = $db->prepare('INSERT INTO bar_paste VALUES(?,?,?,?,?,?,?,?,?)');
  243. $statement->execute(
  244. array(
  245. Helper::getPasteId(),
  246. $paste['data'],
  247. $paste['meta']['postdate'],
  248. $paste['meta']['expire_date'],
  249. 0,
  250. 0,
  251. json_encode($meta),
  252. null,
  253. null,
  254. )
  255. );
  256. $statement->closeCursor();
  257. $this->assertTrue($model->exists(Helper::getPasteId()), 'paste exists after storing it');
  258. $this->assertEquals(json_decode(json_encode($original)), $model->read(Helper::getPasteId()));
  259. Helper::rmDir($this->_path);
  260. }
  261. public function testTableUpgrade()
  262. {
  263. mkdir($this->_path);
  264. $path = $this->_path . DIRECTORY_SEPARATOR . 'db-test.sq3';
  265. if (is_file($path)) {
  266. unlink($path);
  267. }
  268. $this->_options['dsn'] = 'sqlite:' . $path;
  269. $this->_options['tbl'] = 'foo_';
  270. $db = new PDO(
  271. $this->_options['dsn'],
  272. $this->_options['usr'],
  273. $this->_options['pwd'],
  274. $this->_options['opt']
  275. );
  276. $db->exec(
  277. 'CREATE TABLE foo_paste ( ' .
  278. 'dataid CHAR(16), ' .
  279. 'data TEXT, ' .
  280. 'postdate INT, ' .
  281. 'expiredate INT, ' .
  282. 'opendiscussion INT, ' .
  283. 'burnafterreading INT );'
  284. );
  285. $db->exec(
  286. 'CREATE TABLE foo_comment ( ' .
  287. 'dataid CHAR(16) NOT NULL, ' .
  288. 'pasteid CHAR(16), ' .
  289. 'parentid CHAR(16), ' .
  290. 'data BLOB, ' .
  291. 'nickname BLOB, ' .
  292. 'vizhash BLOB, ' .
  293. 'postdate INT );'
  294. );
  295. $this->assertInstanceOf('PrivateBin\\Data\\Database', Database::getInstance($this->_options));
  296. // check if version number was upgraded in created configuration table
  297. $statement = $db->prepare('SELECT value FROM foo_config WHERE id LIKE ?');
  298. $statement->execute(array('VERSION'));
  299. $result = $statement->fetch(PDO::FETCH_ASSOC);
  300. $statement->closeCursor();
  301. $this->assertEquals(Controller::VERSION, $result['value']);
  302. Helper::rmDir($this->_path);
  303. }
  304. }