Completed
Push — master ( 76bf8f...bb8cc0 )
by Greg
02:30
created

CollectionCest::toAbortRollbackOrCompletion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 31

Duplication

Lines 31
Ratio 100 %

Importance

Changes 0
Metric Value
dl 31
loc 31
rs 9.424
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
namespace Robo;
3
4
use \CliGuy;
5
6
use Robo\Collection\Temporary;
7
use Robo\Exception\AbortTasksException;
8
9
class CollectionCest
10
{
11
    public function _before(CliGuy $I)
12
    {
13
        $I->amInPath(codecept_data_dir().'sandbox');
14
    }
15
16
    public function toRunMultipleTasksViaACollectionBuilder(CliGuy $I)
17
    {
18
        // This tests creating multiple tasks in a single builder,
19
        // which implicitly adds them to a collection.  To keep things
20
        // simple, we are only going to use taskFilesystemStack.  It
21
        // would be possible, of course, to do these operations with
22
        // a single FilesystemStack, but our goal is to test creating
23
        // multiple tasks with a builder, and ensure that a propper
24
        // collection is built.
25
        $collection = $I->collectionBuilder();
26
        $result = $collection->taskFilesystemStack()
27
                ->mkdir('a')
28
                ->touch('a/a.txt')
29
            ->rollback(
30
                $I->taskDeleteDir('a')
31
            )
32
            ->taskFilesystemStack()
33
                ->mkdir('a/b')
34
                ->touch('a/b/b.txt')
35
            ->taskFilesystemStack()
36
                ->mkdir('a/c')
37
                ->touch('a/c/c.txt')
38
            ->run();
39
40
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
41
42
        // All of the tasks created by the builder should be added
43
        // to a collection, and `run()` should run them all.
44
        $I->seeDirFound('a');
45
        $I->seeFileFound('a/a.txt');
46
        $I->seeDirFound('a/b');
47
        $I->seeFileFound('a/b/b.txt');
48
        $I->seeDirFound('a/c');
49
        $I->seeFileFound('a/c/c.txt');
50
    }
51
52
    public function toUseAWorkingDirWithACollectionBuilder(CliGuy $I)
53
    {
54
        // Run the same test with a working directory.  The working
55
        // directory path will point to a temporary directory which
56
        // will be moved into place once the tasks complete.
57
        $collection = $I->collectionBuilder();
58
        $workDirPath = $collection->workDir("build");
59
        $I->assertNotEquals("build", basename($workDirPath));
60
        $result = $collection->taskFilesystemStack()
61
                ->mkdir("{$workDirPath}/a")
62
                ->touch("{$workDirPath}/a/a.txt")
63
            ->taskFilesystemStack()
64
                ->mkdir("{$workDirPath}/a/b")
65
                ->touch("{$workDirPath}/a/b/b.txt")
66
            ->taskFilesystemStack()
67
                ->mkdir("{$workDirPath}/a/c")
68
                ->touch("{$workDirPath}/a/c/c.txt")
69
            ->run();
70
71
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
72
73
        // All of the tasks created by the builder should be added
74
        // to a collection, and `run()` should run them all.
75
        $I->seeDirFound('build/a');
76
        $I->seeFileFound('build/a/a.txt');
77
        $I->seeDirFound('build/a/b');
78
        $I->seeFileFound('build/a/b/b.txt');
79
        $I->seeDirFound('build/a/c');
80
        $I->seeFileFound('build/a/c/c.txt');
81
    }
82
83 View Code Duplication
    public function toRollbackAfterFailureViaACollectionBuilder(CliGuy $I)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
    {
85
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
86
        // except we force an error at the end, and confirm that the
87
        // rollback function is called.
88
        $collection = $I->collectionBuilder();
89
        $result = $collection->taskFilesystemStack()
90
                ->mkdir('j')
91
                ->touch('j/j.txt')
92
            ->rollback(
93
                $I->taskDeleteDir('j')
94
            )
95
            ->taskFilesystemStack()
96
                ->mkdir('j/k')
97
                ->touch('j/k/k.txt')
98
            ->taskFilesystemStack()
99
                ->mkdir('j/k/m')
100
                ->touch('j/k/m/m.txt')
101
            ->taskCopyDir(['doesNotExist' => 'copied'])
102
            ->run();
103
104
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
105
106
        // All of the tasks created by the builder should be added
107
        // to a collection, and `run()` should run them all.
108
        $I->dontSeeFileFound('q/q.txt');
109
        $I->dontSeeFileFound('j/j.txt');
110
        $I->dontSeeFileFound('j/k/k.txt');
111
        $I->dontSeeFileFound('j/k/m/m.txt');
112
    }
113
114 View Code Duplication
    public function toAbortRollbackOrCompletion(CliGuy $I)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        // This is like the previous test, except we throw a ForcedException()
117
        // inside the rollback to abort the rollback.
118
        $collection = $I->collectionBuilder();
119
        $result = $collection->taskFilesystemStack()
120
            ->mkdir('j')
121
            ->touch('j/j.txt')
122
            ->rollback(
123
                $I->taskDeleteDir('j')
124
            )
125
            ->rollbackCode(function () {
126
                throw new AbortTasksException('Aborting rollback.');
127
            })
128
            ->taskFilesystemStack()
129
            ->mkdir('j/k')
130
            ->touch('j/k/k.txt')
131
            ->taskFilesystemStack()
132
            ->mkdir('j/k/m')
133
            ->touch('j/k/m/m.txt')
134
            ->taskCopyDir(['doesNotExist' => 'copied'])
135
            ->run();
136
137
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
138
139
        // All of the tasks created by the builder should be added
140
        // to a collection, and `run()` should run them all.
141
        $I->seeFileFound('j/j.txt');
142
        $I->seeFileFound('j/k/k.txt');
143
        $I->seeFileFound('j/k/m/m.txt');
144
    }
145
146
    public function toRollbackAWorkingDir(CliGuy $I)
147
    {
148
        // Run the same test with a working directory.  The working
149
        // directory path will point to a temporary directory which
150
        // will be moved into place once the tasks complete.
151
        $collection = $I->collectionBuilder();
152
        $workDirPath = $collection->workDir("build");
153
        $I->assertNotEquals("build", basename($workDirPath));
154
        $result = $collection->taskFilesystemStack()
155
                ->mkdir("{$workDirPath}/a")
156
                ->touch("{$workDirPath}/a/a.txt")
157
            ->taskFilesystemStack()
158
                ->mkdir("{$workDirPath}/a/b")
159
                ->touch("{$workDirPath}/a/b/b.txt")
160
            ->taskFilesystemStack()
161
                ->mkdir("{$workDirPath}/a/c")
162
                ->touch("{$workDirPath}/a/c/c.txt")
163
            ->taskCopyDir(['doesNotExist' => 'copied'])
164
            ->run();
165
166
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
167
168
        // All of the tasks created by the builder should be added
169
        // to a collection, and `run()` should run them all.
170
        $I->dontSeeFileFound('build/a');
171
        $I->dontSeeFileFound($workDirPath);
172
    }
173
174
    public function toBuildFilesViaAddIterable(CliGuy $I)
175
    {
176
        $processList = ['cats', 'dogs', 'sheep', 'fish', 'horses', 'cows'];
177
178
        $collection = $I->collectionBuilder();
179
        $result = $collection
180
            ->taskFilesystemStack()
181
                ->mkdir('stuff')
182
            ->taskForEach($processList)
183
                ->withBuilder(
184
                    function ($builder, $key, $value) {
185
                        return $builder
186
                            ->taskFilesystemStack()
187
                                ->touch("stuff/{$value}.txt");
188
                    }
189
                )
190
            ->run();
191
192
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
193
194
        $I->seeFileFound('stuff/cats.txt');
195
        $I->seeFileFound('stuff/dogs.txt');
196
        $I->seeFileFound('stuff/sheep.txt');
197
        $I->seeFileFound('stuff/fish.txt');
198
        $I->seeFileFound('stuff/horses.txt');
199
        $I->seeFileFound('stuff/cows.txt');
200
    }
201
202
    public function toRollbackANestedCollection(CliGuy $I)
203
    {
204
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
205
        // except we force an error at the end, and confirm that the
206
        // rollback function is called.
207
        $collection = $I->collectionBuilder();
208
        $collection->taskFilesystemStack()
209
                ->mkdir('j')
210
                ->touch('j/j.txt')
211
            ->rollback(
212
                $I->taskDeleteDir('j')
213
            )
214
            ->taskFilesystemStack()
215
                ->mkdir('j/k')
216
                ->touch('j/k/k.txt')
217
            ->taskFilesystemStack()
218
                ->mkdir('j/k/m')
219
                ->touch('j/k/m/m.txt');
220
221
        $result = $I->collectionBuilder()
222
            ->taskFilesystemStack()
223
                ->mkdir('q')
224
                ->touch('q/q.txt')
225
            ->addTask($collection)
226
            ->taskCopyDir(['doesNotExist' => 'copied'])
227
            ->run();
228
229
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
230
231
        // All of the tasks created by the builder should be added
232
        // to a collection, and `run()` should run them all.
233
        $I->seeFileFound('q/q.txt');
234
        $I->dontSeeFileFound('j/j.txt');
235
        $I->dontSeeFileFound('j/k/k.txt');
236
        $I->dontSeeFileFound('j/k/m/m.txt');
237
    }
238
239
    public function toRollbackInCorrectOrder(CliGuy $I)
240
    {
241
        $expected_order = [6,5,4,3,2,1];
242
        $actual_order = [];
243
        $collection = $I->collectionBuilder();
244
        $collection->rollbackCode(function () use (&$actual_order) {
245
            $actual_order[] = 1;
246
        });
247
        $collection->rollbackCode(function () use (&$actual_order) {
248
            $actual_order[] = 2;
249
        });
250
        $collection->rollbackCode(function () use (&$actual_order) {
251
            $actual_order[] = 3;
252
        });
253
        // Add a nested collection with rollbacks.
254
        $nested_collection = $I->collectionBuilder();
255
        $nested_collection->rollbackCode(function () use (&$actual_order) {
256
            $actual_order[] = 4;
257
        });
258
        $nested_collection->rollbackCode(function () use (&$actual_order) {
259
            $actual_order[] = 5;
260
        });
261
        $collection->addTask($nested_collection);
262
263
        $collection->rollbackCode(function () use (&$actual_order) {
264
            $actual_order[] = 6;
265
        });
266
        $collection->addCode(function () {
267
            return Result::EXITCODE_ERROR;
268
        });
269
        $result = $collection->run();
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
270
        $I->assertEquals($expected_order, $actual_order);
271
    }
272
273 View Code Duplication
    public function toCreateDirViaCollection(CliGuy $I)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
274
    {
275
        // Set up a collection to add tasks to
276
        $collection = $I->collectionBuilder();
277
278
        // Set up a filesystem stack
279
        $collection->taskFilesystemStack()
280
            ->mkdir('log')
281
            ->touch('log/error.txt');
282
283
        // FilesystemStack has not run yet, so file should not be found.
284
        $I->dontSeeFileFound('log/error.txt');
285
286
        // Run the task collection; now the files should be present
287
        $collection->run();
288
        $I->seeFileFound('log/error.txt');
289
        $I->seeDirFound('log');
290
    }
291
292
    public function toUseATmpDirAndConfirmItIsDeleted(CliGuy $I)
293
    {
294
        // Set up a collection to add tasks to
295
        $collection = $I->collectionBuilder();
296
297
        // Get a temporary directory to work in. Note that we get a
298
        // name back, but the directory is not created until the task
299
        // runs.  This technically is not thread-safe, but we create
300
        // a random name, so it is unlikely to conflict.
301
        $tmpPath = $collection->tmpDir();
302
303
        // Set up a filesystem stack, but use a collection to defer execution
304
        $collection->taskFilesystemStack()
305
            ->mkdir("$tmpPath/tmp")
306
            ->touch("$tmpPath/tmp/error.txt")
307
            ->rename("$tmpPath/tmp", "$tmpPath/log");
308
309
        // Copy our tmp directory to a location that is not transient
310
        $collection->taskCopyDir([$tmpPath => 'copied']);
311
312
        // FilesystemStack has not run yet, so no files should be found.
313
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
314
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
315
        $I->dontSeeFileFound('copied/log/error.txt');
316
317
        // Run the task collection
318
        $result = $collection->run();
319
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
320
        $I->assertEquals($result['path'], $tmpPath, "Tmp dir result matches accessor.");
321
322
        // The file 'error.txt' should have been copied into the "copied" dir.
323
        // This also proves that the tmp directory was created.
324
        $I->seeFileFound('copied/log/error.txt');
325
        // $tmpPath should be deleted after $collection->run() completes.
326
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
327
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
328
        $I->dontSeeFileFound("$tmpPath");
329
    }
330
331
    public function toUseATmpDirAndChangeWorkingDirectory(CliGuy $I)
332
    {
333
        // Set up a collection to add tasks to
334
        $collection = $I->collectionBuilder();
335
336
        $cwd = getcwd();
337
338
        $tmpPath = $collection->taskTmpDir()
339
            ->cwd()
340
            ->getPath();
341
342
        // Set up a filesystem stack, but use a collection to defer execution.
343
        // Note that since we used 'cwd()' above, the relative file paths
344
        // used below will be inside the temporary directory.
345
        $collection->taskFilesystemStack()
346
            ->mkdir("log")
347
            ->touch("log/error.txt");
348
349
        // Copy our tmp directory to a location that is not transient
350
        $collection->taskCopyDir(['log' => "$cwd/copied2"]);
351
352
        // FilesystemStack has not run yet, so no files should be found.
353
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
354
        $I->dontSeeFileFound('$cwd/copied2/log/error.txt');
355
356
        // Run the task collection
357
        $result = $collection->run();
358
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
359
360
        // The file 'error.txt' should have been copied into the "copied" dir
361
        $I->seeFileFound("$cwd/copied2/error.txt");
362
        // $tmpPath should be deleted after $collection->run() completes.
363
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
364
        // Make sure that 'log' was created in the temporary directory, not
365
        // at the current working directory.
366
        $I->dontSeeFileFound("$cwd/log/error.txt");
367
368
        // Make sure that our working directory was restored.
369
        $finalWorkingDir = getcwd();
370
        $I->assertEquals($cwd, $finalWorkingDir);
371
    }
372
373
    public function toCreateATmpFileAndConfirmItIsDeleted(CliGuy $I)
374
    {
375
        // Set up a collection to add tasks to
376
        $collection = $I->collectionBuilder();
377
378
        // Write to a temporary file. Note that we can get the path
379
        // to the tempoary file that will be created, even though the
380
        // the file is not created until the task collecction runs.
381
        $tmpPath = $collection->taskTmpFile('tmp', '.txt')
382
            ->line("This is a test file")
383
            ->getPath();
384
385
        // Copy our tmp directory to a location that is not transient
386
        $collection->taskFilesystemStack()
387
            ->copy($tmpPath, 'copied.txt');
388
389
        // FilesystemStack has not run yet, so no files should be found.
390
        $I->dontSeeFileFound("$tmpPath");
391
        $I->dontSeeFileFound('copied.txt');
392
393
        // Run the task collection
394
        $result = $collection->run();
395
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
396
397
        // The file 'copied.txt' should have been copied from the tmp file
398
        $I->seeFileFound('copied.txt');
399
        // $tmpPath should be deleted after $collection->run() completes.
400
        $I->dontSeeFileFound("$tmpPath");
401
    }
402
403
    public function toUseATmpDirWithAlternateSyntax(CliGuy $I)
404
    {
405
        $collection = $I->collectionBuilder();
406
407
        // This test is equivalent to toUseATmpDirAndConfirmItIsDeleted,
408
        // but uses a different technique to create a collection of tasks.
409
        $tmpPath = $collection->tmpDir();
410
411
        // Now, rather than creating the tasks with a collection builder,
412
        // which automatically adds the tasks to the collection as they are
413
        // created, we will instead create them individually and then add
414
        // them to the collection via the addTaskList() method.
415
        $result = $collection->addTaskList(
416
            [
417
                $I->taskFilesystemStack()->mkdir("$tmpPath/log")->touch("$tmpPath/log/error.txt"),
418
                $I->taskCopyDir([$tmpPath => 'copied3']),
419
            ]
420
        )->run();
421
422
        // The results of this operation should be the same.
423
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
424
        $I->seeFileFound('copied3/log/error.txt');
425
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
426
    }
427
428
    public function toCreateATmpDirWithoutACollection(CliGuy $I)
429
    {
430
        // Create a temporary directory, using our function name as
431
        // the prefix for the directory name.
432
        $tmpDirTask = $I->taskTmpDir(__FUNCTION__);
433
        $tmpPath = $tmpDirTask->getPath();
434
        $I->dontSeeFileFound($tmpPath);
435
        $tmpDirTask->run();
436
        $I->seeDirFound($tmpPath);
437
        // Creating a temporary directory without a task collection will
438
        // cause the temporary directory to be deleted when the program
439
        // terminates.  We can force it to clean up sooner by calling
440
        // TransientManager::complete(); note that this deletes ALL global tmp
441
        // directories, so this is not thread-safe!  Useful in tests, though.
442
        Temporary::complete();
443
        $I->dontSeeFileFound($tmpPath);
444
    }
445
446
    public function toCreateATmpDirUsingShortcut(CliGuy $I)
447
    {
448
        // Create a temporary directory, using our function name as
449
        // the prefix for the directory name.
450
        $tmpPath = $I->shortcutTmpDir(__FUNCTION__);
451
        $I->seeDirFound($tmpPath);
452
        // Creating a temporary directory without a task collection will
453
        // cause the temporary directory to be deleted when the program
454
        // terminates.  We can force it to clean up sooner by calling
455
        // TransientManager::complete(); note that this deletes ALL global tmp
456
        // directories, so this is not thread-safe!  Useful in tests, though.
457
        Temporary::complete();
458
        $I->dontSeeFileFound($tmpPath);
459
    }
460
461
    public function toThrowAnExceptionAndConfirmItIsCaught(CliGuy $I)
462
    {
463
        $collection = $I->getContainer()->get('collection');
464
465
        $collection->addCode(
466
            function () {
467
                throw new \RuntimeException('Error');
468
            }
469
        );
470
        $result = $collection->run();
471
        $I->assertEquals('Error', $result->getMessage());
472
        $I->assertEquals(1, $result->getExitCode());
473
    }
474
475
    public function toChainData(CliGuy $I)
476
    {
477
        $collection = $I->collectionBuilder();
478
479
        $result = $collection
0 ignored issues
show
Unused Code introduced by
$result is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
480
            ->taskValueProvider()
481
                ->provideMessage('1st') // Sets Result's message to '1st'
482
                ->storeState('one') // Copy Result's message to $state['one']
483
            ->taskValueProvider()
484
                ->provideMessage('2nd')
485
                ->storeState('two')
486
            ->taskValueProvider()
487
                ->deferTaskConfiguration('provideItem', 'one') // Same as ->proivdeItem($state['one']), but runs immediately before this task's run() method.
488
                ->deferTaskConfiguration('provideMessage', 'two')
489
                ->storeState('final')
490
            ->run();
491
492
        $state = $collection->getState();
493
        $I->assertEquals('1st', $state['one']);
494
        $I->assertEquals('1st', $state['item']);
495
        $I->assertEquals('2nd', $state['final']);
496
    }
497
}
498