Completed
Push — master ( e56856...67d12b )
by Antonio
04:26
created

RedisQueueStoreAdapterTest::testEnqueDequeueWithDelay()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 45
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 45
rs 8.8571
cc 1
eloc 37
nc 1
nop 0
1
<?php
2
namespace Da\Mailer\Test\Queue\Backend\Redis;
3
4
use Da\Mailer\Model\MailMessage;
5
use Da\Mailer\Queue\Backend\Redis\RedisQueueStoreAdapter;
6
use Da\Mailer\Queue\Backend\Redis\RedisQueueStoreConnection;
7
use Da\Mailer\Test\Fixture\FixtureHelper;
8
use PHPUnit_Framework_TestCase;
9
use Mockery;
10
11
class RedisQueueStoreAdapterTest extends PHPUnit_Framework_TestCase
12
{
13
    private $mailJob;
14
    private $payload;
15
16
    protected function setUp()
17
    {
18
        parent::setUp();
19
        $this->mailJob = FixtureHelper::getRedisMailJob();
20
        $this->payload = json_encode([
21
            'id' => '123456789',
22
            'attempt' => $this->mailJob->getAttempt(),
23
            'message' => $this->mailJob->getMessage()
24
        ]);
25
    }
26
27
    public function testEnqueueDequeueAndAcknowledge()
28
    {
29
        $payload = $this->payload;
30
        $redisClient = Mockery::mock('\Predis\Client')
31
            ->shouldReceive('zadd')
32
                ->andReturn(1)
33
            ->shouldReceive('rpush')
34
                ->andReturn(1)
35
            ->shouldReceive('llen')
36
                ->twice()
37
                ->andReturnUsing(
38
                    function (){
39
                        static $f = false;
40
                        return $f = !$f ? 1 : 0;
41
                    }
42
                )
43
            ->shouldReceive('zrem')
44
            ->andReturn(1)
45
            ->shouldReceive('lpop')
46
            ->with(Mockery::mustBe('mail_queue'))
47
            ->andReturnUsing(function() use ($payload) {
48
                static $f = false;
49
                return $f = !$f ? $payload : null;
50
            })
51
            ->shouldReceive('transaction')
52
            ->andReturn(1)
53
            ->getMock();
54
55
        $redisStoreConnection = Mockery::mock('\Da\Mailer\Queue\Backend\Redis\RedisQueueStoreConnection')
56
            ->shouldReceive('connect')
57
            ->andReturnSelf()
58
            ->shouldReceive('getInstance')
59
            ->andReturn($redisClient)
60
            ->getMock();
61
62
        $redisQueueStore = new RedisQueueStoreAdapter($redisStoreConnection);
63
64
        $this->assertSame($redisQueueStore, $redisQueueStore->init());
65
        $this->assertTrue($redisQueueStore->enqueue($this->mailJob) === 1);
66
67
        $this->assertTrue($redisQueueStore->isEmpty() === false);
68
69
        $mailJob = $redisQueueStore->dequeue();
70
71
        $this->assertTrue($redisQueueStore->isEmpty() === true);
72
73
        $this->assertTrue(!empty($mailJob->getMessage()));
74
75
        $dequeuedMailMessage = MailMessage::fromArray(json_decode($mailJob->getMessage(), true));
76
77
        $this->assertEquals(FixtureHelper::getMailMessage(), $dequeuedMailMessage);
78
79
        $mailJob->markAsCompleted();
80
        $redisQueueStore->ack($mailJob);
81
82
        $this->assertTrue($redisQueueStore->dequeue() === null);
83
    }
84
85
    public function testEnqueDequeueWithDelay()
86
    {
87
        $time = time() + 2;
88
89
        $redisClient = Mockery::mock('\Predis\Client')
90
            ->shouldReceive('zadd')
91
            ->with('mail_queue:delayed', $time)
92
            ->twice()
93
            ->withAnyArgs()
94
            ->andReturn(1)
95
            ->shouldReceive('rpush')
96
            ->andReturn(1)
97
            ->shouldReceive('llen')
98
            ->once()
99
            ->andReturn(0)
100
            ->shouldReceive('lpop')
101
            ->with(Mockery::mustBe('mail_queue'))
102
            ->andReturn($this->payload)
103
            ->shouldReceive('zrem')
104
            ->with('mail_queue:reserved', $this->payload)
105
            ->shouldReceive('transaction')
106
            ->andReturn(1)
107
            ->getMock();
108
109
        $redisStoreConnection = Mockery::mock('\Da\Mailer\Queue\Backend\Redis\RedisQueueStoreConnection')
110
            ->shouldReceive('connect')
111
            ->andReturnSelf()
112
            ->shouldReceive('getInstance')
113
            ->andReturn($redisClient)
114
            ->getMock();
115
116
        $redisQueueStore = new RedisQueueStoreAdapter($redisStoreConnection);
117
118
        $mailJob = $this->mailJob;
119
        $mailJob->setTimeToSend($time);
120
        $this->assertTrue($redisQueueStore->enqueue($mailJob) === 1);
121
        $this->assertTrue($redisQueueStore->isEmpty() === true);
122
        sleep(3); // sleep three seconds to expire in delayed
123
        $mailJob = $redisQueueStore->dequeue(); // now it should have migrated
124
125
        $this->assertTrue(!empty($mailJob->getMessage()));
126
127
        $mailJob->markAsCompleted();
128
        $redisQueueStore->ack($mailJob);
129
    }
130
131
    public function testEnqueDequeueWithPossibleFailure()
132
    {
133
        $time = time() + 2;
134
        $redisClient = Mockery::mock('\Predis\Client')
135
            ->shouldReceive('rpush')
136
            ->once()
137
            ->andReturn(1)
138
            ->shouldReceive('zadd')
139
            ->twice()
140
            ->withAnyArgs()
141
            ->andReturn(1)
142
            ->shouldReceive('llen')
143
            ->twice()
144
            ->andReturnUsing(
145
                function (){
146
                    static $f = false;
147
                    return $f = !$f ? 1 : 0;
148
                }
149
            )
150
            ->shouldReceive('lpop')
151
            ->with('queue')
152
            ->andReturn($this->payload)
153
            ->shouldReceive('zrem')
154
            ->with('queue:reserved', $this->payload)
155
            ->andReturn(1)
156
            ->shouldReceive('transaction')
157
            ->andReturn(1)
158
            ->getMock();
159
160
        $redisStoreConnection = Mockery::mock('\Da\Mailer\Queue\Backend\Redis\RedisQueueStoreConnection')
161
            ->shouldReceive('connect')
162
            ->andReturnSelf()
163
            ->shouldReceive('getInstance')
164
            ->andReturn($redisClient)
165
            ->getMock();
166
167
        $redisQueueStore = new RedisQueueStoreAdapter($redisStoreConnection, 'queue', 2);
168
169
        $mailJob = FixtureHelper::getRedisMailJob();
170
        $this->assertSame($redisQueueStore, $redisQueueStore->init());
171
        $this->assertTrue($redisQueueStore->enqueue($mailJob) === 1);
172
173
        $this->assertTrue($redisQueueStore->isEmpty() === false);
174
175
        $mailJob = $redisQueueStore->dequeue(); // it should be in reserved
176
177
        sleep(3); // lets imagine we have a failure, wait 3 seconds
178
179
        $againMailJob = $redisQueueStore->dequeue(); // it should has come back and placed again in reserved
180
        $this->assertEquals($mailJob, $againMailJob);
181
182
        $mailJob->markAsCompleted();
183
        $redisQueueStore->ack($mailJob); // finish everything
184
185
        $this->assertTrue($redisQueueStore->isEmpty());
186
    }
187
188
    /**
189
     * @expectedException \Da\Mailer\Exception\InvalidCallException
190
     */
191
    public function testBadMethodCallExceptionOnAck()
192
    {
193
        $mailJob = FixtureHelper::getRedisMailJob();
194
        $connection = new RedisQueueStoreConnection([]);
195
        $redisQueueStore = new RedisQueueStoreAdapter($connection);
196
        $redisQueueStore->ack($mailJob);
197
    }
198
199
    public function testNonCompletedAck()
200
    {
201
        $payload = $this->payload;
202
        $redisClient = Mockery::mock('\Predis\Client')
203
            ->shouldReceive('zadd')
204
            ->times(2)
205
            ->andReturn(1)
206
            ->shouldReceive('rpush')
207
            ->andReturn(1)
208
            ->shouldReceive('llen')
209
            ->twice()
210
            ->andReturnUsing(
211
                function (){
212
                    static $f = false;
213
                    return $f = !$f ? 1 : 0;
214
                }
215
            )
216
            ->shouldReceive('zrem')
217
            ->andReturn(1)
218
            ->shouldReceive('lpop')
219
            ->with(Mockery::mustBe('mail_queue'))
220
            ->andReturnUsing(function() use ($payload) {
221
                static $f = false;
222
                return $f = !$f ? $payload : null;
223
            })
224
            ->shouldReceive('transaction')
225
            ->andReturn(1)
226
            ->getMock();
227
228
        $redisStoreConnection = Mockery::mock('\Da\Mailer\Queue\Backend\Redis\RedisQueueStoreConnection')
229
            ->shouldReceive('connect')
230
            ->andReturnSelf()
231
            ->shouldReceive('getInstance')
232
            ->andReturn($redisClient)
233
            ->getMock();
234
235
        $redisQueueStore = new RedisQueueStoreAdapter($redisStoreConnection);
236
237
        $this->assertSame($redisQueueStore, $redisQueueStore->init());
238
        $this->assertTrue($redisQueueStore->enqueue($this->mailJob) === 1);
239
240
        $this->assertTrue($redisQueueStore->isEmpty() === false);
241
242
        $mailJob = $redisQueueStore->dequeue();
243
244
        $this->assertTrue($redisQueueStore->isEmpty() === true);
245
246
        $this->assertTrue(!empty($mailJob->getMessage()));
247
248
        $dequeuedMailMessage = MailMessage::fromArray(json_decode($mailJob->getMessage(), true));
249
250
        $this->assertEquals(FixtureHelper::getMailMessage(), $dequeuedMailMessage);
251
        $redisQueueStore->ack($mailJob);
252
    }
253
}
254