[TASK] Disable a series of functional tests with mssql
[Packages/TYPO3.CMS.git] / typo3 / sysext / typo3db_legacy / Tests / Functional / Database / DatabaseConnectionTest.php
1 <?php
2 namespace TYPO3\CMS\Typo3DbLegacy\Tests\Functional\Database;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 use TYPO3\CMS\Typo3DbLegacy\Database\DatabaseConnection;
17 use TYPO3\TestingFramework\Core\AccessibleObjectInterface;
18
19 /**
20 * Test case for \TYPO3\CMS\Core\Database\DatabaseConnection
21 */
22 class DatabaseConnectionTest extends \TYPO3\TestingFramework\Core\Functional\FunctionalTestCase
23 {
24 /**
25 * @var array
26 */
27 protected $coreExtensionsToLoad = ['typo3db_legacy'];
28
29 /**
30 * @var DatabaseConnection
31 */
32 protected $subject = null;
33
34 /**
35 * @var string
36 */
37 protected $testTable = 'test_database_connection';
38
39 /**
40 * @var string
41 */
42 protected $testField = 'test_field';
43
44 /**
45 * @var string
46 */
47 protected $anotherTestField = 'another_test_field';
48
49 /**
50 * Set the test up
51 */
52 protected function setUp()
53 {
54 parent::setUp();
55 $this->subject = $GLOBALS['TYPO3_DB'];
56 $this->subject->sql_query(
57 "CREATE TABLE {$this->testTable} (" .
58 ' id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,' .
59 " {$this->testField} MEDIUMBLOB," .
60 " {$this->anotherTestField} MEDIUMBLOB," .
61 ' PRIMARY KEY (id)' .
62 ') ENGINE=MyISAM DEFAULT CHARSET=utf8;'
63 );
64 }
65
66 /**
67 * Tear the test down
68 */
69 protected function tearDown()
70 {
71 $this->subject->sql_query("DROP TABLE {$this->testTable};");
72 unset($this->subject);
73 }
74
75 /**
76 * @test
77 *
78 * @group not-postgres
79 * @group not-mssql
80 */
81 public function selectDbReturnsTrue()
82 {
83 $this->assertTrue($this->subject->sql_select_db());
84 }
85
86 /**
87 * @test
88 *
89 * @group not-postgres
90 * @group not-mssql
91 */
92 public function selectDbReturnsFalse()
93 {
94 $this->expectException(\RuntimeException::class);
95 $this->expectExceptionCode(1270853883);
96 $this->expectExceptionMessage('TYPO3 Fatal Error: Cannot connect to the current database, "Foo"!');
97
98 $this->subject->setDatabaseName('Foo');
99 $this->assertFalse($this->subject->sql_select_db());
100 }
101
102 /**
103 * @test
104 *
105 * @group not-postgres
106 * @group not-mssql
107 */
108 public function sqlAffectedRowsReturnsCorrectAmountOfRows()
109 {
110 $this->subject->exec_INSERTquery($this->testTable, [$this->testField => 'test']);
111 $this->assertEquals(1, $this->subject->sql_affected_rows());
112 }
113
114 /**
115 * @test
116 *
117 * @group not-postgres
118 * @group not-mssql
119 */
120 public function sqlInsertIdReturnsCorrectId()
121 {
122 $this->subject->exec_INSERTquery($this->testTable, [$this->testField => 'test']);
123 $this->assertEquals(1, $this->subject->sql_insert_id());
124 }
125
126 /**
127 * @test
128 *
129 * @group not-postgres
130 * @group not-mssql
131 */
132 public function noSqlError()
133 {
134 $this->subject->exec_INSERTquery($this->testTable, [$this->testField => 'test']);
135 $this->assertEquals('', $this->subject->sql_error());
136 }
137
138 /**
139 * @test
140 *
141 * @group not-postgres
142 * @group not-mssql
143 */
144 public function sqlErrorWhenInsertIntoInexistentField()
145 {
146 $this->subject->exec_INSERTquery($this->testTable, ['test' => 'test']);
147 $this->assertEquals('Unknown column \'test\' in \'field list\'', $this->subject->sql_error());
148 }
149
150 /**
151 * @test
152 *
153 * @group not-postgres
154 * @group not-mssql
155 */
156 public function noSqlErrorCode()
157 {
158 $this->subject->exec_INSERTquery($this->testTable, [$this->testField => 'test']);
159 $this->assertEquals(0, $this->subject->sql_errno());
160 }
161
162 /**
163 * @test
164 *
165 * @group not-postgres
166 * @group not-mssql
167 */
168 public function sqlErrorNoWhenInsertIntoInexistentField()
169 {
170 $this->subject->exec_INSERTquery($this->testTable, ['test' => 'test']);
171 $this->assertEquals(1054, $this->subject->sql_errno());
172 }
173
174 /**
175 * @test
176 *
177 * @group not-postgres
178 * @group not-mssql
179 */
180 public function sqlPconnectReturnsInstanceOfMySqli()
181 {
182 $this->assertInstanceOf('mysqli', $this->subject->sql_pconnect());
183 }
184
185 /**
186 * @test
187 *
188 * @group not-postgres
189 * @group not-mssql
190 */
191 public function connectDbThrowsExeptionsWhenNoDatabaseIsGiven()
192 {
193 $this->expectException(\RuntimeException::class);
194 $this->expectExceptionCode(1270853882);
195
196 /** @var DatabaseConnection|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface $subject */
197 $subject = $this->getAccessibleMock(DatabaseConnection::class, ['dummy'], [], '', false);
198 $subject->connectDB();
199 }
200
201 /**
202 * @test
203 *
204 * @group not-postgres
205 * @group not-mssql
206 */
207 public function connectDbConnectsToDatabaseWithoutErrors()
208 {
209 $this->subject->connectDB();
210 $this->assertTrue($this->subject->isConnected());
211 }
212
213 /**
214 * @test
215 *
216 * @group not-postgres
217 * @group not-mssql
218 */
219 public function disconnectIfConnectedDisconnects()
220 {
221 $this->assertTrue($this->subject->isConnected());
222 $this->subject->setDatabaseHost('127.0.0.1');
223 $this->assertFalse($this->subject->isConnected());
224 }
225
226 /**
227 * Data Provider for fullQuoteStrReturnsQuotedString()
228 *
229 * @see fullQuoteStrReturnsQuotedString()
230 *
231 * @return array
232 */
233 public function fullQuoteStrReturnsQuotedStringDataProvider()
234 {
235 return [
236 'NULL string with ReturnNull is allowed' => [
237 [null, true],
238 'NULL',
239 ],
240 'NULL string with ReturnNull is false' => [
241 [null, false],
242 "''",
243 ],
244 'Normal string' => [
245 ['Foo', false],
246 "'Foo'",
247 ],
248 'Single quoted string' => [
249 ["'Hello'", false],
250 "'\\'Hello\\''",
251 ],
252 'Double quoted string' => [
253 ['"Hello"', false],
254 "'\\\"Hello\\\"'",
255 ],
256 'String with internal single tick' => [
257 ['It\'s me', false],
258 "'It\\'s me'",
259 ],
260 'Slashes' => [
261 ['/var/log/syslog.log', false],
262 "'/var/log/syslog.log'",
263 ],
264 'Backslashes' => [
265 ['\\var\\log\\syslog.log', false],
266 "'\\\\var\\\\log\\\\syslog.log'",
267 ],
268 ];
269 }
270
271 /**
272 * @test
273 * @dataProvider fullQuoteStrReturnsQuotedStringDataProvider
274 *
275 * @param string $values
276 * @param string $expectedResult
277 *
278 * @group not-postgres
279 * @group not-mssql
280 */
281 public function fullQuoteStrReturnsQuotedString($values, $expectedResult)
282 {
283 /** @var DatabaseConnection $subject */
284 $quotedStr = $this->subject->fullQuoteStr($values[0], 'tt_content', $values[1]);
285 $this->assertEquals($expectedResult, $quotedStr);
286 }
287
288 /**
289 * Data Provider for fullQuoteArrayQuotesArray()
290 *
291 * @see fullQuoteArrayQuotesArray()
292 *
293 * @return array
294 */
295 public function fullQuoteArrayQuotesArrayDataProvider()
296 {
297 return [
298 'NULL array with ReturnNull is allowed' => [
299 [
300 [null, null],
301 false,
302 true,
303 ],
304 ['NULL', 'NULL'],
305 ],
306
307 'NULL array with ReturnNull is false' => [
308 [
309 [null, null],
310 false,
311 false,
312 ],
313 ["''", "''"],
314 ],
315
316 'Strings in array' => [
317 [
318 ['Foo', 'Bar'],
319 false,
320 false,
321 ],
322 ["'Foo'", "'Bar'"],
323 ],
324
325 'Single quotes in array' => [
326 [
327 ["'Hello'"],
328 false,
329 false,
330 ],
331 ["'\\'Hello\\''"],
332 ],
333
334 'Double quotes in array' => [
335 [
336 ['"Hello"'],
337 false,
338 false,
339 ],
340 ["'\\\"Hello\\\"'"],
341 ],
342
343 'Slashes in array' => [
344 [
345 ['/var/log/syslog.log'],
346 false,
347 false,
348 ],
349 ["'/var/log/syslog.log'"],
350 ],
351
352 'Backslashes in array' => [
353 [
354 ['\var\log\syslog.log'],
355 false,
356 false,
357 ],
358 ["'\\\\var\\\\log\\\\syslog.log'"],
359 ],
360
361 'Strings with internal single tick' => [
362 [
363 ['Hey!', 'It\'s me'],
364 false,
365 false,
366 ],
367 ["'Hey!'", "'It\\'s me'"],
368 ],
369
370 'no quotes strings from array' => [
371 [
372 [
373 'First' => 'Hey!',
374 'Second' => 'It\'s me',
375 'Third' => 'O\' Reily',
376 ],
377 ['First', 'Third'],
378 false,
379 ],
380 ['First' => 'Hey!', 'Second' => "'It\\'s me'", 'Third' => "O' Reily"],
381 ],
382
383 'no quotes strings from string' => [
384 [
385 [
386 'First' => 'Hey!',
387 'Second' => 'It\'s me',
388 'Third' => 'O\' Reily',
389 ],
390 'First,Third',
391 false,
392 ],
393 ['First' => 'Hey!', 'Second' => "'It\\'s me'", 'Third' => "O' Reily"],
394 ],
395 ];
396 }
397
398 /**
399 * @test
400 * @dataProvider fullQuoteArrayQuotesArrayDataProvider
401 *
402 * @param string $values
403 * @param string $expectedResult
404 *
405 * @group not-postgres
406 * @group not-mssql
407 */
408 public function fullQuoteArrayQuotesArray($values, $expectedResult)
409 {
410 $quotedResult = $this->subject->fullQuoteArray($values[0], $this->testTable, $values[1], $values[2]);
411 $this->assertSame($expectedResult, $quotedResult);
412 }
413
414 /**
415 * Data Provider for quoteStrQuotesDoubleQuotesCorrectly()
416 *
417 * @see quoteStrQuotesDoubleQuotesCorrectly()
418 *
419 * @return array
420 */
421 public function quoteStrQuotesCorrectlyDataProvider()
422 {
423 return [
424 'Double Quotes' => [
425 '"Hello"',
426 '\\"Hello\\"'
427 ],
428 'Single Quotes' => [
429 '\'Hello\'',
430 "\\'Hello\\'"
431 ],
432 'Slashes' => [
433 '/var/log/syslog.log',
434 '/var/log/syslog.log'
435 ],
436 'Literal Backslashes' => [
437 '\\var\\log\\syslog.log',
438 '\\\\var\\\\log\\\\syslog.log'
439 ],
440 'Fallback Literal Backslashes' => [
441 '\var\log\syslog.log',
442 '\\\\var\\\\log\\\\syslog.log'
443 ],
444 ];
445 }
446
447 /**
448 * @test
449 * @dataProvider quoteStrQuotesCorrectlyDataProvider
450 *
451 * @param string $string String to quote
452 * @param string $expectedResult Quoted string we expect
453 *
454 * @group not-postgres
455 * @group not-mssql
456 */
457 public function quoteStrQuotesDoubleQuotesCorrectly($string, $expectedResult)
458 {
459 $quotedString = $this->subject->quoteStr($string, $this->testTable);
460 $this->assertSame($expectedResult, $quotedString);
461 }
462
463 /**
464 * @test
465 *
466 * @group not-postgres
467 * @group not-mssql
468 */
469 public function adminQueryReturnsTrueForInsertQuery()
470 {
471 $this->assertTrue(
472 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('foo')")
473 );
474 }
475
476 /**
477 * @test
478 *
479 * @group not-postgres
480 * @group not-mssql
481 */
482 public function adminQueryReturnsTrueForUpdateQuery()
483 {
484 $this->assertTrue(
485 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('foo')")
486 );
487 $id = $this->subject->sql_insert_id();
488 $this->assertTrue(
489 $this->subject->admin_query("UPDATE {$this->testTable} SET {$this->testField}='bar' WHERE id={$id}")
490 );
491 }
492
493 /**
494 * @test
495 *
496 * @group not-postgres
497 * @group not-mssql
498 */
499 public function adminQueryReturnsTrueForDeleteQuery()
500 {
501 $this->assertTrue(
502 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('foo')")
503 );
504 $id = $this->subject->sql_insert_id();
505 $this->assertTrue($this->subject->admin_query("DELETE FROM {$this->testTable} WHERE id={$id}"));
506 }
507
508 /**
509 * @test
510 *
511 * @group not-postgres
512 * @group not-mssql
513 */
514 public function adminQueryReturnsResultForSelectQuery()
515 {
516 $this->assertTrue(
517 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('foo')")
518 );
519 $res = $this->subject->admin_query("SELECT {$this->testField} FROM {$this->testTable}");
520 $this->assertInstanceOf('mysqli_result', $res);
521 $result = $res->fetch_assoc();
522 $this->assertEquals('foo', $result[$this->testField]);
523 }
524
525 /**
526 * @test
527 *
528 * @group not-postgres
529 * @group not-mssql
530 */
531 public function adminGetCharsetsReturnsArrayWithCharsets()
532 {
533 $columnsRes = $this->subject->admin_query('SHOW CHARACTER SET');
534 $result = $this->subject->admin_get_charsets();
535 $this->assertEquals(count($result), $columnsRes->num_rows);
536
537 /** @var array $row */
538 while (($row = $columnsRes->fetch_assoc())) {
539 $this->assertArrayHasKey($row['Charset'], $result);
540 }
541 }
542
543 /**
544 * @test
545 *
546 * @group not-postgres
547 * @group not-mssql
548 */
549 public function adminGetKeysReturnIndexKeysOfTable()
550 {
551 $result = $this->subject->admin_get_keys($this->testTable);
552 $this->assertEquals('id', $result[0]['Column_name']);
553 }
554
555 /**
556 * @test
557 *
558 * @group not-postgres
559 * @group not-mssql
560 */
561 public function adminGetFieldsReturnFieldInformationsForTable()
562 {
563 $result = $this->subject->admin_get_fields($this->testTable);
564 $this->assertArrayHasKey('id', $result);
565 $this->assertArrayHasKey($this->testField, $result);
566 }
567
568 /**
569 * @test
570 *
571 * @group not-postgres
572 * @group not-mssql
573 */
574 public function adminGetTablesReturnAllTablesFromDatabase()
575 {
576 $result = $this->subject->admin_get_tables();
577 $this->assertArrayHasKey('tt_content', $result);
578 $this->assertArrayHasKey('pages', $result);
579 }
580
581 /**
582 * @test
583 *
584 * @group not-postgres
585 * @group not-mssql
586 */
587 public function adminGetDbsReturnsAllDatabases()
588 {
589 /** @noinspection SqlResolve */
590 $databases = $this->subject->admin_query('SELECT SCHEMA_NAME FROM information_schema.SCHEMATA');
591 $result = $this->subject->admin_get_dbs();
592 $this->assertSame(count($result), $databases->num_rows);
593
594 $i = 0;
595 while ($database = $databases->fetch_assoc()) {
596 $this->assertSame($database['SCHEMA_NAME'], $result[$i]);
597 $i++;
598 }
599 }
600
601 /**
602 * Data Provider for sqlNumRowsReturnsCorrectAmountOfRows()
603 *
604 * @see sqlNumRowsReturnsCorrectAmountOfRows()
605 *
606 * @return array
607 */
608 public function sqlNumRowsReturnsCorrectAmountOfRowsProvider()
609 {
610 $sql1 = "SELECT * FROM {$this->testTable} WHERE {$this->testField}='baz'";
611 $sql2 = "SELECT * FROM {$this->testTable} WHERE {$this->testField}='baz' OR {$this->testField}='bar'";
612 $sql3 = "SELECT * FROM {$this->testTable} WHERE {$this->testField} IN ('baz', 'bar', 'foo')";
613
614 return [
615 'One result' => [$sql1, 1],
616 'Two results' => [$sql2, 2],
617 'Three results' => [$sql3, 3],
618 ];
619 }
620
621 /**
622 * @test
623 * @dataProvider sqlNumRowsReturnsCorrectAmountOfRowsProvider
624 *
625 * @param string $sql
626 * @param string $expectedResult
627 *
628 * @group not-postgres
629 * @group not-mssql
630 */
631 public function sqlNumRowsReturnsCorrectAmountOfRows($sql, $expectedResult)
632 {
633 $this->assertTrue(
634 $this->subject->admin_query(
635 "INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('foo'), ('bar'), ('baz')"
636 )
637 );
638
639 $res = $this->subject->admin_query($sql);
640 $numRows = $this->subject->sql_num_rows($res);
641 $this->assertSame($expectedResult, $numRows);
642 }
643
644 /**
645 * @test
646 *
647 * @group not-postgres
648 * @group not-mssql
649 */
650 public function sqlNumRowsReturnsFalse()
651 {
652 $res = $this->subject->admin_query("SELECT * FROM {$this->testTable} WHERE test='baz'");
653 $numRows = $this->subject->sql_num_rows($res);
654 $this->assertFalse($numRows);
655 }
656
657 /**
658 * Prepares the test table for the fetch* Tests
659 */
660 protected function prepareTableForFetchTests()
661 {
662 $this->assertTrue(
663 $this->subject->sql_query(
664 "ALTER TABLE {$this->testTable} " .
665 'ADD name mediumblob, ' .
666 'ADD deleted int, ' .
667 'ADD street varchar(100), ' .
668 'ADD city varchar(50), ' .
669 'ADD country varchar(100)'
670 )
671 );
672
673 $this->assertTrue(
674 $this->subject->admin_query(
675 "INSERT INTO {$this->testTable} (name,street,city,country,deleted) VALUES " .
676 "('Mr. Smith','Oakland Road','Los Angeles','USA',0)," .
677 "('Ms. Smith','Oakland Road','Los Angeles','USA',0)," .
678 "('Alice im Wunderland','Große Straße','Königreich der Herzen','Wunderland',0)," .
679 "('Agent Smith','Unbekannt','Unbekannt','Matrix',1)"
680 )
681 );
682 }
683
684 /**
685 * @test
686 *
687 * @group not-postgres
688 * @group not-mssql
689 */
690 public function sqlFetchAssocReturnsAssocArray()
691 {
692 $this->prepareTableForFetchTests();
693
694 $res = $this->subject->admin_query("SELECT * FROM {$this->testTable} ORDER BY id");
695 $expectedResult = [
696 [
697 'id' => '1',
698 $this->testField => null,
699 $this->anotherTestField => null,
700 'name' => 'Mr. Smith',
701 'deleted' => '0',
702 'street' => 'Oakland Road',
703 'city' => 'Los Angeles',
704 'country' => 'USA',
705 ],
706 [
707 'id' => '2',
708 $this->testField => null,
709 $this->anotherTestField => null,
710 'name' => 'Ms. Smith',
711 'deleted' => '0',
712 'street' => 'Oakland Road',
713 'city' => 'Los Angeles',
714 'country' => 'USA',
715 ],
716 [
717 'id' => '3',
718 $this->testField => null,
719 $this->anotherTestField => null,
720 'name' => 'Alice im Wunderland',
721 'deleted' => '0',
722 'street' => 'Große Straße',
723 'city' => 'Königreich der Herzen',
724 'country' => 'Wunderland',
725 ],
726 [
727 'id' => '4',
728 $this->testField => null,
729 $this->anotherTestField => null,
730 'name' => 'Agent Smith',
731 'deleted' => '1',
732 'street' => 'Unbekannt',
733 'city' => 'Unbekannt',
734 'country' => 'Matrix',
735 ],
736 ];
737 $i = 0;
738 while ($row = $this->subject->sql_fetch_assoc($res)) {
739 $this->assertSame($expectedResult[$i], $row);
740 $i++;
741 }
742 }
743
744 /**
745 * @test
746 *
747 * @group not-postgres
748 * @group not-mssql
749 */
750 public function sqlFetchRowReturnsNumericArray()
751 {
752 $this->prepareTableForFetchTests();
753 $res = $this->subject->admin_query("SELECT * FROM {$this->testTable} ORDER BY id");
754 $expectedResult = [
755 ['1', null, null, 'Mr. Smith', '0', 'Oakland Road', 'Los Angeles', 'USA'],
756 ['2', null, null, 'Ms. Smith', '0', 'Oakland Road', 'Los Angeles', 'USA'],
757 ['3', null, null, 'Alice im Wunderland', '0', 'Große Straße', 'Königreich der Herzen', 'Wunderland'],
758 ['4', null, null, 'Agent Smith', '1', 'Unbekannt', 'Unbekannt', 'Matrix'],
759 ];
760 $i = 0;
761 while ($row = $this->subject->sql_fetch_row($res)) {
762 $this->assertSame($expectedResult[$i], $row);
763 $i++;
764 }
765 }
766
767 /**
768 * @test
769 *
770 * @group not-postgres
771 * @group not-mssql
772 */
773 public function sqlFreeResultReturnsFalseOnFailure()
774 {
775 $this->assertTrue(
776 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('baz')")
777 );
778 $res = $this->subject->admin_query("SELECT * FROM {$this->testTable} WHERE {$this->testField}=baz");
779 $this->assertFalse($this->subject->sql_free_result($res));
780 }
781
782 /**
783 * @test
784 *
785 * @group not-postgres
786 * @group not-mssql
787 */
788 public function sqlFreeResultReturnsTrueOnSuccess()
789 {
790 $this->assertTrue(
791 $this->subject->admin_query("INSERT INTO {$this->testTable} ({$this->testField}) VALUES ('baz')")
792 );
793 $res = $this->subject->admin_query("SELECT * FROM {$this->testTable} WHERE {$this->testField}='baz'");
794 $this->assertTrue($this->subject->sql_free_result($res));
795 }
796 }