Skip to content

Commit 637a4a6

Browse files
damsfxLukeTowers
andauthored
Register schedule commands (#218)
Co-authored-by: Luke Towers <[email protected]>
1 parent bff7a4e commit 637a4a6

File tree

3 files changed

+243
-4
lines changed

3 files changed

+243
-4
lines changed

src/Foundation/Providers/ArtisanServiceProvider.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
<?php namespace Winter\Storm\Foundation\Providers;
1+
<?php
2+
3+
namespace Winter\Storm\Foundation\Providers;
24

35
use Winter\Storm\Foundation\Console\KeyGenerateCommand;
46
use Winter\Storm\Foundation\Console\ClearCompiledCommand;
@@ -41,7 +43,10 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase
4143
'RouteClear' => \Illuminate\Foundation\Console\RouteClearCommand::class,
4244
'RouteList' => \Illuminate\Foundation\Console\RouteListCommand::class,
4345
'ScheduleFinish' => \Illuminate\Console\Scheduling\ScheduleFinishCommand::class,
46+
'ScheduleList' => \Illuminate\Console\Scheduling\ScheduleListCommand::class,
4447
'ScheduleRun' => \Illuminate\Console\Scheduling\ScheduleRunCommand::class,
48+
'ScheduleTest' => \Illuminate\Console\Scheduling\ScheduleTestCommand::class,
49+
'ScheduleWork' => \Illuminate\Console\Scheduling\ScheduleWorkCommand::class,
4550
'Up' => \Illuminate\Foundation\Console\UpCommand::class,
4651
'ViewClear' => \Illuminate\Foundation\Console\ViewClearCommand::class,
4752

@@ -54,10 +59,7 @@ class ArtisanServiceProvider extends ArtisanServiceProviderBase
5459
// 'OptimizeClear' => OptimizeClearCommand::class,
5560
// 'QueueClear' => QueueClearCommand::class,
5661
// 'SchemaDump' => DumpCommand::class,
57-
// 'ScheduleList' => \Illuminate\Console\Scheduling\ScheduleListCommand::class,
5862
// 'ScheduleClearCache' => ScheduleClearCacheCommand::class,
59-
// 'ScheduleTest' => ScheduleTestCommand::class,
60-
// 'ScheduleWork' => ScheduleWorkCommand::class,
6163
// 'ViewCache' => ViewCacheCommand::class,
6264

6365
// Explicitly unsupported in Winter:
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
<?php
2+
3+
namespace Winter\Storm\Tests\Scheduling;
4+
5+
use Illuminate\Console\Command;
6+
use Illuminate\Console\Scheduling\Schedule;
7+
use Illuminate\Console\Scheduling\ScheduleListCommand;
8+
use Illuminate\Support\Carbon;
9+
use Illuminate\Support\ProcessUtils;
10+
11+
use Winter\Storm\Tests\TestCase;
12+
13+
class ScheduleListCommandTest extends TestCase
14+
{
15+
public $schedule;
16+
17+
protected function setUp(): void
18+
{
19+
parent::setUp();
20+
21+
Carbon::setTestNow('2023-01-01');
22+
ScheduleListCommand::resolveTerminalWidthUsing(fn () => 80);
23+
24+
$this->schedule = $this->app->make(Schedule::class);
25+
}
26+
27+
public function testDisplayEmptySchedule()
28+
{
29+
$this->artisan(ScheduleListCommand::class)
30+
->assertSuccessful()
31+
->expectsOutputToContain('No scheduled tasks have been defined.');
32+
}
33+
34+
public function testDisplaySchedule()
35+
{
36+
$this->schedule->command(FooCommand::class)->quarterly();
37+
$this->schedule->command('inspire')->twiceDaily(14, 18);
38+
$this->schedule->command('foobar', ['a' => 'b'])->everyMinute();
39+
$this->schedule->job(FooJob::class)->everyMinute();
40+
$this->schedule->command('inspire')->cron('0 9,17 * * *');
41+
$this->schedule->command('inspire')->cron("0 10\t* * *");
42+
$this->schedule->call(FooCall::class)->everyMinute();
43+
$this->schedule->call([FooCall::class, 'fooFunction'])->everyMinute();
44+
45+
$this->schedule->call(fn () => '')->everyMinute();
46+
$closureLineNumber = __LINE__ - 1;
47+
$closureFilePath = __FILE__;
48+
49+
$this->artisan(ScheduleListCommand::class)
50+
->assertSuccessful()
51+
->expectsOutput(' 0 0 1 1-12/3 * php artisan foo:command .... Next Due: 3 months from now')
52+
->expectsOutput(' 0 14,18 * * * php artisan inspire ........ Next Due: 14 hours from now')
53+
->expectsOutput(' * * * * * php artisan foobar a='.ProcessUtils::escapeArgument('b').' ... Next Due: 1 minute from now')
54+
->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now')
55+
->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now')
56+
->expectsOutput(' 0 10 * * * php artisan inspire ........ Next Due: 10 hours from now')
57+
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now')
58+
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now')
59+
->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now');
60+
}
61+
62+
public function testDisplayScheduleWithSort()
63+
{
64+
$this->schedule->command(FooCommand::class)->quarterly();
65+
$this->schedule->command('inspire')->twiceDaily(14, 18);
66+
$this->schedule->command('foobar', ['a' => 'b'])->everyMinute();
67+
$this->schedule->job(FooJob::class)->everyMinute();
68+
$this->schedule->command('inspire')->cron('0 9,17 * * *');
69+
$this->schedule->command('inspire')->cron("0 10\t* * *");
70+
$this->schedule->call(FooCall::class)->everyMinute();
71+
$this->schedule->call([FooCall::class, 'fooFunction'])->everyMinute();
72+
73+
$this->schedule->call(fn () => '')->everyMinute();
74+
$closureLineNumber = __LINE__ - 1;
75+
$closureFilePath = __FILE__;
76+
77+
$this->artisan(ScheduleListCommand::class, ['--next' => true])
78+
->assertSuccessful()
79+
->expectsOutput(' * * * * * php artisan foobar a='.ProcessUtils::escapeArgument('b').' ... Next Due: 1 minute from now')
80+
->expectsOutput(' * * * * * Winter\Storm\Tests\Scheduling\FooJob Next Due: 1 minute from now')
81+
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall Next Due: 1 minute from now')
82+
->expectsOutput(' * * * * * Closure at: Winter\Storm\Tests\Scheduling\FooCall::fooFunction Next Due: 1 minute from now')
83+
->expectsOutput(' * * * * * Closure at: '.$closureFilePath.':'.$closureLineNumber.' Next Due: 1 minute from now')
84+
->expectsOutput(' 0 9,17 * * * php artisan inspire ......... Next Due: 9 hours from now')
85+
->expectsOutput(' 0 10 * * * php artisan inspire ........ Next Due: 10 hours from now')
86+
->expectsOutput(' 0 14,18 * * * php artisan inspire ........ Next Due: 14 hours from now')
87+
->expectsOutput(' 0 0 1 1-12/3 * php artisan foo:command .... Next Due: 3 months from now');
88+
}
89+
90+
public function testDisplayScheduleInVerboseMode()
91+
{
92+
$this->schedule->command(FooCommand::class)->everyMinute();
93+
94+
$this->artisan(ScheduleListCommand::class, ['-v' => true])
95+
->assertSuccessful()
96+
->expectsOutputToContain('Next Due: '.now()->setMinutes(1)->format('Y-m-d H:i:s P'))
97+
->expectsOutput(' ⇁ This is the description of the command.');
98+
}
99+
100+
protected function tearDown(): void
101+
{
102+
putenv('SHELL_VERBOSITY');
103+
104+
parent::tearDown();
105+
}
106+
}
107+
108+
class FooCommand extends Command
109+
{
110+
protected $signature = 'foo:command';
111+
112+
protected $description = 'This is the description of the command.';
113+
}
114+
115+
class FooJob
116+
{
117+
}
118+
119+
class FooParamJob
120+
{
121+
public function __construct($param)
122+
{
123+
}
124+
}
125+
126+
class FooCall
127+
{
128+
public function __invoke(): void
129+
{
130+
}
131+
132+
public function fooFunction(): void
133+
{
134+
}
135+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
<?php
2+
3+
namespace Winter\Storm\Tests\Scheduling;
4+
5+
use Illuminate\Console\Application;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Console\Scheduling\Schedule;
8+
use Illuminate\Console\Scheduling\ScheduleTestCommand;
9+
use Illuminate\Support\Carbon;
10+
use Winter\Storm\Tests\TestCase;
11+
12+
class ScheduleTestCommandTest extends TestCase
13+
{
14+
public $schedule;
15+
16+
protected function setUp(): void
17+
{
18+
parent::setUp();
19+
20+
Carbon::setTestNow(now()->startOfYear());
21+
22+
$this->schedule = $this->app->make(Schedule::class);
23+
}
24+
25+
public function testRunNoDefinedCommands()
26+
{
27+
$this->artisan(ScheduleTestCommand::class)
28+
->assertSuccessful()
29+
->expectsOutputToContain('No scheduled commands have been defined.');
30+
}
31+
32+
public function testRunNoMatchingCommand()
33+
{
34+
$this->schedule->command(BarCommandStub::class);
35+
36+
$this->artisan(ScheduleTestCommand::class, ['--name' => 'missing:command'])
37+
->assertSuccessful()
38+
->expectsOutputToContain('No matching scheduled command found.');
39+
}
40+
41+
public function testRunUsingNameOption()
42+
{
43+
$this->schedule->command(BarCommandStub::class)->name('bar-command');
44+
$this->schedule->job(BarJobStub::class);
45+
$this->schedule->call(fn () => true)->name('callback');
46+
47+
$expectedOutput = windows_os()
48+
? 'Running ["artisan" bar:command]'
49+
: "Running ['artisan' bar:command]";
50+
51+
$this->artisan(ScheduleTestCommand::class, ['--name' => 'bar:command'])
52+
->assertSuccessful()
53+
->expectsOutputToContain($expectedOutput);
54+
55+
$this->artisan(ScheduleTestCommand::class, ['--name' => BarJobStub::class])
56+
->assertSuccessful()
57+
->expectsOutputToContain(sprintf('Running [%s]', BarJobStub::class));
58+
59+
$this->artisan(ScheduleTestCommand::class, ['--name' => 'callback'])
60+
->assertSuccessful()
61+
->expectsOutputToContain('Running [callback]');
62+
}
63+
64+
public function testRunUsingChoices()
65+
{
66+
$this->schedule->command(BarCommandStub::class)->name('bar-command');
67+
$this->schedule->job(BarJobStub::class);
68+
$this->schedule->call(fn () => true)->name('callback');
69+
70+
$this->artisan(ScheduleTestCommand::class)
71+
->assertSuccessful()
72+
->expectsChoice(
73+
'Which command would you like to run?',
74+
'callback',
75+
[Application::formatCommandString('bar:command'), BarJobStub::class, 'callback'],
76+
true
77+
)
78+
->expectsOutputToContain('Running [callback]');
79+
}
80+
81+
protected function tearDown(): void
82+
{
83+
parent::tearDown();
84+
85+
Carbon::setTestNow(null);
86+
}
87+
}
88+
89+
class BarCommandStub extends Command
90+
{
91+
protected $signature = 'bar:command';
92+
93+
protected $description = 'This is the description of the command.';
94+
}
95+
96+
class BarJobStub
97+
{
98+
public function __invoke()
99+
{
100+
// ..
101+
}
102+
}

0 commit comments

Comments
 (0)