From d0c69d2ef085d1f250931957deec9c6c3e71916c Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Sat, 24 Feb 2018 01:49:59 +0700 Subject: [PATCH 1/9] Refactored Model class. --- src/B8Framework/Model.php | 77 -------------------- src/PHPCensor/Controller/BuildController.php | 10 +-- src/PHPCensor/Model/Build.php | 10 --- src/PHPCensor/Model/BuildError.php | 10 --- src/PHPCensor/Model/BuildMeta.php | 10 --- src/PHPCensor/Model/Environment.php | 10 --- src/PHPCensor/Model/Project.php | 10 --- src/PHPCensor/Model/ProjectGroup.php | 10 --- src/PHPCensor/Model/User.php | 10 --- src/PHPCensor/Store/EnvironmentStore.php | 6 +- 10 files changed, 6 insertions(+), 157 deletions(-) diff --git a/src/B8Framework/Model.php b/src/B8Framework/Model.php index a269c346..7c0784ca 100644 --- a/src/B8Framework/Model.php +++ b/src/B8Framework/Model.php @@ -7,7 +7,6 @@ use Symfony\Component\Cache\Simple\ArrayCache; class Model { - public static $sleepable = []; protected $getters = []; protected $setters = []; protected $data = []; @@ -35,82 +34,6 @@ class Model return $this->tableName; } - /** - * @param integer $depth - * @param integer $currentDepth - * - * @return array - */ - public function toArray($depth = 2, $currentDepth = 0) - { - if (isset(static::$sleepable) && is_array(static::$sleepable) && count(static::$sleepable)) { - $sleepable = static::$sleepable; - } else { - $sleepable = array_keys($this->getters); - } - - $rtn = []; - foreach ($sleepable as $property) { - $rtn[$property] = $this->propertyToArray($property, $currentDepth, $depth); - } - - return $rtn; - } - - /** - * @param string $property - * @param integer $currentDepth - * @param integer $depth - * - * @return mixed - */ - protected function propertyToArray($property, $currentDepth, $depth) - { - $rtn = null; - - if (array_key_exists($property, $this->getters)) { - $method = $this->getters[$property]; - $rtn = $this->{$method}(); - - if (is_object($rtn) || is_array($rtn)) { - $rtn = ($depth > $currentDepth) ? $this->valueToArray($rtn, $currentDepth, $depth) : null; - } - } - - return $rtn; - } - - /** - * @param mixed $value - * @param integer $currentDepth - * @param integer $depth - * - * @return mixed - */ - protected function valueToArray($value, $currentDepth, $depth) - { - $rtn = null; - if (!is_null($value)) { - if (is_object($value) && method_exists($value, 'toArray')) { - $rtn = $value->toArray($depth, $currentDepth + 1); - } elseif (is_array($value)) { - $childArray = []; - - foreach ($value as $k => $v) { - $childArray[$k] = $this->valueToArray($v, $currentDepth + 1, $depth); - } - - $rtn = $childArray; - } else { - $rtn = (is_string($value) && !mb_check_encoding($value, 'UTF-8')) - ? mb_convert_encoding($value, 'UTF-8') - : $value; - } - } - - return $rtn; - } - /** * @return array */ diff --git a/src/PHPCensor/Controller/BuildController.php b/src/PHPCensor/Controller/BuildController.php index 29382310..936c13dc 100644 --- a/src/PHPCensor/Controller/BuildController.php +++ b/src/PHPCensor/Controller/BuildController.php @@ -300,18 +300,14 @@ class BuildController extends Controller */ protected function formatBuilds($builds) { - Project::$sleepable = ['id', 'title', 'reference', 'type']; - $rtn = ['count' => $builds['count'], 'items' => []]; + /** @var Build $build */ foreach ($builds['items'] as $build) { - $item = $build->toArray(1); - - $header = new View('Build/header-row'); + $header = new View('Build/header-row'); $header->build = $build; - $item['header_row'] = $header->render(); - $rtn['items'][$item['id']] = $item; + $rtn['items'][$build->getId()]['header_row'] = $header->render(); } ksort($rtn['items']); diff --git a/src/PHPCensor/Model/Build.php b/src/PHPCensor/Model/Build.php index bcdf56fc..2a40d684 100644 --- a/src/PHPCensor/Model/Build.php +++ b/src/PHPCensor/Model/Build.php @@ -34,21 +34,11 @@ class Build extends Model const SOURCE_WEBHOOK = 4; const SOURCE_WEBHOOK_PULL_REQUEST = 5; - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'build'; - /** - * @var string - */ - protected $modelName = 'Build'; - /** * @var integer */ diff --git a/src/PHPCensor/Model/BuildError.php b/src/PHPCensor/Model/BuildError.php index 5b7bbf1c..a031b395 100644 --- a/src/PHPCensor/Model/BuildError.php +++ b/src/PHPCensor/Model/BuildError.php @@ -12,21 +12,11 @@ class BuildError extends Model const SEVERITY_NORMAL = 2; const SEVERITY_LOW = 3; - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'build_error'; - /** - * @var string - */ - protected $modelName = 'BuildError'; - /** * @var array */ diff --git a/src/PHPCensor/Model/BuildMeta.php b/src/PHPCensor/Model/BuildMeta.php index 1c2881a2..f1bd45c4 100644 --- a/src/PHPCensor/Model/BuildMeta.php +++ b/src/PHPCensor/Model/BuildMeta.php @@ -7,21 +7,11 @@ use b8\Store\Factory; class BuildMeta extends Model { - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'build_meta'; - /** - * @var string - */ - protected $modelName = 'BuildMeta'; - /** * @var array */ diff --git a/src/PHPCensor/Model/Environment.php b/src/PHPCensor/Model/Environment.php index e70da4ee..427a9be8 100644 --- a/src/PHPCensor/Model/Environment.php +++ b/src/PHPCensor/Model/Environment.php @@ -6,21 +6,11 @@ use PHPCensor\Model; class Environment extends Model { - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'environment'; - /** - * @var string - */ - protected $modelName = 'Environment'; - /** * @var array */ diff --git a/src/PHPCensor/Model/Project.php b/src/PHPCensor/Model/Project.php index c6ad79be..4c581fcf 100644 --- a/src/PHPCensor/Model/Project.php +++ b/src/PHPCensor/Model/Project.php @@ -14,21 +14,11 @@ use Symfony\Component\Yaml\Dumper as YamlDumper; */ class Project extends Model { - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'project'; - /** - * @var string - */ - protected $modelName = 'Project'; - /** * @var array */ diff --git a/src/PHPCensor/Model/ProjectGroup.php b/src/PHPCensor/Model/ProjectGroup.php index 68824381..2847c8a6 100644 --- a/src/PHPCensor/Model/ProjectGroup.php +++ b/src/PHPCensor/Model/ProjectGroup.php @@ -7,21 +7,11 @@ use b8\Store\Factory; class ProjectGroup extends Model { - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'project_group'; - /** - * @var string - */ - protected $modelName = 'ProjectGroup'; - /** * @var array */ diff --git a/src/PHPCensor/Model/User.php b/src/PHPCensor/Model/User.php index d49c7472..dd1dceb6 100644 --- a/src/PHPCensor/Model/User.php +++ b/src/PHPCensor/Model/User.php @@ -10,21 +10,11 @@ use PHPCensor\Model; */ class User extends Model { - /** - * @var array - */ - public static $sleepable = []; - /** * @var string */ protected $tableName = 'user'; - /** - * @var string - */ - protected $modelName = 'User'; - /** * @var array */ diff --git a/src/PHPCensor/Store/EnvironmentStore.php b/src/PHPCensor/Store/EnvironmentStore.php index bb9d1d9c..8bee7f08 100644 --- a/src/PHPCensor/Store/EnvironmentStore.php +++ b/src/PHPCensor/Store/EnvironmentStore.php @@ -12,17 +12,17 @@ class EnvironmentStore extends Store /** * @var string */ - protected $tableName = 'environment'; + protected $tableName = 'environment'; /** * @var string */ - protected $modelName = '\PHPCensor\Model\Environment'; + protected $modelName = '\PHPCensor\Model\Environment'; /** * @var string */ - protected $primaryKey = 'id'; + protected $primaryKey = 'id'; /** * Get a Environment by primary key (Id) From 58f1004652806dca5dbe37d97b5be7516d4b3d1e Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 10:00:10 +0700 Subject: [PATCH 2/9] Renamed projects types and build classes: 'remote'/RemoteGitBuild to 'git'/GitBuild, MercurialBuild to HgBuild, SubversionBuild to SvnBuild, 'bitbuckethg' to 'bitbucket-hg'. --- src/PHPCensor/BuildFactory.php | 26 +++++++++---------- .../20180228024622_renamed_build_types.php | 18 +++++++++++++ src/PHPCensor/Model/Build/BitbucketBuild.php | 2 +- .../Model/Build/BitbucketHgBuild.php | 2 +- .../{RemoteGitBuild.php => GitBuild.php} | 2 +- src/PHPCensor/Model/Build/GithubBuild.php | 2 +- src/PHPCensor/Model/Build/GitlabBuild.php | 4 +-- src/PHPCensor/Model/Build/GogsBuild.php | 2 +- .../Build/{MercurialBuild.php => HgBuild.php} | 2 +- .../{SubversionBuild.php => SvnBuild.php} | 6 ++--- 10 files changed, 42 insertions(+), 24 deletions(-) create mode 100644 src/PHPCensor/Migrations/20180228024622_renamed_build_types.php rename src/PHPCensor/Model/Build/{RemoteGitBuild.php => GitBuild.php} (99%) rename src/PHPCensor/Model/Build/{MercurialBuild.php => HgBuild.php} (98%) rename src/PHPCensor/Model/Build/{SubversionBuild.php => SvnBuild.php} (98%) diff --git a/src/PHPCensor/BuildFactory.php b/src/PHPCensor/BuildFactory.php index 95690732..a2ef1af3 100644 --- a/src/PHPCensor/BuildFactory.php +++ b/src/PHPCensor/BuildFactory.php @@ -7,7 +7,7 @@ use PHPCensor\Model\Build; /** * BuildFactory - Takes in a generic "Build" and returns a type-specific build model. - * + * * @author Dan Cryer */ class BuildFactory @@ -43,33 +43,33 @@ class BuildFactory if (!empty($project)) { switch ($project->getType()) { - case 'remote': - $type = 'RemoteGitBuild'; - break; case 'local': $type = 'LocalBuild'; break; + case 'git': + $type = 'GitBuild'; + break; case 'github': $type = 'GithubBuild'; break; case 'bitbucket': $type = 'BitbucketBuild'; break; - case 'bitbuckethg': - $type = 'BitbucketHgBuild'; - break; case 'gitlab': $type = 'GitlabBuild'; break; - case 'hg': - $type = 'MercurialBuild'; - break; - case 'svn': - $type = 'SubversionBuild'; - break; case 'gogs': $type = 'GogsBuild'; break; + case 'hg': + $type = 'HgBuild'; + break; + case 'bitbucket-hg': + $type = 'BitbucketHgBuild'; + break; + case 'svn': + $type = 'SvnBuild'; + break; default: return $build; } diff --git a/src/PHPCensor/Migrations/20180228024622_renamed_build_types.php b/src/PHPCensor/Migrations/20180228024622_renamed_build_types.php new file mode 100644 index 00000000..4cd2255f --- /dev/null +++ b/src/PHPCensor/Migrations/20180228024622_renamed_build_types.php @@ -0,0 +1,18 @@ +execute("UPDATE project SET type = 'git' WHERE type = 'remote'"); + $this->execute("UPDATE project SET type = 'bitbucket-hg' WHERE type = 'bitbuckethg'"); + } + + public function down() + { + $this->execute("UPDATE project SET type = 'remote' WHERE type = 'git'"); + $this->execute("UPDATE project SET type = 'bitbuckethg' WHERE type = 'bitbucket-hg'"); + } +} diff --git a/src/PHPCensor/Model/Build/BitbucketBuild.php b/src/PHPCensor/Model/Build/BitbucketBuild.php index 2e84802f..3b29d38d 100644 --- a/src/PHPCensor/Model/Build/BitbucketBuild.php +++ b/src/PHPCensor/Model/Build/BitbucketBuild.php @@ -15,7 +15,7 @@ use PHPCensor\Model\BuildError; * * @author Dan Cryer */ -class BitbucketBuild extends RemoteGitBuild +class BitbucketBuild extends GitBuild { /** * Get link to commit from another source (i.e. BitBucket) diff --git a/src/PHPCensor/Model/Build/BitbucketHgBuild.php b/src/PHPCensor/Model/Build/BitbucketHgBuild.php index 6be40937..574abf61 100644 --- a/src/PHPCensor/Model/Build/BitbucketHgBuild.php +++ b/src/PHPCensor/Model/Build/BitbucketHgBuild.php @@ -9,7 +9,7 @@ use PHPCensor\Model\Build; * * @author Artem Bochkov */ -class BitbucketHgBuild extends MercurialBuild +class BitbucketHgBuild extends HgBuild { /** * Get link to commit from another source (i.e. BitBucket) diff --git a/src/PHPCensor/Model/Build/RemoteGitBuild.php b/src/PHPCensor/Model/Build/GitBuild.php similarity index 99% rename from src/PHPCensor/Model/Build/RemoteGitBuild.php rename to src/PHPCensor/Model/Build/GitBuild.php index 49753393..40ecf59c 100644 --- a/src/PHPCensor/Model/Build/RemoteGitBuild.php +++ b/src/PHPCensor/Model/Build/GitBuild.php @@ -11,7 +11,7 @@ use Psr\Log\LogLevel; * * @author Dan Cryer */ -class RemoteGitBuild extends Build +class GitBuild extends Build { /** * Get the URL to be used to clone this remote repository. diff --git a/src/PHPCensor/Model/Build/GithubBuild.php b/src/PHPCensor/Model/Build/GithubBuild.php index be2b5d31..b3968b93 100644 --- a/src/PHPCensor/Model/Build/GithubBuild.php +++ b/src/PHPCensor/Model/Build/GithubBuild.php @@ -15,7 +15,7 @@ use PHPCensor\Model\BuildError; * * @author Dan Cryer */ -class GithubBuild extends RemoteGitBuild +class GithubBuild extends GitBuild { /** * Get link to commit from another source (i.e. Github) diff --git a/src/PHPCensor/Model/Build/GitlabBuild.php b/src/PHPCensor/Model/Build/GitlabBuild.php index 35525b37..ad5a30b9 100644 --- a/src/PHPCensor/Model/Build/GitlabBuild.php +++ b/src/PHPCensor/Model/Build/GitlabBuild.php @@ -4,10 +4,10 @@ namespace PHPCensor\Model\Build; /** * Gitlab Build Model - * + * * @author André Cianfarani */ -class GitlabBuild extends RemoteGitBuild +class GitlabBuild extends GitBuild { /** diff --git a/src/PHPCensor/Model/Build/GogsBuild.php b/src/PHPCensor/Model/Build/GogsBuild.php index cab9ad54..9f5d95e6 100644 --- a/src/PHPCensor/Model/Build/GogsBuild.php +++ b/src/PHPCensor/Model/Build/GogsBuild.php @@ -5,7 +5,7 @@ namespace PHPCensor\Model\Build; /** * GogsBuild Build Model */ -class GogsBuild extends RemoteGitBuild +class GogsBuild extends GitBuild { /** * Get link to commit from Gogs repository diff --git a/src/PHPCensor/Model/Build/MercurialBuild.php b/src/PHPCensor/Model/Build/HgBuild.php similarity index 98% rename from src/PHPCensor/Model/Build/MercurialBuild.php rename to src/PHPCensor/Model/Build/HgBuild.php index 4711fbe3..7073144e 100644 --- a/src/PHPCensor/Model/Build/MercurialBuild.php +++ b/src/PHPCensor/Model/Build/HgBuild.php @@ -10,7 +10,7 @@ use PHPCensor\Builder; * * @author Pavel Gopanenko */ -class MercurialBuild extends Build +class HgBuild extends Build { /** * Get the URL to be used to clone this remote repository. diff --git a/src/PHPCensor/Model/Build/SubversionBuild.php b/src/PHPCensor/Model/Build/SvnBuild.php similarity index 98% rename from src/PHPCensor/Model/Build/SubversionBuild.php rename to src/PHPCensor/Model/Build/SvnBuild.php index 68a2ff7d..12fb57a2 100644 --- a/src/PHPCensor/Model/Build/SubversionBuild.php +++ b/src/PHPCensor/Model/Build/SvnBuild.php @@ -7,10 +7,10 @@ use PHPCensor\Builder; /** * Remote Subversion Build Model - * + * * @author Nadir Dzhilkibaev */ -class SubversionBuild extends Build +class SvnBuild extends Build { protected $svnCommand = 'svn export -q --non-interactive '; @@ -21,7 +21,7 @@ class SubversionBuild extends Build { $url = rtrim($this->getProject()->getReference(), '/') . '/'; $branch = ltrim($this->getBranch(), '/'); - + // For empty default branch or default branch name like "/trunk" or "trunk" (-> "trunk") if (empty($branch) || $branch == 'trunk') { $url .= 'trunk'; From 008dc74ff2d09ee8d520598aacb0e748729c64e5 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 10:19:02 +0700 Subject: [PATCH 3/9] Moved commit message to the new line in the timeline widget at home page. --- src/PHPCensor/View/WidgetLastBuilds/update.phtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/PHPCensor/View/WidgetLastBuilds/update.phtml b/src/PHPCensor/View/WidgetLastBuilds/update.phtml index b07bdb80..772a2039 100644 --- a/src/PHPCensor/View/WidgetLastBuilds/update.phtml +++ b/src/PHPCensor/View/WidgetLastBuilds/update.phtml @@ -87,6 +87,7 @@ use PHPCensor\Model\Build; From 27f381982aa44bcfa631c4acaf305c2326869c4c Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 17:28:31 +0700 Subject: [PATCH 4/9] Updated dependencies. --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index b910c90e..87368801 100644 --- a/composer.lock +++ b/composer.lock @@ -220,16 +220,16 @@ }, { "name": "codeception/codeception", - "version": "2.3.8", + "version": "2.3.9", "source": { "type": "git", "url": "https://github.com/Codeception/Codeception.git", - "reference": "43eade17a8cd68e9cde401e8585b09d11d41b12d" + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Codeception/Codeception/zipball/43eade17a8cd68e9cde401e8585b09d11d41b12d", - "reference": "43eade17a8cd68e9cde401e8585b09d11d41b12d", + "url": "https://api.github.com/repos/Codeception/Codeception/zipball/104f46fa0bde339f1bcc3a375aac21eb36e65a1e", + "reference": "104f46fa0bde339f1bcc3a375aac21eb36e65a1e", "shasum": "" }, "require": { @@ -310,7 +310,7 @@ "functional testing", "unit testing" ], - "time": "2018-01-27T22:47:33+00:00" + "time": "2018-02-26T23:29:41+00:00" }, { "name": "codeception/stub", From 8d0d23f5f421b7a921f1ac097c432fcf7e372a0f Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 18:37:22 +0700 Subject: [PATCH 5/9] Merged PostgreSQL and MySQL tests inti one PHPUnit XML config. --- .php-censor.yml | 2 +- .travis.yml | 10 +- phpunit.pgsql.xml | 62 ------------ phpunit.mysql.xml => phpunit.xml | 10 +- src/B8Framework/Database.php | 2 +- ...DatabaseTest.php => DatabaseMysqlTest.php} | 20 ++-- tests/B8Framework/DatabasePostgresqlTest.php | 96 +++++++++++++++++++ .../Plugin/Util/PhpUnitResultTest.php | 2 +- tests/bootstrap.php | 11 ++- 9 files changed, 126 insertions(+), 89 deletions(-) delete mode 100644 phpunit.pgsql.xml rename phpunit.mysql.xml => phpunit.xml (88%) rename tests/B8Framework/{DatabaseTest.php => DatabaseMysqlTest.php} (80%) create mode 100755 tests/B8Framework/DatabasePostgresqlTest.php diff --git a/.php-censor.yml b/.php-censor.yml index c927f4de..a08ed6fd 100644 --- a/.php-censor.yml +++ b/.php-censor.yml @@ -11,7 +11,7 @@ setup: test: php_unit: config: - - phpunit.pgsql.xml + - phpunit.xml php_mess_detector: allow_failures: true diff --git a/.travis.yml b/.travis.yml index 80bf4f4b..34fc0f3d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,20 +15,16 @@ php: matrix: fast_finish: true -env: - - TYPE=mysql - - TYPE=pgsql - install: - composer selfupdate - composer install before_script: - - if [[ "$TYPE" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS b8_test;" -uroot; fi - - if [[ "$TYPE" == "pgsql" ]]; then psql -c 'create database b8_test;' -U postgres; fi + - mysql -e "create database IF NOT EXISTS b8_test;" -uroot + - psql -c 'create database b8_test;' -U postgres script: - - vendor/bin/phpunit --configuration phpunit.$TYPE.xml --coverage-clover=coverage.xml + - vendor/bin/phpunit --configuration phpunit.xml --coverage-clover=coverage.xml after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/phpunit.pgsql.xml b/phpunit.pgsql.xml deleted file mode 100644 index 3eab7c62..00000000 --- a/phpunit.pgsql.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - ./tests/B8Framework - - - - ./tests/PHPCensor/Helper - - - ./tests/PHPCensor/Controller - - - ./tests/PHPCensor/Logging - - - ./tests/PHPCensor/Model - - - ./tests/PHPCensor/Plugin - - - ./tests/PHPCensor/Service - - - ./tests/PHPCensor/Command - - - ./tests/PHPCensor/ProcessControl - - - ./tests/PHPCensor/Security - - - - - ./src - - ./src/PHPCensor/Migrations - ./src/PHPCensor/Languages - - - - diff --git a/phpunit.mysql.xml b/phpunit.xml similarity index 88% rename from phpunit.mysql.xml rename to phpunit.xml index 74bdde60..a77aa947 100644 --- a/phpunit.mysql.xml +++ b/phpunit.xml @@ -12,10 +12,12 @@ bootstrap="./tests/bootstrap.php" > - - - - + + + + + + diff --git a/src/B8Framework/Database.php b/src/B8Framework/Database.php index 15cda019..eef6c2b9 100644 --- a/src/B8Framework/Database.php +++ b/src/B8Framework/Database.php @@ -103,7 +103,7 @@ class Database extends \PDO } // No connection? Oh dear. - if (!$connection && $type == 'read') { + if (!$connection && $type === 'read') { throw new \Exception('Could not connect to any ' . $type . ' servers.'); } diff --git a/tests/B8Framework/DatabaseTest.php b/tests/B8Framework/DatabaseMysqlTest.php similarity index 80% rename from tests/B8Framework/DatabaseTest.php rename to tests/B8Framework/DatabaseMysqlTest.php index 7a353e8d..be649d9f 100755 --- a/tests/B8Framework/DatabaseTest.php +++ b/tests/B8Framework/DatabaseMysqlTest.php @@ -4,8 +4,9 @@ namespace Tests\b8; use b8\Config; use b8\Database; +use PHPUnit\Framework\TestCase; -class DatabaseTest extends \PHPUnit\Framework\TestCase +class DatabaseMysqlTest extends TestCase { protected function setUp() { @@ -20,13 +21,14 @@ class DatabaseTest extends \PHPUnit\Framework\TestCase ['host' => 'localhost'], ], ], - 'type' => DB_TYPE, - 'name' => DB_NAME, - 'username' => DB_USER, - 'password' => DB_PASS, + 'type' => 'mysql', + 'name' => MYSQL_DBNAME, + 'username' => MYSQL_USER, + 'password' => MYSQL_PASSWORD, ], ], ]); + Database::reset(); } protected function checkDatabaseConnection() @@ -56,9 +58,9 @@ class DatabaseTest extends \PHPUnit\Framework\TestCase $details = Database::getConnection('read')->getDetails(); self::assertTrue(is_array($details)); - self::assertTrue(($details['db'] == DB_NAME)); - self::assertTrue(($details['user'] == DB_USER)); - self::assertTrue(($details['pass'] == DB_PASS)); + self::assertTrue(($details['db'] === MYSQL_DBNAME)); + self::assertTrue(($details['user'] === MYSQL_USER)); + self::assertTrue(($details['pass'] === MYSQL_PASSWORD)); } /** @@ -81,7 +83,7 @@ class DatabaseTest extends \PHPUnit\Framework\TestCase ['host' => 'localhost'], ], ], - 'type' => DB_TYPE, + 'type' => 'mysql', 'name' => 'b8_test_2', 'username' => '', 'password' => '', diff --git a/tests/B8Framework/DatabasePostgresqlTest.php b/tests/B8Framework/DatabasePostgresqlTest.php new file mode 100755 index 00000000..5e7c1fde --- /dev/null +++ b/tests/B8Framework/DatabasePostgresqlTest.php @@ -0,0 +1,96 @@ + [ + 'database' => [ + 'servers' => [ + 'read' => [ + ['host' => 'localhost'], + ], + 'write' => [ + ['host' => 'localhost'], + ], + ], + 'type' => 'pgsql', + 'name' => POSTGRESQL_DBNAME, + 'username' => POSTGRESQL_USER, + 'password' => POSTGRESQL_PASSWORD, + ], + ], + ]); + Database::reset(); + } + + protected function checkDatabaseConnection() + { + try { + $connection = Database::getConnection('read'); + } catch (\Exception $e) { + if ('Could not connect to any read servers.' === $e->getMessage()) { + $this->markTestSkipped('Test skipped because test database doesn`t exist.'); + } else { + throw $e; + } + } + } + + public function testGetWriteConnection() + { + $this->checkDatabaseConnection(); + + $connection = Database::getConnection('write'); + self::assertInstanceOf('\b8\Database', $connection); + } + + public function testGetDetails() + { + $this->checkDatabaseConnection(); + + $details = Database::getConnection('read')->getDetails(); + self::assertTrue(is_array($details)); + self::assertTrue(($details['db'] === POSTGRESQL_DBNAME)); + self::assertTrue(($details['user'] === POSTGRESQL_USER)); + self::assertTrue(($details['pass'] === POSTGRESQL_PASSWORD)); + } + + /** + * @expectedException \Exception + */ + public function testConnectionFailure() + { + $this->checkDatabaseConnection(); + + Database::reset(); + + $config = new Config([ + 'b8' => [ + 'database' => [ + 'servers' => [ + 'read' => [ + ['host' => 'localhost'], + ], + 'write' => [ + ['host' => 'localhost'], + ], + ], + 'type' => 'pgsql', + 'name' => 'b8_test_2', + 'username' => '', + 'password' => '', + ], + ], + ]); + + Database::getConnection('read'); + } +} diff --git a/tests/PHPCensor/Plugin/Util/PhpUnitResultTest.php b/tests/PHPCensor/Plugin/Util/PhpUnitResultTest.php index 58d119b8..9eeaa50a 100644 --- a/tests/PHPCensor/Plugin/Util/PhpUnitResultTest.php +++ b/tests/PHPCensor/Plugin/Util/PhpUnitResultTest.php @@ -83,7 +83,7 @@ class PhpUnitResultTest extends \PHPUnit\Framework\TestCase public static function getTestData() { return [ - 'json' => [PhpUnitResultJson::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt'], + 'json' => [PhpUnitResultJson::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money.txt'], 'junit' => [PhpUnitResultJunit::class, 'tests/PHPCensor/Plugin/SampleFiles/phpunit_money_junit.xml'], ]; } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f308bdc6..85a5c392 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -45,7 +45,10 @@ if (!defined('APP_URL') && !empty($config)) { \PHPCensor\Helper\Lang::init($config, 'en'); -define('DB_NAME', getenv('DB_NAME')); -define('DB_USER', getenv('DB_USER')); -define('DB_TYPE', getenv('DB_TYPE')); -define('DB_PASS', getenv('DB_PASS')); +define('MYSQL_DBNAME', getenv('MYSQL_DBNAME')); +define('MYSQL_USER', getenv('MYSQL_USER')); +define('MYSQL_PASSWORD', getenv('MYSQL_PASSWORD')); + +define('POSTGRESQL_DBNAME', getenv('POSTGRESQL_DBNAME')); +define('POSTGRESQL_USER', getenv('POSTGRESQL_USER')); +define('POSTGRESQL_PASSWORD', getenv('POSTGRESQL_PASSWORD')); From 4cb041e8fb4b9b80109fc5b45c3a7f4484ff1747 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 20:53:21 +0700 Subject: [PATCH 6/9] PHPUnit tests improvements. --- bootstrap.php | 14 ++-- phpunit.xml | 12 ++-- src/B8Framework/Database.php | 52 +++++++++------ tests/B8Framework/DatabaseMysqlTest.php | 69 ++++++++++++++++---- tests/B8Framework/DatabasePostgresqlTest.php | 69 ++++++++++++++++---- tests/bootstrap.php | 32 +++------ 6 files changed, 171 insertions(+), 77 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index a74f2dfd..628eb8de 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,27 +1,27 @@ - - - - - - + + + + + + diff --git a/src/B8Framework/Database.php b/src/B8Framework/Database.php index eef6c2b9..600dd093 100644 --- a/src/B8Framework/Database.php +++ b/src/B8Framework/Database.php @@ -4,11 +4,13 @@ namespace b8; class Database extends \PDO { + const MYSQL_TYPE = 'mysql'; + const POSTGRESQL_TYPE = 'pgsql'; + protected static $initialised = false; protected static $servers = ['read' => [], 'write' => []]; protected static $connections = ['read' => null, 'write' => null]; protected static $details = []; - protected static $lastUsed = ['read' => null, 'write' => null]; /** * @param string $table @@ -17,7 +19,7 @@ class Database extends \PDO */ public function lastInsertIdExtended($table = null) { - if ($table && $this->getAttribute(self::ATTR_DRIVER_NAME) == 'pgsql') { + if ($table && self::POSTGRESQL_TYPE === $this->getAttribute(self::ATTR_DRIVER_NAME)) { return parent::lastInsertId($table . '_id_seq'); } @@ -31,10 +33,11 @@ class Database extends \PDO self::$servers['read'] = $settings['servers']['read']; self::$servers['write'] = $settings['servers']['write']; - self::$details['type'] = $settings['type']; - self::$details['db'] = $settings['name']; - self::$details['user'] = $settings['username']; - self::$details['pass'] = $settings['password']; + + self::$details['type'] = $settings['type']; + self::$details['db'] = $settings['name']; + self::$details['user'] = $settings['username']; + self::$details['pass'] = $settings['password']; self::$initialised = true; } @@ -52,11 +55,6 @@ class Database extends \PDO self::init(); } - // If the connection hasn't been used for 5 minutes, force a reconnection: - if (!is_null(self::$lastUsed[$type]) && (time() - self::$lastUsed[$type]) > 300) { - self::$connections[$type] = null; - } - if (is_null(self::$connections[$type])) { // Shuffle, so we pick a random server: $servers = self::$servers[$type]; @@ -80,7 +78,7 @@ class Database extends \PDO \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_TIMEOUT => 2, ]; - if ('mysql' === self::$details['type']) { + if (self::MYSQL_TYPE === self::$details['type']) { $pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'"; } @@ -110,11 +108,12 @@ class Database extends \PDO self::$connections[$type] = $connection; } - self::$lastUsed[$type] = time(); - return self::$connections[$type]; } + /** + * @return array + */ public function getDetails() { return self::$details; @@ -123,21 +122,34 @@ class Database extends \PDO public static function reset() { self::$connections = ['read' => null, 'write' => null]; - self::$lastUsed = ['read' => null, 'write' => null]; self::$initialised = false; } - public function prepareCommon($statement, array $driver_options = []) + /** + * @param string $statement + * + * @return string + */ + protected function quoteNames($statement) { $quote = ''; - if ('mysql' === self::$details['type']) { + if (self::MYSQL_TYPE === self::$details['type']) { $quote = '`'; - } elseif ('pgsql' === self::$details['type']) { + } elseif (self::POSTGRESQL_TYPE === self::$details['type']) { $quote = '"'; } - $statement = preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement); + return preg_replace('/{{(.*?)}}/', ($quote . '\1' . $quote), $statement); + } - return parent::prepare($statement, $driver_options); + /** + * @param string $statement + * @param array $driver_options + * + * @return \PDOStatement + */ + public function prepareCommon($statement, array $driver_options = []) + { + return parent::prepare($this->quoteNames($statement), $driver_options); } } diff --git a/tests/B8Framework/DatabaseMysqlTest.php b/tests/B8Framework/DatabaseMysqlTest.php index be649d9f..9802abab 100755 --- a/tests/B8Framework/DatabaseMysqlTest.php +++ b/tests/B8Framework/DatabaseMysqlTest.php @@ -21,7 +21,7 @@ class DatabaseMysqlTest extends TestCase ['host' => 'localhost'], ], ], - 'type' => 'mysql', + 'type' => Database::MYSQL_TYPE, 'name' => MYSQL_DBNAME, 'username' => MYSQL_USER, 'password' => MYSQL_PASSWORD, @@ -33,6 +33,10 @@ class DatabaseMysqlTest extends TestCase protected function checkDatabaseConnection() { + if (!extension_loaded('mysqli')) { + $this->markTestSkipped('Test skipped because Mysqli extension doesn`t exist.'); + } + try { $connection = Database::getConnection('read'); } catch (\Exception $e) { @@ -44,23 +48,66 @@ class DatabaseMysqlTest extends TestCase } } - public function testGetWriteConnection() + public function testGetConnection() { $this->checkDatabaseConnection(); - $connection = Database::getConnection('write'); - self::assertInstanceOf('\b8\Database', $connection); + $writeConnection = Database::getConnection('write'); + $readConnection = Database::getConnection('read'); + + self::assertInstanceOf('\b8\Database', $writeConnection); + self::assertInstanceOf('\b8\Database', $readConnection); + + $writeDetails = Database::getConnection('write')->getDetails(); + + self::assertTrue(is_array($writeDetails)); + self::assertEquals(MYSQL_DBNAME, $writeDetails['db']); + self::assertEquals(MYSQL_USER, $writeDetails['user']); + self::assertEquals(MYSQL_PASSWORD, $writeDetails['pass']); + + $readDetails = Database::getConnection('read')->getDetails(); + + self::assertTrue(is_array($readDetails)); + self::assertEquals(MYSQL_DBNAME, $readDetails['db']); + self::assertEquals(MYSQL_USER, $readDetails['user']); + self::assertEquals(MYSQL_PASSWORD, $readDetails['pass']); } - public function testGetDetails() + public function testGetWriteConnectionWithPort() { + $config = new Config([ + 'b8' => [ + 'database' => [ + 'servers' => [ + 'read' => [ + [ + 'host' => 'localhost', + 'port' => 3306, + ], + ], + 'write' => [ + [ + 'host' => 'localhost', + 'port' => 3306, + ], + ], + ], + 'type' => Database::MYSQL_TYPE, + 'name' => MYSQL_DBNAME, + 'username' => MYSQL_USER, + 'password' => MYSQL_PASSWORD, + ], + ], + ]); + Database::reset(); + $this->checkDatabaseConnection(); - $details = Database::getConnection('read')->getDetails(); - self::assertTrue(is_array($details)); - self::assertTrue(($details['db'] === MYSQL_DBNAME)); - self::assertTrue(($details['user'] === MYSQL_USER)); - self::assertTrue(($details['pass'] === MYSQL_PASSWORD)); + $writeConnection = Database::getConnection('write'); + $readConnection = Database::getConnection('read'); + + self::assertInstanceOf('\b8\Database', $writeConnection); + self::assertInstanceOf('\b8\Database', $readConnection); } /** @@ -83,7 +130,7 @@ class DatabaseMysqlTest extends TestCase ['host' => 'localhost'], ], ], - 'type' => 'mysql', + 'type' => Database::MYSQL_TYPE, 'name' => 'b8_test_2', 'username' => '', 'password' => '', diff --git a/tests/B8Framework/DatabasePostgresqlTest.php b/tests/B8Framework/DatabasePostgresqlTest.php index 5e7c1fde..b5c88166 100755 --- a/tests/B8Framework/DatabasePostgresqlTest.php +++ b/tests/B8Framework/DatabasePostgresqlTest.php @@ -21,7 +21,7 @@ class DatabasePostgresqlTest extends TestCase ['host' => 'localhost'], ], ], - 'type' => 'pgsql', + 'type' => Database::POSTGRESQL_TYPE, 'name' => POSTGRESQL_DBNAME, 'username' => POSTGRESQL_USER, 'password' => POSTGRESQL_PASSWORD, @@ -33,6 +33,10 @@ class DatabasePostgresqlTest extends TestCase protected function checkDatabaseConnection() { + if (!extension_loaded('pgsql')) { + $this->markTestSkipped('Test skipped because Pgsql extension doesn`t exist.'); + } + try { $connection = Database::getConnection('read'); } catch (\Exception $e) { @@ -44,23 +48,66 @@ class DatabasePostgresqlTest extends TestCase } } - public function testGetWriteConnection() + public function testGetConnection() { $this->checkDatabaseConnection(); - $connection = Database::getConnection('write'); - self::assertInstanceOf('\b8\Database', $connection); + $writeConnection = Database::getConnection('write'); + $readConnection = Database::getConnection('read'); + + self::assertInstanceOf('\b8\Database', $writeConnection); + self::assertInstanceOf('\b8\Database', $readConnection); + + $writeDetails = Database::getConnection('write')->getDetails(); + + self::assertTrue(is_array($writeDetails)); + self::assertEquals(POSTGRESQL_DBNAME, $writeDetails['db']); + self::assertEquals(POSTGRESQL_USER, $writeDetails['user']); + self::assertEquals(POSTGRESQL_PASSWORD, $writeDetails['pass']); + + $readDetails = Database::getConnection('read')->getDetails(); + + self::assertTrue(is_array($readDetails)); + self::assertEquals(POSTGRESQL_DBNAME, $readDetails['db']); + self::assertEquals(POSTGRESQL_USER, $readDetails['user']); + self::assertEquals(POSTGRESQL_PASSWORD, $readDetails['pass']); } - public function testGetDetails() + public function testGetWriteConnectionWithPort() { + $config = new Config([ + 'b8' => [ + 'database' => [ + 'servers' => [ + 'read' => [ + [ + 'host' => 'localhost', + 'port' => 5432, + ], + ], + 'write' => [ + [ + 'host' => 'localhost', + 'port' => 5432, + ], + ], + ], + 'type' => Database::POSTGRESQL_TYPE, + 'name' => POSTGRESQL_DBNAME, + 'username' => POSTGRESQL_USER, + 'password' => POSTGRESQL_PASSWORD, + ], + ], + ]); + Database::reset(); + $this->checkDatabaseConnection(); - $details = Database::getConnection('read')->getDetails(); - self::assertTrue(is_array($details)); - self::assertTrue(($details['db'] === POSTGRESQL_DBNAME)); - self::assertTrue(($details['user'] === POSTGRESQL_USER)); - self::assertTrue(($details['pass'] === POSTGRESQL_PASSWORD)); + $writeConnection = Database::getConnection('write'); + $readConnection = Database::getConnection('read'); + + self::assertInstanceOf('\b8\Database', $writeConnection); + self::assertInstanceOf('\b8\Database', $readConnection); } /** @@ -83,7 +130,7 @@ class DatabasePostgresqlTest extends TestCase ['host' => 'localhost'], ], ], - 'type' => 'pgsql', + 'type' => Database::POSTGRESQL_TYPE, 'name' => 'b8_test_2', 'username' => '', 'password' => '', diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 85a5c392..113bf8bf 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,54 +1,42 @@ loadYaml($configFile); -} - if (!defined('APP_URL') && !empty($config)) { define('APP_URL', $config->get('php-censor.url', '') . '/'); } -\PHPCensor\Helper\Lang::init($config, 'en'); - -define('MYSQL_DBNAME', getenv('MYSQL_DBNAME')); -define('MYSQL_USER', getenv('MYSQL_USER')); -define('MYSQL_PASSWORD', getenv('MYSQL_PASSWORD')); - -define('POSTGRESQL_DBNAME', getenv('POSTGRESQL_DBNAME')); -define('POSTGRESQL_USER', getenv('POSTGRESQL_USER')); -define('POSTGRESQL_PASSWORD', getenv('POSTGRESQL_PASSWORD')); +\PHPCensor\Helper\Lang::init($config); From c9087df799dde851d26ed35fa70f2c225d64a138 Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 23:01:40 +0700 Subject: [PATCH 7/9] Added PHPUnit DBUnit extension. --- composer.json | 239 +++++++++++++++++++++++++++----------------------- composer.lock | 60 ++++++++++++- 2 files changed, 185 insertions(+), 114 deletions(-) diff --git a/composer.json b/composer.json index ab540543..75966be4 100644 --- a/composer.json +++ b/composer.json @@ -1,115 +1,130 @@ { - "name": "php-censor/php-censor", - "description": "PHP Censor is a open source self-hosted continuous integration server for PHP projects (PHPCI fork).", - "minimum-stability": "stable", - "type": "application", - "keywords": ["php", "php-censor", "phpci", "ci-server", "testing", "self-hosted", "open-source", "ci", "continuous integration"], - "homepage": "http://php-censor.info", - "license": "BSD-2-Clause", - "authors": [ - { - "name": "Dmitry Khomutov", - "email": "poisoncorpsee@gmail.com", - "homepage": "http://corpsee.com", - "role": "PHP Censor developer" - }, - { - "name": "Dan Cryer", - "email": "dan.cryer@block8.co.uk", - "homepage": "http://www.block8.co.uk", - "role": "PHPCI developer" - } - ], - "support": { - "issues": "https://github.com/php-censor/php-censor/issues", - "source": "https://github.com/php-censor/php-censor" - }, - "autoload": { - "psr-4": { - "PHPCensor\\": "src/PHPCensor/", - "b8\\": "src/B8Framework/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\PHPCensor\\": "tests/PHPCensor/", - "Tests\\b8\\": "tests/B8Framework/" - } - }, - "require": { - "php": ">=5.6.0", - "ext-openssl": "*", - "ext-pdo": "*", - "ext-json": "*", - "ext-xml": "*", - "ext-curl": "*", - - "swiftmailer/swiftmailer": "~5.4.0", - "symfony/yaml": "~3.4.0", - "symfony/console": "~3.4.0", - "symfony/finder": "~3.4.0", - "symfony/dom-crawler": "~3.4.0", - "symfony/css-selector": "~3.4.0", - "symfony/browser-kit": "~3.4.0", - "symfony/process": "~3.4.0", - "symfony/filesystem": "~3.4.0", - "symfony/debug": "~3.4.0", - "symfony/dependency-injection": "~3.4.0", - "symfony/event-dispatcher": "~3.4.0", - "symfony/cache": "~3.4.0", - "psr/log": "~1.0.0", - "monolog/monolog": "~1.22.0", - "pimple/pimple": "~3.0.0", - "robmorgan/phinx": "~0.8.0", - "sensiolabs/ansi-to-html": "~1.1.0", - "pda/pheanstalk": "~3.1.0", - "guzzlehttp/guzzle": "~6.2.0", - "jasongrimes/paginator": "~1.0.0", - - "phpunit/phpunit": "~5.7.0", - "codeception/codeception": "~2.3.0", - "phpmd/phpmd": "~2.6.0", - "sebastian/phpcpd": "~2.0.0", - "squizlabs/php_codesniffer": "~2.8.0", - "block8/php-docblock-checker": "~1.3.0", - "phploc/phploc": "~4.0.0", - "jakub-onderka/php-parallel-lint": "~0.9.0", - "sensiolabs/security-checker": "~4.0.0", - - "doctrine/instantiator": "~1.0.0", - "phpunit/php-token-stream": "~1.4.0", - "phpdocumentor/reflection-docblock": "~2.0.0", - - "oomphinc/composer-installers-extender": "~1.1.0", - - "npm-asset/sprintf-js": "~1.0.0", - "npm-asset/codemirror": "~5.23.0", - "bower-asset/admin-lte": "~2.3.0", - "bower-asset/font-awesome": "~4.7.0", - "bower-asset/ionicons": "~2.0.0", - "bower-asset/raphael": "~2.2.0" - }, - "suggest": { - "maknz/slack": "For SlackNotify plugin", - "hipchat/hipchat-php": "For HipchatNotify plugin", - "mremi/flowdock": "For FlowdockNotify plugin" - }, - "extra": { - "platform": { - "php": "5.6.*" - }, - "installer-types": [ - "bower-asset", - "npm-asset" + "name": "php-censor/php-censor", + "description": "PHP Censor is a open source self-hosted continuous integration server for PHP projects (PHPCI fork).", + "minimum-stability": "stable", + "type": "application", + "keywords": [ + "php", + "php-censor", + "phpci", + "ci-server", + "testing", + "self-hosted", + "open-source", + "ci", + "continuous integration" ], - "installer-paths": { - "public/assets/vendor/{$name}/": ["type:bower-asset", "type:npm-asset"] - } - }, - "repositories": [ - { - "type": "composer", - "url": "https://asset-packagist.org" - } - ] + "homepage": "http://php-censor.info", + "license": "BSD-2-Clause", + "authors": [ + { + "name": "Dmitry Khomutov", + "email": "poisoncorpsee@gmail.com", + "homepage": "http://corpsee.com", + "role": "PHP Censor developer" + }, + { + "name": "Dan Cryer", + "email": "dan.cryer@block8.co.uk", + "homepage": "http://www.block8.co.uk", + "role": "PHPCI developer" + } + ], + "support": { + "issues": "https://github.com/php-censor/php-censor/issues", + "source": "https://github.com/php-censor/php-censor" + }, + "autoload": { + "psr-4": { + "PHPCensor\\": "src/PHPCensor/", + "b8\\": "src/B8Framework/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\PHPCensor\\": "tests/PHPCensor/", + "Tests\\b8\\": "tests/B8Framework/" + } + }, + "require": { + "php": ">=5.6.0", + "ext-openssl": "*", + "ext-pdo": "*", + "ext-json": "*", + "ext-xml": "*", + "ext-curl": "*", + + "swiftmailer/swiftmailer": "~5.4.0", + "symfony/yaml": "~3.4.0", + "symfony/console": "~3.4.0", + "symfony/finder": "~3.4.0", + "symfony/dom-crawler": "~3.4.0", + "symfony/css-selector": "~3.4.0", + "symfony/browser-kit": "~3.4.0", + "symfony/process": "~3.4.0", + "symfony/filesystem": "~3.4.0", + "symfony/debug": "~3.4.0", + "symfony/dependency-injection": "~3.4.0", + "symfony/event-dispatcher": "~3.4.0", + "symfony/cache": "~3.4.0", + "psr/log": "~1.0.0", + "monolog/monolog": "~1.22.0", + "pimple/pimple": "~3.0.0", + "robmorgan/phinx": "~0.8.0", + "sensiolabs/ansi-to-html": "~1.1.0", + "pda/pheanstalk": "~3.1.0", + "guzzlehttp/guzzle": "~6.2.0", + "jasongrimes/paginator": "~1.0.0", + "phpunit/phpunit": "~5.7.0", + "codeception/codeception": "~2.3.0", + "phpmd/phpmd": "~2.6.0", + "sebastian/phpcpd": "~2.0.0", + "squizlabs/php_codesniffer": "~2.8.0", + "block8/php-docblock-checker": "~1.3.0", + "phploc/phploc": "~4.0.0", + "jakub-onderka/php-parallel-lint": "~0.9.0", + "sensiolabs/security-checker": "~4.0.0", + + "doctrine/instantiator": "~1.0.0", + "phpunit/php-token-stream": "~1.4.0", + "phpdocumentor/reflection-docblock": "~2.0.0", + + "oomphinc/composer-installers-extender": "~1.1.0", + + "npm-asset/sprintf-js": "~1.0.0", + "npm-asset/codemirror": "~5.23.0", + "bower-asset/admin-lte": "~2.3.0", + "bower-asset/font-awesome": "~4.7.0", + "bower-asset/ionicons": "~2.0.0", + "bower-asset/raphael": "~2.2.0" + }, + "require-dev": { + "phpunit/dbunit": "~2.0.0" + }, + "suggest": { + "maknz/slack": "For SlackNotify plugin", + "hipchat/hipchat-php": "For HipchatNotify plugin", + "mremi/flowdock": "For FlowdockNotify plugin" + }, + "extra": { + "platform": { + "php": "5.6.*" + }, + "installer-types": [ + "bower-asset", + "npm-asset" + ], + "installer-paths": { + "public/assets/vendor/{$name}/": [ + "type:bower-asset", + "type:npm-asset" + ] + } + }, + "repositories": [ + { + "type": "composer", + "url": "https://asset-packagist.org" + } + ] } diff --git a/composer.lock b/composer.lock index 87368801..6999424c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "e04dd5f7a7f3a869724c591daf5d8f2e", + "content-hash": "86960b0e8aee816f39921ca1c3e6bfc3", "packages": [ { "name": "behat/gherkin", @@ -3945,7 +3945,63 @@ "time": "2017-06-30T11:53:12+00:00" } ], - "packages-dev": [], + "packages-dev": [ + { + "name": "phpunit/dbunit", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/dbunit.git", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/dbunit/zipball/5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "reference": "5c35d74549c21ba55d0ea74ba89d191a51f8cf25", + "shasum": "" + }, + "require": { + "ext-pdo": "*", + "ext-simplexml": "*", + "php": "^5.4 || ^7.0", + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0", + "symfony/yaml": "^2.1 || ^3.0" + }, + "bin": [ + "dbunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "DbUnit port for PHP/PHPUnit to support database interaction testing.", + "homepage": "https://github.com/sebastianbergmann/dbunit/", + "keywords": [ + "database", + "testing", + "xunit" + ], + "time": "2016-12-02T14:39:14+00:00" + } + ], "aliases": [], "minimum-stability": "stable", "stability-flags": [], From 5a76868e0bf2789c0e3e2b465d84a0a6678beb0d Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Wed, 28 Feb 2018 23:34:07 +0700 Subject: [PATCH 8/9] Added tests for DB connections DSN. --- src/B8Framework/Database.php | 82 ++++++++++++++++---- tests/B8Framework/DatabaseMysqlTest.php | 8 +- tests/B8Framework/DatabasePostgresqlTest.php | 8 +- 3 files changed, 77 insertions(+), 21 deletions(-) diff --git a/src/B8Framework/Database.php b/src/B8Framework/Database.php index 600dd093..b8a50d8a 100644 --- a/src/B8Framework/Database.php +++ b/src/B8Framework/Database.php @@ -7,10 +7,41 @@ class Database extends \PDO const MYSQL_TYPE = 'mysql'; const POSTGRESQL_TYPE = 'pgsql'; + /** + * @var string + */ + protected $type = 'read'; + + /** + * @var boolean + */ protected static $initialised = false; - protected static $servers = ['read' => [], 'write' => []]; - protected static $connections = ['read' => null, 'write' => null]; - protected static $details = []; + + /** + * @var array + */ + protected static $servers = [ + 'read' => [], + 'write' => [] + ]; + + /** + * @var array + */ + protected static $connections = [ + 'read' => null, + 'write' => null + ]; + + /** + * @var array + */ + protected static $dsn = [ + 'read' => '', + 'write' => '' + ]; + + protected static $details = []; /** * @param string $table @@ -34,10 +65,10 @@ class Database extends \PDO self::$servers['read'] = $settings['servers']['read']; self::$servers['write'] = $settings['servers']['write']; - self::$details['type'] = $settings['type']; - self::$details['db'] = $settings['name']; - self::$details['user'] = $settings['username']; - self::$details['pass'] = $settings['password']; + self::$details['driver'] = $settings['type']; + self::$details['db'] = $settings['name']; + self::$details['user'] = $settings['username']; + self::$details['pass'] = $settings['password']; self::$initialised = true; } @@ -67,29 +98,30 @@ class Database extends \PDO // Pull the next server: $server = array_shift($servers); - $dns = self::$details['type'] . ':host=' . $server['host']; + self::$dsn[$type] = self::$details['driver'] . ':host=' . $server['host']; if (isset($server['port'])) { - $dns .= ';port=' . (integer)$server['port']; + self::$dsn[$type] .= ';port=' . (integer)$server['port']; } - $dns .= ';dbname=' . self::$details['db']; + self::$dsn[$type] .= ';dbname=' . self::$details['db']; $pdoOptions = [ - \PDO::ATTR_PERSISTENT => false, - \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, - \PDO::ATTR_TIMEOUT => 2, + \PDO::ATTR_PERSISTENT => false, + \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, + \PDO::ATTR_TIMEOUT => 2, ]; - if (self::MYSQL_TYPE === self::$details['type']) { + if (self::MYSQL_TYPE === self::$details['driver']) { $pdoOptions[\PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES 'UTF8'"; } // Try to connect: try { $connection = new self( - $dns, + self::$dsn[$type], self::$details['user'], self::$details['pass'], $pdoOptions ); + $connection->setType($type); } catch (\PDOException $ex) { $connection = false; } @@ -119,6 +151,22 @@ class Database extends \PDO return self::$details; } + /** + * @return string + */ + public function getDsn() + { + return self::$dsn[$this->type]; + } + + /** + * @param string $type + */ + public function setType($type) + { + $this->type = $type; + } + public static function reset() { self::$connections = ['read' => null, 'write' => null]; @@ -133,9 +181,9 @@ class Database extends \PDO protected function quoteNames($statement) { $quote = ''; - if (self::MYSQL_TYPE === self::$details['type']) { + if (self::MYSQL_TYPE === self::$details['driver']) { $quote = '`'; - } elseif (self::POSTGRESQL_TYPE === self::$details['type']) { + } elseif (self::POSTGRESQL_TYPE === self::$details['driver']) { $quote = '"'; } diff --git a/tests/B8Framework/DatabaseMysqlTest.php b/tests/B8Framework/DatabaseMysqlTest.php index 9802abab..1a6edc18 100755 --- a/tests/B8Framework/DatabaseMysqlTest.php +++ b/tests/B8Framework/DatabaseMysqlTest.php @@ -58,19 +58,21 @@ class DatabaseMysqlTest extends TestCase self::assertInstanceOf('\b8\Database', $writeConnection); self::assertInstanceOf('\b8\Database', $readConnection); - $writeDetails = Database::getConnection('write')->getDetails(); + $writeDetails = $writeConnection->getDetails(); self::assertTrue(is_array($writeDetails)); self::assertEquals(MYSQL_DBNAME, $writeDetails['db']); self::assertEquals(MYSQL_USER, $writeDetails['user']); self::assertEquals(MYSQL_PASSWORD, $writeDetails['pass']); - $readDetails = Database::getConnection('read')->getDetails(); + $readDetails = $readConnection->getDetails(); self::assertTrue(is_array($readDetails)); self::assertEquals(MYSQL_DBNAME, $readDetails['db']); self::assertEquals(MYSQL_USER, $readDetails['user']); self::assertEquals(MYSQL_PASSWORD, $readDetails['pass']); + + self::assertEquals('mysql:host=localhost;dbname=b8_test', $readConnection->getDsn()); } public function testGetWriteConnectionWithPort() @@ -108,6 +110,8 @@ class DatabaseMysqlTest extends TestCase self::assertInstanceOf('\b8\Database', $writeConnection); self::assertInstanceOf('\b8\Database', $readConnection); + + self::assertEquals('mysql:host=localhost;port=3306;dbname=b8_test', $readConnection->getDsn()); } /** diff --git a/tests/B8Framework/DatabasePostgresqlTest.php b/tests/B8Framework/DatabasePostgresqlTest.php index b5c88166..9bf3af66 100755 --- a/tests/B8Framework/DatabasePostgresqlTest.php +++ b/tests/B8Framework/DatabasePostgresqlTest.php @@ -58,19 +58,21 @@ class DatabasePostgresqlTest extends TestCase self::assertInstanceOf('\b8\Database', $writeConnection); self::assertInstanceOf('\b8\Database', $readConnection); - $writeDetails = Database::getConnection('write')->getDetails(); + $writeDetails = $writeConnection->getDetails(); self::assertTrue(is_array($writeDetails)); self::assertEquals(POSTGRESQL_DBNAME, $writeDetails['db']); self::assertEquals(POSTGRESQL_USER, $writeDetails['user']); self::assertEquals(POSTGRESQL_PASSWORD, $writeDetails['pass']); - $readDetails = Database::getConnection('read')->getDetails(); + $readDetails = $readConnection->getDetails(); self::assertTrue(is_array($readDetails)); self::assertEquals(POSTGRESQL_DBNAME, $readDetails['db']); self::assertEquals(POSTGRESQL_USER, $readDetails['user']); self::assertEquals(POSTGRESQL_PASSWORD, $readDetails['pass']); + + self::assertEquals('pgsql:host=localhost;dbname=b8_test', $readConnection->getDsn()); } public function testGetWriteConnectionWithPort() @@ -108,6 +110,8 @@ class DatabasePostgresqlTest extends TestCase self::assertInstanceOf('\b8\Database', $writeConnection); self::assertInstanceOf('\b8\Database', $readConnection); + + self::assertEquals('pgsql:host=localhost;port=5432;dbname=b8_test', $readConnection->getDsn()); } /** From 409ac11c4742f025eaa68b96252f1f322c1a12db Mon Sep 17 00:00:00 2001 From: Dmitry Khomutov Date: Thu, 1 Mar 2018 15:11:26 +0700 Subject: [PATCH 9/9] Added more tests for Database (for PostgreSQL and MySQL). --- tests/B8Framework/DatabaseMysqlTest.php | 144 ++++++++++++++---- tests/B8Framework/DatabasePostgresqlTest.php | 148 +++++++++++++++---- 2 files changed, 232 insertions(+), 60 deletions(-) diff --git a/tests/B8Framework/DatabaseMysqlTest.php b/tests/B8Framework/DatabaseMysqlTest.php index 1a6edc18..139f4d81 100755 --- a/tests/B8Framework/DatabaseMysqlTest.php +++ b/tests/B8Framework/DatabaseMysqlTest.php @@ -4,13 +4,94 @@ namespace Tests\b8; use b8\Config; use b8\Database; -use PHPUnit\Framework\TestCase; -class DatabaseMysqlTest extends TestCase +class DatabaseMysqlTest extends \PHPUnit_Extensions_Database_TestCase { + /** + * @var \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection|null + */ + protected $connection = null; + + /** + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + + if (extension_loaded('mysqli')) { + if (null === $this->connection) { + try { + $pdo = new \PDO( + 'mysql:host=localhost;dbname=' . MYSQL_DBNAME, + MYSQL_USER, + MYSQL_PASSWORD + ); + + $this->connection = $this->createDefaultDBConnection($pdo, MYSQL_DBNAME); + + $this->connection->getConnection()->query(' + CREATE TABLE IF NOT EXISTS `database_mysql_test` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `projectId` int(11) NOT NULL, + `branch` varchar(250) NOT NULL DEFAULT \'master\', + `createDate` datetime, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + '); + } catch (\PDOException $ex) { + $this->connection = null; + } + } + } else { + $this->connection = null; + } + } + + /** + * @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected function getConnection() + { + if (null === $this->connection) { + $this->markTestSkipped('Test skipped because MySQL database/user/extension doesn`t exist.'); + } + + return $this->connection; + } + + /** + * @return \PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected function getDataSet() + { + return $this->createArrayDataSet([ + 'database_mysql_test' => [[ + 'id' => 1, + 'projectId' => 1, + 'branch' => 'master', + 'createDate' => null, + ], [ + 'id' => 2, + 'projectId' => 2, + 'branch' => 'dev', + 'createDate' => '2018-02-20 01:01:01', + ], [ + 'id' => 3, + 'projectId' => 2, + 'branch' => 'master', + 'createDate' => '2018-02-21 02:02:02', + ]], + ]); + } + protected function setUp() { - $config = new Config([ + parent::setUp(); + + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -31,27 +112,8 @@ class DatabaseMysqlTest extends TestCase Database::reset(); } - protected function checkDatabaseConnection() - { - if (!extension_loaded('mysqli')) { - $this->markTestSkipped('Test skipped because Mysqli extension doesn`t exist.'); - } - - try { - $connection = Database::getConnection('read'); - } catch (\Exception $e) { - if ('Could not connect to any read servers.' === $e->getMessage()) { - $this->markTestSkipped('Test skipped because test database doesn`t exist.'); - } else { - throw $e; - } - } - } - public function testGetConnection() { - $this->checkDatabaseConnection(); - $writeConnection = Database::getConnection('write'); $readConnection = Database::getConnection('read'); @@ -77,7 +139,7 @@ class DatabaseMysqlTest extends TestCase public function testGetWriteConnectionWithPort() { - $config = new Config([ + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -103,8 +165,6 @@ class DatabaseMysqlTest extends TestCase ]); Database::reset(); - $this->checkDatabaseConnection(); - $writeConnection = Database::getConnection('write'); $readConnection = Database::getConnection('read'); @@ -119,11 +179,7 @@ class DatabaseMysqlTest extends TestCase */ public function testConnectionFailure() { - $this->checkDatabaseConnection(); - - Database::reset(); - - $config = new Config([ + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -141,7 +197,35 @@ class DatabaseMysqlTest extends TestCase ], ], ]); + Database::reset(); Database::getConnection('read'); } + + public function testPrepareCommon() + { + $readConnection = Database::getConnection('read'); + + $sql = 'SELECT * FROM {{database_mysql_test}} WHERE {{projectId}} = :projectId'; + $query = $readConnection->prepareCommon($sql); + + $query->bindValue(':projectId', 2); + $query->execute(); + + $data = $query->fetchAll(\PDO::FETCH_ASSOC); + + self::assertEquals(2, count($data)); + } + + public function testLastInsertIdExtended() + { + $writeConnection = Database::getConnection('write'); + + $sql = 'INSERT INTO {{database_mysql_test}} ({{projectId}}) VALUES (3)'; + $query = $writeConnection->prepareCommon($sql); + + $query->execute(); + + self::assertEquals(4, $writeConnection->lastInsertIdExtended()); + } } diff --git a/tests/B8Framework/DatabasePostgresqlTest.php b/tests/B8Framework/DatabasePostgresqlTest.php index 9bf3af66..c571d6e4 100755 --- a/tests/B8Framework/DatabasePostgresqlTest.php +++ b/tests/B8Framework/DatabasePostgresqlTest.php @@ -4,13 +4,94 @@ namespace Tests\b8; use b8\Config; use b8\Database; -use PHPUnit\Framework\TestCase; -class DatabasePostgresqlTest extends TestCase +class DatabasePostgresqlTest extends \PHPUnit_Extensions_Database_TestCase { + /** + * @var \PHPUnit_Extensions_Database_DB_DefaultDatabaseConnection|null + */ + protected $connection = null; + + /** + * @param string $name + * @param array $data + * @param string $dataName + */ + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + + if (extension_loaded('pgsql')) { + if (null === $this->connection) { + try { + $pdo = new \PDO( + 'pgsql:host=localhost;dbname=' . POSTGRESQL_DBNAME, + POSTGRESQL_USER, + POSTGRESQL_PASSWORD + ); + + $this->connection = $this->createDefaultDBConnection($pdo, POSTGRESQL_DBNAME); + + $this->connection->getConnection()->query(' + CREATE TABLE IF NOT EXISTS "database_mysql_test" ( + "id" SERIAL, + "projectId" integer NOT NULL, + "branch" character varying(250) NOT NULL DEFAULT \'master\', + "createDate" timestamp without time zone, + PRIMARY KEY ("id") + ); + '); + } catch (\PDOException $ex) { + $this->connection = null; + } + } + } else { + $this->connection = null; + } + } + + /** + * @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection + */ + protected function getConnection() + { + if (null === $this->connection) { + $this->markTestSkipped('Test skipped because PostgreSQL database/user/extension doesn`t exist.'); + } + + return $this->connection; + } + + /** + * @return \PHPUnit_Extensions_Database_DataSet_IDataSet + */ + protected function getDataSet() + { + return $this->createArrayDataSet([ + 'database_mysql_test' => [[ + 'id' => 1, + 'projectId' => 1, + 'branch' => 'master', + 'createDate' => null, + ], [ + 'id' => 2, + 'projectId' => 2, + 'branch' => 'dev', + 'createDate' => '2018-02-20 01:01:01', + ], [ + 'id' => 3, + 'projectId' => 2, + 'branch' => 'master', + 'createDate' => '2018-02-21 02:02:02', + ]], + ]); + } + protected function setUp() { - $config = new Config([ + parent::setUp(); + + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -31,27 +112,8 @@ class DatabasePostgresqlTest extends TestCase Database::reset(); } - protected function checkDatabaseConnection() - { - if (!extension_loaded('pgsql')) { - $this->markTestSkipped('Test skipped because Pgsql extension doesn`t exist.'); - } - - try { - $connection = Database::getConnection('read'); - } catch (\Exception $e) { - if ('Could not connect to any read servers.' === $e->getMessage()) { - $this->markTestSkipped('Test skipped because test database doesn`t exist.'); - } else { - throw $e; - } - } - } - public function testGetConnection() { - $this->checkDatabaseConnection(); - $writeConnection = Database::getConnection('write'); $readConnection = Database::getConnection('read'); @@ -77,7 +139,7 @@ class DatabasePostgresqlTest extends TestCase public function testGetWriteConnectionWithPort() { - $config = new Config([ + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -103,8 +165,6 @@ class DatabasePostgresqlTest extends TestCase ]); Database::reset(); - $this->checkDatabaseConnection(); - $writeConnection = Database::getConnection('write'); $readConnection = Database::getConnection('read'); @@ -119,11 +179,7 @@ class DatabasePostgresqlTest extends TestCase */ public function testConnectionFailure() { - $this->checkDatabaseConnection(); - - Database::reset(); - - $config = new Config([ + new Config([ 'b8' => [ 'database' => [ 'servers' => [ @@ -141,7 +197,39 @@ class DatabasePostgresqlTest extends TestCase ], ], ]); + Database::reset(); Database::getConnection('read'); } + + public function testPrepareCommon() + { + $readConnection = Database::getConnection('read'); + + $sql = 'SELECT * FROM {{database_mysql_test}} WHERE {{projectId}} = :projectId'; + $query = $readConnection->prepareCommon($sql); + + $query->bindValue(':projectId', 2); + $query->execute(); + + $data = $query->fetchAll(\PDO::FETCH_ASSOC); + + self::assertEquals(2, count($data)); + } + + public function testLastInsertIdExtended() + { + $this->connection->getConnection()->query(' + ALTER SEQUENCE "database_mysql_test_id_seq" RESTART WITH 4; + '); + + $writeConnection = Database::getConnection('write'); + + $sql = 'INSERT INTO {{database_mysql_test}} ({{projectId}}) VALUES (3)'; + $query = $writeConnection->prepareCommon($sql); + + $query->execute(); + + self::assertEquals(4, $writeConnection->lastInsertIdExtended('database_mysql_test')); + } }