Improved foundational backend unit tests (#1405)

* part one of adding tests, updating core

* Apply fixes from StyleCI

[ci skip] [skip ci]

* we need xdebug for code coverage, and hhvm was already removed

* forgot about the sidecar for mysql completely 🤦

* gitignore removed this installed json we need to fake that we have extensions

* using reguarded closure
This commit is contained in:
Daniël Klabbers 2018-04-17 11:15:28 +02:00 committed by GitHub
parent 51a4c845f1
commit 77bb82bda4
17 changed files with 319 additions and 13 deletions

View File

@ -15,5 +15,5 @@ indent_size = 2
[*.{diff,md}] [*.{diff,md}]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.php] [*.{php,xml}]
indent_size = 4 indent_size = 4

View File

@ -3,6 +3,6 @@ composer.lock
composer.phar composer.phar
.DS_Store .DS_Store
Thumbs.db Thumbs.db
tests/_output/* /tests/tmp
.vagrant .vagrant
.idea/* .idea/*

View File

@ -1,5 +1,10 @@
language: php language: php
env:
- DB_USERNAME=travis
services:
- mysql
php: php:
- 7.0 - 7.0
- 7.1 - 7.1
@ -7,9 +12,9 @@ php:
matrix: matrix:
fast_finish: true fast_finish: true
before_install:
- mysql -e 'CREATE DATABASE flarum;'
before_script: before_script:
- if [[ "$TRAVIS_PHP_VERSION" != "hhvm" ]]; then phpenv config-rm xdebug.ini; fi;
- composer self-update - composer self-update
- composer install - composer install

View File

@ -11,9 +11,12 @@
syntaxCheck="false"> syntaxCheck="false">
<testsuites> <testsuites>
<testsuite name="installation">
<directory suffix="Test.php">./tests/Install</directory>
</testsuite>
<testsuite name="all"> <testsuite name="all">
<directory suffix="Test.php">./tests</directory> <directory suffix="Test.php">./tests</directory>
<exclude>./tests/Install</exclude>
</testsuite> </testsuite>
</testsuites> </testsuites>
</phpunit> </phpunit>

View File

@ -20,4 +20,6 @@ interface DataProviderInterface
public function getAdminUser(); public function getAdminUser();
public function getSettings(); public function getSettings();
public function isDebugMode(): bool;
} }

View File

@ -23,6 +23,8 @@ class DefaultsDataProvider implements DataProviderInterface
'port' => '3306', 'port' => '3306',
]; ];
protected $debug = false;
protected $baseUrl = 'http://flarum.local'; protected $baseUrl = 'http://flarum.local';
protected $adminUser = [ protected $adminUser = [
@ -96,4 +98,14 @@ class DefaultsDataProvider implements DataProviderInterface
{ {
$this->settings[$key] = $value; $this->settings[$key] = $value;
} }
public function isDebugMode(): bool
{
return $this->debug;
}
public function setDebugMode(bool $debug = true)
{
$this->debug = $debug;
}
} }

View File

@ -18,6 +18,7 @@ use Symfony\Component\Yaml\Yaml;
class FileDataProvider implements DataProviderInterface class FileDataProvider implements DataProviderInterface
{ {
protected $default; protected $default;
protected $debug = false;
protected $baseUrl = null; protected $baseUrl = null;
protected $databaseConfiguration = []; protected $databaseConfiguration = [];
protected $adminUser = []; protected $adminUser = [];
@ -44,10 +45,11 @@ class FileDataProvider implements DataProviderInterface
} }
// Define configuration variables // Define configuration variables
$this->debug = $configuration['debug'] ?? false;
$this->baseUrl = isset($configuration['baseUrl']) ? rtrim($configuration['baseUrl'], '/') : null; $this->baseUrl = isset($configuration['baseUrl']) ? rtrim($configuration['baseUrl'], '/') : null;
$this->databaseConfiguration = isset($configuration['databaseConfiguration']) ? $configuration['databaseConfiguration'] : []; $this->databaseConfiguration = $configuration['databaseConfiguration'] ?? [];
$this->adminUser = isset($configuration['adminUser']) ? $configuration['adminUser'] : []; $this->adminUser = $configuration['adminUser'] ?? [];
$this->settings = isset($configuration['settings']) ? $configuration['settings'] : []; $this->settings = $configuration['settings'] ?? [];
} else { } else {
throw new Exception('Configuration file does not exist.'); throw new Exception('Configuration file does not exist.');
} }
@ -72,4 +74,9 @@ class FileDataProvider implements DataProviderInterface
{ {
return $this->settings + $this->default->getSettings(); return $this->settings + $this->default->getSettings();
} }
public function isDebugMode(): bool
{
return $this->debug;
}
} }

View File

@ -138,6 +138,7 @@ class InstallCommand extends AbstractCommand
protected function install() protected function install()
{ {
try { try {
$this->debug = $this->dataSource->isDebugMode();
$this->dbConfig = $this->dataSource->getDatabaseConfiguration(); $this->dbConfig = $this->dataSource->getDatabaseConfiguration();
$validation = $this->getValidator()->make( $validation = $this->getValidator()->make(
@ -214,7 +215,7 @@ class InstallCommand extends AbstractCommand
$dbConfig = $this->dbConfig; $dbConfig = $this->dbConfig;
$config = [ $config = [
'debug' => false, 'debug' => $this->debug,
'database' => [ 'database' => [
'driver' => $dbConfig['driver'], 'driver' => $dbConfig['driver'],
'host' => $dbConfig['host'], 'host' => $dbConfig['host'],

View File

@ -109,4 +109,9 @@ class UserDataProvider implements DataProviderInterface
return $this->questionHelper->ask($this->input, $this->output, $question); return $this->questionHelper->ask($this->input, $this->output, $question);
} }
public function isDebugMode(): bool
{
return false;
}
} }

View File

@ -0,0 +1,51 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Tests\Install;
use Flarum\Install\Console\InstallCommand;
use Flarum\Install\InstallServiceProvider;
use Flarum\Tests\Test\TestCase;
use Flarum\User\User;
use Symfony\Component\Console\Input\StringInput;
use Symfony\Component\Console\Output\StreamOutput;
class DefaultInstallationCommandTest extends TestCase
{
protected $isInstalled = false;
/**
* @test
*/
public function allows_forum_installation()
{
if (file_exists($this->app->basePath().DIRECTORY_SEPARATOR.'config.php')) {
unlink($this->app->basePath().DIRECTORY_SEPARATOR.'config.php');
}
$this->app->register(InstallServiceProvider::class);
/** @var InstallCommand $command */
$command = $this->app->make(InstallCommand::class);
$command->setDataSource($this->configuration);
$body = fopen('php://temp', 'wb+');
$input = new StringInput('');
$output = new StreamOutput($body);
$command->run($input, $output);
$this->assertFileExists($this->app->basePath().DIRECTORY_SEPARATOR.'config.php');
$admin = $this->configuration->getAdminUser();
$this->assertEquals(User::find(1)->username, $admin['username']);
}
}

View File

@ -0,0 +1,150 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Tests\Test\Concerns;
use Flarum\Database\Migrator;
use Flarum\Foundation\Application;
use Flarum\Foundation\Site;
use Flarum\Http\Server;
use Flarum\Install\Console\DataProviderInterface;
use Flarum\Install\Console\DefaultsDataProvider;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Database\Schema\Builder;
trait CreatesForum
{
/**
* @var Server
*/
protected $http;
/**
* @var Site
*/
protected $site;
/**
* @var Application
*/
protected $app;
/**
* @var DataProviderInterface
*/
protected $configuration;
/**
* Make the test set up Flarum as an installed app.
*
* @var bool
*/
protected $isInstalled = true;
protected function createsSite()
{
$this->site = (new Site)
->setBasePath(__DIR__.'/../../tmp')
->setPublicPath(__DIR__.'/../../tmp/public');
}
protected function createsHttpForum()
{
$this->http = Server::fromSite(
$this->site
);
$this->app = $this->http->app;
}
protected function refreshApplication()
{
$this->createsSite();
$data = new DefaultsDataProvider();
$data->setDebugMode();
$data->setSetting('mail_driver', 'log');
$database = $data->getDatabaseConfiguration();
$database['database'] = env('DB_DATABASE', 'flarum');
$database['username'] = env('DB_USERNAME', 'root');
$database['password'] = env('DB_PASSWORD', '');
$data->setDatabaseConfiguration($database);
$this->configuration = $data;
$this->setsApplicationConfiguration($data);
$this->seedsApplication();
$this->createsHttpForum();
}
protected function teardownApplication()
{
/** @var ConnectionInterface $connection */
$connection = $this->app->make(ConnectionInterface::class);
$connection->rollBack();
}
protected function setsApplicationConfiguration(DataProviderInterface $data)
{
if ($this->isInstalled) {
$dbConfig = $data->getDatabaseConfiguration();
$this->site->setConfig(
$config = [
'debug' => $data->isDebugMode(),
'database' => [
'driver' => $dbConfig['driver'],
'host' => $dbConfig['host'],
'database' => $dbConfig['database'],
'username' => $dbConfig['username'],
'password' => $dbConfig['password'],
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => $dbConfig['prefix'],
'port' => $dbConfig['port'],
'strict' => false
],
'url' => $data->getBaseUrl(),
'paths' => [
'api' => 'api',
'admin' => 'admin',
],
]
);
}
}
protected function seedsApplication()
{
if ($this->isInstalled) {
$app = app(\Illuminate\Contracts\Foundation\Application::class);
$app->bind(Builder::class, function ($container) {
return $container->make(ConnectionInterface::class)->getSchemaBuilder();
});
/** @var Migrator $migrator */
$migrator = $app->make(Migrator::class);
if (! $migrator->getRepository()->repositoryExists()) {
$migrator->getRepository()->createRepository();
}
$migrator->run(__DIR__.'/../../../migrations');
/** @var ConnectionInterface $connection */
$connection = $app->make(\Illuminate\Database\ConnectionInterface::class);
$connection->beginTransaction();
}
}
}

View File

@ -0,0 +1,31 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Tests\Test\Concerns;
use Flarum\Api\ApiServiceProvider;
use Flarum\Api\Client;
use Flarum\User\Guest;
use Flarum\User\User;
use Psr\Http\Message\ResponseInterface;
trait MakesApiRequests
{
public function call(string $controller, User $actor = null, array $queryParams = [], array $body = []): ResponseInterface
{
$this->app->register(ApiServiceProvider::class);
$this->app->make('flarum.api.middleware');
/** @var Client $api */
$api = $this->app->make(Client::class);
return $api->send($controller, $actor ?? new Guest, $queryParams, $body);
}
}

View File

@ -0,0 +1,37 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Tests\Test\Concerns;
use Flarum\User\User;
trait RetrievesAuthorizedUsers
{
protected $userAttributes = [
'username' => 'normal',
'password' => 'too-obscure',
'email' => 'normal@machine.local'
];
public function getAdminUser()
{
return User::find(1);
}
public function getNormalUser()
{
User::unguarded(function () {
return User::firstOrCreate([
'username' => $this->userAttributes['username']
], $this->userAttributes);
});
}
}

View File

@ -11,20 +11,21 @@
namespace Flarum\Tests\Test; namespace Flarum\Tests\Test;
use Mockery;
use PHPUnit\Framework\TestCase as Test; use PHPUnit\Framework\TestCase as Test;
abstract class TestCase extends Test abstract class TestCase extends Test
{ {
use Concerns\CreatesForum,
Concerns\MakesApiRequests;
public function setUp() public function setUp()
{ {
Mockery::close(); $this->refreshApplication();
$this->init(); $this->init();
} }
protected function init() protected function init()
{ {
// To be overloaded by children - saves having to do setUp/mockery::close every time // .. allows implementation by children without the need to call the parent.
} }
} }

View File

@ -0,0 +1 @@
{}