ConnectionTest.php 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. <?php
  2. /**
  3. * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace Test\DB;
  9. use Doctrine\DBAL\Platforms\SqlitePlatform;
  10. use OC\DB\MDB2SchemaManager;
  11. use OCP\DB\QueryBuilder\IQueryBuilder;
  12. /**
  13. * Class Connection
  14. *
  15. * @group DB
  16. *
  17. * @package Test\DB
  18. */
  19. class ConnectionTest extends \Test\TestCase {
  20. /**
  21. * @var \OCP\IDBConnection
  22. */
  23. private $connection;
  24. public static function setUpBeforeClass() {
  25. self::dropTestTable();
  26. parent::setUpBeforeClass();
  27. }
  28. public static function tearDownAfterClass() {
  29. self::dropTestTable();
  30. parent::tearDownAfterClass();
  31. }
  32. protected static function dropTestTable() {
  33. if (\OC::$server->getConfig()->getSystemValue('dbtype', 'sqlite') !== 'oci') {
  34. \OC::$server->getDatabaseConnection()->dropTable('table');
  35. }
  36. }
  37. public function setUp() {
  38. parent::setUp();
  39. $this->connection = \OC::$server->getDatabaseConnection();
  40. }
  41. public function tearDown() {
  42. parent::tearDown();
  43. $this->connection->dropTable('table');
  44. }
  45. /**
  46. * @param string $table
  47. */
  48. public function assertTableExist($table) {
  49. if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
  50. // sqlite removes the tables after closing the DB
  51. $this->addToAssertionCount(1);
  52. } else {
  53. $this->assertTrue($this->connection->tableExists($table), 'Table ' . $table . ' exists.');
  54. }
  55. }
  56. /**
  57. * @param string $table
  58. */
  59. public function assertTableNotExist($table) {
  60. if ($this->connection->getDatabasePlatform() instanceof SqlitePlatform) {
  61. // sqlite removes the tables after closing the DB
  62. $this->addToAssertionCount(1);
  63. } else {
  64. $this->assertFalse($this->connection->tableExists($table), 'Table ' . $table . " doesn't exist.");
  65. }
  66. }
  67. private function makeTestTable() {
  68. $schemaManager = new MDB2SchemaManager($this->connection);
  69. $schemaManager->createDbFromStructure(__DIR__ . '/testschema.xml');
  70. }
  71. public function testTableExists() {
  72. $this->assertTableNotExist('table');
  73. $this->makeTestTable();
  74. $this->assertTableExist('table');
  75. }
  76. /**
  77. * @depends testTableExists
  78. */
  79. public function testDropTable() {
  80. $this->makeTestTable();
  81. $this->assertTableExist('table');
  82. $this->connection->dropTable('table');
  83. $this->assertTableNotExist('table');
  84. }
  85. private function getTextValueByIntergerField($integerField) {
  86. $builder = $this->connection->getQueryBuilder();
  87. $query = $builder->select('textfield')
  88. ->from('table')
  89. ->where($builder->expr()->eq('integerfield', $builder->createNamedParameter($integerField, IQueryBuilder::PARAM_INT)));
  90. $result = $query->execute();
  91. return $result->fetchColumn();
  92. }
  93. public function testSetValues() {
  94. $this->makeTestTable();
  95. $this->connection->setValues('table', [
  96. 'integerfield' => 1
  97. ], [
  98. 'textfield' => 'foo',
  99. 'clobfield' => 'not_null'
  100. ]);
  101. $this->assertEquals('foo', $this->getTextValueByIntergerField(1));
  102. }
  103. public function testSetValuesOverWrite() {
  104. $this->makeTestTable();
  105. $this->connection->setValues('table', [
  106. 'integerfield' => 1
  107. ], [
  108. 'textfield' => 'foo'
  109. ]);
  110. $this->connection->setValues('table', [
  111. 'integerfield' => 1
  112. ], [
  113. 'textfield' => 'bar'
  114. ]);
  115. $this->assertEquals('bar', $this->getTextValueByIntergerField(1));
  116. }
  117. public function testSetValuesOverWritePrecondition() {
  118. $this->makeTestTable();
  119. $this->connection->setValues('table', [
  120. 'integerfield' => 1
  121. ], [
  122. 'textfield' => 'foo',
  123. 'booleanfield' => true,
  124. 'clobfield' => 'not_null'
  125. ]);
  126. $this->connection->setValues('table', [
  127. 'integerfield' => 1
  128. ], [
  129. 'textfield' => 'bar'
  130. ], [
  131. 'booleanfield' => true
  132. ]);
  133. $this->assertEquals('bar', $this->getTextValueByIntergerField(1));
  134. }
  135. /**
  136. * @expectedException \OCP\PreConditionNotMetException
  137. */
  138. public function testSetValuesOverWritePreconditionFailed() {
  139. $this->makeTestTable();
  140. $this->connection->setValues('table', [
  141. 'integerfield' => 1
  142. ], [
  143. 'textfield' => 'foo',
  144. 'booleanfield' => true,
  145. 'clobfield' => 'not_null'
  146. ]);
  147. $this->connection->setValues('table', [
  148. 'integerfield' => 1
  149. ], [
  150. 'textfield' => 'bar'
  151. ], [
  152. 'booleanfield' => false
  153. ]);
  154. }
  155. public function testSetValuesSameNoError() {
  156. $this->makeTestTable();
  157. $this->connection->setValues('table', [
  158. 'integerfield' => 1
  159. ], [
  160. 'textfield' => 'foo',
  161. 'clobfield' => 'not_null'
  162. ]);
  163. // this will result in 'no affected rows' on certain optimizing DBs
  164. // ensure the PreConditionNotMetException isn't thrown
  165. $this->connection->setValues('table', [
  166. 'integerfield' => 1
  167. ], [
  168. 'textfield' => 'foo'
  169. ]);
  170. $this->addToAssertionCount(1);
  171. }
  172. public function testInsertIfNotExist() {
  173. $this->makeTestTable();
  174. $categoryEntries = [
  175. ['user' => 'test', 'category' => 'Family', 'expectedResult' => 1],
  176. ['user' => 'test', 'category' => 'Friends', 'expectedResult' => 1],
  177. ['user' => 'test', 'category' => 'Coworkers', 'expectedResult' => 1],
  178. ['user' => 'test', 'category' => 'Coworkers', 'expectedResult' => 0],
  179. ['user' => 'test', 'category' => 'School', 'expectedResult' => 1],
  180. ['user' => 'test2', 'category' => 'Coworkers2', 'expectedResult' => 1],
  181. ['user' => 'test2', 'category' => 'Coworkers2', 'expectedResult' => 0],
  182. ['user' => 'test2', 'category' => 'School2', 'expectedResult' => 1],
  183. ['user' => 'test2', 'category' => 'Coworkers', 'expectedResult' => 1],
  184. ];
  185. foreach($categoryEntries as $entry) {
  186. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  187. [
  188. 'textfield' => $entry['user'],
  189. 'clobfield' => $entry['category'],
  190. ]);
  191. $this->assertEquals($entry['expectedResult'], $result);
  192. }
  193. $query = $this->connection->prepare('SELECT * FROM `*PREFIX*table`');
  194. $result = $query->execute();
  195. $this->assertTrue((bool)$result);
  196. $this->assertEquals(7, count($query->fetchAll()));
  197. }
  198. public function testInsertIfNotExistNull() {
  199. $this->makeTestTable();
  200. $categoryEntries = [
  201. ['addressbookid' => 123, 'fullname' => null, 'expectedResult' => 1],
  202. ['addressbookid' => 123, 'fullname' => null, 'expectedResult' => 0],
  203. ['addressbookid' => 123, 'fullname' => 'test', 'expectedResult' => 1],
  204. ];
  205. foreach($categoryEntries as $entry) {
  206. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  207. [
  208. 'integerfield_default' => $entry['addressbookid'],
  209. 'clobfield' => $entry['fullname'],
  210. ]);
  211. $this->assertEquals($entry['expectedResult'], $result);
  212. }
  213. $query = $this->connection->prepare('SELECT * FROM `*PREFIX*table`');
  214. $result = $query->execute();
  215. $this->assertTrue((bool)$result);
  216. $this->assertEquals(2, count($query->fetchAll()));
  217. }
  218. public function testInsertIfNotExistDonTOverwrite() {
  219. $this->makeTestTable();
  220. $fullName = 'fullname test';
  221. $uri = 'uri_1';
  222. // Normal test to have same known data inserted.
  223. $query = $this->connection->prepare('INSERT INTO `*PREFIX*table` (`textfield`, `clobfield`) VALUES (?, ?)');
  224. $result = $query->execute([$fullName, $uri]);
  225. $this->assertEquals(1, $result);
  226. $query = $this->connection->prepare('SELECT `textfield`, `clobfield` FROM `*PREFIX*table` WHERE `clobfield` = ?');
  227. $result = $query->execute([$uri]);
  228. $this->assertTrue($result);
  229. $rowset = $query->fetchAll();
  230. $this->assertEquals(1, count($rowset));
  231. $this->assertArrayHasKey('textfield', $rowset[0]);
  232. $this->assertEquals($fullName, $rowset[0]['textfield']);
  233. // Try to insert a new row
  234. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  235. [
  236. 'textfield' => $fullName,
  237. 'clobfield' => $uri,
  238. ]);
  239. $this->assertEquals(0, $result);
  240. $query = $this->connection->prepare('SELECT `textfield`, `clobfield` FROM `*PREFIX*table` WHERE `clobfield` = ?');
  241. $result = $query->execute([$uri]);
  242. $this->assertTrue($result);
  243. // Test that previously inserted data isn't overwritten
  244. // And that a new row hasn't been inserted.
  245. $rowset = $query->fetchAll();
  246. $this->assertEquals(1, count($rowset));
  247. $this->assertArrayHasKey('textfield', $rowset[0]);
  248. $this->assertEquals($fullName, $rowset[0]['textfield']);
  249. }
  250. public function testInsertIfNotExistsViolating() {
  251. $this->makeTestTable();
  252. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  253. [
  254. 'textfield' => md5('welcome.txt'),
  255. 'clobfield' => $this->getUniqueID()
  256. ]);
  257. $this->assertEquals(1, $result);
  258. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  259. [
  260. 'textfield' => md5('welcome.txt'),
  261. 'clobfield' => $this->getUniqueID()
  262. ],['textfield']);
  263. $this->assertEquals(0, $result);
  264. }
  265. public function insertIfNotExistsViolatingThrows() {
  266. return [
  267. [null],
  268. [['clobfield']],
  269. ];
  270. }
  271. /**
  272. * @dataProvider insertIfNotExistsViolatingThrows
  273. *
  274. * @param array $compareKeys
  275. */
  276. public function testInsertIfNotExistsViolatingUnique($compareKeys) {
  277. $this->makeTestTable();
  278. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  279. [
  280. 'integerfield' => 1,
  281. 'clobfield' => $this->getUniqueID()
  282. ]);
  283. $this->assertEquals(1, $result);
  284. $result = $this->connection->insertIfNotExist('*PREFIX*table',
  285. [
  286. 'integerfield' => 1,
  287. 'clobfield' => $this->getUniqueID()
  288. ], $compareKeys);
  289. $this->assertEquals(0, $result);
  290. }
  291. /**
  292. * @expectedException \Doctrine\DBAL\Exception\UniqueConstraintViolationException
  293. */
  294. public function testUniqueConstraintViolating() {
  295. $this->makeTestTable();
  296. $testQuery = 'INSERT INTO `*PREFIX*table` (`integerfield`, `textfield`) VALUES(?, ?)';
  297. $testParams = [1, 'hello'];
  298. $this->connection->executeUpdate($testQuery, $testParams);
  299. $this->connection->executeUpdate($testQuery, $testParams);
  300. }
  301. }