Skip to content

Commit 7fb3015

Browse files
committed
Add MySQL proxy tests
1 parent b1e4db9 commit 7fb3015

File tree

9 files changed

+260
-0
lines changed

9 files changed

+260
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: MySQL Proxy Tests
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
name: MySQL Proxy Tests
12+
runs-on: ubuntu-latest
13+
timeout-minutes: 20
14+
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
19+
- name: Set up PHP
20+
uses: shivammathur/setup-php@v2
21+
with:
22+
php-version: '7.4'
23+
24+
- name: Install Composer dependencies
25+
uses: ramsey/composer-install@v3
26+
with:
27+
ignore-cache: "yes"
28+
composer-options: "--optimize-autoloader"
29+
working-directory: packages/wp-mysql-proxy
30+
31+
- name: Run MySQL Proxy tests
32+
run: composer run test
33+
working-directory: packages/wp-mysql-proxy
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit bootstrap="tests/bootstrap/bootstrap.php" colors="true" stopOnFailure="false">
3+
<testsuites>
4+
<testsuite name="WP MySQL Proxy Test Suite">
5+
<directory>tests/</directory>
6+
</testsuite>
7+
</testsuites>
8+
</phpunit>

packages/wp-mysql-proxy/src/mysql-server.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,7 @@ public function __construct( MySQLQueryHandler $query_handler, $options = array(
672672

673673
public function start() {
674674
$this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
675+
socket_set_option( $this->socket, SOL_SOCKET, SO_REUSEADDR, 1 );
675676
socket_bind( $this->socket, '0.0.0.0', $this->port );
676677
socket_listen( $this->socket );
677678
echo "MySQL PHP Server listening on port {$this->port}...\n";
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
class WP_MySQL_Proxy_MySQLi_Test extends WP_MySQL_Proxy_Test {
4+
/** @var mysqli */
5+
private $mysqli;
6+
7+
public function setUp(): void {
8+
parent::setUp();
9+
$this->mysqli = new mysqli( '127.0.0.1', 'WordPress', 'WordPress', 'WordPress', $this->port );
10+
}
11+
12+
public function test_query(): void {
13+
$result = $this->mysqli->query( 'CREATE TABLE t (id INT PRIMARY KEY, name TEXT)' );
14+
$this->assertTrue( $result );
15+
16+
$result = $this->mysqli->query( 'INSERT INTO t (id, name) VALUES (123, "abc"), (456, "def")' );
17+
$this->assertEquals( 2, $result );
18+
}
19+
20+
public function test_prepared_statement(): void {
21+
// TODO: Implement prepared statements in the MySQL proxy.
22+
$this->markTestSkipped( 'Prepared statements are not supported yet.' );
23+
}
24+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
class WP_MySQL_Proxy_PDO_Test extends WP_MySQL_Proxy_Test {
4+
/** @var PDO */
5+
private $pdo;
6+
7+
public function setUp(): void {
8+
parent::setUp();
9+
10+
$this->pdo = new PDO(
11+
sprintf( 'mysql:host=127.0.0.1;port=%d', $this->port ),
12+
'WordPress',
13+
'WordPress'
14+
);
15+
}
16+
17+
public function test_exec(): void {
18+
$result = $this->pdo->exec( 'CREATE TABLE t (id INT PRIMARY KEY, name TEXT)' );
19+
$this->assertEquals( 0, $result );
20+
21+
$result = $this->pdo->exec( 'INSERT INTO t (id, name) VALUES (123, "abc"), (456, "def")' );
22+
$this->assertEquals( 2, $result );
23+
}
24+
25+
public function test_query(): void {
26+
$this->pdo->exec( 'CREATE TABLE t (id INT PRIMARY KEY, name TEXT)' );
27+
$this->pdo->exec( 'INSERT INTO t (id, name) VALUES (123, "abc"), (456, "def")' );
28+
29+
$result = $this->pdo->query( "SELECT 'test'" );
30+
$this->assertEquals( 'test', $result->fetchColumn() );
31+
32+
$result = $this->pdo->query( 'SELECT * FROM t' );
33+
$this->assertEquals( 2, $result->rowCount() );
34+
$this->assertEquals(
35+
array(
36+
array(
37+
'id' => 123,
38+
'name' => 'abc',
39+
),
40+
array(
41+
'id' => 456,
42+
'name' => 'def',
43+
),
44+
),
45+
$result->fetchAll( PDO::FETCH_ASSOC )
46+
);
47+
}
48+
49+
public function test_prepared_statement(): void {
50+
$this->pdo->exec( 'CREATE TABLE t (id INT PRIMARY KEY, name TEXT)' );
51+
$this->pdo->exec( 'INSERT INTO t (id, name) VALUES (123, "abc"), (456, "def")' );
52+
53+
$stmt = $this->pdo->prepare( 'SELECT * FROM t WHERE id = ?' );
54+
$stmt->execute( array( 123 ) );
55+
$this->assertEquals(
56+
array(
57+
array(
58+
'id' => 123,
59+
'name' => 'abc',
60+
),
61+
),
62+
$stmt->fetchAll( PDO::FETCH_ASSOC )
63+
);
64+
}
65+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
<?php
2+
3+
use PHPUnit\Framework\TestCase;
4+
5+
abstract class WP_MySQL_Proxy_Test extends TestCase {
6+
/** @var int */
7+
protected $port = 3306;
8+
9+
/** @var MySQL_Server_Process */
10+
protected $server;
11+
12+
public function setUp(): void {
13+
$this->server = new MySQL_Server_Process(
14+
array(
15+
'port' => $this->port,
16+
'db_path' => ':memory:',
17+
)
18+
);
19+
}
20+
21+
public function tearDown(): void {
22+
$this->server->stop();
23+
$exit_code = $this->server->get_exit_code();
24+
if ( $this->hasFailed() || ( $exit_code > 0 && 143 !== $exit_code ) ) {
25+
$hr = str_repeat( '-', 80 );
26+
fprintf(
27+
STDERR,
28+
"\n\n$hr\nSERVER OUTPUT:\n$hr\n[RETURN CODE]: %d\n\n[STDOUT]:\n%s\n\n[STDERR]:\n%s\n$hr\n",
29+
$this->server->get_exit_code(),
30+
$this->server->get_stdout(),
31+
$this->server->get_stderr()
32+
);
33+
}
34+
}
35+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
require_once __DIR__ . '/../../vendor/autoload.php';
4+
require_once __DIR__ . '/mysql-server-process.php';
5+
require_once __DIR__ . '/../WP_MySQL_Proxy_Test.php';
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
/**
3+
* Manages the MySQL server as a subprocess for tests
4+
*/
5+
6+
use Symfony\Component\Process\Process;
7+
8+
class MySQL_Server_Process {
9+
/** @var Process */
10+
private $process;
11+
12+
public function __construct( array $options = array() ) {
13+
$port = $options['port'] ?? 3306;
14+
$env = array_merge(
15+
$_ENV,
16+
array(
17+
'PORT' => $port,
18+
'DB_PATH' => $options['db_path'] ?? ':memory:',
19+
)
20+
);
21+
$this->process = new Process(
22+
array( PHP_BINARY, __DIR__ . '/run-server.php' ),
23+
null,
24+
$env
25+
);
26+
$this->process->start();
27+
28+
// Wait for the server to be ready.
29+
for ( $i = 0; $i < 20; $i++ ) {
30+
$connection = @fsockopen( '127.0.0.1', $port ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
31+
if ( $connection ) {
32+
fclose( $connection );
33+
return;
34+
}
35+
usleep( 100000 );
36+
}
37+
38+
// Connection timed out.
39+
$this->stop();
40+
$error = $this->process->getErrorOutput();
41+
throw new Exception(
42+
sprintf( 'Server failed to start on port %d: %s', $port, $error )
43+
);
44+
}
45+
46+
public function stop(): void {
47+
if ( isset( $this->process ) ) {
48+
$this->process->stop();
49+
}
50+
}
51+
52+
public function get_exit_code(): ?int {
53+
if ( ! isset( $this->process ) ) {
54+
return null;
55+
}
56+
return $this->process->getExitCode() ?? null;
57+
}
58+
59+
public function get_stdout(): string {
60+
if ( ! isset( $this->process ) ) {
61+
return '';
62+
}
63+
return $this->process->getOutput();
64+
}
65+
66+
public function get_stderr(): string {
67+
if ( ! isset( $this->process ) ) {
68+
return '';
69+
}
70+
return $this->process->getErrorOutput();
71+
}
72+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
use WP_MySQL_Proxy\MySQL_Proxy;
4+
use WP_MySQL_Proxy\Adapter\SQLite_Adapter;
5+
6+
require_once __DIR__ . '/../../vendor/autoload.php';
7+
8+
// Configuration.
9+
$port = (int) ( $_ENV['PORT'] ?? 3306 );
10+
$db_path = $_ENV['DB_PATH'] ?? ':memory:';
11+
12+
// Server.
13+
$proxy = new MySQL_Proxy(
14+
new SQLite_Adapter( $db_path ),
15+
array( 'port' => $port )
16+
);
17+
$proxy->start();

0 commit comments

Comments
 (0)