Skip to content

Commit 7796b9b

Browse files
authored
[12.x] Fix prevent group attribute pollution in schedule (#56677)
* fix: prevent group attribute pollution in schedule Use clone to ensure group attributes are isolated and not affected by reference issues. Fixes: #56497 * test: add grouped schedule execution tests with time-based scenarios
1 parent ab76a52 commit 7796b9b

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

src/Illuminate/Console/Scheduling/Schedule.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ public function group(Closure $events)
312312
throw new RuntimeException('Invoke an attribute method such as Schedule::daily() before defining a schedule group.');
313313
}
314314

315-
$this->groupStack[] = $this->attributes;
315+
$this->groupStack[] = clone $this->attributes;
316316

317317
$events($this);
318318

tests/Integration/Console/Scheduling/ScheduleGroupTest.php

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Illuminate\Tests\Integration\Console\Scheduling;
66

77
use Illuminate\Console\Scheduling\Schedule as ScheduleClass;
8+
use Illuminate\Support\Carbon;
89
use Illuminate\Support\Facades\Schedule;
910
use Orchestra\Testbench\TestCase;
1011
use PHPUnit\Framework\Attributes\DataProvider;
@@ -117,4 +118,66 @@ public static function groupAttributes(): array
117118
'withoutOverlapping' => ['withoutOverlapping', rand(1000, 1400)],
118119
];
119120
}
121+
122+
#[DataProvider('scheduleTestCases')]
123+
public function testGroupedScheduleExecution($time, $expected, $description)
124+
{
125+
Carbon::setTestNow($time);
126+
$app = app();
127+
128+
Schedule::days([1, 2, 3, 4, 5, 6])->group(function () {
129+
Schedule::between('07:00', '08:00')->group(function () {
130+
Schedule::call(fn () => 'Task 1')->everyMinute();
131+
Schedule::call(fn () => 'Task 2')->everyFiveMinutes();
132+
});
133+
134+
Schedule::call(fn () => 'Task 3')->at('08:05');
135+
});
136+
137+
$events = Schedule::events();
138+
139+
foreach (array_keys($expected) as $index => $task) {
140+
$this->assertTaskExecution(
141+
$events[$index],
142+
$app,
143+
$expected[$task],
144+
"[$description] $task should ".($expected[$task] ? 'run' : 'not run')
145+
);
146+
}
147+
148+
Carbon::setTestNow();
149+
}
150+
151+
private function assertTaskExecution($event, $app, $expected, $message): void
152+
{
153+
$this->assertSame(
154+
$expected,
155+
$event->filtersPass($app) && $event->isDue($app),
156+
$message
157+
);
158+
}
159+
160+
public static function scheduleTestCases()
161+
{
162+
return [
163+
[
164+
Carbon::create(2024, 1, 1, 7, 30),
165+
[
166+
'Task 1' => true,
167+
'Task 2' => true,
168+
'Task 3' => false,
169+
],
170+
'Tasks at 07:30',
171+
],
172+
[
173+
Carbon::create(2024, 1, 1, 8, 5),
174+
[
175+
'Task 1' => false,
176+
'Task 2' => false,
177+
'Task 3' => true,
178+
],
179+
'Tasks at 08:05',
180+
],
181+
];
182+
}
120183
}

0 commit comments

Comments
 (0)