Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/scripts/random-tests-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Config
Cookie
# DataCaster
# DataConverter
# Database
Database
# Debug
Email
# Encryption
Expand Down
15 changes: 14 additions & 1 deletion system/Database/OCI8/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
use ErrorException;
use stdClass;

defined('OCI_COMMIT_ON_SUCCESS') || define('OCI_COMMIT_ON_SUCCESS', 32);

/**
* Connection for OCI8
*
Expand Down Expand Up @@ -150,6 +152,17 @@ public function connect(bool $persistent = false)
: $func($this->username, $this->password, $this->DSN, $this->charset);
}

public function initialize()
{
parent::initialize();

if ($this->connID) {
$this->simpleQuery("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
$this->simpleQuery("ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS'");
$this->simpleQuery("ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT='YYYY-MM-DD HH24:MI:SS'");
}
}

/**
* Close the database connection.
*
Expand Down Expand Up @@ -422,7 +435,7 @@ protected function _indexData(string $table): array
$retVal[$row->INDEX_NAME] = new stdClass();
$retVal[$row->INDEX_NAME]->name = $row->INDEX_NAME;
$retVal[$row->INDEX_NAME]->fields = [$row->COLUMN_NAME];
$retVal[$row->INDEX_NAME]->type = $constraintTypes[$row->CONSTRAINT_TYPE] ?? 'INDEX';
$retVal[$row->INDEX_NAME]->type = $constraintTypes[$row->CONSTRAINT_TYPE ?? ''] ?? 'INDEX';
}

return $retVal;
Expand Down
20 changes: 18 additions & 2 deletions system/Database/Postgre/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use PgSql\Result as PgSqlResult;
use stdClass;
use Stringable;
use Throwable;

/**
* Connection for Postgre
Expand Down Expand Up @@ -149,15 +150,30 @@ private function convertDSN()
*/
protected function _close()
{
pg_close($this->connID);
if ($this->connID !== false) {
try {
pg_close($this->connID);
} catch (Throwable) {
} finally {
$this->connID = false;
}
}
}

/**
* Ping the database connection.
*/
protected function _ping(): bool
{
return pg_ping($this->connID);
if ($this->connID === false) {
return false;
}

try {
return pg_ping($this->connID);
} catch (Throwable) {
return false;
}
}

/**
Expand Down
67 changes: 66 additions & 1 deletion tests/_support/Config/Registrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

namespace Tests\Support\Config;

use mysqli;
use PDO;
use Throwable;

/**
* Class Registrar
*
Expand Down Expand Up @@ -137,7 +141,68 @@ public static function Database(): array
// so that we can test against multiple databases.
$group = env('DB', 'SQLite3');

$config['tests'] = self::$dbConfig[$group] ?? [];
if ($group === 'Oracle') {
$group = 'OCI8';
}

$dbParams = self::$dbConfig[$group] ?? [];

if (! empty($dbParams) && ! in_array($group, ['SQLite3', 'OCI8'], true)) {
$componentName = '';

foreach ($_SERVER['argv'] ?? [] as $arg) {
if (str_contains($arg, 'tests/system/')) {
$parts = explode('tests/system/', $arg);
if (isset($parts[1])) {
$componentName = explode('/', $parts[1])[0];
break;
}
}
}

if ($componentName !== '') {
$dbParams['database'] = 'test_' . strtolower($componentName);

try {
if ($group === 'MySQLi') {
$conn = new mysqli(
$dbParams['hostname'],
$dbParams['username'],
$dbParams['password'],
'',
(int) $dbParams['port'],
);
if (! $conn->connect_error) {
$conn->query('CREATE DATABASE IF NOT EXISTS ' . $conn->real_escape_string($dbParams['database']));
$conn->close();
}
} elseif ($group === 'Postgre') {
$dsn = 'pgsql:host=' . $dbParams['hostname'] . ';port=' . $dbParams['port'] . ';user=' . $dbParams['username'] . ';password=' . $dbParams['password'];
$pdo = new PDO($dsn);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT 1 FROM pg_database WHERE datname = ?');
$stmt->execute([$dbParams['database']]);
if (! $stmt->fetchColumn()) {
$dbName = str_replace('"', '""', $dbParams['database']);
$pdo->exec('CREATE DATABASE "' . $dbName . '"');
}
} elseif ($group === 'SQLSRV') {
$dsn = 'sqlsrv:Server=' . $dbParams['hostname'] . ',' . $dbParams['port'] . ';Encrypt=False;TrustServerCertificate=True';
$pdo = new PDO($dsn, $dbParams['username'], $dbParams['password']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $pdo->prepare('SELECT 1 FROM sys.databases WHERE name = ?');
$stmt->execute([$dbParams['database']]);
if (! $stmt->fetchColumn()) {
$pdo->exec('CREATE DATABASE [' . str_replace(']', ']]', $dbParams['database']) . '] COLLATE Latin1_General_100_CS_AS_SC_UTF8');
}
}
} catch (Throwable) {
// Ignore any error and let the connection fail naturally
}
}
}

$config['tests'] = $dbParams;

return $config;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Tests\Support\Database\Migrations;

use CodeIgniter\Database\Migration;
use Throwable;

class Migration_Create_test_tables extends Migration
{
Expand Down Expand Up @@ -196,9 +197,25 @@ public function down(): void
}

if ($this->db->DBDriver === 'OCI8') {
$this->db->query('DROP PROCEDURE one');
$this->db->query('DROP PROCEDURE plus');
$this->db->query('DROP PACKAGE BODY calculator');
try {
$this->db->query('DROP PROCEDURE one');
} catch (Throwable) {
}

try {
$this->db->query('DROP PROCEDURE plus');
} catch (Throwable) {
}

try {
$this->db->query('DROP PACKAGE BODY calculator');
} catch (Throwable) {
}

try {
$this->db->query('DROP PACKAGE calculator');
} catch (Throwable) {
}
}
}
}
15 changes: 12 additions & 3 deletions tests/system/Database/Live/ConnectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,28 @@ protected function setUp(): void
$this->group2['DBDriver'] = 'Postgre';
}

protected function tearDown(): void
{
parent::tearDown();
$this->setPrivateProperty(Database::class, 'instances', []);
}

public function testConnectWithMultipleCustomGroups(): void
{
$this->group1['DBPrefix'] = uniqid('g1_', true);
$this->group2['DBPrefix'] = uniqid('g2_', true);

// We should have our test database connection already.
$instances = $this->getPrivateProperty(Database::class, 'instances');
$this->assertCount(1, $instances);
$instances = $this->getPrivateProperty(Database::class, 'instances');
$initialCount = count($instances);

$db1 = Database::connect($this->group1);
$db2 = Database::connect($this->group2);

$this->assertNotSame($db1, $db2);

$instances = $this->getPrivateProperty(Database::class, 'instances');
$this->assertCount(3, $instances);
$this->assertCount($initialCount + 2, $instances);
}

public function testConnectReturnsProvidedConnection(): void
Expand Down
15 changes: 11 additions & 4 deletions tests/system/Database/Live/ExecuteLogMessageFormatTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public function testLogMessageWhenExecuteFailsShowFullStructuredBacktrace(): voi
$db->query($sql, [3, 'live', 'Rick']);

$pattern = match ($db->DBDriver) {
'MySQLi' => '/Table \'test\.some_table\' doesn\'t exist/',
'MySQLi' => '/Table \'' . preg_quote($db->database, '/') . '\.some_table\' doesn\'t exist/',
'Postgre' => '/pg_query\(\): Query failed: ERROR: relation "some_table" does not exist/',
'SQLite3' => '/Unable to prepare statement:\s(\d+,\s)?no such table: some_table/',
'OCI8' => '/oci_execute\(\): ORA-00942: table or view "ORACLE"\."SOME_TABLE" does not exist/',
Expand All @@ -60,11 +60,18 @@ public function testLogMessageWhenExecuteFailsShowFullStructuredBacktrace(): voi

if ($db->DBDriver === 'Postgre') {
$messageFromLogs = array_slice($messageFromLogs, 2);
} elseif ($db->DBDriver === 'OCI8') {
$messageFromLogs = array_slice($messageFromLogs, 1);
}

$this->assertMatchesRegularExpression('/^in \S+ on line \d+\.$/', array_shift($messageFromLogs));
$inLine = null;

while (($line = array_shift($messageFromLogs)) !== null) {
if (preg_match('/^in \S+ on line \d+\.$/', $line)) {
$inLine = $line;
break;
}
}

$this->assertNotNull($inLine, 'Could not find "in ... on line ..." in log message');

foreach ($messageFromLogs as $line) {
$this->assertMatchesRegularExpression('/^\s*\d* .+(?:\(\d+\))?: \S+(?:(?:\->|::)\S+)?\(.*\)$/', $line);
Expand Down
63 changes: 57 additions & 6 deletions tests/system/Database/Live/ForgeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,64 @@ final class ForgeTest extends CIUnitTestCase
protected $seed = CITestSeeder::class;
private Forge $forge;

private function dropAllMockTables(): void
{
$tablesToDrop = [
'forge_test_invoices',
'forge_test_inv',
'forge_test_users',
'actions',
'forge_test_table',
'test_exists',
'forge_test_attributes',
'forge_array_constraint',
'forge_nullable_table',
'forge_test_1',
'forge_test_two',
'forge_test_three',
'forge_test_four',
'forge_test_modify',
'droptest',
'key_test_users',
'test_stores',
'user2',
'forge_test_table_dummy',
];

foreach ($tablesToDrop as $table) {
$this->forge->dropTable($table, true);
}
}

protected function setUp(): void
{
$this->forge = Database::forge($this->DBGroup);

// when running locally if one of these tables isn't dropped it may cause error
$this->forge->dropTable('forge_test_invoices', true);
$this->forge->dropTable('forge_test_inv', true);
$this->forge->dropTable('forge_test_users', true);
$this->forge->dropTable('actions', true);
$this->dropAllMockTables();

db_connect($this->DBGroup)->resetDataCache();

parent::setUp();
}

protected function tearDown(): void
{
parent::tearDown();
$this->dropAllMockTables();
}

public function testCreateDatabase(): void
{
if ($this->db->DBDriver === 'OCI8') {
$this->markTestSkipped('OCI8 does not support create database.');
}

try {
$this->forge->dropDatabase('test_forge_database');
} catch (DatabaseException) {
// Ignore if doesn't exist
}

$databaseCreated = $this->forge->createDatabase('test_forge_database');

$this->assertTrue($databaseCreated);
Expand All @@ -68,14 +107,20 @@ public function testCreateDatabaseWithDots(): void

$dbName = 'test_com.sitedb.web';

try {
$this->forge->dropDatabase($dbName);
} catch (DatabaseException) {
// Ignore if doesn't exist
}

$databaseCreated = $this->forge->createDatabase($dbName);

$this->assertTrue($databaseCreated);

// Checks if tableExists() works.
$config = config(Database::class)->{$this->DBGroup};
$config['database'] = $dbName;
$db = db_connect($config);
$db = db_connect($config, false);
$result = $db->tableExists('not_exist');

$this->assertFalse($result);
Expand Down Expand Up @@ -151,6 +196,12 @@ public function testDropDatabase(): void
$this->markTestSkipped('SQLite3 requires file path to drop database');
}

try {
$this->forge->createDatabase('test_forge_database');
} catch (DatabaseException) {
// Ignore if exists
}

$databaseDropped = $this->forge->dropDatabase('test_forge_database');

$this->assertTrue($databaseDropped);
Expand Down
3 changes: 1 addition & 2 deletions tests/system/Database/Live/GetVersionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public function testGetVersion(): void
$this->db->connID = false;

$version = $this->db->getVersion();

$this->assertMatchesRegularExpression('/\A\d+(\.\d+)*\z/', $version);
$this->assertMatchesRegularExpression('/\A\d+(\.\d+)*/', $version);
}
}
Loading
Loading