@@ -39,57 +39,27 @@ public static function setUpBeforeClass(): void
3939 }
4040
4141 self ::flushRedis ();
42-
43- if ($ currentSuite !== 'feature ' ) {
44- return ;
45- }
46-
47- // The first feature test's migrate:fresh runs before setUp() can write
48- // the Cache facade throttle keys, so prime Redis directly before the
49- // background queue workers start polling.
50- self ::primeWatchdogThrottle ();
51-
52- // Explicitly hand our env to Process. testbench/laravel/.env hardcodes
53- // CACHE_DRIVER=file; without an inherited env (or when Symfony Process
54- // ignores the parent's env on some runners) the worker bootstraps its
55- // own file-backed cache and cannot see the LOOP_THROTTLE_KEY the test
56- // process writes to redis — original CI shape under #427. Merging
57- // $_ENV + $_SERVER + getenv() rather than relying on Process's
58- // default null-env inherit covers every environment variable source
59- // GitHub Actions, Orchestra, and the loaded .env.feature might have
60- // populated by this point.
61- $ workerEnv = array_merge (array_filter ($ _SERVER , 'is_string ' ), array_filter ($ _ENV , 'is_string ' ));
62-
63- for ($ i = 0 ; $ i < self ::NUMBER_OF_WORKERS ; $ i ++) {
64- self ::$ workers [$ i ] = new Process (
65- ['php ' , __DIR__ . '/../vendor/bin/testbench ' , 'queue:work ' ],
66- null ,
67- $ workerEnv ,
68- );
69- self ::$ workers [$ i ]->disableOutput ();
70- self ::$ workers [$ i ]->start ();
71- }
7242 }
7343
7444 public static function tearDownAfterClass (): void
7545 {
76- foreach (self ::$ workers as $ worker ) {
77- $ worker ->stop ();
78- }
79-
80- self ::$ workers = [];
81-
46+ self ::stopWorkers ();
8247 self ::flushRedis ();
8348 }
8449
8550 protected function setUp (): void
8651 {
87- if (TestSuiteSubscriber::getCurrentSuite () === 'feature ' ) {
52+ $ currentSuite = TestSuiteSubscriber::getCurrentSuite ();
53+
54+ if ($ currentSuite === 'feature ' ) {
8855 Dotenv::createImmutable (__DIR__ , '.env.feature ' )->safeLoad ();
89- } elseif (TestSuiteSubscriber:: getCurrentSuite () === 'unit ' ) {
56+ } elseif ($ currentSuite === 'unit ' ) {
9057 Dotenv::createImmutable (__DIR__ , '.env.unit ' )->safeLoad ();
9158 }
9259
60+ self ::stopWorkers ();
61+ self ::flushRedis ();
62+
9363 parent ::setUp ();
9464
9565 Queue::swap ($ this ->app ->make ('queue ' ));
@@ -98,10 +68,10 @@ protected function setUp(): void
9868
9969 self ::flushRedis ();
10070
101- if (TestSuiteSubscriber:: getCurrentSuite () === 'feature ' ) {
71+ if ($ currentSuite === 'feature ' ) {
10272 // Block BOTH the V2 TaskWatchdog and the V1 Watchdog for the
10373 // duration of every feature test. The two testbench queue
104- // workers spawned in setUpBeforeClass run both wake()s on every
74+ // workers spawned after the per-test migration run both wake()s on every
10575 // Looping event in separate PHP processes.
10676 //
10777 // V2: almost every V2 feature test uses Queue::fake() with
@@ -128,6 +98,18 @@ protected function setUp(): void
12898 // key and calls runPass(respectThrottle: false) directly.
12999 Cache::put (TaskWatchdog::LOOP_THROTTLE_KEY , true , self ::WATCHDOG_THROTTLE_TTL_SECONDS );
130100 Cache::put (self ::V1_WATCHDOG_LOOP_THROTTLE_KEY , true , self ::WATCHDOG_THROTTLE_TTL_SECONDS );
101+ self ::primeWatchdogThrottle ();
102+ self ::startWorkers ();
103+ }
104+ }
105+
106+ protected function tearDown (): void
107+ {
108+ try {
109+ self ::stopWorkers ();
110+ self ::flushRedis ();
111+ } finally {
112+ parent ::tearDown ();
131113 }
132114 }
133115
@@ -170,6 +152,39 @@ private static function normalizeJsonObject(array $value): array
170152 return $ normalized ;
171153 }
172154
155+ private static function startWorkers (): void
156+ {
157+ if (self ::$ workers !== []) {
158+ return ;
159+ }
160+
161+ $ environment = getenv ();
162+ $ workerEnv = array_merge (
163+ is_array ($ environment ) ? array_filter ($ environment , 'is_string ' ) : [],
164+ array_filter ($ _SERVER , 'is_string ' ),
165+ array_filter ($ _ENV , 'is_string ' ),
166+ );
167+
168+ for ($ i = 0 ; $ i < self ::NUMBER_OF_WORKERS ; $ i ++) {
169+ self ::$ workers [$ i ] = new Process (
170+ ['php ' , __DIR__ . '/../vendor/bin/testbench ' , 'queue:work ' ],
171+ null ,
172+ $ workerEnv ,
173+ );
174+ self ::$ workers [$ i ]->disableOutput ();
175+ self ::$ workers [$ i ]->start ();
176+ }
177+ }
178+
179+ private static function stopWorkers (): void
180+ {
181+ foreach (self ::$ workers as $ worker ) {
182+ $ worker ->stop (3 );
183+ }
184+
185+ self ::$ workers = [];
186+ }
187+
173188 private static function flushRedis (): void
174189 {
175190 $ redis = self ::redisConnection ();
0 commit comments