host = getenv('DB_HOST') ?: ($_ENV['DB_HOST'] ?? ($_SERVER['DB_HOST'] ?? 'db')); $this->db1 = 'dbdiff_test1'; $this->db2 = 'dbdiff_test2'; $this->db = $this->connectWithRetry( "mysql:host={$this->host};port={$this->port}", $this->user, $this->pass ); $version = $this->db->getAttribute(PDO::ATTR_SERVER_VERSION); $this->mysqlMajorVersion = (int) explode('.', $version)[0]; $this->db->exec("DROP DATABASE IF EXISTS `{$this->db1}`;"); $this->db->exec("DROP DATABASE IF EXISTS `{$this->db2}`;"); $this->db->exec("CREATE DATABASE `{$this->db1}`;"); $this->db->exec("CREATE DATABASE `{$this->db2}`;"); } protected function getVersionSuffix(): string { $engine = getenv('DBDIFF_ENGINE') ?: null; if ($engine) { return $engine; } return (string) $this->mysqlMajorVersion; } protected function loadFixture(string $fixtureName): void { $db1File = "tests/fixtures/{$fixtureName}/db1.sql"; $db2File = "tests/fixtures/{$fixtureName}/db2.sql"; if (!file_exists($db1File) || !file_exists($db2File)) { $this->fail("Fixture files not found for: $fixtureName"); } $this->db->exec("USE `{$this->db1}`"); $this->db->exec(file_get_contents($db1File)); $this->db->exec("USE `{$this->db2}`"); $this->db->exec(file_get_contents($db2File)); } protected function driverArgs(): array { return ["--server1={$this->user}:{$this->pass}@{$this->host}:{$this->port}"]; } protected function dbInputArg(): string { return "server1.{$this->db1}:server1.{$this->db2}"; } protected function tableInputArg(string $table): ?string { return "server1.{$this->db1}.{$table}:server1.{$this->db2}.{$table}"; } protected function getServerConfig(): array { return [ 'user' => $this->user, 'password' => $this->pass, 'host' => $this->host, 'port' => $this->port, ]; } protected function tearDownDatabases(): void { if ($this->db) { $this->db->exec("DROP DATABASE IF EXISTS `{$this->db1}`;"); $this->db->exec("DROP DATABASE IF EXISTS `{$this->db2}`;"); } } // ── Dolt-specific skips ────────────────────────────────────────────── // Dolt's strict SQL engine rejects cross-database data diff queries // involving datetime columns with empty-string defaults. These tests // use the basic_schema_data fixture whose `posts.published_at` column // triggers this. Schema-only and legacy E2E data diffs work fine. private function skipOnDolt(): void { if (getenv('DBDIFF_ENGINE') === 'dolt') { $this->markTestSkipped('Dolt: cross-database data diff with datetime columns not yet supported'); } } public function testDataOnlyDiff(): void { $this->skipOnDolt(); parent::testDataOnlyDiff(); } public function testTemplateOutput(): void { $this->skipOnDolt(); parent::testTemplateOutput(); } public function testUpOnlyOutput(): void { $this->skipOnDolt(); parent::testUpOnlyOutput(); } public function testDownOnlyOutput(): void { $this->skipOnDolt(); parent::testDownOnlyOutput(); } public function testConfigFileUsage(): void { $this->skipOnDolt(); parent::testConfigFileUsage(); } public function testConfigFileWithCliOverride(): void { $this->skipOnDolt(); parent::testConfigFileWithCliOverride(); } public function testProgrammableObjectsDiff(): void { if (getenv('DBDIFF_ENGINE') === 'dolt') { $this->markTestSkipped('Dolt: stored procedure/trigger multi-statement fixture loading not supported'); } parent::testProgrammableObjectsDiff(); } }