1717use CodeIgniter \Queue \Entities \QueueJob ;
1818use CodeIgniter \Queue \Handlers \RabbitMQHandler ;
1919use CodeIgniter \Queue \QueuePushResult ;
20+ use CodeIgniter \Test \ReflectionHelper ;
2021use PhpAmqpLib \Connection \AMQPConnectionFactory ;
2122use Tests \Support \Config \Queue as QueueConfig ;
2223use Tests \Support \TestCase ;
2930 */
3031final class RabbitMQDelayTest extends TestCase
3132{
33+ use ReflectionHelper;
34+
3235 private ?RabbitMQHandler $ handler = null ;
36+ private string $ queue ;
3337
3438 protected function setUp (): void
3539 {
3640 parent ::setUp ();
3741
38- $ config = config (QueueConfig::class);
42+ $ config = config (QueueConfig::class);
43+ $ this ->queue = 'delay-test-queue- ' . bin2hex (random_bytes (6 ));
3944
4045 // Skip tests if RabbitMQ is not available
4146 if (! $ this ->isRabbitMQAvailable ()) {
@@ -52,9 +57,8 @@ protected function setUp(): void
5257 protected function tearDown (): void
5358 {
5459 if ($ this ->handler !== null ) {
55- // Clear test queues
5660 try {
57- $ this ->handler -> clear ( ' delay-test-queue ' );
61+ $ this ->deleteDeclaredResources ( );
5862 } catch (Throwable ) {
5963 // Ignore cleanup errors
6064 }
@@ -70,31 +74,31 @@ public function testDelayedMessageWithRealTiming(): void
7074 $ startTime = time ();
7175
7276 // Push a delayed job
73- $ result = $ this ->handler ->setDelay ($ delaySeconds )->push (' delay-test- queue' , 'success ' , ['type ' => 'delayed ' ]);
77+ $ result = $ this ->handler ->setDelay ($ delaySeconds )->push ($ this -> queue , 'success ' , ['type ' => 'delayed ' ]);
7478 $ this ->assertInstanceOf (QueuePushResult::class, $ result );
7579 $ this ->assertTrue ($ result ->getStatus ());
7680
7781 // Push an immediate job
78- $ result = $ this ->handler ->push (' delay-test- queue' , 'success ' , ['type ' => 'immediate ' ]);
82+ $ result = $ this ->handler ->push ($ this -> queue , 'success ' , ['type ' => 'immediate ' ]);
7983 $ this ->assertInstanceOf (QueuePushResult::class, $ result );
8084 $ this ->assertTrue ($ result ->getStatus ());
8185
8286 // Should get immediate job first
83- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
87+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
8488 $ this ->assertInstanceOf (QueueJob::class, $ job );
8589 $ this ->assertSame ('immediate ' , $ job ->payload ['data ' ]['type ' ]);
8690 $ this ->handler ->done ($ job );
8791
8892 // Should not get delayed job yet (within first second)
89- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
93+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
9094 $ this ->assertNull ($ job );
9195
9296 // Wait for delay to expire (with a small buffer)
9397 $ waitTime = $ delaySeconds + 1 ;
9498 sleep ($ waitTime );
9599
96100 // Should now get the delayed job
97- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
101+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
98102 $ this ->assertInstanceOf (QueueJob::class, $ job );
99103 $ this ->assertSame ('delayed ' , $ job ->payload ['data ' ]['type ' ]);
100104
@@ -108,35 +112,32 @@ public function testDelayedMessageWithRealTiming(): void
108112
109113 public function testMultipleDelayedJobsWithDifferentDelays (): void
110114 {
111- // Push jobs with different delays
112- $ result1 = $ this ->handler ->setDelay (1 )->push ('delay-test-queue ' , 'success ' , ['order ' => 'first ' , 'delay ' => 1 ]);
113- $ result2 = $ this ->handler ->setDelay (3 )->push ('delay-test-queue ' , 'success ' , ['order ' => 'second ' , 'delay ' => 3 ]);
114- $ result3 = $ this ->handler ->push ('delay-test-queue ' , 'success ' , ['order ' => 'immediate ' , 'delay ' => 0 ]);
115+ // Push the immediate job first so slow test setup cannot allow a
116+ // delayed job to reach the main queue ahead of it.
117+ $ result1 = $ this ->handler ->push ($ this ->queue , 'success ' , ['order ' => 'immediate ' , 'delay ' => 0 ]);
118+ $ result2 = $ this ->handler ->setDelay (1 )->push ($ this ->queue , 'success ' , ['order ' => 'first ' , 'delay ' => 1 ]);
119+ $ result3 = $ this ->handler ->setDelay (3 )->push ($ this ->queue , 'success ' , ['order ' => 'second ' , 'delay ' => 3 ]);
115120
116121 $ this ->assertTrue ($ result1 ->getStatus ());
117122 $ this ->assertTrue ($ result2 ->getStatus ());
118123 $ this ->assertTrue ($ result3 ->getStatus ());
119124
120125 // Should get immediate job first
121- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
126+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
122127 $ this ->assertInstanceOf (QueueJob::class, $ job );
123128 $ this ->assertSame ('immediate ' , $ job ->payload ['data ' ]['order ' ]);
124129 $ this ->handler ->done ($ job );
125130
126131 // Wait 2 seconds - should get first delayed job
127132 sleep (2 );
128- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
133+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
129134 $ this ->assertInstanceOf (QueueJob::class, $ job );
130135 $ this ->assertSame ('first ' , $ job ->payload ['data ' ]['order ' ]);
131136 $ this ->handler ->done ($ job );
132137
133- // Should not get second job yet
134- $ job = $ this ->handler ->pop ('delay-test-queue ' , ['default ' ]);
135- $ this ->assertNull ($ job );
136-
137138 // Wait another 2 seconds - should get second delayed job
138139 sleep (2 );
139- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
140+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
140141 $ this ->assertInstanceOf (QueueJob::class, $ job );
141142 $ this ->assertSame ('second ' , $ job ->payload ['data ' ]['order ' ]);
142143 $ this ->handler ->done ($ job );
@@ -145,22 +146,51 @@ public function testMultipleDelayedJobsWithDifferentDelays(): void
145146 public function testZeroDelayWorksImmediately (): void
146147 {
147148 // Jobs with 0 delay should work immediately
148- $ result = $ this ->handler ->setDelay (0 )->push (' delay-test- queue' , 'success ' , ['type ' => 'zero-delay ' ]);
149+ $ result = $ this ->handler ->setDelay (0 )->push ($ this -> queue , 'success ' , ['type ' => 'zero-delay ' ]);
149150 $ this ->assertTrue ($ result ->getStatus ());
150151
151152 // Should be able to pop immediately
152- $ job = $ this ->handler ->pop (' delay-test- queue' , ['default ' ]);
153+ $ job = $ this ->handler ->pop ($ this -> queue , ['default ' ]);
153154 $ this ->assertInstanceOf (QueueJob::class, $ job );
154155 $ this ->assertSame ('zero-delay ' , $ job ->payload ['data ' ]['type ' ]);
155156
156157 $ this ->handler ->done ($ job );
157158 }
158159
160+ public function testFreshHandlerClearsImmediateAndDelayedJobs (): void
161+ {
162+ $ delayedResult = $ this ->handler ->setDelay (1 )->push ($ this ->queue , 'success ' , ['type ' => 'delayed ' ]);
163+ $ this ->assertTrue ($ delayedResult ->getStatus ());
164+
165+ $ immediateResult = $ this ->handler ->push ($ this ->queue , 'success ' , ['type ' => 'immediate ' ]);
166+ $ this ->assertTrue ($ immediateResult ->getStatus ());
167+
168+ $ clearer = new RabbitMQHandler (config (QueueConfig::class));
169+ $ this ->assertTrue ($ clearer ->clear ($ this ->queue ));
170+
171+ sleep (2 );
172+
173+ $ this ->assertNull ($ clearer ->pop ($ this ->queue , ['default ' ]));
174+ }
175+
159176 /**
160177 * Check if RabbitMQ is available for testing.
161178 */
162179 private function isRabbitMQAvailable (): bool
163180 {
164181 return class_exists (AMQPConnectionFactory::class);
165182 }
183+
184+ private function deleteDeclaredResources (): void
185+ {
186+ $ channel = self ::getPrivateProperty ($ this ->handler , 'channel ' );
187+
188+ foreach (array_keys (self ::getPrivateProperty ($ this ->handler , 'declaredQueues ' )) as $ queue ) {
189+ $ channel ->queue_delete ($ queue );
190+ }
191+
192+ foreach (array_keys (self ::getPrivateProperty ($ this ->handler , 'declaredExchanges ' )) as $ exchange ) {
193+ $ channel ->exchange_delete ($ exchange );
194+ }
195+ }
166196}
0 commit comments