From 13a2cd9b184d58e5ca711ccf94b7d7286fa4adb3 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Fri, 6 Sep 2019 23:53:47 +0800 Subject: [PATCH] Refactor setup --- .gitignore | 1 + app/Console/Commands/BsInstallCommand.php | 7 +- app/Http/Controllers/SetupController.php | 149 +++------------ app/Http/Kernel.php | 3 +- app/Http/Middleware/CheckInstallation.php | 8 +- app/Http/Middleware/LockUpdatePage.php | 16 -- app/Http/Middleware/RedirectToSetup.php | 30 +++ app/Providers/RouteServiceProvider.php | 28 --- app/Providers/RuntimeCheckServiceProvider.php | 43 ----- config/app.php | 1 - config/captcha.php | 45 ----- resources/lang/en/setup.yml | 2 +- resources/lang/zh_CN/setup.yml | 2 +- resources/misc/changelogs/en/next.md | 1 + resources/misc/changelogs/zh_CN/next.md | 1 + .../views/setup/updates/success.blade.php | 10 - routes/setup.php | 28 --- routes/web.php | 18 ++ tests/BrowserKitTestCase.php | 5 + tests/CommandsTest/BsInstallCommandTest.php | 29 +-- tests/MiddlewareTest.php | 51 +++-- tests/SetupControllerTest.php | 175 ++++++++---------- tests/TestCase.php | 5 + tests/UpdateControllerTest.php | 1 + 24 files changed, 226 insertions(+), 433 deletions(-) delete mode 100644 app/Http/Middleware/LockUpdatePage.php create mode 100644 app/Http/Middleware/RedirectToSetup.php delete mode 100644 app/Providers/RuntimeCheckServiceProvider.php delete mode 100644 config/captcha.php delete mode 100644 routes/setup.php diff --git a/.gitignore b/.gitignore index 5bc40922..6349f299 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,5 @@ storage/*.sqlite .vscode storage/oauth-public.key storage/oauth-private.key +storage/install.lock .phpunit.result.cache diff --git a/app/Console/Commands/BsInstallCommand.php b/app/Console/Commands/BsInstallCommand.php index 5d44b65e..7fb1a7df 100644 --- a/app/Console/Commands/BsInstallCommand.php +++ b/app/Console/Commands/BsInstallCommand.php @@ -4,6 +4,7 @@ namespace App\Console\Commands; use App\Models\User; use Illuminate\Console\Command; +use Illuminate\Filesystem\Filesystem; class BsInstallCommand extends Command { @@ -11,9 +12,9 @@ class BsInstallCommand extends Command protected $description = 'Execute installation and create a super administrator.'; - public function handle() + public function handle(Filesystem $filesystem) { - if (\App\Http\Controllers\SetupController::checkTablesExist()) { + if ($filesystem->exists(storage_path('install.lock'))) { $this->info('You have installed Blessing Skin Server. Nothing to do.'); return; @@ -44,6 +45,8 @@ class BsInstallCommand extends Command $admin->verified = true; $admin->save(); + $filesystem->put(storage_path('install.lock'), ''); + $this->info('Installation completed!'); $this->info('We recommend to modify your "Site URL" option if incorrect.'); } diff --git a/app/Http/Controllers/SetupController.php b/app/Http/Controllers/SetupController.php index 452e5c0c..34a6b7fb 100644 --- a/app/Http/Controllers/SetupController.php +++ b/app/Http/Controllers/SetupController.php @@ -6,23 +6,22 @@ use DB; use Log; use File; use Option; -use Schema; use Artisan; -use Storage; use App\Models\User; +use Illuminate\Support\Str; use Illuminate\Http\Request; use Composer\Semver\Comparator; +use Illuminate\Filesystem\Filesystem; use App\Exceptions\PrettyPageException; +use Symfony\Component\Finder\SplFileInfo; class SetupController extends Controller { - public function welcome() + public function welcome(Filesystem $filesystem) { - // @codeCoverageIgnoreStart - if (! File::exists(base_path('.env'))) { - File::copy(base_path('.env.example'), base_path('.env')); + if (! $filesystem->exists(base_path('.env'))) { + $filesystem->copy(base_path('.env.example'), base_path('.env')); } - // @codeCoverageIgnoreEnd return view('setup.wizard.welcome'); } @@ -104,31 +103,7 @@ class SetupController extends Controller return redirect('setup/info'); } - public function info() - { - $existingTables = static::checkTablesExist([], true); - - // Not installed completely - if (count($existingTables) > 0) { - Log::info('Remaining tables detected, exit setup wizard now', [$existingTables]); - - $existingTables = array_map(function ($item) { - return get_db_config()['prefix'].$item; - }, $existingTables); - - throw new PrettyPageException(trans('setup.database.table-already-exists', ['tables' => json_encode($existingTables)]), 1); - } - - // @codeCoverageIgnoreStart - if (! function_exists('escapeshellarg')) { - throw new PrettyPageException(trans('setup.disabled-functions.escapeshellarg'), 1); - } - // @codeCoverageIgnoreEnd - - return view('setup.wizard.info'); - } - - public function finish(Request $request) + public function finish(Request $request, Filesystem $filesystem) { $data = $this->validate($request, [ 'email' => 'required|email', @@ -158,7 +133,7 @@ class SetupController extends Controller $siteUrl = url('/'); - if (ends_with($siteUrl, '/index.php')) { + if (Str::endsWith($siteUrl, '/index.php')) { $siteUrl = substr($siteUrl, 0, -10); // @codeCoverageIgnore } @@ -179,7 +154,7 @@ class SetupController extends Controller $user->save(); - $this->createDirectories(); + $filesystem->put(storage_path('install.lock'), ''); return view('setup.wizard.finish')->with([ 'email' => $request->input('email'), @@ -187,102 +162,22 @@ class SetupController extends Controller ]); } - public function update() + public function update(Filesystem $filesystem) { - if (Comparator::lessThanOrEqualTo(config('app.version'), option('version'))) { - // No updates available - return view('setup.locked'); - } - - return view('setup.updates.welcome'); - } - - public function doUpdate() - { - $resource = opendir(database_path('update_scripts')); - $updateScriptExist = false; - - while ($filename = @readdir($resource)) { - if ($filename != '.' && $filename != '..') { - preg_match('/update-(.*)-to-(.*).php/', $filename, $matches); - - // Skip if the file is not valid or expired - if (! isset($matches[2]) || - Comparator::lessThan($matches[2], config('app.version'))) { - continue; - } - - $tips = require database_path('update_scripts')."/$filename"; - $updateScriptExist = true; - } - } - closedir($resource); - - foreach (config('options') as $key => $value) { - if (! Option::has($key)) { - Option::set($key, $value); - } - } - Option::set('version', config('app.version')); + collect($filesystem->files(database_path('update_scripts'))) + ->filter(function (SplFileInfo $file) { + $name = $file->getFilenameWithoutExtension(); + return preg_match('/^\d+\.\d+\.\d+$/', $name) > 0 + && Comparator::greaterThanOrEqualTo($name, option('version')); + }) + ->each(function (SplFileInfo $file) use ($filesystem) { + $filesystem->getRequire($file->getPathname()); + }); + option(['version' => config('app.version')]); Artisan::call('view:clear'); + $filesystem->put(storage_path('install.lock'), ''); - return view('setup.updates.success', ['tips' => $tips ?? []]); - } - - /** - * Check if the given tables exist in current database. - * - * @param array $tables - * @param bool $returnExisting - * @return bool|array - */ - public static function checkTablesExist($tables = [], $returnExistingTables = false) - { - $existingTables = []; - $tables = $tables ?: [ - 'users', - 'user_closet', - 'players', - 'textures', - 'options', - 'reports', - ]; - - foreach ($tables as $tableName) { - if (Schema::hasTable($tableName)) { - $existingTables[] = $tableName; - } - } - - if (count($existingTables) == count($tables)) { - return $returnExistingTables ? $existingTables : true; - } else { - return $returnExistingTables ? $existingTables : false; - } - } - - public static function checkDirectories() - { - $directories = ['storage/textures', 'plugins']; - - try { - foreach ($directories as $dir) { - if (! Storage::disk('root')->has($dir)) { - if (! Storage::disk('root')->makeDirectory($dir)) { - return false; // @codeCoverageIgnore - } - } - } - - return true; - } catch (\Exception $e) { - return false; - } - } - - protected function createDirectories() - { - return self::checkDirectories(); + return view('setup.updates.success'); } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index dd6b548e..5d3f0897 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -31,8 +31,9 @@ class Kernel extends HttpKernel \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, - \App\Http\Middleware\ForbiddenIE::class, \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class, + \App\Http\Middleware\ForbiddenIE::class, + \App\Http\Middleware\RedirectToSetup::class, ], 'api' => [ diff --git a/app/Http/Middleware/CheckInstallation.php b/app/Http/Middleware/CheckInstallation.php index 6ec0abb5..19ab0076 100644 --- a/app/Http/Middleware/CheckInstallation.php +++ b/app/Http/Middleware/CheckInstallation.php @@ -2,17 +2,15 @@ namespace App\Http\Middleware; +use Illuminate\Filesystem\Filesystem; use App\Http\Controllers\SetupController; class CheckInstallation { public function handle($request, \Closure $next) { - if (config('database.default') == 'dummy') { - return $next($request); // @codeCoverageIgnore - } - - if (SetupController::checkTablesExist()) { + $hasLock = resolve(Filesystem::class)->exists(storage_path('install.lock')); + if ($hasLock && ! $request->is('setup/*update')) { return response()->view('setup.locked'); } diff --git a/app/Http/Middleware/LockUpdatePage.php b/app/Http/Middleware/LockUpdatePage.php deleted file mode 100644 index 142e35e0..00000000 --- a/app/Http/Middleware/LockUpdatePage.php +++ /dev/null @@ -1,16 +0,0 @@ -user()->permission < User::SUPER_ADMIN, 503); - - return $next($request); - } -} diff --git a/app/Http/Middleware/RedirectToSetup.php b/app/Http/Middleware/RedirectToSetup.php new file mode 100644 index 00000000..8b610232 --- /dev/null +++ b/app/Http/Middleware/RedirectToSetup.php @@ -0,0 +1,30 @@ +is('setup*') && Comparator::greaterThan($version, option('version', $version))) { + $user = $request->user(); + if ($user && $user->isAdmin()) { + return redirect('/setup/update'); + } else { + abort(503); + } + } + + $hasLock = resolve(Filesystem::class)->exists(storage_path('install.lock')); + if ($hasLock || $request->is('setup*')) { + return $next($request); + } + + return redirect('/setup'); + } +} diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 15eebd0c..8c602214 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -20,16 +20,6 @@ class RouteServiceProvider extends ServiceProvider */ protected $namespace = 'App\Http\Controllers'; - /** - * Define your route model bindings, pattern filters, etc. - * - * @return void - */ - public function boot() - { - parent::boot(); - } - /** * Define the routes for the application. * @@ -38,8 +28,6 @@ class RouteServiceProvider extends ServiceProvider */ public function map(Router $router) { - $this->mapSetupRoutes($router); - $this->mapStaticRoutes($router); $this->mapWebRoutes($router); @@ -74,22 +62,6 @@ class RouteServiceProvider extends ServiceProvider }); } - /** - * Define the "setup" routes for the application. - * - * The routes for setup wizard. - * - * @param \Illuminate\Routing\Router $router - * @return void - */ - protected function mapSetupRoutes(Router $router) - { - Route::prefix('setup') - ->namespace($this->namespace) - ->middleware('web') - ->group(base_path('routes/setup.php')); - } - /** * Define the "static" routes for the application. * diff --git a/app/Providers/RuntimeCheckServiceProvider.php b/app/Providers/RuntimeCheckServiceProvider.php deleted file mode 100644 index 1d16167a..00000000 --- a/app/Providers/RuntimeCheckServiceProvider.php +++ /dev/null @@ -1,43 +0,0 @@ -is('setup*') || $this->app->runningInConsole()) { - return; - } - - $this->checkInstallation(); // @codeCoverageIgnore - } - - /** - * @codeCoverageIgnore - */ - protected function checkInstallation() - { - // Redirect to setup wizard - if (config('database.default') == 'dummy' || ! SetupController::checkTablesExist()) { - return redirect('/setup')->send(); - } - - if (Comparator::greaterThan(config('app.version'), option('version'))) { - return redirect('/setup/update')->send(); - } - - return true; - } -} diff --git a/config/app.php b/config/app.php index d3be00da..867beeab 100644 --- a/config/app.php +++ b/config/app.php @@ -170,7 +170,6 @@ return [ /* * Application Service Providers... */ - App\Providers\RuntimeCheckServiceProvider::class, App\Providers\AppServiceProvider::class, App\Providers\EventServiceProvider::class, App\Providers\PluginServiceProvider::class, diff --git a/config/captcha.php b/config/captcha.php deleted file mode 100644 index 6d349b25..00000000 --- a/config/captcha.php +++ /dev/null @@ -1,45 +0,0 @@ - '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ', - - 'default' => [ - 'length' => 5, - 'width' => 100, - 'height' => 34, - 'quality' => 90, - ], - - 'flat' => [ - 'length' => 6, - 'width' => 160, - 'height' => 46, - 'quality' => 90, - 'lines' => 6, - 'bgImage' => false, - 'bgColor' => '#ecf2f4', - 'fontColors'=> ['#2c3e50', '#c0392b', '#16a085', '#c0392b', '#8e44ad', '#303f9f', '#f57c00', '#795548'], - 'contrast' => -5, - ], - - 'mini' => [ - 'length' => 3, - 'width' => 60, - 'height' => 32, - ], - - 'inverse' => [ - 'length' => 5, - 'width' => 120, - 'height' => 36, - 'quality' => 90, - 'sensitive' => true, - 'angle' => 12, - 'sharpen' => 10, - 'blur' => 2, - 'invert' => true, - 'contrast' => -5, - ], - -]; diff --git a/resources/lang/en/setup.yml b/resources/lang/en/setup.yml index 7e950e5f..a5ee0be1 100644 --- a/resources/lang/en/setup.yml +++ b/resources/lang/en/setup.yml @@ -15,7 +15,7 @@ disabled-functions: locked: title: Already installed - text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the tables in your database first, or use a new table prefix. + text: It appears that you have already installed Blessing Skin Server. To reinstall, please delete the "install.lock" file under "storage" directory. button: Back to homepage updates: diff --git a/resources/lang/zh_CN/setup.yml b/resources/lang/zh_CN/setup.yml index 3bcb6642..c2e37050 100644 --- a/resources/lang/zh_CN/setup.yml +++ b/resources/lang/zh_CN/setup.yml @@ -14,7 +14,7 @@ disabled-functions: locked: title: 已安装过 - text: Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除数据库中的旧数据表,或者换一个数据表前缀。 + text: Blessing Skin Server 看起来已经安装妥当。如果想重新安装,请删除 storage 目录下的 install.lock 文件。 button: 返回首页 updates: diff --git a/resources/misc/changelogs/en/next.md b/resources/misc/changelogs/en/next.md index d5a99633..a52fb783 100644 --- a/resources/misc/changelogs/en/next.md +++ b/resources/misc/changelogs/en/next.md @@ -14,6 +14,7 @@ - Tweaked policy of retrieve CA cert for GuzzleHttp. - Refactor account system. - PHP version requirement is increased to 7.2.0. +- Use `install.lock` file to detect status of installation. ## Fixed diff --git a/resources/misc/changelogs/zh_CN/next.md b/resources/misc/changelogs/zh_CN/next.md index 289b3064..773dbccf 100644 --- a/resources/misc/changelogs/zh_CN/next.md +++ b/resources/misc/changelogs/zh_CN/next.md @@ -14,6 +14,7 @@ - 修改 GuzzleHttp 库获取 CA 证书的策略 - 重构用户系统 - PHP 版本最低要求为 7.2.0 +- 使用 `install.lock` 文件来检测安装状态 ## 修复 diff --git a/resources/views/setup/updates/success.blade.php b/resources/views/setup/updates/success.blade.php index 315f6fad..8e2e5db8 100644 --- a/resources/views/setup/updates/success.blade.php +++ b/resources/views/setup/updates/success.blade.php @@ -8,16 +8,6 @@

@lang('setup.updates.success.text', ['version' => config('app.version')])

-{{-- if any tip is given --}} -@if (is_array($tips) && count($tips) > 0) -

@lang('setup.updates.success.tips')

- -@endif -

@lang('setup.updates.welcome.button')

diff --git a/routes/setup.php b/routes/setup.php deleted file mode 100644 index c7556f32..00000000 --- a/routes/setup.php +++ /dev/null @@ -1,28 +0,0 @@ - 'setup'], function () { - Route::any('/', 'SetupController@welcome'); - Route::any('/database', 'SetupController@database'); - Route::get('/info', 'SetupController@info'); - Route::post('/finish', 'SetupController@finish'); -}); - -Route::group(['middleware' => ['authorize', App\Http\Middleware\LockUpdatePage::class]], function () { - Route::any('/update', 'SetupController@update'); - Route::any('/exec-update', 'SetupController@doUpdate'); - Route::view('/changelog', 'setup.updates.changelog'); -}); diff --git a/routes/web.php b/routes/web.php index 16852a85..d96b3320 100644 --- a/routes/web.php +++ b/routes/web.php @@ -156,3 +156,21 @@ Route::group(['middleware' => ['authorize', 'admin'], 'prefix' => 'admin'], func Route::any('/download', 'UpdateController@download'); }); }); + +/** + * Setup and Update + */ +Route::group(['prefix' => 'setup'], function () { + Route::group(['middleware' => 'setup'], function () { + Route::any('/', 'SetupController@welcome'); + Route::any('/database', 'SetupController@database'); + Route::view('/info', 'setup.wizard.info'); + Route::post('/finish', 'SetupController@finish'); + }); + + Route::group(['middleware' => 'authorize'], function () { + Route::view('/update', 'setup.updates.welcome')->middleware('setup'); + Route::any('/exec-update', 'SetupController@update')->middleware('setup'); + Route::view('/changelog', 'setup.updates.changelog'); + }); +}); diff --git a/tests/BrowserKitTestCase.php b/tests/BrowserKitTestCase.php index 7d3db0df..f1d8b96b 100644 --- a/tests/BrowserKitTestCase.php +++ b/tests/BrowserKitTestCase.php @@ -28,6 +28,11 @@ class BrowserKitTestCase extends TestCase Artisan::call('migrate:refresh'); + $files = $app->make('files'); + if (! $files->exists(storage_path('install.lock'))) { + $files->put(storage_path('install.lock'), ''); + } + return $app; } diff --git a/tests/CommandsTest/BsInstallCommandTest.php b/tests/CommandsTest/BsInstallCommandTest.php index 4e9bf4bc..28989a97 100644 --- a/tests/CommandsTest/BsInstallCommandTest.php +++ b/tests/CommandsTest/BsInstallCommandTest.php @@ -4,6 +4,7 @@ namespace Tests; use Schema; use App\Models\User; +use Illuminate\Filesystem\Filesystem; use Illuminate\Foundation\Testing\DatabaseTransactions; class BsInstallCommandTest extends TestCase @@ -15,25 +16,15 @@ class BsInstallCommandTest extends TestCase $this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka') ->expectsOutput('You have installed Blessing Skin Server. Nothing to do.'); - $tables = [ - 'user_closet', - 'migrations', - 'options', - 'players', - 'textures', - 'users', - 'reports', - 'oauth_auth_codes', - 'oauth_access_tokens', - 'oauth_clients', - 'oauth_personal_access_clients', - 'oauth_refresh_tokens', - 'notifications', - 'jobs', - 'language_lines', - ]; - array_walk($tables, function ($table) { - Schema::dropIfExists($table); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->once() + ->andReturn(false); + $mock->shouldReceive('put') + ->with(storage_path('install.lock'), '') + ->once() + ->andReturn(true); }); $this->artisan('bs:install ibara.mayaka@hyouka.test 12345678 mayaka') diff --git a/tests/MiddlewareTest.php b/tests/MiddlewareTest.php index 1ed878cc..8cb04d11 100644 --- a/tests/MiddlewareTest.php +++ b/tests/MiddlewareTest.php @@ -6,6 +6,7 @@ use Event; use App\Models\User; use App\Models\Player; use App\Services\Facades\Option; +use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Schema; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -84,16 +85,28 @@ class MiddlewareTest extends TestCase { $this->get('/setup')->assertSee('Already installed'); - $tables = [ - 'user_closet', 'migrations', 'options', 'players', 'textures', 'users', - ]; - array_walk($tables, function ($table) { - Schema::dropIfExists($table); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->twice() + ->andReturn(false); + $mock->shouldReceive('exists') + ->with(base_path('.env')) + ->andReturn(true); }); $this->get('/setup')->assertSee(trans( 'setup.wizard.welcome.text', ['version' => config('app.version')] )); + + $this->actAs('superAdmin'); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->andReturn(true); + }); + config(['app.version' => '100.0.0']); + $this->get('/setup/update')->assertSee(trans('setup.updates.welcome.title')); } public function testCheckPlayerExist() @@ -178,6 +191,28 @@ class MiddlewareTest extends TestCase ->assertRedirect('/user'); } + public function testRedirectToSetup() + { + $current = config('app.version'); + config(['app.version' => '100.0.0']); + $this->get('/')->assertStatus(503); + $this->actAs('superAdmin')->get('/')->assertRedirect('/setup/update'); + config(['app.version' => $current]); + + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->andReturn(true, false, false); + + $mock->shouldReceive('exists') + ->with(base_path('.env')) + ->andReturn(true); + }); + $this->get('/')->assertViewIs('index'); + $this->get('/setup')->assertViewIs('setup.wizard.welcome'); + $this->get('/')->assertRedirect('/setup'); + } + public function testRejectBannedUser() { $user = factory(User::class, 'banned')->create(); @@ -210,10 +245,4 @@ class MiddlewareTest extends TestCase $this->get('/', ['user-agent' => 'MSIE'])->assertSee(trans('errors.http.ie')); $this->get('/', ['user-agent' => 'Trident'])->assertSee(trans('errors.http.ie')); } - - public function testLockUpdatePage() - { - $this->actAs('admin')->get('/setup/changelog')->assertStatus(503); - $this->actAs('superAdmin')->get('/setup/changelog')->assertStatus(200); - } } diff --git a/tests/SetupControllerTest.php b/tests/SetupControllerTest.php index 37ebe071..62a6e90b 100644 --- a/tests/SetupControllerTest.php +++ b/tests/SetupControllerTest.php @@ -2,62 +2,48 @@ namespace Tests; -use Mockery; -use Exception; -use CreateAllTables; use Illuminate\Support\Str; -use AddVerificationToUsersTable; use Illuminate\Support\Facades\File; -use Illuminate\Support\Facades\Schema; +use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Artisan; -use Illuminate\Support\Facades\Storage; +use Symfony\Component\Finder\SplFileInfo; use Illuminate\Foundation\Testing\DatabaseTransactions; class SetupControllerTest extends TestCase { use DatabaseTransactions; - protected function tearDown(): void - { - $this->dropAllTables(); - Mockery::close(); - parent::tearDown(); - } - - protected function dropAllTables() - { - $tables = [ - 'user_closet', - 'migrations', - 'options', - 'players', - 'textures', - 'users', - 'reports', - 'oauth_auth_codes', - 'oauth_access_tokens', - 'oauth_clients', - 'oauth_personal_access_clients', - 'oauth_refresh_tokens', - 'notifications', - 'jobs', - ]; - array_walk($tables, function ($table) { - Schema::dropIfExists($table); - }); - - return $this; - } - public function testWelcome() { - $this->dropAllTables(); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->andReturn(false); + $mock->shouldReceive('exists') + ->with(base_path('.env')) + ->once() + ->andReturn(false); + $mock->shouldReceive('copy') + ->with(base_path('.env.example'), base_path('.env')) + ->once() + ->andReturn(true); + }); $this->get('/setup')->assertViewIs('setup.wizard.welcome'); } public function testDatabase() { - $this->dropAllTables(); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->atLeast(1) + ->andReturn(false); + $mock->shouldReceive('put') + ->with(storage_path('install.lock'), '') + ->atLeast(1) + ->andReturn(true); + }); + $fake = [ 'type' => env('DB_CONNECTION'), 'host' => env('DB_HOST'), @@ -76,7 +62,17 @@ class SetupControllerTest extends TestCase public function testReportDatabaseConnectionError() { - $this->dropAllTables(); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->atLeast(1) + ->andReturn(false); + $mock->shouldReceive('put') + ->with(storage_path('install.lock'), '') + ->atLeast(1) + ->andReturn(true); + }); + $this->post('/setup/database', ['type' => 'sqlite', 'host' => 'placeholder', 'db' => 'test']) ->assertSee(trans('setup.database.connection-error', [ 'type' => 'SQLite', @@ -84,18 +80,19 @@ class SetupControllerTest extends TestCase ])); } - public function testInfo() - { - $this->dropAllTables(); - $this->get('/setup/info')->assertViewIs('setup.wizard.info'); - Artisan::call('migrate:refresh'); - Schema::drop('users'); - $this->get('/setup/info')->assertSee('already exist'); - } - public function testFinish() { - $this->dropAllTables(); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->atLeast(1) + ->andReturn(false); + $mock->shouldReceive('put') + ->with(storage_path('install.lock'), '') + ->atLeast(1) + ->andReturn(true); + }); + // Without `email` field $this->post('/setup/finish') ->assertDontSee(trans('setup.wizard.finish.title')); @@ -183,13 +180,7 @@ class SetupControllerTest extends TestCase ], ]) ->once() - ->andReturnUsing(function () { - $migration = new CreateAllTables(); - $migration->up(); - - $migration = new AddVerificationToUsersTable(); - $migration->up(); - }); + ->andReturn(true); $this->post('/setup/finish', [ 'email' => 'a@b.c', 'nickname' => 'nickname', @@ -209,47 +200,41 @@ class SetupControllerTest extends TestCase public function testUpdate() { - $this->actAs('superAdmin') - ->get('/setup/update') - ->assertSee(trans('setup.locked.text')); + $this->mock(Filesystem::class, function ($mock) { + $mock->shouldReceive('exists') + ->with(storage_path('install.lock')) + ->andReturn(true); - option(['version' => '0.1.0']); - $this->get('/setup/update') - ->assertSee(trans('setup.updates.welcome.title')); - } + $mock->shouldReceive('put') + ->with(storage_path('install.lock'), '') + ->once() + ->andReturn(true); - public function testDoUpdate() - { - $current_version = config('app.version'); + $mock->shouldReceive('files') + ->with(database_path('update_scripts')) + ->once() + ->andReturn([ + new SplFileInfo('/1.0.0.php', '', ''), + new SplFileInfo('/99.0.0.php', '', ''), + new SplFileInfo('/100.0.0.php', '', ''), + ]); + + $mock->shouldNotReceive('getRequire')->with('/1.0.0.php'); + + $mock->shouldReceive('getRequire') + ->with('/99.0.0.php') + ->once(); + + $mock->shouldReceive('getRequire') + ->with('/100.0.0.php') + ->once(); + }); + Artisan::shouldReceive('call')->with('view:clear')->once(); config(['app.version' => '100.0.0']); - copy( - database_path('update_scripts/update-3.1-to-3.1.1.php'), - database_path("update_scripts/update-$current_version-to-100.0.0.php") - ); // Just a fixture - config(['options.new_option' => 'value']); - $this->actAs('superAdmin')->get('/setup/exec-update')->assertViewHas('tips'); - $this->assertEquals('value', option('new_option')); + $this->actAs('superAdmin') + ->get('/setup/exec-update') + ->assertViewIs('setup.updates.success'); $this->assertEquals('100.0.0', option('version')); - unlink(database_path("update_scripts/update-$current_version-to-100.0.0.php")); - - option(['version' => '3.0.0']); // Fake old version - $this->get('/setup/exec-update'); - $this->assertEquals('100.0.0', option('version')); - } - - public function testCheckDirectories() - { - Storage::shouldReceive('disk') - ->with('root') - ->andReturnSelf(); - Storage::shouldReceive('has') - ->with('storage/textures') - ->andReturn(false); - Storage::shouldReceive('makeDirectory') - ->with('storage/textures') - ->andThrow(new Exception()); - - $this->assertFalse(\App\Http\Controllers\SetupController::checkDirectories()); } } diff --git a/tests/TestCase.php b/tests/TestCase.php index 45e5dd14..bad4e36b 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -27,6 +27,11 @@ class TestCase extends \Illuminate\Foundation\Testing\TestCase Artisan::call('migrate:refresh'); + $files = $app->make('files'); + if (! $files->exists(storage_path('install.lock'))) { + $files->put(storage_path('install.lock'), ''); + } + return $app; } diff --git a/tests/UpdateControllerTest.php b/tests/UpdateControllerTest.php index a26e5666..ae9f837f 100644 --- a/tests/UpdateControllerTest.php +++ b/tests/UpdateControllerTest.php @@ -91,6 +91,7 @@ class UpdateControllerTest extends TestCase }); $this->mock(\Illuminate\Filesystem\Filesystem::class, function ($mock) { $mock->shouldReceive('delete')->with(storage_path('options/cache.php'))->once(); + $mock->shouldReceive('exists')->with(storage_path('install.lock'))->andReturn(true); }); $this->getJson('/admin/update/download?action=download') ->assertJson(['code' => 0, 'message' => trans('admin.update.complete')]);