DatabaseTest.php 11 KB

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