Completed
Pull Request — master (#812)
by
unknown
02:19
created

CollectionCest::toRollbackInCorrectOrder()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 22
rs 9.568
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
8
class CollectionCest
9
{
10
    public function _before(CliGuy $I)
11
    {
12
        $I->amInPath(codecept_data_dir().'sandbox');
13
    }
14
15
    public function toRunMultipleTasksViaACollectionBuilder(CliGuy $I)
16
    {
17
        // This tests creating multiple tasks in a single builder,
18
        // which implicitly adds them to a collection.  To keep things
19
        // simple, we are only going to use taskFilesystemStack.  It
20
        // would be possible, of course, to do these operations with
21
        // a single FilesystemStack, but our goal is to test creating
22
        // multiple tasks with a builder, and ensure that a propper
23
        // collection is built.
24
        $collection = $I->collectionBuilder();
25
        $result = $collection->taskFilesystemStack()
26
                ->mkdir('a')
27
                ->touch('a/a.txt')
28
            ->rollback(
29
                $I->taskDeleteDir('a')
30
            )
31
            ->taskFilesystemStack()
32
                ->mkdir('a/b')
33
                ->touch('a/b/b.txt')
34
            ->taskFilesystemStack()
35
                ->mkdir('a/c')
36
                ->touch('a/c/c.txt')
37
            ->run();
38
39
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
40
41
        // All of the tasks created by the builder should be added
42
        // to a collection, and `run()` should run them all.
43
        $I->seeDirFound('a');
44
        $I->seeFileFound('a/a.txt');
45
        $I->seeDirFound('a/b');
46
        $I->seeFileFound('a/b/b.txt');
47
        $I->seeDirFound('a/c');
48
        $I->seeFileFound('a/c/c.txt');
49
    }
50
51
    public function toUseAWorkingDirWithACollectionBuilder(CliGuy $I)
52
    {
53
        // Run the same test with a working directory.  The working
54
        // directory path will point to a temporary directory which
55
        // will be moved into place once the tasks complete.
56
        $collection = $I->collectionBuilder();
57
        $workDirPath = $collection->workDir("build");
58
        $I->assertNotEquals("build", basename($workDirPath));
59
        $result = $collection->taskFilesystemStack()
60
                ->mkdir("{$workDirPath}/a")
61
                ->touch("{$workDirPath}/a/a.txt")
62
            ->taskFilesystemStack()
63
                ->mkdir("{$workDirPath}/a/b")
64
                ->touch("{$workDirPath}/a/b/b.txt")
65
            ->taskFilesystemStack()
66
                ->mkdir("{$workDirPath}/a/c")
67
                ->touch("{$workDirPath}/a/c/c.txt")
68
            ->run();
69
70
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
71
72
        // All of the tasks created by the builder should be added
73
        // to a collection, and `run()` should run them all.
74
        $I->seeDirFound('build/a');
75
        $I->seeFileFound('build/a/a.txt');
76
        $I->seeDirFound('build/a/b');
77
        $I->seeFileFound('build/a/b/b.txt');
78
        $I->seeDirFound('build/a/c');
79
        $I->seeFileFound('build/a/c/c.txt');
80
    }
81
82
    public function toRollbackAfterFailureViaACollectionBuilder(CliGuy $I)
83
    {
84
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
85
        // except we force an error at the end, and confirm that the
86
        // rollback function is called.
87
        $collection = $I->collectionBuilder();
88
        $result = $collection->taskFilesystemStack()
89
                ->mkdir('j')
90
                ->touch('j/j.txt')
91
            ->rollback(
92
                $I->taskDeleteDir('j')
93
            )
94
            ->taskFilesystemStack()
95
                ->mkdir('j/k')
96
                ->touch('j/k/k.txt')
97
            ->taskFilesystemStack()
98
                ->mkdir('j/k/m')
99
                ->touch('j/k/m/m.txt')
100
            ->taskCopyDir(['doesNotExist' => 'copied'])
101
            ->run();
102
103
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
104
105
        // All of the tasks created by the builder should be added
106
        // to a collection, and `run()` should run them all.
107
        $I->dontSeeFileFound('q/q.txt');
108
        $I->dontSeeFileFound('j/j.txt');
109
        $I->dontSeeFileFound('j/k/k.txt');
110
        $I->dontSeeFileFound('j/k/m/m.txt');
111
    }
112
113
    public function toRollbackAWorkingDir(CliGuy $I)
114
    {
115
        // Run the same test with a working directory.  The working
116
        // directory path will point to a temporary directory which
117
        // will be moved into place once the tasks complete.
118
        $collection = $I->collectionBuilder();
119
        $workDirPath = $collection->workDir("build");
120
        $I->assertNotEquals("build", basename($workDirPath));
121
        $result = $collection->taskFilesystemStack()
122
                ->mkdir("{$workDirPath}/a")
123
                ->touch("{$workDirPath}/a/a.txt")
124
            ->taskFilesystemStack()
125
                ->mkdir("{$workDirPath}/a/b")
126
                ->touch("{$workDirPath}/a/b/b.txt")
127
            ->taskFilesystemStack()
128
                ->mkdir("{$workDirPath}/a/c")
129
                ->touch("{$workDirPath}/a/c/c.txt")
130
            ->taskCopyDir(['doesNotExist' => 'copied'])
131
            ->run();
132
133
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
134
135
        // All of the tasks created by the builder should be added
136
        // to a collection, and `run()` should run them all.
137
        $I->dontSeeFileFound('build/a');
138
        $I->dontSeeFileFound($workDirPath);
139
    }
140
141
    public function toBuildFilesViaAddIterable(CliGuy $I)
142
    {
143
        $processList = ['cats', 'dogs', 'sheep', 'fish', 'horses', 'cows'];
144
145
        $collection = $I->collectionBuilder();
146
        $result = $collection
147
            ->taskFilesystemStack()
148
                ->mkdir('stuff')
149
            ->taskForEach($processList)
150
                ->withBuilder(
151
                    function ($builder, $key, $value) {
152
                        return $builder
153
                            ->taskFilesystemStack()
154
                                ->touch("stuff/{$value}.txt");
155
                    }
156
                )
157
            ->run();
158
159
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
160
161
        $I->seeFileFound('stuff/cats.txt');
162
        $I->seeFileFound('stuff/dogs.txt');
163
        $I->seeFileFound('stuff/sheep.txt');
164
        $I->seeFileFound('stuff/fish.txt');
165
        $I->seeFileFound('stuff/horses.txt');
166
        $I->seeFileFound('stuff/cows.txt');
167
    }
168
169
    public function toRollbackANestedCollection(CliGuy $I)
170
    {
171
        // This is like the previous test, toRunMultipleTasksViaACollectionBuilder,
172
        // except we force an error at the end, and confirm that the
173
        // rollback function is called.
174
        $collection = $I->collectionBuilder();
175
        $collection->taskFilesystemStack()
176
                ->mkdir('j')
177
                ->touch('j/j.txt')
178
            ->rollback(
179
                $I->taskDeleteDir('j')
180
            )
181
            ->taskFilesystemStack()
182
                ->mkdir('j/k')
183
                ->touch('j/k/k.txt')
184
            ->taskFilesystemStack()
185
                ->mkdir('j/k/m')
186
                ->touch('j/k/m/m.txt');
187
188
        $result = $I->collectionBuilder()
189
            ->taskFilesystemStack()
190
                ->mkdir('q')
191
                ->touch('q/q.txt')
192
            ->addTask($collection)
193
            ->taskCopyDir(['doesNotExist' => 'copied'])
194
            ->run();
195
196
        $I->assertEquals(1, $result->getExitCode(), $result->getMessage());
197
198
        // All of the tasks created by the builder should be added
199
        // to a collection, and `run()` should run them all.
200
        $I->seeFileFound('q/q.txt');
201
        $I->dontSeeFileFound('j/j.txt');
202
        $I->dontSeeFileFound('j/k/k.txt');
203
        $I->dontSeeFileFound('j/k/m/m.txt');
204
    }
205
206
    public function toRollbackInCorrectOrder(CliGuy $I) {
207
        $expected_order = [4,3,2,1];
208
        $actual_order = [];
209
        $collection = $I->collectionBuilder();
210
        $collection->rollbackCode(function () use (&$actual_order) {
211
            $actual_order[] = 1;
212
        });
213
        $collection->rollbackCode(function () use (&$actual_order) {
214
            $actual_order[] = 2;
215
        });
216
        $collection->rollbackCode(function () use (&$actual_order) {
217
            $actual_order[] = 3;
218
        });
219
        $collection->rollbackCode(function () use (&$actual_order) {
220
            $actual_order[] = 4;
221
        });
222
        $collection->addCode(function () {
223
            return Result::EXITCODE_ERROR;
224
        });
225
        $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...
226
        $I->assertEquals($expected_order, $actual_order);
227
    }
228
229 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...
230
    {
231
        // Set up a collection to add tasks to
232
        $collection = $I->collectionBuilder();
233
234
        // Set up a filesystem stack
235
        $collection->taskFilesystemStack()
236
            ->mkdir('log')
237
            ->touch('log/error.txt');
238
239
        // FilesystemStack has not run yet, so file should not be found.
240
        $I->dontSeeFileFound('log/error.txt');
241
242
        // Run the task collection; now the files should be present
243
        $collection->run();
244
        $I->seeFileFound('log/error.txt');
245
        $I->seeDirFound('log');
246
    }
247
248
    public function toUseATmpDirAndConfirmItIsDeleted(CliGuy $I)
249
    {
250
        // Set up a collection to add tasks to
251
        $collection = $I->collectionBuilder();
252
253
        // Get a temporary directory to work in. Note that we get a
254
        // name back, but the directory is not created until the task
255
        // runs.  This technically is not thread-safe, but we create
256
        // a random name, so it is unlikely to conflict.
257
        $tmpPath = $collection->tmpDir();
258
259
        // Set up a filesystem stack, but use a collection to defer execution
260
        $collection->taskFilesystemStack()
261
            ->mkdir("$tmpPath/tmp")
262
            ->touch("$tmpPath/tmp/error.txt")
263
            ->rename("$tmpPath/tmp", "$tmpPath/log");
264
265
        // Copy our tmp directory to a location that is not transient
266
        $collection->taskCopyDir([$tmpPath => 'copied']);
267
268
        // FilesystemStack has not run yet, so no files should be found.
269
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
270
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
271
        $I->dontSeeFileFound('copied/log/error.txt');
272
273
        // Run the task collection
274
        $result = $collection->run();
275
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
276
        $I->assertEquals($result['path'], $tmpPath, "Tmp dir result matches accessor.");
277
278
        // The file 'error.txt' should have been copied into the "copied" dir.
279
        // This also proves that the tmp directory was created.
280
        $I->seeFileFound('copied/log/error.txt');
281
        // $tmpPath should be deleted after $collection->run() completes.
282
        $I->dontSeeFileFound("$tmpPath/tmp/error.txt");
283
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
284
        $I->dontSeeFileFound("$tmpPath");
285
    }
286
287
    public function toUseATmpDirAndChangeWorkingDirectory(CliGuy $I)
288
    {
289
        // Set up a collection to add tasks to
290
        $collection = $I->collectionBuilder();
291
292
        $cwd = getcwd();
293
294
        $tmpPath = $collection->taskTmpDir()
295
            ->cwd()
296
            ->getPath();
297
298
        // Set up a filesystem stack, but use a collection to defer execution.
299
        // Note that since we used 'cwd()' above, the relative file paths
300
        // used below will be inside the temporary directory.
301
        $collection->taskFilesystemStack()
302
            ->mkdir("log")
303
            ->touch("log/error.txt");
304
305
        // Copy our tmp directory to a location that is not transient
306
        $collection->taskCopyDir(['log' => "$cwd/copied2"]);
307
308
        // FilesystemStack has not run yet, so no files should be found.
309
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
310
        $I->dontSeeFileFound('$cwd/copied2/log/error.txt');
311
312
        // Run the task collection
313
        $result = $collection->run();
314
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
315
316
        // The file 'error.txt' should have been copied into the "copied" dir
317
        $I->seeFileFound("$cwd/copied2/error.txt");
318
        // $tmpPath should be deleted after $collection->run() completes.
319
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
320
        // Make sure that 'log' was created in the temporary directory, not
321
        // at the current working directory.
322
        $I->dontSeeFileFound("$cwd/log/error.txt");
323
324
        // Make sure that our working directory was restored.
325
        $finalWorkingDir = getcwd();
326
        $I->assertEquals($cwd, $finalWorkingDir);
327
    }
328
329
    public function toCreateATmpFileAndConfirmItIsDeleted(CliGuy $I)
330
    {
331
        // Set up a collection to add tasks to
332
        $collection = $I->collectionBuilder();
333
334
        // Write to a temporary file. Note that we can get the path
335
        // to the tempoary file that will be created, even though the
336
        // the file is not created until the task collecction runs.
337
        $tmpPath = $collection->taskTmpFile('tmp', '.txt')
338
            ->line("This is a test file")
339
            ->getPath();
340
341
        // Copy our tmp directory to a location that is not transient
342
        $collection->taskFilesystemStack()
343
            ->copy($tmpPath, 'copied.txt');
344
345
        // FilesystemStack has not run yet, so no files should be found.
346
        $I->dontSeeFileFound("$tmpPath");
347
        $I->dontSeeFileFound('copied.txt');
348
349
        // Run the task collection
350
        $result = $collection->run();
351
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
352
353
        // The file 'copied.txt' should have been copied from the tmp file
354
        $I->seeFileFound('copied.txt');
355
        // $tmpPath should be deleted after $collection->run() completes.
356
        $I->dontSeeFileFound("$tmpPath");
357
    }
358
359
    public function toUseATmpDirWithAlternateSyntax(CliGuy $I)
360
    {
361
        $collection = $I->collectionBuilder();
362
363
        // This test is equivalent to toUseATmpDirAndConfirmItIsDeleted,
364
        // but uses a different technique to create a collection of tasks.
365
        $tmpPath = $collection->tmpDir();
366
367
        // Now, rather than creating the tasks with a collection builder,
368
        // which automatically adds the tasks to the collection as they are
369
        // created, we will instead create them individually and then add
370
        // them to the collection via the addTaskList() method.
371
        $result = $collection->addTaskList(
372
            [
373
                $I->taskFilesystemStack()->mkdir("$tmpPath/log")->touch("$tmpPath/log/error.txt"),
374
                $I->taskCopyDir([$tmpPath => 'copied3']),
375
            ]
376
        )->run();
377
378
        // The results of this operation should be the same.
379
        $I->assertEquals(0, $result->getExitCode(), $result->getMessage());
380
        $I->seeFileFound('copied3/log/error.txt');
381
        $I->dontSeeFileFound("$tmpPath/log/error.txt");
382
    }
383
384
    public function toCreateATmpDirWithoutACollection(CliGuy $I)
385
    {
386
        // Create a temporary directory, using our function name as
387
        // the prefix for the directory name.
388
        $tmpDirTask = $I->taskTmpDir(__FUNCTION__);
389
        $tmpPath = $tmpDirTask->getPath();
390
        $I->dontSeeFileFound($tmpPath);
391
        $tmpDirTask->run();
392
        $I->seeDirFound($tmpPath);
393
        // Creating a temporary directory without a task collection will
394
        // cause the temporary directory to be deleted when the program
395
        // terminates.  We can force it to clean up sooner by calling
396
        // TransientManager::complete(); note that this deletes ALL global tmp
397
        // directories, so this is not thread-safe!  Useful in tests, though.
398
        Temporary::complete();
399
        $I->dontSeeFileFound($tmpPath);
400
    }
401
402
    public function toCreateATmpDirUsingShortcut(CliGuy $I)
403
    {
404
        // Create a temporary directory, using our function name as
405
        // the prefix for the directory name.
406
        $tmpPath = $I->shortcutTmpDir(__FUNCTION__);
407
        $I->seeDirFound($tmpPath);
408
        // Creating a temporary directory without a task collection will
409
        // cause the temporary directory to be deleted when the program
410
        // terminates.  We can force it to clean up sooner by calling
411
        // TransientManager::complete(); note that this deletes ALL global tmp
412
        // directories, so this is not thread-safe!  Useful in tests, though.
413
        Temporary::complete();
414
        $I->dontSeeFileFound($tmpPath);
415
    }
416
417
    public function toThrowAnExceptionAndConfirmItIsCaught(CliGuy $I)
418
    {
419
        $collection = $I->getContainer()->get('collection');
420
421
        $collection->addCode(
422
            function () {
423
                throw new \RuntimeException('Error');
424
            }
425
        );
426
        $result = $collection->run();
427
        $I->assertEquals('Error', $result->getMessage());
428
        $I->assertEquals(1, $result->getExitCode());
429
    }
430
431
    public function toChainData(CliGuy $I)
432
    {
433
        $collection = $I->collectionBuilder();
434
435
        $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...
436
            ->taskValueProvider()
437
                ->provideMessage('1st') // Sets Result's message to '1st'
438
                ->storeState('one') // Copy Result's message to $state['one']
439
            ->taskValueProvider()
440
                ->provideMessage('2nd')
441
                ->storeState('two')
442
            ->taskValueProvider()
443
                ->deferTaskConfiguration('provideItem', 'one') // Same as ->proivdeItem($state['one']), but runs immediately before this task's run() method.
444
                ->deferTaskConfiguration('provideMessage', 'two')
445
                ->storeState('final')
446
            ->run();
447
448
        $state = $collection->getState();
449
        $I->assertEquals('1st', $state['one']);
450
        $I->assertEquals('1st', $state['item']);
451
        $I->assertEquals('2nd', $state['final']);
452
    }
453
}
454