Passed
Pull Request — master (#2)
by Kevin
03:06 queued 01:22
created

full_task_configuration()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 73
Code Lines 57

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 57
c 0
b 0
f 0
dl 0
loc 73
rs 8.9381
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
namespace Zenstruck\ScheduleBundle\Tests\DependencyInjection;
4
5
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
6
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
7
use Zenstruck\ScheduleBundle\Command\ScheduleListCommand;
8
use Zenstruck\ScheduleBundle\Command\ScheduleRunCommand;
9
use Zenstruck\ScheduleBundle\DependencyInjection\ZenstruckScheduleExtension;
10
use Zenstruck\ScheduleBundle\EventListener\ConfigureScheduleSubscriber;
11
use Zenstruck\ScheduleBundle\EventListener\ConfigureTasksSubscriber;
12
use Zenstruck\ScheduleBundle\EventListener\LogScheduleSubscriber;
13
use Zenstruck\ScheduleBundle\EventListener\ScheduleBuilderSubscriber;
14
use Zenstruck\ScheduleBundle\EventListener\SelfSchedulingSubscriber;
15
use Zenstruck\ScheduleBundle\EventListener\TimezoneSubscriber;
16
use Zenstruck\ScheduleBundle\Schedule\Extension\EmailExtension;
17
use Zenstruck\ScheduleBundle\Schedule\Extension\EnvironmentExtension;
18
use Zenstruck\ScheduleBundle\Schedule\Extension\ExtensionHandlerRegistry;
19
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\EmailHandler;
20
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\EnvironmentHandler;
21
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\PingHandler;
22
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\SelfHandlingHandler;
23
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\SingleServerHandler;
24
use Zenstruck\ScheduleBundle\Schedule\Extension\Handler\WithoutOverlappingHandler;
25
use Zenstruck\ScheduleBundle\Schedule\Extension\PingExtension;
26
use Zenstruck\ScheduleBundle\Schedule\Extension\SingleServerExtension;
27
use Zenstruck\ScheduleBundle\Schedule\Extension\WithoutOverlappingExtension;
28
use Zenstruck\ScheduleBundle\Schedule\ScheduleRunner;
29
use Zenstruck\ScheduleBundle\Schedule\Task\Runner\CommandTaskRunner;
30
use Zenstruck\ScheduleBundle\Schedule\Task\Runner\SelfRunningTaskRunner;
31
32
/**
33
 * @author Kevin Bond <[email protected]>
34
 */
35
final class ZenstruckScheduleExtensionTest extends AbstractExtensionTestCase
36
{
37
    /**
38
     * @test
39
     */
40
    public function empty_config_loads_default_services()
41
    {
42
        $this->load([]);
43
44
        $this->assertContainerBuilderHasService(ScheduleListCommand::class);
45
        $this->assertContainerBuilderHasServiceDefinitionWithTag(ScheduleListCommand::class, 'console.command');
46
47
        $this->assertContainerBuilderHasService(ScheduleRunCommand::class);
48
        $this->assertContainerBuilderHasServiceDefinitionWithTag(ScheduleRunCommand::class, 'console.command');
49
50
        $this->assertContainerBuilderHasService(ScheduleRunner::class);
51
52
        $this->assertContainerBuilderHasService(ScheduleBuilderSubscriber::class);
53
        $this->assertContainerBuilderHasServiceDefinitionWithTag(ScheduleBuilderSubscriber::class, 'kernel.event_subscriber');
54
55
        $this->assertContainerBuilderHasService(ConfigureScheduleSubscriber::class);
56
        $this->assertContainerBuilderHasServiceDefinitionWithTag(ConfigureScheduleSubscriber::class, 'kernel.event_subscriber');
57
58
        $this->assertContainerBuilderHasService(SelfSchedulingSubscriber::class);
59
        $this->assertContainerBuilderHasServiceDefinitionWithTag(SelfSchedulingSubscriber::class, 'kernel.event_subscriber');
60
61
        $this->assertContainerBuilderHasService(CommandTaskRunner::class);
62
        $this->assertContainerBuilderHasServiceDefinitionWithTag(CommandTaskRunner::class, 'schedule.task_runner');
63
64
        $this->assertContainerBuilderHasService(SelfRunningTaskRunner::class);
65
        $this->assertContainerBuilderHasServiceDefinitionWithTag(SelfRunningTaskRunner::class, 'schedule.task_runner');
66
67
        $this->assertContainerBuilderHasService(LogScheduleSubscriber::class);
68
        $this->assertContainerBuilderHasServiceDefinitionWithTag(LogScheduleSubscriber::class, 'kernel.event_subscriber');
69
        $this->assertContainerBuilderHasServiceDefinitionWithTag(LogScheduleSubscriber::class, 'monolog.logger', ['channel' => 'schedule']);
70
71
        $this->assertContainerBuilderHasService(ExtensionHandlerRegistry::class);
72
73
        $this->assertContainerBuilderHasService(SelfHandlingHandler::class);
74
        $this->assertContainerBuilderHasServiceDefinitionWithTag(SelfHandlingHandler::class, 'schedule.extension_handler', ['priority' => -100]);
75
76
        $this->assertContainerBuilderHasService(EnvironmentHandler::class);
77
        $this->assertContainerBuilderHasServiceDefinitionWithTag(EnvironmentHandler::class, 'schedule.extension_handler');
78
79
        $this->assertContainerBuilderHasService(ConfigureTasksSubscriber::class);
80
        $this->assertContainerBuilderHasServiceDefinitionWithTag(ScheduleBuilderSubscriber::class, 'kernel.event_subscriber');
81
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(ConfigureTasksSubscriber::class, 0, []);
82
    }
83
84
    /**
85
     * @test
86
     */
87
    public function can_configure_default_timezone()
88
    {
89
        $this->load(['timezone' => 'UTC']);
90
91
        $this->assertContainerBuilderHasService(TimezoneSubscriber::class);
92
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(TimezoneSubscriber::class, 0, 'UTC');
93
        $this->assertContainerBuilderHasServiceDefinitionWithTag(TimezoneSubscriber::class, 'kernel.event_subscriber');
94
    }
95
96
    /**
97
     * @test
98
     */
99
    public function timezone_must_be_valid()
100
    {
101
        $this->expectException(InvalidConfigurationException::class);
102
        $this->expectExceptionMessage('Invalid configuration for path "zenstruck_schedule.timezone": Timezone "invalid" is not available');
103
104
        $this->load(['timezone' => 'invalid']);
105
    }
106
107
    /**
108
     * @test
109
     */
110
    public function can_configure_single_server_lock_factory()
111
    {
112
        $this->load(['single_server_handler' => 'my_factory']);
113
114
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(SingleServerHandler::class, 0, 'my_factory');
115
        $this->assertContainerBuilderHasServiceDefinitionWithTag(SingleServerHandler::class, 'schedule.extension_handler');
116
    }
117
118
    /**
119
     * @test
120
     */
121
    public function can_configure_without_overlapping_handler_lock_factory()
122
    {
123
        $this->load(['without_overlapping_handler' => 'my_factory']);
124
125
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(WithoutOverlappingHandler::class, 0, 'my_factory');
126
        $this->assertContainerBuilderHasServiceDefinitionWithTag(WithoutOverlappingHandler::class, 'schedule.extension_handler');
127
    }
128
129
    /**
130
     * @test
131
     */
132
    public function can_configure_ping_handler_http_client()
133
    {
134
        $this->load(['ping_handler' => 'my_client']);
135
136
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(PingHandler::class, 0, 'my_client');
137
        $this->assertContainerBuilderHasServiceDefinitionWithTag(PingHandler::class, 'schedule.extension_handler');
138
    }
139
140
    /**
141
     * @test
142
     */
143
    public function can_configure_email_handler()
144
    {
145
        $this->load(['email_handler' => [
146
            'service' => 'my_mailer',
147
            'default_from' => '[email protected]',
148
            'default_to' => '[email protected]',
149
            'subject_prefix' => '[Acme Inc]',
150
        ]]);
151
152
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 0, 'my_mailer');
153
        $this->assertContainerBuilderHasServiceDefinitionWithTag(EmailHandler::class, 'schedule.extension_handler');
154
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 1, '[email protected]');
155
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 2, '[email protected]');
156
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 3, '[Acme Inc]');
157
    }
158
159
    /**
160
     * @test
161
     */
162
    public function minimum_email_handler_configuration()
163
    {
164
        $this->load(['email_handler' => [
165
            'service' => 'my_mailer',
166
        ]]);
167
168
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 0, 'my_mailer');
169
        $this->assertContainerBuilderHasServiceDefinitionWithTag(EmailHandler::class, 'schedule.extension_handler');
170
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 1, null);
171
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 2, null);
172
        $this->assertContainerBuilderHasServiceDefinitionWithArgument(EmailHandler::class, 3, null);
173
    }
174
175
    /**
176
     * @test
177
     */
178
    public function can_add_schedule_environment_as_string()
179
    {
180
        $this->load(['schedule_extensions' => [
181
            'environments' => 'prod',
182
        ]]);
183
184
        $this->assertContainerBuilderHasService('zenstruck_schedule.extension.environments', EnvironmentExtension::class);
185
        $this->assertContainerBuilderHasServiceDefinitionWithArgument('zenstruck_schedule.extension.environments', 0, ['prod']);
186
        $this->assertContainerBuilderHasServiceDefinitionWithTag('zenstruck_schedule.extension.environments', 'schedule.configured_extension');
187
    }
188
189
    /**
190
     * @test
191
     */
192
    public function can_add_schedule_environment_as_array()
193
    {
194
        $this->load(['schedule_extensions' => [
195
            'environments' => ['prod', 'stage'],
196
        ]]);
197
198
        $this->assertContainerBuilderHasServiceDefinitionWithArgument('zenstruck_schedule.extension.environments', 0, ['prod', 'stage']);
199
    }
200
201
    /**
202
     * @test
203
     */
204
    public function can_enable_single_server_schedule_extension()
205
    {
206
        $this->load(['schedule_extensions' => [
207
            'on_single_server' => null,
208
        ]]);
209
210
        $this->assertContainerBuilderHasService('zenstruck_schedule.extension.on_single_server', SingleServerExtension::class);
211
        $this->assertContainerBuilderHasServiceDefinitionWithTag('zenstruck_schedule.extension.on_single_server', 'schedule.configured_extension');
212
    }
213
214
    /**
215
     * @test
216
     */
217
    public function can_enable_email_on_failure_schedule_extension()
218
    {
219
        $this->load(['schedule_extensions' => [
220
            'email_on_failure' => [
221
                'to' => '[email protected]',
222
                'subject' => 'my subject',
223
            ],
224
        ]]);
225
226
        $this->assertContainerBuilderHasService('zenstruck_schedule.extension.email_on_failure', EmailExtension::class);
227
        $this->assertContainerBuilderHasServiceDefinitionWithTag('zenstruck_schedule.extension.email_on_failure', 'schedule.configured_extension');
228
229
        $definition = $this->container->getDefinition('zenstruck_schedule.extension.email_on_failure');
230
231
        $this->assertSame([EmailExtension::class, 'scheduleFailure'], $definition->getFactory());
232
        $this->assertSame(['[email protected]', 'my subject'], $definition->getArguments());
233
    }
234
235
    /**
236
     * @test
237
     * @dataProvider pingScheduleExtensionProvider
238
     */
239
    public function can_enable_ping_schedule_extensions($key, $method)
240
    {
241
        $this->load(['schedule_extensions' => [
242
            $key => [
243
                'url' => 'example.com',
244
            ],
245
        ]]);
246
247
        $this->assertContainerBuilderHasService('zenstruck_schedule.extension.'.$key, PingExtension::class);
248
        $this->assertContainerBuilderHasServiceDefinitionWithTag('zenstruck_schedule.extension.'.$key, 'schedule.configured_extension');
249
250
        $definition = $this->container->getDefinition('zenstruck_schedule.extension.'.$key);
251
252
        $this->assertSame([PingExtension::class, $method], $definition->getFactory());
253
        $this->assertSame(['example.com', 'GET', []], $definition->getArguments());
254
    }
255
256
    public static function pingScheduleExtensionProvider()
257
    {
258
        return [
259
            ['ping_before', 'scheduleBefore'],
260
            ['ping_after', 'scheduleAfter'],
261
            ['ping_on_success', 'scheduleSuccess'],
262
            ['ping_on_failure', 'scheduleFailure'],
263
        ];
264
    }
265
266
    /**
267
     * @test
268
     */
269
    public function minimum_task_configuration()
270
    {
271
        $this->load([
272
            'tasks' => [
273
                [
274
                    'command' => 'my:command',
275
                    'frequency' => '0 * * * *',
276
                ],
277
            ],
278
        ]);
279
280
        $config = $this->container->getDefinition(ConfigureTasksSubscriber::class)->getArgument(0)[0];
281
282
        $this->assertSame(['my:command'], $config['command']);
283
        $this->assertSame('0 * * * *', $config['frequency']);
284
        $this->assertNull($config['description']);
285
        $this->assertFalse($config['without_overlapping']['enabled']);
286
        $this->assertFalse($config['between']['enabled']);
287
        $this->assertFalse($config['unless_between']['enabled']);
288
        $this->assertFalse($config['ping_before']['enabled']);
289
        $this->assertFalse($config['ping_after']['enabled']);
290
        $this->assertFalse($config['ping_on_success']['enabled']);
291
        $this->assertFalse($config['ping_on_failure']['enabled']);
292
        $this->assertFalse($config['email_after']['enabled']);
293
        $this->assertFalse($config['email_on_failure']['enabled']);
294
    }
295
296
    /**
297
     * @test
298
     */
299
    public function task_frequency_must_be_valid()
300
    {
301
        $this->expectException(InvalidConfigurationException::class);
302
        $this->expectExceptionMessage('Invalid configuration for path "zenstruck_schedule.tasks.0.frequency": "invalid" is an invalid cron expression.');
303
304
        $this->load([
305
            'tasks' => [
306
                [
307
                    'command' => 'my:command',
308
                    'frequency' => 'invalid',
309
                ],
310
            ],
311
        ]);
312
    }
313
314
    /**
315
     * @test
316
     */
317
    public function full_task_configuration()
318
    {
319
        $this->load([
320
            'tasks' => [
321
                [
322
                    'command' => [
323
                        'my:command --option',
324
                        'another:command',
325
                    ],
326
                    'frequency' => '0 0 * * *',
327
                    'description' => 'my description',
328
                    'without_overlapping' => null,
329
                    'between' => [
330
                        'start' => 9,
331
                        'end' => 17,
332
                    ],
333
                    'unless_between' => [
334
                        'start' => 12,
335
                        'end' => '13:30',
336
                    ],
337
                    'ping_before' => [
338
                        'url' => 'https://example.com/before',
339
                    ],
340
                    'ping_after' => [
341
                        'url' => 'https://example.com/after',
342
                    ],
343
                    'ping_on_success' => [
344
                        'url' => 'https://example.com/success',
345
                    ],
346
                    'ping_on_failure' => [
347
                        'url' => 'https://example.com/failure',
348
                        'method' => 'POST',
349
                    ],
350
                    'email_after' => null,
351
                    'email_on_failure' => [
352
                        'to' => '[email protected]',
353
                        'subject' => 'my subject',
354
                    ],
355
                ],
356
            ],
357
        ]);
358
359
        $config = $this->container->getDefinition(ConfigureTasksSubscriber::class)->getArgument(0)[0];
360
361
        $this->assertSame(['my:command --option', 'another:command'], $config['command']);
362
        $this->assertSame('0 0 * * *', $config['frequency']);
363
        $this->assertSame('my description', $config['description']);
364
        $this->assertTrue($config['without_overlapping']['enabled']);
365
        $this->assertSame(WithoutOverlappingExtension::DEFAULT_TTL, $config['without_overlapping']['ttl']);
366
        $this->assertTrue($config['between']['enabled']);
367
        $this->assertSame(9, $config['between']['start']);
368
        $this->assertSame(17, $config['between']['end']);
369
        $this->assertTrue($config['unless_between']['enabled']);
370
        $this->assertSame(12, $config['unless_between']['start']);
371
        $this->assertSame('13:30', $config['unless_between']['end']);
372
        $this->assertTrue($config['ping_before']['enabled']);
373
        $this->assertSame('https://example.com/before', $config['ping_before']['url']);
374
        $this->assertSame('GET', $config['ping_before']['method']);
375
        $this->assertTrue($config['ping_after']['enabled']);
376
        $this->assertSame('https://example.com/after', $config['ping_after']['url']);
377
        $this->assertSame('GET', $config['ping_after']['method']);
378
        $this->assertTrue($config['ping_on_success']['enabled']);
379
        $this->assertSame('https://example.com/success', $config['ping_on_success']['url']);
380
        $this->assertSame('GET', $config['ping_on_success']['method']);
381
        $this->assertTrue($config['ping_on_failure']['enabled']);
382
        $this->assertSame('https://example.com/failure', $config['ping_on_failure']['url']);
383
        $this->assertSame('POST', $config['ping_on_failure']['method']);
384
        $this->assertTrue($config['email_after']['enabled']);
385
        $this->assertNull($config['email_after']['to']);
386
        $this->assertNull($config['email_after']['subject']);
387
        $this->assertTrue($config['email_on_failure']['enabled']);
388
        $this->assertSame('[email protected]', $config['email_on_failure']['to']);
389
        $this->assertSame('my subject', $config['email_on_failure']['subject']);
390
    }
391
392
    /**
393
     * @test
394
     */
395
    public function email_and_ping_configuration_can_be_shortened()
396
    {
397
        $this->load([
398
            'tasks' => [
399
                [
400
                    'command' => 'my:command --option',
401
                    'frequency' => '0 0 * * *',
402
                    'ping_after' => 'https://example.com/after',
403
                    'email_after' => '[email protected]',
404
                ],
405
            ],
406
        ]);
407
408
        $config = $this->container->getDefinition(ConfigureTasksSubscriber::class)->getArgument(0)[0];
409
410
        $this->assertTrue($config['ping_after']['enabled']);
411
        $this->assertSame('https://example.com/after', $config['ping_after']['url']);
412
        $this->assertSame('GET', $config['ping_after']['method']);
413
        $this->assertSame([], $config['ping_after']['options']);
414
415
        $this->assertTrue($config['email_after']['enabled']);
416
        $this->assertSame('[email protected]', $config['email_after']['to']);
417
        $this->assertNull($config['email_after']['subject']);
418
    }
419
420
    /**
421
     * @test
422
     */
423
    public function between_and_unless_between_config_can_be_shortened()
424
    {
425
        $this->load([
426
            'tasks' => [
427
                [
428
                    'command' => 'my:command --option',
429
                    'frequency' => '0 0 * * *',
430
                    'between' => '9-17',
431
                    'unless_between' => '11:30-13:15',
432
                ],
433
            ],
434
        ]);
435
436
        $config = $this->container->getDefinition(ConfigureTasksSubscriber::class)->getArgument(0)[0];
437
438
        $this->assertTrue($config['between']['enabled']);
439
        $this->assertSame('9', $config['between']['start']);
440
        $this->assertSame('17', $config['between']['end']);
441
442
        $this->assertTrue($config['unless_between']['enabled']);
443
        $this->assertSame('11:30', $config['unless_between']['start']);
444
        $this->assertSame('13:15', $config['unless_between']['end']);
445
    }
446
447
    protected function getContainerExtensions(): array
448
    {
449
        return [new ZenstruckScheduleExtension()];
450
    }
451
}
452