Completed
Push — master ( 8bc6ad...b2c48e )
by Vitaliy
16:26 queued 13:19
created

ServerTest::setUpBeforeClass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 1
eloc 3
nc 1
nop 0
1
<?php
2
3
namespace Xsolla\SDK\Tests\Integration\Webhook;
4
5
use Guzzle\Http\Client;
6
use Guzzle\Http\Exception\BadResponseException;
7
use Symfony\Component\HttpFoundation\Response;
8
use Symfony\Component\Process\Process;
9
use Xsolla\SDK\API\XsollaClient;
10
use Xsolla\SDK\Tests\Helper\DebugHelper;
11
use Xsolla\SDK\Version;
12
13
/**
14
 * @group webhook-php-server
15
 */
16
class ServerTest extends \PHPUnit_Framework_TestCase
17
{
18
    const PROJECT_SECRET_KEY = 'PROJECT_SECRET_KEY';
19
20
    /**
21
     * @var Process
22
     */
23
    protected static $process;
24
25
    /**
26
     * @var Client
27
     */
28
    protected static $httpClient;
29
30
    public static function setUpBeforeClass()
31
    {
32
        self::setUpPhpServer();
33
        self::setUpHttpClient();
34
    }
35
36
    private static function setUpPhpServer()
37
    {
38
        self::$process = new Process('php -S [::1]:8999', __DIR__.'/../../Resources/Scripts');
39
        self::$process->setTimeout(1);
40
        self::$process->start();
41
        usleep(100000);
42
    }
43
44
    private static function setUpHttpClient()
45
    {
46
        self::$httpClient = new Client('http://[::1]:8999');
47
        if (DebugHelper::isDebug()) {
48
            DebugHelper::addDebugOptionsToHttpClient(self::$httpClient);
49
        }
50
    }
51
52
    public static function tearDownAfterClass()
53
    {
54
        self::$process->stop(0);
55
    }
56
57
    /**
58
     * @dataProvider cbProvider
59
     */
60
    public function testResponse(
61
        $expectedStatusCode,
62
        $expectedResponseContent,
63
        $request,
64
        $testCase,
65
        $testHeaders
66
    ) {
67
        $signature = sha1($request.self::PROJECT_SECRET_KEY);
68
        if ($testHeaders) {
69
            $headers = $testHeaders;
70
        } else {
71
            $headers = array('Authorization' => 'Signature '.$signature);
72
        }
73
        $request = self::$httpClient->post('/webhook_server.php?test_case='.$testCase, $headers, $request);
74
        try {
75
            $response = $request->send();
76
        } catch (BadResponseException $e) {
77
            $response = $e->getResponse();
78
        }
79
        static::assertSame($expectedResponseContent, $response->getBody(true));
80
        static::assertSame($expectedStatusCode, $response->getStatusCode());
81
        static::assertArrayHasKey('x-xsolla-sdk', $response->getHeaders());
82
        static::assertSame(Version::getVersion(), (string) $response->getHeader('x-xsolla-sdk'));
83
        static::assertArrayHasKey('content-type', $response->getHeaders());
84
        if (Response::HTTP_NO_CONTENT === $response->getStatusCode()) {
85
            static::assertStringStartsWith('text/plain', (string) $response->getHeader('content-type'));
86
        } else {
87
            static::assertStringStartsWith('application/json', (string) $response->getHeader('content-type'));
88
        }
89
    }
90
91
    public function cbProvider()
92
    {
93
        return array(
94
            // notifications
95
            'notification_type:payment success' => array(
96
                'expectedStatusCode' => 204,
97
                'expectedResponseContent' => '',
98
                'request' => '{"notification_type": "payment"}',
99
                'testCase' => 'payment_success',
100
                'testHeaders' => null,
101
            ),
102
            'notification_type:user_validation success' => array(
103
                'expectedStatusCode' => 204,
104
                'expectedResponseContent' => '',
105
                'request' => '{"notification_type": "user_validation"}',
106
                'testCase' => 'user_validation_success',
107
                'testHeaders' => null,
108
            ),
109
            'notification_type:refund success' => array(
110
                'expectedStatusCode' => 204,
111
                'expectedResponseContent' => '',
112
                'request' => '{"notification_type": "refund"}',
113
                'testCase' => 'refund_success',
114
                'testHeaders' => null,
115
            ),
116
            'notification_type:create_subscription success' => array(
117
                'expectedStatusCode' => 204,
118
                'expectedResponseContent' => '',
119
                'request' => '{"notification_type": "create_subscription"}',
120
                'testCase' => 'create_subscription_success',
121
                'testHeaders' => null,
122
            ),
123
            'notification_type:cancel_subscription success' => array(
124
                'expectedStatusCode' => 204,
125
                'expectedResponseContent' => '',
126
                'request' => '{"notification_type": "cancel_subscription"}',
127
                'testCase' => 'cancel_subscription_success',
128
                'testHeaders' => null,
129
            ),
130
            'notification_type:update_subscription success' => array(
131
                'expectedStatusCode' => 204,
132
                'expectedResponseContent' => '',
133
                'request' => '{"notification_type": "update_subscription"}',
134
                'testCase' => 'update_subscription_success',
135
                'testHeaders' => null,
136
            ),
137
            'notification_type:user_balance_operation success' => array(
138
                'expectedStatusCode' => 204,
139
                'expectedResponseContent' => '',
140
                'request' => '{"notification_type": "user_balance_operation"}',
141
                'testCase' => 'user_balance_operation_success',
142
                'testHeaders' => null,
143
            ),
144
            //common errors
145
            'notification_type not sent' => array(
146
                'expectedStatusCode' => 422,
147
                'expectedResponseContent' => XsollaClient::jsonEncode(
148
                    array(
149
                        'error' => array(
150
                            'code' => 'INVALID_PARAMETER',
151
                            'message' => 'notification_type key not found in Xsolla webhook request',
152
                        ),
153
                    )
154
                ),
155
                'request' => '{"foo": "bar"}',
156
                'testCase' => 'empty_request',
157
                'testHeaders' => null,
158
            ),
159
            'Unknown notification_type sent' => array(
160
                'expectedStatusCode' => 422,
161
                'expectedResponseContent' => XsollaClient::jsonEncode(
162
                    array(
163
                        'error' => array(
164
                            'code' => 'INVALID_PARAMETER',
165
                            'message' => 'Unknown notification_type in Xsolla webhook request: unknown',
166
                        ),
167
                    )
168
                ),
169
                'request' => '{"notification_type": "unknown"}',
170
                'testCase' => 'unknown_notification_type',
171
                'testHeaders' => null,
172
            ),
173
            'Invalid signature' => array(
174
                'expectedStatusCode' => 401,
175
                'expectedResponseContent' => XsollaClient::jsonEncode(
176
                    array(
177
                        'error' => array(
178
                            'code' => 'INVALID_SIGNATURE',
179
                            'message' => 'Invalid Signature. Signature provided in "Authorization" header (78143a5ac4b892a68ce8b0b8b49e26667db0fa00) does not match with expected',
180
                        ),
181
                    )
182
                ),
183
                'request' => null,
184
                'testCase' => 'invalid_signature',
185
                'testHeaders' => array('Authorization' => 'Signature 78143a5ac4b892a68ce8b0b8b49e26667db0fa00'),
186
            ),
187
            'Authorization header not sent' => array(
188
                'expectedStatusCode' => 401,
189
                'expectedResponseContent' => XsollaClient::jsonEncode(
190
                    array(
191
                        'error' => array(
192
                            'code' => 'INVALID_SIGNATURE',
193
                            'message' => '"Authorization" header not found in Xsolla webhook request. Please check troubleshooting section in README.md https://github.com/xsolla/xsolla-sdk-php#troubleshooting',
194
                        ),
195
                    )
196
                ),
197
                'request' => null,
198
                'testCase' => 'authorization_header_not_found',
199
                'testHeaders' => array('foo' => 'bar'),
200
            ),
201
            'Authorization header has invalid format' => array(
202
                'expectedStatusCode' => 401,
203
                'expectedResponseContent' => XsollaClient::jsonEncode(
204
                    array(
205
                        'error' => array(
206
                            'code' => 'INVALID_SIGNATURE',
207
                            'message' => 'Signature not found in "Authorization" header from Xsolla webhook request: INVALID_FORMAT',
208
                        ),
209
                    )
210
                ),
211
                'request' => null,
212
                'testCase' => 'invalid_signature_format',
213
                'testHeaders' => array('Authorization' => 'INVALID_FORMAT'),
214
            ),
215
            'Invalid JSON sent' => array(
216
                'expectedStatusCode' => 422,
217
                'expectedResponseContent' => XsollaClient::jsonEncode(
218
                    array(
219
                        'error' => array(
220
                            'code' => 'INVALID_PARAMETER',
221
                            'message' => 'Unable to parse Xsolla webhook request into JSON: Syntax error.',
222
                        ),
223
                    )
224
                ),
225
                'request' => 'INVALID_REQUEST_CONTENT',
226
                'testCase' => 'invalid_request_content',
227
                'testHeaders' => null,
228
            ),
229
            'Request from unknown client ip address rejected' => array(
230
                'expectedStatusCode' => 401,
231
                'expectedResponseContent' => XsollaClient::jsonEncode(
232
                    array(
233
                        'error' => array(
234
                            'code' => 'INVALID_CLIENT_IP',
235
                            'message' => 'Client IP address (::1) not found in allowed IP addresses whitelist (159.255.220.240/28, 185.30.20.16/29, 185.30.21.0/24, 185.30.21.16/29). Please check troubleshooting section in README.md https://github.com/xsolla/xsolla-sdk-php#troubleshooting',
236
                        ),
237
                    )
238
                ),
239
                'request' => null,
240
                'testCase' => 'invalid_ip',
241
                'testHeaders' => null,
242
            ),
243
            // exceptions from callback
244
            'Callback throws ServerErrorException' => array(
245
                'expectedStatusCode' => 500,
246
                'expectedResponseContent' => XsollaClient::jsonEncode(
247
                    array(
248
                        'error' => array(
249
                            'code' => 'SERVER_ERROR',
250
                            'message' => 'callback_server_error',
251
                        ),
252
                    )
253
                ),
254
                'request' => '{"notification_type": "payment"}',
255
                'testCase' => 'callback_server_error',
256
                'testHeaders' => null,
257
            ),
258
            'Callback throws ClientErrorException' => array(
259
                'expectedStatusCode' => 400,
260
                'expectedResponseContent' => XsollaClient::jsonEncode(
261
                    array(
262
                        'error' => array(
263
                            'code' => 'CLIENT_ERROR',
264
                            'message' => 'callback_client_error',
265
                        ),
266
                    )
267
                ),
268
                'request' => '{"notification_type": "payment"}',
269
                'testCase' => 'callback_client_error',
270
                'testHeaders' => null,
271
            ),
272
            'Callback throws \Exception' => array(
273
                'expectedStatusCode' => 500,
274
                'expectedResponseContent' => XsollaClient::jsonEncode(
275
                    array(
276
                        'error' => array(
277
                            'code' => 'FATAL_ERROR',
278
                            'message' => 'callback_exception',
279
                        ),
280
                    )
281
                ),
282
                'request' => '{"notification_type": "payment"}',
283
                'testCase' => 'callback_exception',
284
                'testHeaders' => null,
285
            ),
286
            'Callback throws InvalidUserException' => array(
287
                'expectedStatusCode' => 422,
288
                'expectedResponseContent' => XsollaClient::jsonEncode(
289
                    array(
290
                        'error' => array(
291
                            'code' => 'INVALID_USER',
292
                            'message' => 'callback_invalid_user_exception',
293
                        ),
294
                    )
295
                ),
296
                'request' => '{"notification_type": "payment"}',
297
                'testCase' => 'callback_invalid_user_exception',
298
                'testHeaders' => null,
299
            ),
300
            'Callback throws InvalidAmountException' => array(
301
                'expectedStatusCode' => 422,
302
                'expectedResponseContent' => XsollaClient::jsonEncode(
303
                    array(
304
                        'error' => array(
305
                            'code' => 'INCORRECT_AMOUNT',
306
                            'message' => 'callback_invalid_amount_exception',
307
                        ),
308
                    )
309
                ),
310
                'request' => '{"notification_type": "payment"}',
311
                'testCase' => 'callback_invalid_amount_exception',
312
                'testHeaders' => null,
313
            ),
314
            'Callback throws InvalidInvoiceException' => array(
315
                'expectedStatusCode' => 422,
316
                'expectedResponseContent' => XsollaClient::jsonEncode(
317
                    array(
318
                        'error' => array(
319
                            'code' => 'INCORRECT_INVOICE',
320
                            'message' => 'callback_invalid_invoice_exception',
321
                        ),
322
                    )
323
                ),
324
                'request' => '{"notification_type": "payment"}',
325
                'testCase' => 'callback_invalid_invoice_exception',
326
                'testHeaders' => null,
327
            ),
328
            // get_pincode
329
            'get_pincode with empty webhook response' => array(
330
                'expectedStatusCode' => 204,
331
                'expectedResponseContent' => '',
332
                'request' => '{"notification_type": "get_pincode"}',
333
                'testCase' => 'get_pincode_empty',
334
                'testHeaders' => null,
335
            ),
336
            'get_pincode with webhook response' => array(
337
                'expectedStatusCode' => 200,
338
                'expectedResponseContent' => '{
339
    "pin_code": "CODE"
340
}',
341
                'request' => '{"notification_type": "get_pincode"}',
342
                'testCase' => 'get_pincode_success',
343
                'testHeaders' => null,
344
            ),
345
            'get_pincode invalid pin code from callback' => array(
346
                'expectedStatusCode' => 500,
347
                'expectedResponseContent' => XsollaClient::jsonEncode(
348
                    array(
349
                        'error' => array(
350
                            'code' => 'SERVER_ERROR',
351
                            'message' => 'Pin code should be non-empty string. NULL given',
352
                        ),
353
                    )
354
                ),
355
                'request' => '{"notification_type": "get_pincode"}',
356
                'testCase' => 'get_pincode_invalid',
357
                'testHeaders' => null,
358
            ),
359
            // user_search
360
            'user_search with empty webhook response' => array(
361
                'expectedStatusCode' => 204,
362
                'expectedResponseContent' => '',
363
                'request' => '{"notification_type": "user_search"}',
364
                'testCase' => 'user_search_empty',
365
                'testHeaders' => null,
366
            ),
367
            'user_search with webhook response' => array(
368
                'expectedStatusCode' => 200,
369
                'expectedResponseContent' => '{
370
    "user": {
371
        "id": "USER_ID",
372
        "name": "User Name",
373
        "public_id": "PUBLIC_ID",
374
        "email": "[email protected]",
375
        "phone": "123456789"
376
    }
377
}',
378
                'request' => '{"notification_type": "user_search"}',
379
                'testCase' => 'user_search_success',
380
                'testHeaders' => null,
381
            ),
382
            'user_search invalid user id from callback' => array(
383
                'expectedStatusCode' => 500,
384
                'expectedResponseContent' => XsollaClient::jsonEncode(
385
                    array(
386
                        'error' => array(
387
                            'code' => 'SERVER_ERROR',
388
                            'message' => 'User id should be non-empty string. NULL given',
389
                        ),
390
                    )
391
                ),
392
                'request' => '{"notification_type": "user_search"}',
393
                'testCase' => 'user_search_invalid',
394
                'testHeaders' => null,
395
            ),
396
        );
397
    }
398
}
399