/
githubmirror
/
framework
Обзор
Документация
Войти
/
githubmirror
/
framework
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
13.x
tests/Integration/Console/CommandSchedulingTest.php
212 строк
6 KB
Ahmed Alaa
Add missing void return type to test methods (#56860)
02 сен 2025, 01:45
Не верифицирован
02 сен 2025, 01:45
c0bae54
Код
Авторство
О чём код?
<?php namespace Illuminate\Tests\Integration\Console; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Str; use Orchestra\Testbench\TestCase; use PHPUnit\Framework\Attributes\DataProvider; class CommandSchedulingTest extends TestCase { /** * Each run of this test is assigned a random ID to ensure that separate runs * do not interfere with each other. * * @var string */ protected $id; /** * The path to the file that execution logs will be written to. * * @var string */ protected $logfile; /** * Just in case Testbench starts to ship an `artisan` script, we'll check and save a backup. * * @var string|null */ protected $originalArtisan; /** * The Filesystem instance for writing stubs and logs. * * @var \Illuminate\Filesystem\Filesystem */ protected $fs; protected function setUp(): void { parent::setUp(); $this->fs = new Filesystem; $this->id = Str::random(); $this->logfile = storage_path("logs/command_scheduling_test_{$this->id}.log"); $this->writeArtisanScript(); } protected function tearDown(): void { $this->fs->delete($this->logfile); $this->fs->delete(base_path('artisan')); if (! is_null($this->originalArtisan)) { $this->fs->put(base_path('artisan'), $this->originalArtisan); } parent::tearDown(); } #[DataProvider('executionProvider')] public function testExecutionOrder($background, $expected): void { $schedule = $this->app->make(Schedule::class); $event = $schedule ->command("test:{$this->id}") ->onOneServer() ->after(function () { $this->fs->append($this->logfile, "foreground:after\n"); }) ->before(function () { $this->fs->append($this->logfile, "foreground:before\n"); }); if ($background) { $event->runInBackground(); } // We'll trigger the scheduler three times to simulate multiple servers $this->app->instance(Schedule::class, clone $schedule); $this->artisan('schedule:run'); $this->app->instance(Schedule::class, clone $schedule); $this->artisan('schedule:run'); $this->app->instance(Schedule::class, clone $schedule); $this->artisan('schedule:run'); if ($background) { // Since our command is running in a separate process, we need to wait // until it has finished executing before running our assertions. $this->waitForLogMessages(...$expected); } $this->assertLogged(...$expected); } public static function executionProvider() { return [ 'Foreground' => [false, ['foreground:before', 'handled', 'foreground:after']], 'Background' => [true, ['foreground:before', 'handled', 'background:after']], ]; } protected function waitForLogMessages(...$messages) { $tries = 0; $sleep = 100000; // 100K microseconds = 0.1 second $limit = 50; // 0.1s * 50 = 5 second wait limit do { $log = $this->fs->get($this->logfile); if (Str::containsAll($log, $messages)) { return; } $tries++; usleep($sleep); } while ($tries < $limit); } protected function assertLogged(...$messages) { $log = trim($this->fs->get($this->logfile)); $this->assertEquals(implode("\n", $messages), $log); } protected function writeArtisanScript() { $path = base_path('artisan'); // Save existing artisan script if there is one if ($this->fs->exists($path)) { $this->originalArtisan = $this->fs->get($path); } $thisFile = __FILE__; $logfile = var_export($this->logfile, true); $script = <<<PHP #!/usr/bin/env php <?php // This is a custom artisan script made specifically for: // // {$thisFile} // // It should be automatically cleaned up when the tests have finished executing. // If you are seeing this file, an unexpected error must have occurred. Please // manually remove it. define('LARAVEL_START', microtime(true)); require __DIR__.'/../../../autoload.php'; \$app = require_once __DIR__.'/bootstrap/app.php'; \$kernel = \$app->make(Illuminate\Contracts\Console\Kernel::class); // Here is our custom command for the test class CommandSchedulingTestCommand_{$this->id} extends Illuminate\Console\Command { protected \$signature = 'test:{$this->id}'; public function handle() { \$logfile = {$logfile}; (new Illuminate\Filesystem\Filesystem)->append(\$logfile, "handled\\n"); } } // Register command with Kernel Illuminate\Console\Application::starting(function (\$artisan) { \$artisan->add(new CommandSchedulingTestCommand_{$this->id}); }); // Add command to scheduler so that the after() callback is trigger in our spawned process Illuminate\Foundation\Application::getInstance() ->booted(function (\$app) { \$app->resolving(Illuminate\Console\Scheduling\Schedule::class, function(\$schedule) { \$fs = new Illuminate\Filesystem\Filesystem; \$schedule->command("test:{$this->id}") ->after(function() use (\$fs) { \$logfile = {$logfile}; \$fs->append(\$logfile, "background:after\\n"); }) ->before(function() use (\$fs) { \$logfile = {$logfile}; \$fs->append(\$logfile, "background:before\\n"); }); }); }); \$status = \$kernel->handle( \$input = new Symfony\Component\Console\Input\ArgvInput, new Symfony\Component\Console\Output\ConsoleOutput ); \$kernel->terminate(\$input, \$status); exit(\$status); PHP; $this->fs->put($path, $script); } }