Skip to content

Commit

Permalink
Merge pull request #182 from slaff/feature/sqlsrv-integration-tests
Browse files Browse the repository at this point in the history
Added MS SQL server that can be used to better test the integration.
  • Loading branch information
weierophinney authored Feb 22, 2021
2 parents dc16d07 + 07fe812 commit 80cbba4
Show file tree
Hide file tree
Showing 14 changed files with 268 additions and 15 deletions.
16 changes: 16 additions & 0 deletions .ci/sqlsrv_install_drivers.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env bash
set -x

# Install MSSQL client development libraries
curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
sudo curl https://packages.microsoft.com/config/ubuntu/18.04/prod.list -o /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y msodbcsql17 mssql-tools unixodbc-dev
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bash_profile
echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc

export PATH="$PATH:/opt/mssql-tools/bin"

# Install SqlServer PHP extensions
pecl install sqlsrv
pecl install pdo_sqlsrv
13 changes: 13 additions & 0 deletions .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,16 @@ jobs:
--health-retries 3
ports:
- 5432
mssql:
image: mcr.microsoft.com/mssql/server:2017-latest
env:
ACCEPT_EULA: 'Y'
SA_PASSWORD: 'Password123'
ports:
- 1433
options: >-
--health-cmd="/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P 'Password123' -Q 'SELECT 1' || exit 1"
--health-interval 10s
--health-timeout 5s
--health-retries 3
--health-start-period 10s
3 changes: 2 additions & 1 deletion .laminas-ci.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"pdo-sqlite",
"mysqli",
"pgsql",
"sqlite3"
"sqlite3",
"sqlsrv"
]
}
4 changes: 2 additions & 2 deletions .laminas-ci/phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_MYSQL_PASSWORD" value="password" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_MYSQL_DATABASE" value="laminasdb_test" />

<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV" value="false" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME" value="192.168.20.20" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV" value="true" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME" value="mssql" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_USERNAME" value="sa" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_PASSWORD" value="Password123" />
<env name="TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE" value="laminasdb_test" />
Expand Down
32 changes: 22 additions & 10 deletions test/integration/Adapter/Platform/SqlServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@
namespace LaminasIntegrationTest\Db\Adapter\Platform;

use Laminas\Db\Adapter\Platform\SqlServer;
use PDO;
use PHPUnit\Framework\TestCase;

use function extension_loaded;
use function getenv;
use function sqlsrv_connect;
use function sqlsrv_errors;

/**
* @group integration
* @group integration-sqlserver
Expand All @@ -24,24 +30,29 @@ protected function setUp(): void
if (! getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV')) {
$this->markTestSkipped(__CLASS__ . ' integration tests are not enabled!');
}

$database = getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE');
$database = $database === false ? null : $database;

if (extension_loaded('sqlsrv')) {
$this->adapters['sqlsrv'] = \sqlsrv_connect(
$this->adapters['sqlsrv'] = sqlsrv_connect(
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME'),
[
'UID' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_USERNAME'),
'PWD' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_PASSWORD'),
'Database' => (getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE') ? : null),
'Database' => $database,
]
);
if (! $this->adapters['sqlsrv']) {
var_dump(sqlsrv_errors());
exit;
}
}
if (extension_loaded('pdo')) {
$this->adapters['pdo_sqlsrv'] = new \PDO(
'sqlsrv:Server=' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME')
. ';Database=' . (getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE') ? : null),
if (extension_loaded('pdo') && extension_loaded('pdo_sqlsrv')) {
$this->adapters['pdo_sqlsrv'] = new PDO(
'sqlsrv:Server='
. getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME')
. ';Database=' . ($database ?: ''),
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_USERNAME'),
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_PASSWORD')
);
Expand All @@ -50,11 +61,12 @@ protected function setUp(): void

public function testQuoteValueWithSqlServer()
{
if (! $this->adapters['pdo_sqlsrv']) {
if (! isset($this->adapters['pdo_sqlsrv'])) {
$this->markTestSkipped('SQLServer (pdo_sqlsrv) not configured in unit test configuration file');
}
$sqlite = new SqlServer($this->adapters['pdo_sqlsrv']);
$value = $sqlite->quoteValue('value');
self::assertEquals('\'value\'', $value);

$db = new SqlServer($this->adapters['pdo_sqlsrv']);
$value = $db->quoteValue('value');
self::assertEquals("'value'", $value);
}
}
5 changes: 5 additions & 0 deletions test/integration/IntegrationTestListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use LaminasIntegrationTest\Db\Platform\FixtureLoader;
use LaminasIntegrationTest\Db\Platform\MysqlFixtureLoader;
use LaminasIntegrationTest\Db\Platform\PgsqlFixtureLoader;
use LaminasIntegrationTest\Db\Platform\SqlServerFixtureLoader;
use PHPUnit\Framework\TestListener;
use PHPUnit\Framework\TestListenerDefaultImplementation;
use PHPUnit\Framework\TestSuite as TestSuite;
Expand Down Expand Up @@ -39,6 +40,10 @@ public function startTestSuite(TestSuite $suite): void
$this->fixtureLoaders[] = new PgsqlFixtureLoader();
}

if (getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV')) {
$this->fixtureLoaders[] = new SqlServerFixtureLoader();
}

if (empty($this->fixtureLoaders)) {
return;
}
Expand Down
115 changes: 115 additions & 0 deletions test/integration/Platform/SqlServerFixtureLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

/**
* @see https://github.com/laminas/laminas-db for the canonical source repository
* @copyright https://github.com/laminas/laminas-db/blob/master/COPYRIGHT.md
* @license https://github.com/laminas/laminas-db/blob/master/LICENSE.md New BSD License
*/

namespace LaminasIntegrationTest\Db\Platform;

use function sqlsrv_connect;
use function sqlsrv_errors;
use function sqlsrv_query;

class SqlServerFixtureLoader implements FixtureLoader
{

private $fixtureFilePrefix = __DIR__ . '/../TestFixtures/sqlsrv';
/**
* @var resource
*/
private $connection;

public function createDatabase()
{
$this->connect();

if (false === sqlsrv_query($this->connection, sprintf(
<<<'SQL'
IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '%s')
BEGIN
CREATE DATABASE [%s]
END
SQL,
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'),
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE')
))) {
throw new \Exception(sprintf(
"I cannot create the MSSQL %s database: %s",
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'),
print_r(sqlsrv_errors(), true)
));
}

sqlsrv_query($this->connection, 'USE ' . getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'));

$fixtures = [
'tables' => $this->fixtureFilePrefix.'.sql',
'views' => $this->fixtureFilePrefix.'-views.sql',
'triggers' => $this->fixtureFilePrefix.'-triggers.sql',
];

foreach ($fixtures as $name => $fixtureFile) {
if (false === sqlsrv_query($this->connection, file_get_contents($fixtureFile))) {
throw new \Exception(sprintf(
"I cannot create the %s for %s database. Check the %s file. %s ",
$name,
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'),
$fixtureFile,
print_r(sqlsrv_errors(), true)
));
}
}

$this->disconnect();
}

public function dropDatabase()
{
$this->connect();

sqlsrv_query($this->connection, "USE master");
sqlsrv_query($this->connection, sprintf(
"ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE",
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE')
));

if (false == sqlsrv_query($this->connection, sprintf(
"DROP DATABASE %s",
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE')
))) {
throw new \Exception(sprintf(
"Unable to drop database %s. %s",
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'),
print_r(sqlsrv_errors(), true)
));
}

$this->disconnect();
}

protected function connect()
{
$this->connection = sqlsrv_connect(
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME'),
[
'UID' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_USERNAME'),
'PWD' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_PASSWORD'),
]
);

if (false === $this->connection) {
throw new \Exception(sprintf(
"Unable to connect %s. %s",
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_DATABASE'),
print_r(sqlsrv_errors(), true)
));
}
}

protected function disconnect()
{
$this->connection = null;
}
}
27 changes: 27 additions & 0 deletions test/integration/TestFixtures/mysql.sql
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,30 @@ CREATE TABLE IF NOT EXISTS test_charset (
INSERT INTO test_charset (field$, field_) VALUES
('foo', 'bar'),
('bar', 'baz');

CREATE TABLE test_audit_trail (
id INT NOT NULL AUTO_INCREMENT,
test_id INT NOT NULL,
test_value_old VARCHAR(255) NOT NULL,
test_value_new VARCHAR(255) NOT NULL,
changed TIMESTAMP,
PRIMARY KEY (id)
);

CREATE VIEW test_view
AS
SELECT
name AS v_name,
value AS v_value
FROM
test;

CREATE TRIGGER after_test_update
AFTER UPDATE ON test
FOR EACH ROW
INSERT INTO test_audit_trail
SET
test_id = OLD.id,
test_value_old = OLD.value,
test_value_new = NEW.value,
changed = NOW();
12 changes: 12 additions & 0 deletions test/integration/TestFixtures/sqlsrv-triggers.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CREATE TRIGGER after_test_update ON test
AFTER UPDATE
AS
BEGIN
INSERT INTO test_audit_trail(test_id, test_value_old, test_value_new, changed)
SELECT
id,
value,
inserted.value,
GETDATE()
FROM inserted
END;
8 changes: 8 additions & 0 deletions test/integration/TestFixtures/sqlsrv-views.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE VIEW test_view
AS (
SELECT
name AS v_name,
value AS v_value
FROM
test
);
32 changes: 32 additions & 0 deletions test/integration/TestFixtures/sqlsrv.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
CREATE TABLE test (
id INT NOT NULL IDENTITY,
name VARCHAR(255) NOT NULL,
value VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);

INSERT INTO test (name, value) VALUES
('foo', 'bar'),
('bar', 'baz'),
('123a', 'bar'),
('123', 'bar');

CREATE TABLE test_charset (
id INT NOT NULL IDENTITY,
field$ VARCHAR(255) NOT NULL,
field_ VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);

INSERT INTO test_charset (field$, field_) VALUES
('foo', 'bar'),
('bar', 'baz');

CREATE TABLE test_audit_trail (
id INT NOT NULL IDENTITY,
test_id INT NOT NULL,
test_value_old VARCHAR(255) NOT NULL,
test_value_new VARCHAR(255) NOT NULL,
changed DATETIME2(0),
PRIMARY KEY (id)
);
8 changes: 8 additions & 0 deletions test/unit/Adapter/Driver/Sqlsrv/AbstractIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,13 @@ protected function setUp(): void
if (! extension_loaded('sqlsrv')) {
$this->fail('The phpunit group integration-sqlsrv was enabled, but the extension is not loaded.');
}

$this->adapters['sqlsrv'] = sqlsrv_connect(
getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_HOSTNAME'),
[
'UID' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_USERNAME'),
'PWD' => getenv('TESTS_LAMINAS_DB_ADAPTER_DRIVER_SQLSRV_PASSWORD'),
]
);
}
}
4 changes: 2 additions & 2 deletions test/unit/Adapter/Driver/Sqlsrv/ConnectionIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ConnectionIntegrationTest extends AbstractIntegrationTest
public function testGetCurrentSchema()
{
$connection = new Connection($this->variables);
self::assertInternalType('string', $connection->getCurrentSchema());
self::assertIsString($connection->getCurrentSchema());
}

/**
Expand Down Expand Up @@ -53,7 +53,7 @@ public function testGetResource()
{
$connection = new Connection($this->variables);
$connection->connect();
self::assertInternalType('resource', $connection->getResource());
self::assertIsResource($connection->getResource());

$connection->disconnect();
unset($connection);
Expand Down
4 changes: 4 additions & 0 deletions test/unit/Adapter/Driver/Sqlsrv/PdoSqlSrvIntegrationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class PdoSqlSrvIntegrationTest extends AbstractIntegrationTest
{
public function testParameterizedQuery()
{
if (! isset($this->adapters['pdo_sqlsrv'])) {
$this->markTestSkipped('pdo_sqlsrv adapter is not found');
}

$driver = new Pdo($this->adapters['pdo_sqlsrv']);

$stmt = $driver->createStatement('SELECT ? as col_one');
Expand Down

0 comments on commit 80cbba4

Please sign in to comment.