SyncServiceTest::testSync()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 100
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 1 Features 0
Metric Value
eloc 72
c 9
b 1
f 0
dl 0
loc 100
rs 8.6109
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
declare(strict_types=1);
3
4
namespace TogglJiraTest\Service;
5
6
use AJT\Toggl\TogglClient;
7
use DateTime;
8
use GuzzleHttp\Command\Result;
9
use Mockery\MockInterface;
10
use PHPUnit\Framework\TestCase;
11
use Psr\Log\LoggerInterface;
12
use RuntimeException;
13
use TogglJira\Entity\WorkLogEntry;
14
use TogglJira\Hydrator\WorkLogHydrator;
15
use TogglJira\Jira\Api;
16
use TogglJira\Service\SyncService;
17
18
class SyncServiceTest extends TestCase
19
{
20
    /**
21
     * @var MockInterface
22
     */
23
    private $apiMock;
24
25
    /**
26
     * @var MockInterface
27
     */
28
    private $togglClientMock;
29
30
    /**
31
     * @var MockInterface
32
     */
33
    private $hydratorMock;
34
35
    /**
36
     * @var MockInterface
37
     */
38
    private $loggerMock;
39
40
    /**
41
     * @var SyncService
42
     */
43
    private $service;
44
45
    /**
46
     * @return void
47
     */
48
    public function setUp(): void
49
    {
50
        \Mockery::getConfiguration()->allowMockingNonExistentMethods(true);
51
52
        date_default_timezone_set('Europe/Amsterdam');
53
54
        $this->apiMock = \Mockery::mock(Api::class);
55
        $this->togglClientMock = \Mockery::mock(TogglClient::class);
56
        $this->hydratorMock = \Mockery::mock(WorkLogHydrator::class);
57
        $this->loggerMock = \Mockery::mock(LoggerInterface::class);
58
59
        $this->service = new SyncService(
60
            $this->apiMock,
61
            $this->togglClientMock,
62
            $this->hydratorMock,
63
            'D-Va',
64
            'FOO-01',
65
            'Support'
66
        );
67
68
        $this->service->setLogger($this->loggerMock);
69
    }
70
71
    /**
72
     * @return void
73
     * @throws \Exception
74
     */
75
    public function testSync(): void
76
    {
77
        $startDate = new \DateTime('2017-05-15');
78
        $endDate = new \DateTime('2017-05-16');
79
80
        $timeEntries15th = [
81
            [
82
                'description' => 'SLR-76 Soldier 76',
83
                'duration' => 76,
84
                'comment' => 'Soldier 76, reporting for duty',
85
                'start' => '2018-02-15'
86
            ],
87
            [
88
                'description' => 'DVA-76 D-Va',
89
                'duration' => 42,
90
                'comment' => 'Nerf this!',
91
                'start' => '2018-02-15'
92
            ],
93
        ];
94
95
        $timeEntries16th = [];
96
97
        $this->togglClientMock->shouldReceive('getTimeEntries')
98
            ->with(['start_date' => '2017-05-15T00:00:00+02:00', 'end_date' => '2017-05-15T23:59:59+02:00'])
99
            ->andReturn(new Result($timeEntries15th));
100
101
        $this->togglClientMock->shouldReceive('getTimeEntries')
102
            ->with(['start_date' => '2017-05-16T00:00:00+02:00', 'end_date' => '2017-05-16T23:59:59+02:00'])
103
            ->andReturn(new Result($timeEntries16th));
104
105
        $workLogEntry = new WorkLogEntry();
106
        $workLogEntry->setIssueID('SLR-76');
107
        $workLogEntry->setSpentOn(new \DateTimeImmutable('2018-02-15'));
108
        $workLogEntry->setComment('SLR-76');
109
        $workLogEntry->setTimeSpent(76);
110
111
        $this->hydratorMock->shouldReceive('hydrate')->andReturn($workLogEntry);
112
113
        $user = [
114
            'accountId' => 'D-Va'
115
        ];
116
117
        $this->apiMock->shouldReceive('getUser')->andReturn($user);
118
119
        $result = \Mockery::mock(Result::class);
120
        $result->shouldReceive('getResult')->twice();
121
122
        $this->apiMock->shouldReceive('addWorkLogEntry')->with(
123
            $workLogEntry->getIssueID(),
124
            152,
125
            'D-Va',
126
            $workLogEntry->getComment(),
127
            '2018-02-15T00:00:00.000+0100',
128
            false,
129
            true
130
        )->andReturn($result);
131
        $this->apiMock->shouldReceive('addWorkLogEntry')->with(
132
            'FOO-01',
133
            28708,
134
            'D-Va',
135
            'Support',
136
            '2017-05-15T23:59:59.000+0200',
137
            false,
138
            true
139
        )->andReturn($result);
140
141
        $this->loggerMock
142
            ->shouldReceive('info')
143
            ->with(
144
                'Found time entry for issue',
145
                ['issueID' => 'SLR-76', 'spentOn' => '2018-02-15', 'timeSpent' => '0.02 hours']
146
            );
147
148
        $this->loggerMock
149
            ->shouldReceive('info')
150
            ->with(
151
                'Added time spent for issue',
152
                ['issueID' => 'SLR-76', 'spentOn' => '2018-02-15', 'timeSpent' => '0.04 hours']
153
            );
154
155
        $this->loggerMock
156
            ->shouldReceive('info')
157
            ->with("Added time spent for issue {$workLogEntry->getIssueID()}");
158
159
        $this->loggerMock
160
            ->shouldReceive('info')
161
            ->with(
162
                'Saved worklog entry',
163
                ['issueID' => 'SLR-76', 'spentOn' => '2018-02-15', 'timeSpent' => '0.04 hours']
164
            );
165
        $this->loggerMock
166
            ->shouldReceive('info')
167
            ->with(
168
                'Saved worklog entry',
169
                ['issueID' => 'FOO-01', 'spentOn' => '2017-05-15', 'timeSpent' => '7.97 hours']
170
            );
171
172
        $this->loggerMock->shouldReceive('info')->with('All done for today, time to go home!');
173
174
        $this->service->sync($startDate, $endDate, false);
175
    }
176
177
    /**
178
     * @return void
179
     * @throws \Exception
180
     */
181
    public function testExceptionOnTogglError(): void
182
    {
183
        $startTime = new DateTime('2017-04-15');
184
        $endDate = new DateTime('2017-04-16');
185
186
        $user = [
187
            'accountId' => 'D-Va'
188
        ];
189
190
        $this->apiMock->shouldReceive('getUser')->andReturn($user);
191
192
        $this->togglClientMock->shouldReceive('getTimeEntries')
193
            ->with(['start_date' => '2017-04-15T00:00:00+02:00', 'end_date' => '2017-04-15T23:59:59+02:00'])
194
            ->andThrow(\Exception::class, 'Nerf this!');
195
196
        $this->loggerMock->shouldReceive('error')
197
            ->with('Failed to get time entries from Toggl', \Mockery::any());
198
199
        $this->loggerMock->shouldReceive('info')->with('All done for today, time to go home!');
200
201
        $this->service->sync($startTime, $endDate, false);
202
    }
203
204
    /**
205
     * @return void
206
     * @throws \Exception
207
     */
208
    public function testSyncWithInvalidTimeEntries(): void
209
    {
210
        $startDate = new DateTime('2017-04-15');
211
        $endDate = new DateTime('2017-04-15');
212
213
        $timeEntries = [
214
            [
215
                'description' => 'SLR76 Soldier 76',
216
                'duration' => 76,
217
                'comment' => 'Soldier 76, not reporting for duty',
218
                'start' => '2017-04-15'
219
            ],
220
            [
221
                'description' => 'SLR-76 Soldier 76',
222
                'duration' => -1,
223
                'comment' => 'Soldier 76, not reporting for duty',
224
                'start' => '2017-04-15'
225
            ],
226
        ];
227
228
        $result = new Result($timeEntries);
229
230
        $this->togglClientMock->shouldReceive('getTimeEntries')
231
            ->with(['start_date' => '2017-04-15T00:00:00+02:00', 'end_date' => '2017-04-15T23:59:59+02:00'])
232
            ->andReturn($result);
233
234
        $user = [
235
            'accountId' => 'D-Va'
236
        ];
237
238
        $this->apiMock->shouldReceive('getUser')->andReturn($user);
239
240
        $result = \Mockery::mock(Result::class);
241
242
        $this->apiMock->shouldReceive('addWorkLogEntry')->with(
243
            'FOO-01',
244
            28800,
245
            'D-Va',
246
            'Support',
247
            '2017-04-15T23:59:59.000+0000',
248
            false,
249
            true
250
        )->andReturn($result);
251
252
        $this->loggerMock->shouldReceive('warning')
253
            ->with('Could not parse issue string, cannot link to Jira');
254
255
        $this->loggerMock->shouldReceive('info')
256
            ->with('0 seconds, or timer still running, skipping', ['issueID' => 'SLR-76']);
257
258
        $this->loggerMock
259
            ->shouldReceive('info')
260
            ->with(
261
                'Saved worklog entry',
262
                ['issueID' => 'FOO-01', 'spentOn' => '2017-04-15', 'timeSpent' => '8 hours']
263
            );
264
265
        $this->loggerMock->shouldReceive('info')->with('All done for today, time to go home!');
266
267
        $this->service->sync($startDate, $endDate, false);
268
    }
269
270
    /**
271
     * @return void
272
     * @throws \Exception
273
     */
274
    public function testSyncJiraException(): void
275
    {
276
        $startDate = new DateTime('2017-04-15');
277
        $endDate = new DateTime('2017-04-15');
278
279
        $user = [
280
            'accountId' => 'D-Va'
281
        ];
282
283
        $this->apiMock->shouldReceive('getUser')->andReturn($user);
284
285
        $timeEntries = [
286
            [
287
                'description' => 'SLR-76 Soldier 76',
288
                'duration' => 76,
289
                'comment' => 'Soldier 76, reporting for duty',
290
                'start' => '2018-02-15'
291
            ],
292
            [
293
                'description' => 'DVA-76 D-Va',
294
                'duration' => 42,
295
                'comment' => 'Nerf this!',
296
                'start' => '2018-02-15'
297
            ],
298
        ];
299
300
        $result = new Result($timeEntries);
301
        
302
        $this->togglClientMock->shouldReceive('getTimeEntries')
303
            ->with(['start_date' => '2017-04-15T00:00:00+02:00', 'end_date' => '2017-04-15T23:59:59+02:00'])
304
            ->andReturn($result);
305
306
        $workLogEntry = new WorkLogEntry();
307
        $workLogEntry->setIssueID('SLR-76');
308
        $workLogEntry->setSpentOn(new \DateTimeImmutable('2018-02-15'));
309
        $workLogEntry->setComment('SLR-76');
310
        $workLogEntry->setTimeSpent(76);
311
312
        $this->hydratorMock->shouldReceive('hydrate')->andReturn($workLogEntry);
313
314
        $this->apiMock->shouldReceive('addWorkLogEntry')->with(
315
            $workLogEntry->getIssueID(),
316
            $workLogEntry->getTimeSpent() * 2,
317
            'D-Va',
318
            $workLogEntry->getComment(),
319
            $workLogEntry->getSpentOn()->format('Y-m-d\TH:i:s.vO')
320
        )->andThrow(\Exception::class, 'Nerf this!');
321
322
        $this->loggerMock
323
            ->shouldReceive('info')
324
            ->with(
325
                'Found time entry for issue',
326
                ['issueID' => 'SLR-76', 'spentOn' => '2018-02-15', 'timeSpent' => '0.02 hours']
327
            );
328
329
        $this->loggerMock
330
            ->shouldReceive('error')
331
            ->with('Could not add worklog entry', \Mockery::any());
332
333
        $this->loggerMock
334
            ->shouldReceive('info')
335
            ->with(
336
                'Added time spent for issue',
337
                ['issueID' => 'SLR-76', 'spentOn' => '2018-02-15', 'timeSpent' => '0.04 hours']
338
            );
339
340
        $this->loggerMock->shouldReceive('info')->with('All done for today, time to go home!');
341
342
        $this->service->sync($startDate, $endDate, false);
343
    }
344
345
    /**
346
     * @expectedException RuntimeException
347
     * @expectedExceptionMessage User with username D-Va not found
348
     * @return void
349
     * @throws \Exception
350
     */
351
    public function testExceptionThrownOnUserNotFound(): void
352
    {
353
        $startDate = new DateTime('2017-04-15');
354
        $endDate = new DateTime('2017-04-15');
355
        $this->apiMock->shouldReceive('getUser')->andReturn([]);
356
357
        $this->service->sync($startDate, $endDate, false);
358
    }
359
360
    public function tearDown()/* The :void return type declaration that should be here would cause a BC issue */
361
    {
362
        if ($container = \Mockery::getContainer()) {
363
            $this->addToAssertionCount($container->mockery_getExpectationCount());
364
        }
365
    }
366
}
367