Skip to content

32 tests for mysql pdo native mysql #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 15, 2025
Merged
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 run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ else
TEST_PATH="$BASE_PATH/$1"
fi

"$PHP_EXECUTABLE" "$RUN_TESTS_PATH" --show-diff -m -p "$PHP_EXECUTABLE" "$TEST_PATH"
"$PHP_EXECUTABLE" "$RUN_TESTS_PATH" --show-diff -p "$PHP_EXECUTABLE" "$TEST_PATH"
56 changes: 56 additions & 0 deletions tests/mysqli/001-mysqli_connect_async.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
--TEST--
MySQLi: Basic async connection test
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';
AsyncMySQLiTest::skipIfNoAsync();
AsyncMySQLiTest::skipIfNoMySQLi();
AsyncMySQLiTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';

use function Async\spawn;
use function Async\await;

echo "start\n";

$coroutine = spawn(function() {
try {
// Initialize database first
$mysqli = AsyncMySQLiTest::initDatabase();
echo "connected\n";

// Test simple query
$result = $mysqli->query("SELECT 1 as test");
if ($result) {
$row = $result->fetch_assoc();
echo "query result: " . $row['test'] . "\n";
$result->free();
}

$mysqli->close();
echo "closed\n";

return "success";
} catch (Exception $e) {
echo "error: " . $e->getMessage() . "\n";
return "failed";
}
});

$result = await($coroutine);
echo "awaited: " . $result . "\n";
echo "end\n";

?>
--EXPECT--
start
connected
query result: 1
closed
awaited: success
end
82 changes: 82 additions & 0 deletions tests/mysqli/002-mysqli_query_async.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
--TEST--
MySQLi: Async query execution
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';
AsyncMySQLiTest::skipIfNoAsync();
AsyncMySQLiTest::skipIfNoMySQLi();
AsyncMySQLiTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';

use function Async\spawn;
use function Async\await;

echo "start\n";

$coroutine = spawn(function() {
try {
$mysqli = AsyncMySQLiTest::initDatabase();

// Create and populate test table
$mysqli->query("DROP TEMPORARY TABLE IF EXISTS async_test");
$result = $mysqli->query("CREATE TEMPORARY TABLE async_test (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), value INT)");

if (!$result) {
echo "create table failed: " . $mysqli->error . "\n";
return "failed";
}
echo "table created\n";

// Insert test data
$mysqli->query("INSERT INTO async_test (name, value) VALUES ('test1', 10)");
$mysqli->query("INSERT INTO async_test (name, value) VALUES ('test2', 20)");
$mysqli->query("INSERT INTO async_test (name, value) VALUES ('test3', 30)");
echo "data inserted\n";

// Test SELECT query
$result = $mysqli->query("SELECT * FROM async_test ORDER BY id");
if ($result) {
$count = 0;
while ($row = $result->fetch_assoc()) {
$count++;
echo "row $count: {$row['name']} = {$row['value']}\n";
}
$result->free();
}

// Test aggregate query
$result = $mysqli->query("SELECT COUNT(*) as total, SUM(value) as sum_value FROM async_test");
if ($result) {
$row = $result->fetch_assoc();
echo "total rows: {$row['total']}, sum: {$row['sum_value']}\n";
$result->free();
}

$mysqli->close();
return "completed";
} catch (Exception $e) {
echo "error: " . $e->getMessage() . "\n";
return "failed";
}
});

$result = await($coroutine);
echo "result: " . $result . "\n";
echo "end\n";

?>
--EXPECT--
start
table created
data inserted
row 1: test1 = 10
row 2: test2 = 20
row 3: test3 = 30
total rows: 3, sum: 60
result: completed
end
103 changes: 103 additions & 0 deletions tests/mysqli/003-mysqli_concurrent_connections.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
--TEST--
MySQLi: Concurrent connections in separate coroutines
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';
AsyncMySQLiTest::skipIfNoAsync();
AsyncMySQLiTest::skipIfNoMySQLi();
AsyncMySQLiTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';

use function Async\spawn;
use function Async\await;
use function Async\awaitAllOrFail;

echo "start\n";

// Create multiple coroutines with separate MySQLi connections
$coroutines = [
spawn(function() {
$mysqli = AsyncMySQLiTest::factory();
$result = $mysqli->query("SELECT 'coroutine1' as source, CONNECTION_ID() as conn_id");
$row = $result->fetch_assoc();
$result->free();
$mysqli->close();
return ['source' => $row['source'], 'conn_id' => $row['conn_id']];
}),

spawn(function() {
$mysqli = AsyncMySQLiTest::factory();
$result = $mysqli->query("SELECT 'coroutine2' as source, CONNECTION_ID() as conn_id");
$row = $result->fetch_assoc();
$result->free();
$mysqli->close();
return ['source' => $row['source'], 'conn_id' => $row['conn_id']];
}),

spawn(function() {
$mysqli = AsyncMySQLiTest::factory();
$result = $mysqli->query("SELECT 'coroutine3' as source, CONNECTION_ID() as conn_id");
$row = $result->fetch_assoc();
$result->free();
$mysqli->close();
return ['source' => $row['source'], 'conn_id' => $row['conn_id']];
}),

spawn(function() {
$mysqli = AsyncMySQLiTest::factory();
// Test with some workload
$mysqli->query("CREATE TEMPORARY TABLE temp_work (id INT, data VARCHAR(100))");
$mysqli->query("INSERT INTO temp_work VALUES (1, 'data1'), (2, 'data2')");
$result = $mysqli->query("SELECT COUNT(*) as count, CONNECTION_ID() as conn_id FROM temp_work");
$row = $result->fetch_assoc();
$result->free();
$mysqli->close();
return ['source' => 'coroutine4', 'conn_id' => $row['conn_id'], 'count' => $row['count']];
})
];

$results = awaitAllOrFail($coroutines);

// Display results in deterministic order
usort($results, function($a, $b) {
return strcmp($a['source'], $b['source']);
});

foreach ($results as $result) {
if (isset($result['count'])) {
echo "from {$result['source']} (with work) conn_id: {$result['conn_id']}, count: {$result['count']}\n";
} else {
echo "from {$result['source']} conn_id: {$result['conn_id']}\n";
}
}

// Verify all connections are different
$connectionIds = array_map(function($r) { return $r['conn_id']; }, $results);
$uniqueIds = array_unique($connectionIds);
echo "unique connections: " . count($uniqueIds) . "\n";
echo "total coroutines: " . count($connectionIds) . "\n";

if (count($uniqueIds) === count($connectionIds)) {
echo "isolation: passed\n";
} else {
echo "isolation: failed\n";
}

echo "end\n";

?>
--EXPECTF--
start
from coroutine1 conn_id: %d
from coroutine2 conn_id: %d
from coroutine3 conn_id: %d
from coroutine4 (with work) conn_id: %d, count: 2
unique connections: 4
total coroutines: 4
isolation: passed
end
117 changes: 117 additions & 0 deletions tests/mysqli/004-mysqli_prepared_async.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
--TEST--
MySQLi: Async prepared statements
--EXTENSIONS--
mysqli
--SKIPIF--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';
AsyncMySQLiTest::skipIfNoAsync();
AsyncMySQLiTest::skipIfNoMySQLi();
AsyncMySQLiTest::skip();
?>
--FILE--
<?php
require_once __DIR__ . '/inc/async_mysqli_test.inc';

use function Async\spawn;
use function Async\await;

echo "start\n";

$coroutine = spawn(function() {
try {
$mysqli = AsyncMySQLiTest::factory();

// Create test table
$mysqli->query("DROP TEMPORARY TABLE IF EXISTS async_prepared_test");
$mysqli->query("CREATE TEMPORARY TABLE async_prepared_test (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), score INT, active BOOLEAN)");
echo "table created\n";

// Test INSERT prepared statement
$stmt = $mysqli->prepare("INSERT INTO async_prepared_test (name, score, active) VALUES (?, ?, ?)");
if (!$stmt) {
throw new Exception("Prepare failed: " . $mysqli->error);
}

// Insert multiple records
$name = "user1"; $score = 85; $active = true;
$stmt->bind_param("sii", $name, $score, $active);
$stmt->execute();

$name = "user2"; $score = 92; $active = false;
$stmt->bind_param("sii", $name, $score, $active);
$stmt->execute();

$name = "user3"; $score = 78; $active = true;
$stmt->bind_param("sii", $name, $score, $active);
$stmt->execute();

$stmt->close();
echo "inserted records with prepared statement\n";

// Test SELECT prepared statement
$stmt = $mysqli->prepare("SELECT id, name, score FROM async_prepared_test WHERE score > ? AND active = ? ORDER BY id");
if (!$stmt) {
throw new Exception("Prepare SELECT failed: " . $mysqli->error);
}

$min_score = 80;
$is_active = true;
$stmt->bind_param("ii", $min_score, $is_active);
$stmt->execute();

$result = $stmt->get_result();
echo "records with score > $min_score and active = $is_active:\n";

while ($row = $result->fetch_assoc()) {
echo " id: {$row['id']}, name: {$row['name']}, score: {$row['score']}\n";
}

$stmt->close();

// Test UPDATE prepared statement
$stmt = $mysqli->prepare("UPDATE async_prepared_test SET score = score + ? WHERE name = ?");
if (!$stmt) {
throw new Exception("Prepare UPDATE failed: " . $mysqli->error);
}

$bonus = 5;
$target_name = "user1";
$stmt->bind_param("is", $bonus, $target_name);
$stmt->execute();

echo "updated $target_name with bonus $bonus points\n";
echo "affected rows: " . $stmt->affected_rows . "\n";

$stmt->close();

// Verify update
$result = $mysqli->query("SELECT name, score FROM async_prepared_test WHERE name = 'user1'");
$row = $result->fetch_assoc();
echo "user1 new score: {$row['score']}\n";
$result->free();

$mysqli->close();
return "completed";
} catch (Exception $e) {
echo "error: " . $e->getMessage() . "\n";
return "failed";
}
});

$result = await($coroutine);
echo "result: " . $result . "\n";
echo "end\n";

?>
--EXPECT--
start
table created
inserted records with prepared statement
records with score > 80 and active = 1:
id: 1, name: user1, score: 85
updated user1 with bonus 5 points
affected rows: 1
user1 new score: 90
result: completed
end
Loading
Loading