Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/Foundation/Providers/ArtisanServiceProvider.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
<?php namespace Winter\Storm\Foundation\Providers;
<?php

namespace Winter\Storm\Foundation\Providers;

use Winter\Storm\Foundation\Console\KeyGenerateCommand;
use Winter\Storm\Foundation\Console\ClearCompiledCommand;
Expand Down Expand Up @@ -41,7 +43,10 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase
'RouteClear' => \Illuminate\Foundation\Console\RouteClearCommand::class,
'RouteList' => \Illuminate\Foundation\Console\RouteListCommand::class,
'ScheduleFinish' => \Illuminate\Console\Scheduling\ScheduleFinishCommand::class,
'ScheduleList' => \Illuminate\Console\Scheduling\ScheduleListCommand::class,
'ScheduleRun' => \Illuminate\Console\Scheduling\ScheduleRunCommand::class,
'ScheduleTest' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class,
'ScheduleWork' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class,
'Up' => \Illuminate\Foundation\Console\UpCommand::class,
'ViewClear' => \Illuminate\Foundation\Console\ViewClearCommand::class,

Expand All @@ -54,10 +59,7 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase
// 'OptimizeClear' => OptimizeClearCommand::class,
// 'QueueClear' => QueueClearCommand::class,
// 'SchemaDump' => DumpCommand::class,
// 'ScheduleList' => \Illuminate\Console\Scheduling\ScheduleListCommand::class,
// 'ScheduleClearCache' => ScheduleClearCacheCommand::class,
// 'ScheduleTest' => ScheduleTestCommand::class,
// 'ScheduleWork' => ScheduleWorkCommand::class,
// 'ViewCache' => ViewCacheCommand::class,

// Explicitly unsupported in Winter:
Expand Down
135 changes: 135 additions & 0 deletions tests/Scheduling/ScheduleListCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

namespace Winter\Storm\Tests\Scheduling;

use Illuminate\Console\Command;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\ScheduleListCommand;
use Illuminate\Support\Carbon;
use Illuminate\Support\ProcessUtils;

use Winter\Storm\Tests\TestCase;

class ScheduleListCommandTest extends TestCase
{
public $schedule;

protected function setUp(): void
{
parent::setUp();

Carbon::setTestNow('2023-01-01');
ScheduleListCommand::resolveTerminalWidthUsing(fn () => 80);

$this->schedule = $this->app->make(Schedule::class);
}

public function testDisplayEmptySchedule()
{
$this->artisan(ScheduleListCommand::class)
->assertSuccessful()
->expectsOutputToContain('No scheduled tasks have been defined.');
}

public function testDisplaySchedule()
{
$this->schedule->command(FooCommand::class)->quarterly();
$this->schedule->command('inspire')->twiceDaily(14, 18);
$this->schedule->command('foobar', ['a' => 'b'])->everyMinute();
$this->schedule->job(FooJob::class)->everyMinute();
$this->schedule->command('inspire')->cron('0 9,17 * * *');
$this->schedule->command('inspire')->cron("0 10\t* * *");
$this->schedule->call(FooCall::class)->everyMinute();
$this->schedule->call([FooCall::class, 'fooFunction'])->everyMinute();

$this->schedule->call(fn () => '')->everyMinute();
$closureLineNumber = __LINE__ - 1;
$closureFilePath = __FILE__;

$this->artisan(ScheduleListCommand::class)
->assertSuccessful()
->expectsOutput(' 0 0 1 1-12/3 * php artisan foo:command .... Next Due: 3 months from now')
->expectsOutput(' 0 14,18 * * * php artisan inspire ........ Next Due: 14 hours from now')
->expectsOutput(' * * * * * php artisan foobar a='.ProcessUtils::escapeArgument('b').' ... Next Due: 1 minute from now')
->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now')
->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now')
->expectsOutput(' 0 10 * * * php artisan inspire ........ Next Due: 10 hours from now')
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now')
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now')
->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now');
}

public function testDisplayScheduleWithSort()
{
$this->schedule->command(FooCommand::class)->quarterly();
$this->schedule->command('inspire')->twiceDaily(14, 18);
$this->schedule->command('foobar', ['a' => 'b'])->everyMinute();
$this->schedule->job(FooJob::class)->everyMinute();
$this->schedule->command('inspire')->cron('0 9,17 * * *');
$this->schedule->command('inspire')->cron("0 10\t* * *");
$this->schedule->call(FooCall::class)->everyMinute();
$this->schedule->call([FooCall::class, 'fooFunction'])->everyMinute();

$this->schedule->call(fn () => '')->everyMinute();
$closureLineNumber = __LINE__ - 1;
$closureFilePath = __FILE__;

$this->artisan(ScheduleListCommand::class, ['--next' => true])
->assertSuccessful()
->expectsOutput(' * * * * * php artisan foobar a='.ProcessUtils::escapeArgument('b').' ... Next Due: 1 minute from now')
->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now')
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now')
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now')
->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now')
->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now')
->expectsOutput(' 0 10 * * * php artisan inspire ........ Next Due: 10 hours from now')
->expectsOutput(' 0 14,18 * * * php artisan inspire ........ Next Due: 14 hours from now')
->expectsOutput(' 0 0 1 1-12/3 * php artisan foo:command .... Next Due: 3 months from now');
}

public function testDisplayScheduleInVerboseMode()
{
$this->schedule->command(FooCommand::class)->everyMinute();

$this->artisan(ScheduleListCommand::class, ['-v' => true])
->assertSuccessful()
->expectsOutputToContain('Next Due: '.now()->setMinutes(1)->format('Y-m-d H:i:s P'))
->expectsOutput(' ⇁ This is the description of the command.');
}

protected function tearDown(): void
{
putenv('SHELL_VERBOSITY');

parent::tearDown();
}
}

class FooCommand extends Command
{
protected $signature = 'foo:command';

protected $description = 'This is the description of the command.';
}

class FooJob
{
}

class FooParamJob
{
public function __construct($param)
{
}
}

class FooCall
{
public function __invoke(): void
{
}

public function fooFunction(): void
{
}
}
102 changes: 102 additions & 0 deletions tests/Scheduling/ScheduleTestCommandTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace Winter\Storm\Tests\Scheduling;

use Illuminate\Console\Application;
use Illuminate\Console\Command;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Console\Scheduling\ScheduleTestCommand;
use Illuminate\Support\Carbon;
use Winter\Storm\Tests\TestCase;

class ScheduleTestCommandTest extends TestCase
{
public $schedule;

protected function setUp(): void
{
parent::setUp();

Carbon::setTestNow(now()->startOfYear());

$this->schedule = $this->app->make(Schedule::class);
}

public function testRunNoDefinedCommands()
{
$this->artisan(ScheduleTestCommand::class)
->assertSuccessful()
->expectsOutputToContain('No scheduled commands have been defined.');
}

public function testRunNoMatchingCommand()
{
$this->schedule->command(BarCommandStub::class);

$this->artisan(ScheduleTestCommand::class, ['--name' => 'missing:command'])
->assertSuccessful()
->expectsOutputToContain('No matching scheduled command found.');
}

public function testRunUsingNameOption()
{
$this->schedule->command(BarCommandStub::class)->name('bar-command');
$this->schedule->job(BarJobStub::class);
$this->schedule->call(fn () => true)->name('callback');

$expectedOutput = windows_os()
? 'Running ["artisan" bar:command]'
: "Running ['artisan' bar:command]";

$this->artisan(ScheduleTestCommand::class, ['--name' => 'bar:command'])
->assertSuccessful()
->expectsOutputToContain($expectedOutput);

$this->artisan(ScheduleTestCommand::class, ['--name' => BarJobStub::class])
->assertSuccessful()
->expectsOutputToContain(sprintf('Running [%s]', BarJobStub::class));

$this->artisan(ScheduleTestCommand::class, ['--name' => 'callback'])
->assertSuccessful()
->expectsOutputToContain('Running [callback]');
}

public function testRunUsingChoices()
{
$this->schedule->command(BarCommandStub::class)->name('bar-command');
$this->schedule->job(BarJobStub::class);
$this->schedule->call(fn () => true)->name('callback');

$this->artisan(ScheduleTestCommand::class)
->assertSuccessful()
->expectsChoice(
'Which command would you like to run?',
'callback',
[Application::formatCommandString('bar:command'), BarJobStub::class, 'callback'],
true
)
->expectsOutputToContain('Running [callback]');
}

protected function tearDown(): void
{
parent::tearDown();

Carbon::setTestNow(null);
}
}

class BarCommandStub extends Command
{
protected $signature = 'bar:command';

protected $description = 'This is the description of the command.';
}

class BarJobStub
{
public function __invoke()
{
// ..
}
}
Loading