Skip to content

Commit

Permalink
Merge pull request #2 from andriuspetrauskis/database-check-upgrade
Browse files Browse the repository at this point in the history
Database check upgrade
  • Loading branch information
developer-ns authored May 5, 2021
2 parents b11d5a5 + b2dffc7 commit 32b8fc7
Show file tree
Hide file tree
Showing 6 changed files with 468 additions and 7 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: CI

on: [push]

jobs:
build-test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: php-actions/composer@v5

- name: PHPUnit Tests
uses: php-actions/phpunit@v2
with:
bootstrap: vendor/autoload.php
configuration: phpunit.xml.dist
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
vendor/
composer.lock
phpunit.xml
.phpunit.cache/
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
}
},
"suggest": {
"illuminate/database": "Needed for DatabaseChecker",
"ext-pdo": "Needed for DatabaseChecker",
"php-amqplib/php-amqplib": "Needed for RabbitMqChecker",
"influxdb/influxdb-php": "Needed for InfluxDbChecker",
"predis/predis": "Needed for RedisChecker"
},
"require-dev": {
"squizlabs/php_codesniffer": "^2.7"
"squizlabs/php_codesniffer": "^2.7",
"phpunit/phpunit": "^9.5"
}
}
26 changes: 26 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="true"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnRisky="true"
failOnWarning="true"
verbose="true">
<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>

<coverage cacheDirectory=".phpunit.cache/code-coverage"
processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
</coverage>
</phpunit>
145 changes: 140 additions & 5 deletions src/Services/DatabaseChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@
namespace Nordsec\StatusChecker\Services;

use Exception;
use Illuminate\Database\Capsule\Manager as Capsule;

class DatabaseChecker implements StatusCheckerInterface
{
protected const DEFAULT_DRIVER = 'mysql';
protected const DEFAULT_HOST = 'localhost';
protected const DEFAULT_PORT = 3306;
protected const DEFAULT_USER = 'root';
protected const DEFAULT_PASSWORD = '';

private $name;
private $configuration;
private $critical = true;
Expand Down Expand Up @@ -41,15 +46,145 @@ public function needsOutput(): bool

public function checkStatus(): string
{
$capsule = new Capsule();
$capsule->addConnection($this->configuration);

try {
$capsule->getConnection()->select('select 1');
$this->executeSelect('select 1');
} catch (Exception $exception) {
return StatusCheckerInterface::STATUS_FAIL;
}

return StatusCheckerInterface::STATUS_OK;
}

protected function createConnection(string $dsn, $user = null, $password = null, array $options = []): \PDO
{
return new \PDO($dsn, $user, $password, $options);
}

private function executeSelect(string $query): void
{
$config = $this->resolveConfig();

$dsn = $this->resolveDsn($config);
$user = $this->resolveUser($config);
$pass = $this->resolvePassword($config);

$pdo = $this->createConnection($dsn, $user, $pass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]);

$pdo->exec($query);
}

private function resolveDsn(array $config): string
{
if (
is_string($this->configuration) &&
strpos($this->configuration, ':') !== false &&
strpos($this->configuration, ':') !== strpos($this->configuration, '://')
) {
return $this->configuration;
}

return $config['dsn'] ?? $this->buildDsn($config);
}

private function resolveConfig(): array
{
if (
is_string($this->configuration) &&
strpos($this->configuration, '://') !== false &&
strpos($this->configuration, '://') === strpos($this->configuration, ':')
) {
return $this->resolveConfigFromUrl($this->configuration);
}

if (is_array($this->configuration)) {
if (isset($this->configuration['url'])) {
return $this->resolveConfigFromUrl($this->configuration['url']);
}
if (isset($this->configuration['driver']) || isset($this->configuration['adapter'])) {
return $this->configuration;
}

$firstElement = reset($this->configuration);
if (isset($firstElement['url'])) {
return $this->resolveConfigFromUrl($firstElement['url']);
}
if (isset($firstElement['driver']) || isset($firstElement['adapter'])) {
return $firstElement;
}
}

$urlFromEnv = getenv('DATABASE_URL');
if (!empty($urlFromEnv)) {
return $this->resolveConfigFromUrl($urlFromEnv);
}

return [];
}

private function buildDsn(array $config): string
{
if (($config['driver'] ?? '') === 'sqlite') {
return sprintf('%s:%s', $config['driver'], $config['database'] ?? $config['path']);
}

return sprintf(
'%s:host=%s;port=%d;dbname=%s',
$this->resolveDriver($config),
$config['host'] ?? $config['read']['host'] ?? $config['write']['host'] ?? static::DEFAULT_HOST,
$config['port'] ?? static::DEFAULT_PORT,
$config['dbname'] ?? $config['database'] ?? null,
);
}

private function resolveConfigFromUrl(string $url): array
{
$details = parse_url($url);
$additionalPathChars = 1;

if ($details === false) {
// $url is in format sqlite:///path/to/file
preg_match('|^(?<scheme>\w+)://(?<path>.*)$|', $url, $details);
$additionalPathChars = 0;
}

$result = [
'driver' => $details['scheme'],
'user' => $details['user'] ?? '',
'password' => $details['pass'] ?? '',
'database' => substr($details['path'] ?? null, $additionalPathChars),
'host' => $details['host'] ?? '',
];

if (empty($result['database']) && !empty($result['host']) && $result['driver'] === 'sqlite') {
// $url is in format sqlite://file_in_current_dir
$result['database'] = $result['host'];
$result['host'] = '';
}

return $result;
}

private function resolveUser(array $config): string
{
return $config['user'] ?? $config['username'] ?? $config['dbuser'] ?? static::DEFAULT_USER;
}

private function resolvePassword(array $config): string
{
return $config['password'] ?? $config['pass'] ?? $config['dbpass'] ?? static::DEFAULT_PASSWORD;
}

private function resolveDriver(array $config): string
{
$driver = $config['driver'] ?? $config['adapter'] ?? static::DEFAULT_DRIVER;

if ($driver === 'mysqli') {
$driver = 'mysql';
}
if (strpos($driver, 'pdo_') !== false) {
$driver = str_replace('pdo_', '', $driver);
}

return $driver;
}
}
Loading

0 comments on commit 32b8fc7

Please sign in to comment.