Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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 ext/pdo/tests/bug_73234.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ if (str_starts_with(getenv('PDOTEST_DSN'), "firebird")) die('xfail firebird driv
require_once $dir . 'pdo_test.inc';
PDOTest::skip();

$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'oci') {
die("xfail PDO::PARAM_NULL is not honored by OCI driver, related with bug #81586");
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/tests/bug_79106.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $dir = getenv('REDIR_TEST_DIR');
if (!$dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
try {
$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
} catch (PDOException $e) {
die('skip ' . $e->getMessage());
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/tests/bug_79106_collision.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ $dir = getenv('REDIR_TEST_DIR');
if (!$dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
try {
$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
} catch (PDOException $e) {
die('skip ' . $e->getMessage());
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/tests/debug_emulated_prepares.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();

$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'pgsql') die('skip pgsql has its own test for this feature');
if (!@$db->getAttribute(PDO::ATTR_EMULATE_PREPARES) && !@$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, true)) die('skip driver cannot emulate prepared statements');
?>
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/tests/gh8626.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();

$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
if ($db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'oci') {
die("xfail OCI driver errorInfo is inconsistent with other PDO drivers");
}
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo/tests/pdo_017.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();

$db = PDOTest::factory();
$db = PDOTest::factoryForSkip();
try {
$db->beginTransaction();
$db->rollback();
Expand Down
88 changes: 78 additions & 10 deletions ext/pdo/tests/pdo_test.inc
Original file line number Diff line number Diff line change
Expand Up @@ -16,26 +16,31 @@ if (getenv('PDOTEST_DSN') === false) {
}

class PDOTest {
private static function getAttributes(string $environmentVariable): ?array {
$attributes = getenv($environmentVariable);
if (is_string($attributes) && strlen($attributes)) {
return unserialize($attributes);
}
return null;
}

// create an instance of the PDO driver, based on
// the current environment
static function factory($classname = PDO::class, bool $useConnectMethod = false) {
static function factory($classname = PDO::class, bool $useConnectMethod = false, ?array $attributes = null) {
$dsn = getenv('PDOTEST_DSN');
$user = getenv('PDOTEST_USER');
$pass = getenv('PDOTEST_PASS');
$attr = getenv('PDOTEST_ATTR');
if (is_string($attr) && strlen($attr)) {
$attr = unserialize($attr);
} else {
$attr = null;
if ($attributes === null) {
$attributes = self::getAttributes('PDOTEST_ATTR');
}

if ($user === false) $user = NULL;
if ($pass === false) $pass = NULL;

if ($useConnectMethod) {
$db = $classname::connect($dsn, $user, $pass, $attr);
$db = $classname::connect($dsn, $user, $pass, $attributes);
} else {
$db = new $classname($dsn, $user, $pass, $attr);
$db = new $classname($dsn, $user, $pass, $attributes);
}

if (!$db) {
Expand All @@ -50,14 +55,77 @@ class PDOTest {
return $db;
}

static function skip() {
private static function getSkipCacheFile(): ?string {
$directory = getenv('TEST_PHP_SHARED_CACHE_DIR');
if (!is_string($directory) || !is_dir($directory)) {
return null;
}

$configuration = [
getenv('PDOTEST_DSN'),
getenv('PDOTEST_USER'),
getenv('PDOTEST_PASS'),
getenv('PDOTEST_ATTR'),
getenv('PDOTEST_SKIP_ATTR'),
];
return $directory . DIRECTORY_SEPARATOR . 'pdo-' . hash('sha256', serialize($configuration));
}

static function factoryForSkip() {
$attributes = self::getAttributes('PDOTEST_ATTR');
$skipAttributes = self::getAttributes('PDOTEST_SKIP_ATTR');
if ($skipAttributes !== null) {
$attributes = $skipAttributes + ($attributes ?? []);
}
return PDOTest::factory(PDO::class, false, $attributes);
}

private static function connectOrSkip(): void {
try {
$db = PDOTest::factory();
self::factoryForSkip();
} catch (PDOException $e) {
die("skip " . $e->getMessage());
}
}

static function skip() {
$cacheFile = self::getSkipCacheFile();
if ($cacheFile === null) {
self::connectOrSkip();
return;
}

$cache = @fopen($cacheFile, 'c+');
if ($cache === false || !flock($cache, LOCK_EX)) {
if (is_resource($cache)) {
fclose($cache);
}
self::connectOrSkip();
return;
}

$cached = stream_get_contents($cache);
$reason = $cached !== '' ? $cached : null;
if ($reason === null) {
// Only failures are shared; successful checks still create their own connection.
try {
self::factoryForSkip();
} catch (PDOException $e) {
$reason = $e->getMessage();
rewind($cache);
ftruncate($cache, 0);
fwrite($cache, $reason);
fflush($cache);
}
}

flock($cache, LOCK_UN);
fclose($cache);
if (is_string($reason)) {
die("skip $reason");
}
}

static function test_factory($file, $classname = PDO::class, bool $useConnectMethod = false) {
$config = self::get_config($file);
foreach ($config['ENV'] as $k => $v) {
Expand Down
74 changes: 74 additions & 0 deletions ext/pdo/tests/pdo_test_skip_cache.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
--TEST--
PDO test helper caches connection failures for one test run
--EXTENSIONS--
pdo
--FILE--
<?php
function run_pdo_skip_check(string $code, array $environment): string
{
$command = getenv('TEST_PHP_EXECUTABLE_ESCAPED')
. ' '
. getenv('TEST_PHP_EXTRA_ARGS')
. ' -d opcache.enable_cli=0 -d opcache.jit_buffer_size=0 -r '
. escapeshellarg($code);
$process = proc_open(
$command,
[
1 => ['pipe', 'w'],
2 => ['redirect', 1],
],
$pipes,
null,
$environment,
['bypass_shell' => true],
);
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);

if (0 !== $exitCode = proc_close($process)) {
throw new Exception("PHP subprocess exited with code $exitCode: $output");
}

return $output;
}

$dsn = 'missing_' . getmypid() . ':';
$cacheDirectory = __DIR__ . '/pdo_test_skip_cache_' . getmypid();
mkdir($cacheDirectory);

$environment = getenv();
$environment['PDOTEST_DSN'] = $dsn;
$environment['PDOTEST_USER'] = 'test';
$environment['PDOTEST_PASS'] = 'test';
$environment['TEST_PHP_SHARED_CACHE_DIR'] = $cacheDirectory;
unset($environment['PDOTEST_ATTR']);

$helperDirectory = getenv('REDIR_TEST_DIR') ?: __DIR__;
$helper = var_export($helperDirectory . '/pdo_test.inc', true);
$code = "require $helper; PDOTest::skip();";
$first = run_pdo_skip_check($code, $environment);

$cacheFiles = glob($cacheDirectory . '/pdo-*');
if (count($cacheFiles) !== 1) {
throw new Exception('Expected exactly one cache file');
}
$cacheFile = $cacheFiles[0];
$cachedReason = file_get_contents($cacheFile);
file_put_contents($cacheFile, 'cached connection failure');

$second = run_pdo_skip_check($code, $environment);
echo "$first\n$cachedReason\n$second\n";
?>
--CLEAN--
<?php
foreach (glob(__DIR__ . '/pdo_test_skip_cache_*') ?: [] as $directory) {
foreach (glob($directory . '/*') ?: [] as $file) {
@unlink($file);
}
@rmdir($directory);
}
?>
--EXPECT--
skip could not find driver
could not find driver
skip cached connection failure
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/GHSA-5hqh-c84r-qjcv.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (PHP_INT_SIZE != 4) die("skip for 32bit platforms only");
if (PHP_OS_FAMILY === "Windows") die("skip not for Windows because the virtual address space for application is only 2GiB");
if (getenv("SKIP_SLOW_TESTS")) die("skip slow test");
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--INI--
memory_limit=-1
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_ins_exec.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_ins_sel_up_del.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_ins_up.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_rowcount.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_transaction.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/batch_stmt_try.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db = skipIfNoDbConnection();
if (!driver_supports_batch_statements_without_select($db)) die('xfail test will fail with this version of FreeTDS');
?>
--FILE--
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_38955.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_45876.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--CONFLICTS--
all
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_47588.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_50755.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pdo_dblib
<?php
if (getenv('SKIP_REPEAT')) die('skip May fail on repeat');
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--CONFLICTS--
all
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_54648.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_67130.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_68957.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_69592.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
2 changes: 1 addition & 1 deletion ext/pdo_dblib/tests/bug_69757.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
skipIfNoDbConnection();
?>
--FILE--
<?php
Expand Down
Loading
Loading