GithubControllerTest   A
last analyzed

Complexity

Total Complexity 5

Size/Duplication

Total Lines 271
Duplicated Lines 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
eloc 144
dl 0
loc 271
rs 10
c 4
b 0
f 0
wmc 5

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setUp() 0 4 1
A testUnlinkIssue() 0 55 1
A testSyncIssueStatus() 0 45 1
A testCreateIssue() 0 62 1
A testLinkIssue() 0 68 1
1
<?php
2
3
/**
4
 * Tests for Github Controller actions
5
 *
6
 * phpMyAdmin Error reporting server
7
 * Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
8
 *
9
 * Licensed under The MIT License
10
 * For full copyright and license information, please see the LICENSE.txt
11
 * Redistributions of files must retain the above copyright notice.
12
 *
13
 * @copyright Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
14
 * @license   https://opensource.org/licenses/mit-license.php MIT License
15
 *
16
 * @see      https://www.phpmyadmin.net/
17
 */
18
19
namespace App\Test\TestCase\Controller;
20
21
use Cake\Core\Configure;
22
use Cake\ORM\TableRegistry;
23
use Cake\TestSuite\IntegrationTestTrait;
24
use Cake\TestSuite\TestCase;
25
use phpmock\phpunit\PHPMock;
26
27
use function file_get_contents;
28
use function json_decode;
29
use function json_encode;
30
31
use const DS;
32
33
/**
34
 * App\Controller\GithubController Test Case
35
 */
36
class GithubControllerTest extends TestCase
37
{
38
    use PHPMock;
39
    use IntegrationTestTrait;
40
41
    /**
42
     * Fixtures.
43
     *
44
     * @var array
45
     */
46
    public $fixtures = [
47
        'app.Reports',
48
        'app.Developers',
49
        'app.Incidents',
50
        'app.Notifications',
51
    ];
52
53
    public function setUp(): void
54
    {
55
        $this->session(['Developer.id' => 1, 'access_token' => 'abc']);
56
        $this->Reports = TableRegistry::getTableLocator()->get('Reports');
57
    }
58
59
    /**
60
     * Test create_issue method
61
     */
62
    public function testCreateIssue(): void
63
    {
64
        // Mock functions `curl_exec` and `curl_getinfo` in GithubApiComponent
65
        // so that we don't actually hit the Github Api
66
        $curlExecMock = $this->getFunctionMock('\App\Controller\Component', 'curl_exec');
67
        $curlGetInfoMock = $this->getFunctionMock('\App\Controller\Component', 'curl_getinfo');
68
69
        // Case 1. Test with an invalid reportId
70
        $this->get('github/create_issue/123');
71
        $this->assertResponseContains('The report does not exist.');
72
73
        // Case 2. Test form with valid reportId
74
        $this->get('github/create_issue/5');
75
        $this->assertResponseContains('Lorem ipsum dolor sit amet'); // Description
76
77
        $issueResponse = file_get_contents(TESTS . 'Fixture' . DS . 'issue_response.json');
78
79
        // Github unsuccessful response followed by successful response
80
        $curlExecMock->expects($this->exactly(2))->willReturnOnConsecutiveCalls(
81
            $issueResponse,
82
            $issueResponse
83
        );
84
        $curlGetInfoMock->expects($this->exactly(2))->willReturnOnConsecutiveCalls(
85
            403,
86
            201
87
        );
88
89
        // Case 3. Test submission of form with unsuccessful github response
90
        $this->post(
91
            'github/create_issue/5',
92
            [
93
                'summary' => 'Error testing',
94
                'milestone' => '3.8',
95
                'description' => 'Lorem ipsum dolor sit amet',
96
                'labels' => 'test-pma',
97
            ]
98
        );
99
100
        $this->enableRetainFlashMessages();
101
        $report = $this->Reports->get(5);
102
        $this->assertEquals(null, $report->sourceforge_bug_id);
103
        $this->assertEquals('new', $report->status);
104
        $this->assertSession(
105
            'Unauthorised access to Github. github credentials may be out of date.'
106
            . ' Please check and try again later.',
107
            'Flash.flash.0.message'
108
        );
109
110
        // Case 4. Test submission of form with successful Github response
111
        $this->post(
112
            'github/create_issue/5',
113
            [
114
                'summary' => 'Error testing',
115
                'milestone' => '3.8',
116
                'description' => 'Lorem ipsum dolor sit amet',
117
                'labels' => 'test-pma',
118
            ]
119
        );
120
121
        $report = $this->Reports->get(5);
122
        $this->assertEquals(1347, $report->sourceforge_bug_id);
123
        $this->assertEquals('forwarded', $report->status);
124
    }
125
126
    /**
127
     * Test link_issue method
128
     */
129
    public function testLinkIssue(): void
130
    {
131
        // Mock functions `curl_exec` and `curl_getinfo` in GithubApiComponent
132
        // so that we don't actually hit the Github Api
133
        $curlExecMock = $this->getFunctionMock('\App\Controller\Component', 'curl_exec');
134
        $curlGetInfoMock = $this->getFunctionMock('\App\Controller\Component', 'curl_getinfo');
135
136
        // Case 1.1 Test with an invalid reportId
137
        $this->get('github/link_issue/123?ticket_id=1');
138
        $this->assertResponseContains('The report does not exist.');
139
140
        // Case 1.2 Test with an invalid ticketId
141
        $this->get('github/link_issue/5?ticket_id=');
142
        $this->assertResponseContains('Invalid Ticket ID');
143
144
        $issueResponse = file_get_contents(TESTS . 'Fixture' . DS . 'issue_response.json');
145
        $decodedResponse = json_decode($issueResponse, true);
146
        $decodedResponse['state'] = 'closed';
147
        $issueResponseWithClosed = json_encode($decodedResponse);
148
149
        // Github response unsuccessful followed by successful (open) and successful (closed)
150
        $curlExecMock->expects($this->exactly(5))->willReturnOnConsecutiveCalls(
151
            $issueResponse,
152
            $issueResponse,
153
            $issueResponse,
154
            $issueResponseWithClosed,
155
            $issueResponseWithClosed
156
        );
157
        $curlGetInfoMock->expects($this->exactly(5))->willReturnOnConsecutiveCalls(
158
            404,
159
            201,
160
            200,
161
            201,
162
            200
163
        );
164
165
        // Case 2. Test submission of form with unsuccessful github response
166
        $this->get(
167
            'github/link_issue/5?ticket_id=9999999'
168
        );
169
170
        $this->enableRetainFlashMessages();
171
        $report = $this->Reports->get(5);
172
        $this->assertEquals(null, $report->sourceforge_bug_id);
173
        $this->assertEquals('new', $report->status);
174
        $this->assertSession(
175
            'Bug Issue not found on Github. Are you sure the issue number is correct? '
176
            . 'Please check and try again!',
177
            'Flash.flash.0.message'
178
        );
179
180
        // Case 3. Test submission of form with successful Github response (with issue open)
181
        $this->get(
182
            'github/link_issue/5?ticket_id=1387'
183
        );
184
185
        $report = $this->Reports->get(5);
186
        $this->assertEquals(1387, $report->sourceforge_bug_id);
187
        $this->assertEquals('forwarded', $report->status);
188
189
        // Case 4. Test submission of form with successful Github response (with issue closed)
190
        $this->get(
191
            'github/link_issue/5?ticket_id=1387'
192
        );
193
194
        $report = $this->Reports->get(5);
195
        $this->assertEquals(1387, $report->sourceforge_bug_id);
196
        $this->assertEquals('resolved', $report->status);
197
    }
198
199
    /**
200
     * Test unlink_issue method
201
     */
202
    public function testUnlinkIssue(): void
203
    {
204
        // Mock functions `curl_exec` and `curl_getinfo` in GithubApiComponent
205
        // so that we don't actually hit the Github Api
206
        $curlExecMock = $this->getFunctionMock('\App\Controller\Component', 'curl_exec');
207
        $curlGetInfoMock = $this->getFunctionMock('\App\Controller\Component', 'curl_getinfo');
208
209
        // Case 1.1 Test with an invalid reportId
210
        $this->get('github/unlink_issue/123');
211
        $this->assertResponseContains('The report does not exist.');
212
213
        // Case 1.2 Test unlinked with an already unlinked issue
214
        $this->get('github/unlink_issue/5');
215
        $this->assertResponseContains('Invalid Ticket ID');
216
217
        $commentResponse = file_get_contents(TESTS . 'Fixture' . DS . 'comment_response.json');
218
219
        // Github response unsuccessful followed by successful
220
        $curlExecMock->expects($this->exactly(2))->willReturnOnConsecutiveCalls(
221
            json_encode(['message' => 'Unauthorised access']),
222
            $commentResponse
223
        );
224
        $curlGetInfoMock->expects($this->exactly(2))->willReturnOnConsecutiveCalls(
225
            401,
226
            201
227
        );
228
229
        // Link the report before trying to unlink
230
        $report = $this->Reports->get(5);
231
        $report->sourceforge_bug_id = 1387;
232
        $report->status = 'forwarded';
233
        $this->Reports->save($report);
234
235
        // Case 2. Test submission of form with unsuccessful and unexpected github response
236
        $this->get(
237
            'github/unlink_issue/5'
238
        );
239
240
        $this->enableRetainFlashMessages();
241
        $report = $this->Reports->get(5);
242
        $this->assertEquals(1387, $report->sourceforge_bug_id);
243
        $this->assertEquals('forwarded', $report->status);
244
        $this->assertSession(
245
            'Unhandled response code received: 401',
246
            'Flash.flash.0.message'
247
        );
248
249
        // Case 3. Test submission of form with successful Github response
250
        $this->get(
251
            'github/unlink_issue/5'
252
        );
253
254
        $report = $this->Reports->get(5);
255
        $this->assertEquals(null, $report->sourceforge_bug_id);
256
        $this->assertEquals('new', $report->status);
257
    }
258
259
    /**
260
     * Test sync_issue_status method
261
     */
262
    public function testSyncIssueStatus(): void
263
    {
264
        // Mock functions `curl_exec` and `curl_getinfo` in GithubApiComponent
265
        // so that we don't actually hit the Github Api
266
        $curlExecMock = $this->getFunctionMock('\App\Controller\Component', 'curl_exec');
267
        $curlGetInfoMock = $this->getFunctionMock('\App\Controller\Component', 'curl_getinfo');
268
269
        // Test via web interface
270
        Configure::write('CronDispatcher', false);
271
        $this->enableRetainFlashMessages();
272
        $this->get('github/sync_issue_status');
273
        $this->assertRedirect('/');
274
275
        $issueResponse = file_get_contents(TESTS . 'Fixture' . DS . 'issue_response.json');
276
        $decodedResponse = json_decode($issueResponse, true);
277
        $decodedResponse['state'] = 'closed';
278
        $issueResponseWithClosed = json_encode($decodedResponse);
279
280
        // Github response unsuccessful followed by two successful responses
281
        $curlExecMock->expects($this->exactly(3))->willReturnOnConsecutiveCalls(
282
            json_encode(['message' => 'Unauthorised access']),
283
            $issueResponse,
284
            $issueResponseWithClosed
285
        );
286
        $curlGetInfoMock->expects($this->exactly(3))->willReturnOnConsecutiveCalls(
287
            401,
288
            200,
289
            200
290
        );
291
292
        // Test via cli (i.e. the CronDispatcher setting should be defined)
293
        Configure::write('CronDispatcher', true);
294
        $this->get('github/sync_issue_status');
295
296
        // 401
297
        $report = $this->Reports->get(1);
298
        $this->assertEquals('forwarded', $report->status);
299
300
        // 200 (open state)
301
        $report = $this->Reports->get(2);
302
        $this->assertEquals('forwarded', $report->status);
303
304
        // 200 (closed state)
305
        $report = $this->Reports->get(4);
306
        $this->assertEquals('resolved', $report->status);
307
    }
308
}
309