Completed
Push — master ( 42ada5...e5d943 )
by Joschi
02:42
created

testRepositoryCreationOverExistingSizeDescriptor()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 14
rs 9.4285
cc 1
eloc 9
nc 1
nop 0
1
<?php
2
3
/**
4
 * apparat-object
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Object
8
 * @subpackage  Apparat\Object\Infrastructure
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Object\Tests;
38
39
use Apparat\Object\Domain\Factory\SelectorFactory;
40
use Apparat\Object\Domain\Model\Object\Collection;
41
use Apparat\Object\Domain\Model\Path\RepositoryPath;
42
use Apparat\Object\Domain\Repository\Repository;
43
use Apparat\Object\Domain\Repository\SelectorInterface;
44
use Apparat\Object\Infrastructure\Factory\AdapterStrategyFactory;
45
use Apparat\Object\Infrastructure\Repository\FileAdapterStrategy;
46
use Apparat\Object\Module;
47
use Apparat\Object\Ports\Repository as RepositoryFactory;
48
49
/**
50
 * Repository test
51
 *
52
 * @package Apparat\Object
53
 * @subpackage ApparatTest
54
 */
55
class RepositoryTest extends AbstractDisabledAutoconnectorTest
56
{
57
    /**
58
     * Temporary glob directory
59
     *
60
     * @var string
61
     */
62
    protected static $globBase = null;
63
    /**
64
     * Created temporary files
65
     *
66
     * @var array
67
     */
68
    protected static $globFiles = [];
69
    /**
70
     * Created temporary directories
71
     *
72
     * @var array
73
     */
74
    protected static $globDirs = [];
75
    /**
76
     * Type counter
77
     *
78
     * @var array
79
     */
80
    protected static $globTypes = ['event' => 0, 'article' => 0, 'note' => 0];
81
    /**
82
     * Revision counter
83
     *
84
     * @var array
85
     */
86
    protected static $globRevisions = ['' => 0, '-0' => 0, '-1' => 0];
87
88
    /**
89
     * Setup
90
     */
91
    public static function setUpBeforeClass()
92
    {
93
        parent::setUpBeforeClass();
94
        self::$globDirs[] =
95
        self::$globBase = sys_get_temp_dir().DIRECTORY_SEPARATOR.'glob';
96
97
        $types = array_keys(self::$globTypes);
98
        $revisions = array_keys(self::$globRevisions);
99
        $index = 0;
100
101
        // Setup test directories & files
102
        for ($currentYear = intval(date('Y')), $year = $currentYear; $year < $currentYear + 3; ++$year) {
103
            self::$globDirs[] =
104
            $yearDir = self::$globBase.DIRECTORY_SEPARATOR.$year;
105
            for ($month = 1; $month < 13; ++$month) {
106
                self::$globDirs[] =
107
                $monthDir = $yearDir.DIRECTORY_SEPARATOR.str_pad($month, 2, '0', STR_PAD_LEFT);
108
                $days = [];
109
                while (count($days) < 3) {
110
                    $day = rand(1, date('t', mktime(0, 0, 0, $month, 1, $year)));
111
                    $days[$day] = $day;
112
                }
113
                foreach ($days as $day) {
114
                    self::$globDirs[] =
115
                    $dayDir = $monthDir.DIRECTORY_SEPARATOR.str_pad($day, 2, '0', STR_PAD_LEFT);
116
                    mkdir($dayDir, 0777, true);
117
                    self::$globDirs[] =
118
                    $hourDir = $dayDir.DIRECTORY_SEPARATOR.'00';
119
                    mkdir($hourDir, 0777, true);
120
                    self::$globDirs[] =
121
                    $minuteDir = $hourDir.DIRECTORY_SEPARATOR.'00';
122
                    mkdir($minuteDir, 0777, true);
123
                    self::$globDirs[] =
124
                    $secondDir = $minuteDir.DIRECTORY_SEPARATOR.'00';
125
                    mkdir($secondDir, 0777, true);
126
127
128
                    // Create random subfolders and object files
129
                    for ($object = 1; $object < 3; ++$object) {
130
                        ++$index;
131
                        $type = $types[rand(0, 2)];
132
                        $revision = $revisions[rand(0, 2)];
133
                        ++self::$globTypes[$type];
134
                        ++self::$globRevisions[$revision];
135
                        self::$globDirs[] =
136
                        $objectDir = $secondDir.DIRECTORY_SEPARATOR.$index.'.'.$type;
137
                        mkdir($objectDir);
138
                        self::$globFiles[] =
139
                        $objectFile = $objectDir.DIRECTORY_SEPARATOR.$index.$revision;
140
                        touch($objectFile);
141
                    }
142
                }
143
            }
144
        }
145
146
        putenv('OBJECT_DATE_PRECISION=6');
147
    }
148
149
    /**
150
     * Teardown
151
     */
152
    public static function tearDownAfterClass()
153
    {
154
        parent::tearDownAfterClass();
155
        foreach (self::$globFiles as $globFile) {
156
            @unlink($globFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
157
        }
158
        foreach (array_reverse(self::$globDirs) as $globDir) {
159
            @rmdir($globDir);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
160
        }
161
162
        putenv('OBJECT_DATE_PRECISION=3');
163
    }
164
165
    /**
166
     * Test a bare URL with invalid schema
167
     *
168
     * @expectedException \RuntimeException
169
     * @expectedExceptionCode 1451776352
170
     */
171
    public static function testInvalidSchemaBareUrl()
172
    {
173
        Module::isAbsoluteBareUrl('ftp://example.com');
174
    }
175
176
    /**
177
     * Test a bare URL with query
178
     *
179
     * @expectedException \RuntimeException
180
     * @expectedExceptionCode 1451776509
181
     */
182
    public static function testInvalidQueryBareUrl()
183
    {
184
        Module::isAbsoluteBareUrl('http://example.com/?a=1');
185
    }
186
187
    /**
188
     * Test a bare URL with fragment
189
     *
190
     * @expectedException \RuntimeException
191
     * @expectedExceptionCode 1451776570
192
     */
193
    public static function testInvalidFragmentBareUrl()
194
    {
195
        Module::isAbsoluteBareUrl('http://example.com/#1');
196
    }
197
198
    /**
199
     * Test invalid query repository URL registration
200
     *
201
     * @expectedException \Apparat\Object\Infrastructure\Repository\InvalidArgumentException
202
     * @expectedExceptionCode 1451776509
203
     */
204
    public function testRegisterInvalidQueryRepositoryUrl()
205
    {
206
        RepositoryFactory::register(getenv('REPOSITORY_URL').'?a=1', []);
207
    }
208
209
    /**
210
     * Test invalid query repository URL registration
211
     *
212
     * @expectedException \Apparat\Object\Infrastructure\Repository\InvalidArgumentException
213
     * @expectedExceptionCode 1451776509
214
     */
215
    public function testInstantiateInvalidQueryRepositoryUrl()
216
    {
217
        RepositoryFactory::register(
218
            getenv('REPOSITORY_URL'),
219
            [
220
                'type' => FileAdapterStrategy::TYPE,
221
                'root' => __DIR__,
222
            ]
223
        );
224
        RepositoryFactory::instance(getenv('REPOSITORY_URL').'?a=1');
225
    }
226
227
    /**
228
     * Test unknown public repository URL instantiation
229
     *
230
     * @expectedException \Apparat\Object\Infrastructure\Repository\InvalidArgumentException
231
     * @expectedExceptionCode 1451771889
232
     */
233
    public function testInstantiateUnknownRepositoryUrl()
234
    {
235
        RepositoryFactory::instance('unknown');
236
    }
237
238
    /**
239
     * Test empty repository config
240
     *
241
     * @expectedException \Apparat\Object\Infrastructure\Factory\InvalidArgumentException
242
     * @expectedExceptionCode 1449956347
243
     */
244
    public function testEmptyRepositoryConfig()
245
    {
246
        RepositoryFactory::register(getenv('REPOSITORY_URL'), []);
247
    }
248
249
    /**
250
     * Test empty adapter strategy configuration
251
     *
252
     * @expectedException \Apparat\Object\Infrastructure\Factory\InvalidArgumentException
253
     * @expectedExceptionCode 1449956347
254
     */
255
    public function testEmptyAdapterStrategyConfig()
256
    {
257
        (new AdapterStrategyFactory)->createFromConfig([]);
258
    }
259
260
    /**
261
     * Test invalid adapter strategy type
262
     *
263
     * @expectedException \Apparat\Object\Infrastructure\Factory\InvalidArgumentException
264
     * @expectedExceptionCode 1449956471
265
     */
266
    public function testInvalidAdapterStrategyType()
267
    {
268
        (new AdapterStrategyFactory)->createFromConfig(
269
            [
270
                'type' => 'invalid',
271
            ]
272
        );
273
    }
274
275
    /**
276
     * Test file adapter strategy type
277
     */
278
    public function testFileAdapterStrategy()
279
    {
280
        $fileAdapterStrategy = (new AdapterStrategyFactory)->createFromConfig(
281
            [
282
                'type' => FileAdapterStrategy::TYPE,
283
                'root' => __DIR__,
284
            ]
285
        );
286
        $this->assertInstanceOf(FileAdapterStrategy::class, $fileAdapterStrategy);
287
        $this->assertEquals(FileAdapterStrategy::TYPE, $fileAdapterStrategy->getType());
288
    }
289
290
    /**
291
     * Test invalid file adapter strategy root
292
     *
293
     * @expectedException \Apparat\Object\Domain\Repository\InvalidArgumentException
294
     * @expectedExceptionCode 1450136346
295
     */
296
    public function testMissingFileStrategyRoot()
297
    {
298
        RepositoryFactory::register(
299
            getenv('REPOSITORY_URL'),
300
            [
301
                'type' => FileAdapterStrategy::TYPE,
302
            ]
303
        );
304
        RepositoryFactory::instance(getenv('REPOSITORY_URL'));
305
    }
306
307
    /**
308
     * Test empty file adapter strategy root
309
     *
310
     * @expectedException \Apparat\Object\Infrastructure\Repository\InvalidArgumentException
311
     * @expectedExceptionCode 1449956977
312
     */
313
    public function testEmptyFileStrategyRoot()
314
    {
315
        RepositoryFactory::register(
316
            getenv('REPOSITORY_URL'),
317
            [
318
                'type' => FileAdapterStrategy::TYPE,
319
                'root' => '',
320
            ]
321
        );
322
        RepositoryFactory::instance(getenv('REPOSITORY_URL'));
323
    }
324
325
    /**
326
     * Test invalid file adapter strategy root
327
     *
328
     * @expectedException \Apparat\Object\Infrastructure\Repository\InvalidArgumentException
329
     * @expectedExceptionCode 1449957017
330
     */
331
    public function testInvalidFileStrategyRoot()
332
    {
333
        RepositoryFactory::register(
334
            getenv('REPOSITORY_URL'),
335
            [
336
                'type' => FileAdapterStrategy::TYPE,
337
                'root' => '__FILE__',
338
            ]
339
        );
340
        RepositoryFactory::instance(getenv('REPOSITORY_URL'));
341
    }
342
343
    /**
344
     * Test invalid repository URL during instantiation
345
     *
346
     * @expectedException \Apparat\Object\Domain\Repository\InvalidArgumentException
347
     * @expectedExceptionCode 1451771889
348
     */
349
    public function testUnknownRepositoryUrlInstance()
350
    {
351
        RepositoryFactory::register(
352
            getenv('REPOSITORY_URL'),
353
            [
354
                'type' => FileAdapterStrategy::TYPE,
355
                'root' => self::$globBase,
356
            ]
357
        );
358
        RepositoryFactory::instance('http://example.com');
359
    }
360
361
    /**
362
     * Test file repository
363
     */
364
    public function testFileRepository()
365
    {
366
        RepositoryFactory::register(
367
            getenv('REPOSITORY_URL'),
368
            [
369
                'type' => FileAdapterStrategy::TYPE,
370
                'root' => self::$globBase,
371
            ]
372
        );
373
        $fileRepository = RepositoryFactory::instance(getenv('REPOSITORY_URL'));
374
        $this->assertInstanceOf(Repository::class, $fileRepository);
375
376
        $selector = SelectorFactory::createFromString('/*');
377
        $this->assertInstanceOf(SelectorInterface::class, $selector);
378
        $collection = $fileRepository->findObjects($selector);
379
        $this->assertInstanceOf(Collection::class, $collection);
380
        $this->assertEquals(array_sum(self::$globTypes), count($collection));
381
        $this->assertEquals(0, $fileRepository->getSize());
382
    }
383
384
    /**
385
     * Test file repository with revisions
386
     */
387
    public function testFileRepositoryRevisions()
388
    {
389
        RepositoryFactory::register(
390
            getenv('REPOSITORY_URL'),
391
            [
392
                'type' => FileAdapterStrategy::TYPE,
393
                'root' => self::$globBase,
394
            ]
395
        );
396
        $fileRepository = RepositoryFactory::instance(getenv('REPOSITORY_URL'));
397
398
        $selector = SelectorFactory::createFromString('/*/*/*/*/*/*/*.*/*-1');
399
        $collection = $fileRepository->findObjects($selector);
400
        $this->assertInstanceOf(Collection::class, $collection);
401
        $this->assertEquals(self::$globRevisions['-1'], count($collection));
402
    }
403
404
    /**
405
     * Test a repository path
406
     */
407
    public function testRepositoryPath()
408
    {
409
        RepositoryFactory::register(
410
            getenv('REPOSITORY_URL'),
411
            [
412
                'type' => FileAdapterStrategy::TYPE,
413
                'root' => self::$globBase,
414
            ]
415
        );
416
        $fileRepository = RepositoryFactory::instance(getenv('REPOSITORY_URL'));
417
        $repositoryPath = new RepositoryPath($fileRepository, '/2015/10/01/00/00/00/36704.event/36704-1');
418
        $this->assertInstanceOf(RepositoryPath::class, $repositoryPath);
419
        $this->assertEquals($fileRepository, $repositoryPath->getRepository());
420
    }
421
422
    /**
423
     * Test the creation of a new repository
424
     */
425
    public function testRepositoryCreation()
426
    {
427
        $this->tmpFiles[] = $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
428
        $this->tmpFiles[] = $tempRepoConfigDir = $tempRepoDirectory.DIRECTORY_SEPARATOR.'.repo';
429
        $this->tmpFiles[] = $tempRepoConfigDir.DIRECTORY_SEPARATOR.'size.txt';
430
        $fileRepository = RepositoryFactory::create(
431
            getenv('REPOSITORY_URL'),
432
            [
433
                'type' => FileAdapterStrategy::TYPE,
434
                'root' => $tempRepoDirectory,
435
            ]
436
        );
437
        $this->assertInstanceOf(Repository::class, $fileRepository);
438
    }
439
440
    /**
441
     * Test creation of a repository over an existing file
442
     *
443
     * @expectedException \Apparat\Object\Domain\Repository\RuntimeException
444
     * @expectedExceptionCode 1461276430
445
     */
446
    public function testRepositoryCreationOverExistingFile()
447
    {
448
        $tempFile = $this->createTemporaryFile();
449
        RepositoryFactory::create(
450
            getenv('REPOSITORY_URL'),
451
            [
452
                'type' => FileAdapterStrategy::TYPE,
453
                'root' => $tempFile,
454
            ]
455
        );
456
    }
457
458
    /**
459
     * Test creation of a repository over an existing size descriptor directory
460
     *
461
     * @expectedException \Apparat\Object\Domain\Repository\RuntimeException
462
     * @expectedExceptionCode 1461276603
463
     */
464
    public function testRepositoryCreationOverExistingSizeDescriptor()
465
    {
466
        $this->tmpFiles[] = $tempRepoDirectory = sys_get_temp_dir().DIRECTORY_SEPARATOR.'temp-repo';
467
        $this->tmpFiles[] = $tempRepoConfigDirectory = $tempRepoDirectory.DIRECTORY_SEPARATOR.'.repo';
468
        $this->tmpFiles[] = $tempSizeDescriptor = $tempRepoConfigDirectory.DIRECTORY_SEPARATOR.'size.txt';
469
        @mkdir($tempSizeDescriptor, 0777, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
470
        RepositoryFactory::create(
471
            getenv('REPOSITORY_URL'),
472
            [
473
                'type' => FileAdapterStrategy::TYPE,
474
                'root' => $tempRepoDirectory,
475
            ]
476
        );
477
    }
478
}
479