Passed
Push — master ( 28ec5a...07f855 )
by Adrien
06:14
created

DatatransHandlerTest::providerProcess()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 238
Code Lines 155

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 155
dl 0
loc 238
rs 8
c 0
b 0
f 0
cc 1
nc 1
nop 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace ApplicationTest\Handler;
6
7
use Application\DBAL\Types\MessageTypeType;
8
use Application\Handler\DatatransHandler;
9
use Application\Model\Message;
10
use Application\Model\Order;
11
use Application\Service\MessageQueuer;
12
use ApplicationTest\Traits\TestWithTransactionAndUser;
13
use Doctrine\ORM\EntityManager;
14
use Ecodev\Felix\Service\Mailer;
15
use Ecodev\Felix\Service\MessageRenderer;
16
use Laminas\Diactoros\ServerRequest;
17
use Mezzio\Template\TemplateRendererInterface;
18
use PHPUnit\Framework\TestCase;
19
20
class DatatransHandlerTest extends TestCase
21
{
22
    use TestWithTransactionAndUser;
23
24
    public function testNotifications(): void
25
    {
26
        // Valid request
27
        $request = new ServerRequest();
28
        $request = $request->withParsedBody([
29
            'uppTransactionId' => '123456789012345678',
30
            'status' => 'success',
31
            'refno' => '16001',
32
            'amount' => '1000',
33
            'currency' => 'CHF',
34
            'responseMessage' => 'Payment was successful',
35
        ]);
36
37
        // Mailer will not actually send the message, but it will still flush it in DB as usual
38
        $mailer = $this->createMock(Mailer::class);
39
        $mailer->expects(self::exactly(2))
40
            ->method('sendMessageAsync')
41
            ->willReturnCallback(function (): void {
42
                _em()->flush();
43
            });
44
45
        global $container;
46
        $renderer = $container->get(TemplateRendererInterface::class);
47
48
        $entityManager = $container->get(EntityManager::class);
49
        $messageRenderer = $container->get(MessageRenderer::class);
50
51
        $messageQueuer = new MessageQueuer(
52
            $entityManager,
53
            $messageRenderer,
54
            ['email' => ['admins' => ['[email protected]']]],
55
        );
56
57
        $handler = new DatatransHandler(_em(), $renderer, [], $mailer, $messageQueuer);
58
59
        // Before we have no notifications at all
60
        self::assertFalse($this->hasUserNotification());
61
        self::assertFalse($this->hasAdminNotification());
62
63
        $handler->handle($request);
64
65
        // After we have exactly 1 notification for user and 1 for admin
66
        self::assertTrue($this->hasUserNotification());
67
        self::assertTrue($this->hasAdminNotification());
68
    }
69
70
    private function hasUserNotification(): bool
71
    {
72
        return $this->hasMessage('[email protected]', MessageTypeType::USER_VALIDATED_ORDER);
73
    }
74
75
    private function hasAdminNotification(): bool
76
    {
77
        return $this->hasMessage('[email protected]', MessageTypeType::ADMIN_VALIDATED_ORDER);
78
    }
79
80
    private function hasMessage(string $email, string $type): bool
81
    {
82
        $sql = "SELECT COUNT(*) = 1 FROM message WHERE email = '$email' AND type = '$type'";
83
        $result = (bool) _em()->getConnection()->fetchOne($sql);
84
85
        return $result;
86
    }
87
88
    /**
89
     * @dataProvider providerProcess
90
     */
91
    public function testProcess(?array $data, array $expectedViewModel, bool $expectedWebTemporaryAccess): void
92
    {
93
        // Message always include input data
94
        $expectedViewModel['message']['detail'] = $data ?? [];
95
        $renderer = $this->createMock(TemplateRendererInterface::class);
96
        $renderer->expects(self::once())->method('render')->with('app::datatrans', $expectedViewModel)->willReturn('');
97
98
        $request = new ServerRequest();
99
        $request = $request->withParsedBody($data);
100
101
        $config = [
102
            'key' => '1a03b7bcf2752c8c8a1b46616b0c12658d2c7643403e655450bedb7c78bb2d2f659c2ff4e647e4ea72d37ef6745ebda6733c7b859439107069f291cda98f4844',
103
        ];
104
105
        $mailer = $this->createMock(Mailer::class);
106
107
        $messageQueuer = $this->createMock(MessageQueuer::class);
108
        $messageQueuer->expects(self::any())
109
            ->method('getAllEmailsToNotify')
110
            ->willReturn(['[email protected]']);
111
        if ($expectedViewModel['message']['status'] === 'success') {
112
            $messageQueuer->expects(self::once())->method('queueUserValidatedOrder')->willReturn(new Message());
113
            $messageQueuer->expects(self::once())->method('queueAdminValidatedOrder')->willReturn(new Message());
114
        }
115
116
        $handler = new DatatransHandler(_em(), $renderer, $config, $mailer, $messageQueuer);
117
        $handler->handle($request);
118
119
        $orderId = $data['refno'] ?? null;
120
        if ($orderId) {
121
            $expectedStatus = $expectedViewModel['message']['status'] === 'success' || $orderId === '16002' ? Order::STATUS_VALIDATED : Order::STATUS_PENDING;
122
            $actualStatus = _em()->getConnection()->fetchOne('SELECT status FROM `order` WHERE id = ' . $orderId);
123
            self::assertSame($expectedStatus, $actualStatus);
124
125
            $actualWebTemporaryAccess = _em()->getConnection()->fetchOne('SELECT web_temporary_access FROM `user` INNER JOIN `order` ON `user`.id = `order`.owner_id WHERE `order`.id = ' . $orderId);
126
            self::assertEquals($expectedWebTemporaryAccess ? '1' : '0', $actualWebTemporaryAccess);
127
        }
128
129
        self::assertTrue(true); // Workaround when we only assert via mock
130
    }
131
132
    public function providerProcess(): array
133
    {
134
        return [
135
            'normal' => [
136
                [
137
                    'uppTransactionId' => '123456789012345678',
138
                    'status' => 'success',
139
                    'refno' => '16001',
140
                    'amount' => '1000',
141
                    'currency' => 'CHF',
142
                    'responseMessage' => 'Payment was successful',
143
                    'sign' => 'c0a817ad85a2bc830f8fd9d4f1cd0f3a2a8757239f98ec1700a182e7f182c6a7',
144
                ],
145
                [
146
                    'message' => [
147
                        'status' => 'success',
148
                        'message' => 'Payment was successful',
149
                    ],
150
                ],
151
                false,
152
            ],
153
            'invalid HMAC signature' => [
154
                [
155
                    'uppTransactionId' => '123456789012345678',
156
                    'status' => 'success',
157
                    'refno' => '16001',
158
                    'amount' => '1000',
159
                    'currency' => 'CHF',
160
                    'responseMessage' => 'Payment was successful',
161
                    'sign' => 'a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0',
162
                ],
163
                [
164
                    'message' => [
165
                        'status' => 'error',
166
                        'message' => 'Invalid HMAC signature',
167
                    ],
168
                ],
169
                false,
170
            ],
171
            'missing HMAC signature' => [
172
                [
173
                    'uppTransactionId' => '123456789012345678',
174
                    'status' => 'success',
175
                    'refno' => '16001',
176
                    'amount' => '1000',
177
                    'currency' => 'CHF',
178
                    'responseMessage' => 'Payment was successful',
179
                ],
180
                [
181
                    'message' => [
182
                        'status' => 'error',
183
                        'message' => 'Missing HMAC signature',
184
                    ],
185
                ],
186
                false,
187
            ],
188
            'error' => [
189
                [
190
                    'uppTransactionId' => '876543210987654321',
191
                    'status' => 'error',
192
                    'refno' => '16001',
193
                    'errorMessage' => 'Dear Sir/Madam, Fire! fire! help me! All the best, Maurice Moss.',
194
                    'sign' => '8015e6fef2caf41bb11cd2f54077bedb6339bd1aecf418091f77662ee13f81eb',
195
                ],
196
                [
197
                    'message' => [
198
                        'status' => 'error',
199
                        'message' => 'Dear Sir/Madam, Fire! fire! help me! All the best, Maurice Moss.',
200
                    ],
201
                ],
202
                false,
203
            ],
204
            'cancel' => [
205
                [
206
                    'uppTransactionId' => '876543210987654321',
207
                    'status' => 'cancel',
208
                    'refno' => '16001',
209
                    'sign' => '8015e6fef2caf41bb11cd2f54077bedb6339bd1aecf418091f77662ee13f81eb',
210
                ],
211
                [
212
                    'message' => [
213
                        'status' => 'cancel',
214
                        'message' => 'Cancelled',
215
                    ],
216
                ],
217
                false,
218
            ],
219
            'invalid body' => [
220
                null,
221
                [
222
                    'message' => [
223
                        'status' => 'error',
224
                        'message' => 'Parsed body is expected to be an array but got: NULL',
225
                    ],
226
                ],
227
                false,
228
            ],
229
            'invalid status' => [
230
                [
231
                    'uppTransactionId' => '123456789012345678',
232
                    'status' => 'non-existing-status',
233
                    'refno' => '16001',
234
                    'amount' => '10000',
235
                    'currency' => 'CHF',
236
                    'responseMessage' => 'Payment was successful',
237
                    'sign' => '811cb0cd3333311a242adb9907052b74d1c462fb94b071ef4d8790faa7f7fd72',
238
                ],
239
                [
240
                    'message' => [
241
                        'status' => 'error',
242
                        'message' => 'Unsupported status in Datatrans data: non-existing-status',
243
                    ],
244
                ],
245
                false,
246
            ],
247
            'non-existing order' => [
248
                [
249
                    'uppTransactionId' => '123456789012345678',
250
                    'status' => 'success',
251
                    'amount' => '10000',
252
                    'currency' => 'CHF',
253
                    'responseMessage' => 'Payment was successful',
254
                    'sign' => 'd7f9a1716b1538e2cd8f239230526435bc0dcf289a1769f7426badcbaa0efbc8',
255
                ],
256
                [
257
                    'message' => [
258
                        'status' => 'error',
259
                        'message' => 'Cannot validate an order without a valid order ID',
260
                    ],
261
                ],
262
                false,
263
            ],
264
            'non-existing amount' => [
265
                [
266
                    'uppTransactionId' => '123456789012345678',
267
                    'status' => 'success',
268
                    'refno' => '16001',
269
                    'currency' => 'CHF',
270
                    'responseMessage' => 'Payment was successful',
271
                    'sign' => 'd3f6f15797038879787e6d79e8041a7e9a9cb5cd1d7c5dabdd62ac8d3052db34',
272
                ],
273
                [
274
                    'message' => [
275
                        'status' => 'error',
276
                        'message' => 'Cannot validate an order without an amount',
277
                    ],
278
                ],
279
                false,
280
            ],
281
            'invalid currency' => [
282
                [
283
                    'uppTransactionId' => '123456789012345678',
284
                    'status' => 'success',
285
                    'refno' => '16001',
286
                    'amount' => '10000',
287
                    'currency' => 'USD',
288
                    'responseMessage' => 'Payment was successful',
289
                    'sign' => '8583b8d14fb4efa85d905ad8646074ce3ce1abe16464299e116e4cb68dd44752',
290
                ],
291
                [
292
                    'message' => [
293
                        'status' => 'error',
294
                        'message' => 'Can only accept payment in CHF or EUR, but got: USD',
295
                    ],
296
                ],
297
                false,
298
            ],
299
            'incorrect amount' => [
300
                [
301
                    'uppTransactionId' => '123456789012345678',
302
                    'status' => 'success',
303
                    'refno' => '16001',
304
                    'amount' => '1111',
305
                    'currency' => 'CHF',
306
                    'responseMessage' => 'Payment was successful',
307
                    'sign' => '2f2bb61733d8b95101c8c938290acf0efb17daf359266262d73b67165c3ce30b',
308
                ],
309
                [
310
                    'message' => [
311
                        'status' => 'error',
312
                        'message' => 'Cannot validate an order with incorrect balance. Expected 10.00 CHF, or 0.00 EUR, but got: 11.11 CHF',
313
                    ],
314
                ],
315
                false,
316
            ],
317
            'incorrect payment method' => [
318
                [
319
                    'uppTransactionId' => '123456789012345678',
320
                    'status' => 'success',
321
                    'refno' => '16003',
322
                    'amount' => '10000',
323
                    'currency' => 'CHF',
324
                    'responseMessage' => 'Payment was successful',
325
                    'sign' => '3111e1c3e63a77a13d9ae067690d52523c00c992b7aba262ab41de7f6e81bdad',
326
                ],
327
                [
328
                    'message' => [
329
                        'status' => 'error',
330
                        'message' => 'Cannot validate an order whose payment method is: ebanking',
331
                    ],
332
                ],
333
                false,
334
            ],
335
            'incorrect status' => [
336
                [
337
                    'uppTransactionId' => '123456789012345678',
338
                    'status' => 'success',
339
                    'refno' => '16002',
340
                    'amount' => '10000',
341
                    'currency' => 'CHF',
342
                    'responseMessage' => 'Payment was successful',
343
                    'sign' => 'f19af94a1cafd91e8da390308e2d4a1f8bfc4ac1e2e18cf2963e1de63cec37f8',
344
                ],
345
                [
346
                    'message' => [
347
                        'status' => 'error',
348
                        'message' => 'Cannot validate an order which is already validated',
349
                    ],
350
                ],
351
                false,
352
            ],
353
            'validating numeric subscription will give webTemporaryAccess' => [
354
                [
355
                    'uppTransactionId' => '123456789012345678',
356
                    'status' => 'success',
357
                    'refno' => '16004',
358
                    'amount' => '8000',
359
                    'currency' => 'CHF',
360
                    'responseMessage' => 'Payment was successful',
361
                    'sign' => 'a54523b461058df8d61cdbe2328bcd161bae411ec9e6206bbf4da773e3c88493',
362
                ],
363
                [
364
                    'message' => [
365
                        'status' => 'success',
366
                        'message' => 'Payment was successful',
367
                    ],
368
                ],
369
                true,
370
            ],
371
        ];
372
    }
373
}
374