Completed
Push — master ( 60f162...70e2b0 )
by André
11:26
created

BaseTest::refreshSearch()   B

Complexity

Conditions 4
Paths 3

Size

Total Lines 28
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 3
nop 1
dl 0
loc 28
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * File containing the BaseTest class.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 */
9
namespace eZ\Publish\API\Repository\Tests;
10
11
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
12
use PHPUnit\Framework\TestCase;
13
use eZ\Publish\API\Repository\Repository;
14
use eZ\Publish\API\Repository\Values\ValueObject;
15
use eZ\Publish\API\Repository\Values\User\Limitation\RoleLimitation;
16
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
17
use eZ\Publish\Core\REST\Client\Sessionable;
18
use DateTime;
19
use ArrayObject;
20
use Exception;
21
use PDOException;
22
23
/**
24
 * Base class for api specific tests.
25
 */
26
abstract class BaseTest extends TestCase
27
{
28
    /**
29
     * Maximum integer number accepted by the different backends.
30
     */
31
    const DB_INT_MAX = 2147483647;
32
33
    /**
34
     * @var \eZ\Publish\API\Repository\Tests\SetupFactory
35
     */
36
    private $setupFactory;
37
38
    /**
39
     * @var \eZ\Publish\API\Repository\Repository
40
     */
41
    private $repository;
42
43
    protected function setUp()
44
    {
45
        parent::setUp();
46
47
        try {
48
            // Use setup factory instance here w/o clearing data in case test don't need to
49
            $repository = $this->getSetupFactory()->getRepository(false);
50
51
            // Set session if we are testing the REST backend to make it
52
            // possible to persist data in the memory backend during multiple
53
            // requests.
54
            if ($repository instanceof Sessionable) {
55
                $repository->setSession($id = md5(microtime()));
56
            }
57
        } catch (PDOException $e) {
58
            $this->fail(
59
                'The communication with the database cannot be established. ' .
60
                "This is required in order to perform the tests.\n\n" .
61
                'Exception: ' . $e
62
            );
63
        } catch (Exception $e) {
64
            $this->fail(
65
                'Cannot create a repository with predefined user. ' .
66
                'Check the UserService or RoleService implementation. ' .
67
                PHP_EOL . PHP_EOL .
68
                'Exception: ' . $e
69
            );
70
        }
71
    }
72
73
    /**
74
     * Resets the temporary used repository between each test run.
75
     */
76
    protected function tearDown()
77
    {
78
        $this->repository = null;
79
        parent::tearDown();
80
    }
81
82
    /**
83
     * Returns the ID generator, fitting to the repository implementation.
84
     *
85
     * @return \eZ\Publish\API\Repository\Tests\IdManager
86
     */
87
    protected function getIdManager()
88
    {
89
        return $this->getSetupFactory()->getIdManager();
90
    }
91
92
    /**
93
     * Generates a repository specific ID value.
94
     *
95
     * @param string $type
96
     * @param mixed $rawId
97
     *
98
     * @return mixed
99
     */
100
    protected function generateId($type, $rawId)
101
    {
102
        return $this->getIdManager()->generateId($type, $rawId);
103
    }
104
105
    /**
106
     * Parses a repository specific ID value.
107
     *
108
     * @param string $type
109
     * @param mixed $id
110
     *
111
     * @return mixed
112
     */
113
    protected function parseId($type, $id)
114
    {
115
        return $this->getIdManager()->parseId($type, $id);
116
    }
117
118
    /**
119
     * Returns a config setting provided by the setup factory.
120
     *
121
     * @param string $configKey
122
     *
123
     * @return mixed
124
     */
125
    protected function getConfigValue($configKey)
126
    {
127
        return $this->getSetupFactory()->getConfigValue($configKey);
128
    }
129
130
    /**
131
     * Tests if the currently tested api is based on a V4 implementation.
132
     *
133
     * @return bool
134
     */
135
    protected function isVersion4()
136
    {
137
        return isset($_ENV['backendVersion']) && '4' === $_ENV['backendVersion'];
138
    }
139
140
    /**
141
     * @param bool $initialInitializeFromScratch Only has an effect if set in first call within a test
142
     *
143
     * @return \eZ\Publish\API\Repository\Repository
144
     */
145
    protected function getRepository($initialInitializeFromScratch = true)
146
    {
147
        if (null === $this->repository) {
148
            $this->repository = $this->getSetupFactory()->getRepository($initialInitializeFromScratch);
149
        }
150
151
        return $this->repository;
152
    }
153
154
    /**
155
     * @return \eZ\Publish\API\Repository\Tests\SetupFactory
156
     */
157
    protected function getSetupFactory()
158
    {
159
        if (null === $this->setupFactory) {
160
            if (false === isset($_ENV['setupFactory'])) {
161
                throw new \ErrorException(
162
                    'Missing mandatory setting $_ENV["setupFactory"], this should normally be set in the relevant phpunit-integration-*.xml file and refer to a setupFactory for the given StorageEngine/SearchEngine in use'
163
                );
164
            }
165
166
            $setupClass = $_ENV['setupFactory'];
167
            if (false === class_exists($setupClass)) {
168
                throw new \ErrorException(
169
                    sprintf(
170
                        '$_ENV["setupFactory"] does not reference an existing class: %s. Did you forget to install an package dependency?',
171
                        $setupClass
172
                    )
173
                );
174
            }
175
176
            $this->setupFactory = new $setupClass();
177
        }
178
179
        return $this->setupFactory;
180
    }
181
182
    /**
183
     * Asserts that properties given in $expectedValues are correctly set in
184
     * $actualObject.
185
     *
186
     * @param mixed[] $expectedValues
187
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
188
     */
189
    protected function assertPropertiesCorrect(array $expectedValues, ValueObject $actualObject)
190
    {
191
        foreach ($expectedValues as $propertyName => $propertyValue) {
192
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
193
        }
194
    }
195
196
    /**
197
     * Asserts that properties given in $expectedValues are correctly set in
198
     * $actualObject.
199
     *
200
     * If the property type is array, it will be sorted before comparison.
201
     *
202
     * @TODO: introduced because of randomly failing tests, ref: https://jira.ez.no/browse/EZP-21734
203
     *
204
     * @param mixed[] $expectedValues
205
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
206
     */
207
    protected function assertPropertiesCorrectUnsorted(array $expectedValues, ValueObject $actualObject)
208
    {
209
        foreach ($expectedValues as $propertyName => $propertyValue) {
210
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName, true);
211
        }
212
    }
213
214
    /**
215
     * Asserts all properties from $expectedValues are correctly set in
216
     * $actualObject. Additional (virtual) properties can be asserted using
217
     * $additionalProperties.
218
     *
219
     * @param \eZ\Publish\API\Repository\Values\ValueObject $expectedValues
220
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
221
     * @param array $propertyNames
0 ignored issues
show
Bug introduced by
There is no parameter named $propertyNames. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
222
     */
223
    protected function assertStructPropertiesCorrect(ValueObject $expectedValues, ValueObject $actualObject, array $additionalProperties = array())
224
    {
225
        foreach ($expectedValues as $propertyName => $propertyValue) {
0 ignored issues
show
Bug introduced by
The expression $expectedValues of type object<eZ\Publish\API\Re...ory\Values\ValueObject> is not traversable.
Loading history...
226
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
227
        }
228
229
        foreach ($additionalProperties as $propertyName) {
230
            $this->assertPropertiesEqual($propertyName, $expectedValues->$propertyName, $actualObject->$propertyName);
231
        }
232
    }
233
234
    /**
235
     * @see \eZ\Publish\API\Repository\Tests\BaseTest::assertPropertiesCorrectUnsorted()
236
     *
237
     * @param array $items An array of scalar values
238
     */
239
    private function sortItems(array &$items)
240
    {
241
        $sorter = function ($a, $b) {
242
            if (!is_scalar($a) || !is_scalar($b)) {
243
                $this->fail('Wrong usage: method ' . __METHOD__ . ' accepts only an array of scalar values');
244
            }
245
246
            return strcmp($a, $b);
247
        };
248
        usort($items, $sorter);
249
    }
250
251
    private function assertPropertiesEqual($propertyName, $expectedValue, $actualValue, $sortArray = false)
252
    {
253
        if ($expectedValue instanceof ArrayObject) {
254
            $expectedValue = $expectedValue->getArrayCopy();
255
        } elseif ($expectedValue instanceof DateTime) {
256
            $expectedValue = $expectedValue->format(DateTime::RFC850);
257
        }
258
        if ($actualValue instanceof ArrayObject) {
259
            $actualValue = $actualValue->getArrayCopy();
260
        } elseif ($actualValue instanceof DateTime) {
261
            $actualValue = $actualValue->format(DateTime::RFC850);
262
        }
263
264
        if ($sortArray && is_array($actualValue) && is_array($expectedValue)) {
265
            $this->sortItems($actualValue);
266
            $this->sortItems($expectedValue);
267
        }
268
269
        $this->assertEquals(
270
            $expectedValue,
271
            $actualValue,
272
            sprintf('Object property "%s" incorrect.', $propertyName)
273
        );
274
    }
275
276
    /**
277
     * Create a user in editor user group.
278
     *
279
     * @param string $login
280
     *
281
     * @return \eZ\Publish\API\Repository\Values\User\User
282
     */
283
    protected function createUserVersion1($login = 'user')
284
    {
285
        $repository = $this->getRepository();
286
287
        /* BEGIN: Inline */
288
        // ID of the "Editors" user group in an eZ Publish demo installation
289
        $editorsGroupId = 13;
290
291
        $userService = $repository->getUserService();
292
293
        // Instantiate a create struct with mandatory properties
294
        $userCreate = $userService->newUserCreateStruct(
295
            $login,
296
            "{$login}@example.com",
297
            'secret',
298
            'eng-US'
299
        );
300
        $userCreate->enabled = true;
301
302
        // Set some fields required by the user ContentType
303
        $userCreate->setField('first_name', 'Example');
304
        $userCreate->setField('last_name', 'User');
305
306
        // Load parent group for the user
307
        $group = $userService->loadUserGroup($editorsGroupId);
308
309
        // Create a new user instance.
310
        $user = $userService->createUser($userCreate, array($group));
311
        /* END: Inline */
312
313
        return $user;
314
    }
315
316
    /**
317
     * Create a user in new user group with editor rights limited to Media Library (/1/48/).
318
     *
319
     * @uses ::createCustomUserVersion1()
320
     *
321
     * @return \eZ\Publish\API\Repository\Values\User\User
322
     */
323
    protected function createMediaUserVersion1()
324
    {
325
        return $this->createCustomUserVersion1(
326
            'Media Editor',
327
            'Editor',
328
            new SubtreeLimitation(array('limitationValues' => array('/1/43/')))
329
        );
330
    }
331
332
    /**
333
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
334
     *
335
     * @param string $userGroupName Name of the new user group to create
336
     * @param string $roleIdentifier Role identifier to assign to the new group
337
     * @param RoleLimitation|null $roleLimitation
338
     *
339
     * @return \eZ\Publish\API\Repository\Values\User\User
340
     */
341
    protected function createCustomUserVersion1($userGroupName, $roleIdentifier, RoleLimitation $roleLimitation = null)
342
    {
343
        return $this->createCustomUserWithLogin(
344
            'user',
345
            '[email protected]',
346
            $userGroupName,
347
            $roleIdentifier,
348
            $roleLimitation
349
        );
350
    }
351
352
    /**
353
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
354
     *
355
     * @param string $login User login
356
     * @param string $email User e-mail
357
     * @param string $userGroupName Name of the new user group to create
358
     * @param string $roleIdentifier Role identifier to assign to the new group
359
     * @param RoleLimitation|null $roleLimitation
360
     * @return \eZ\Publish\API\Repository\Values\User\User
361
     */
362
    protected function createCustomUserWithLogin(
363
        $login,
364
        $email,
365
        $userGroupName,
366
        $roleIdentifier,
367
        RoleLimitation $roleLimitation = null
368
    ) {
369
        $repository = $this->getRepository();
370
371
        /* BEGIN: Inline */
372
        // ID of the "Users" user group in an eZ Publish demo installation
373
        $rootUsersGroupId = $this->generateId('location', 4);
374
375
        $roleService = $repository->getRoleService();
376
        $userService = $repository->getUserService();
377
378
        // Get a group create struct
379
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
380
        $userGroupCreate->setField('name', $userGroupName);
381
382
        // Create new group with media editor rights
383
        $userGroup = $userService->createUserGroup(
384
            $userGroupCreate,
385
            $userService->loadUserGroup($rootUsersGroupId)
386
        );
387
        $roleService->assignRoleToUserGroup(
388
            $roleService->loadRoleByIdentifier($roleIdentifier),
389
            $userGroup,
390
            $roleLimitation
391
        );
392
393
        // Instantiate a create struct with mandatory properties
394
        $userCreate = $userService->newUserCreateStruct(
395
            $login,
396
            $email,
397
            'secret',
398
            'eng-US'
399
        );
400
        $userCreate->enabled = true;
401
402
        // Set some fields required by the user ContentType
403
        $userCreate->setField('first_name', 'Example');
404
        $userCreate->setField('last_name', ucfirst($login));
405
406
        // Create a new user instance.
407
        $user = $userService->createUser($userCreate, array($userGroup));
408
        /* END: Inline */
409
410
        return $user;
411
    }
412
413
    /**
414
     * Create a user using given data.
415
     *
416
     * @param string $login
417
     * @param string $firstName
418
     * @param string $lastName
419
     * @return \eZ\Publish\API\Repository\Values\User\User
420
     */
421
    protected function createUser($login, $firstName, $lastName)
422
    {
423
        $repository = $this->getRepository();
424
425
        $userService = $repository->getUserService();
426
        $userGroup = $userService->loadUserGroup(13);
427
428
        // Instantiate a create struct with mandatory properties
429
        $userCreate = $userService->newUserCreateStruct(
430
            $login,
431
            "{$login}@example.com",
432
            'secret',
433
            'eng-US'
434
        );
435
        $userCreate->enabled = true;
436
437
        // Set some fields required by the user ContentType
438
        $userCreate->setField('first_name', $firstName);
439
        $userCreate->setField('last_name', $lastName);
440
441
        // Create a new user instance.
442
        $user = $userService->createUser($userCreate, array($userGroup));
443
444
        return $user;
445
    }
446
447
    /**
448
     * Only for internal use.
449
     *
450
     * Creates a \DateTime object for $timestamp in the current time zone
451
     *
452
     * @param int $timestamp
453
     *
454
     * @return \DateTime
455
     */
456 View Code Duplication
    public function createDateTime($timestamp = null)
457
    {
458
        $dateTime = new \DateTime();
459
        if ($timestamp !== null) {
460
            $dateTime->setTimestamp($timestamp);
461
        }
462
463
        return $dateTime;
464
    }
465
466
    /**
467
     * Calls given Repository's aggregated SearchHandler::refresh().
468
     *
469
     * Currently implemented only in Solr search engine.
470
     *
471
     * @param \eZ\Publish\API\Repository\Repository $repository
472
     */
473
    protected function refreshSearch(Repository $repository)
474
    {
475
        $setupFactory = $this->getSetupFactory();
476
477
        if (!$setupFactory instanceof LegacySolrSetupFactory) {
0 ignored issues
show
Bug introduced by
The class EzSystems\EzPlatformSolr...tory\LegacySetupFactory does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
478
            return;
479
        }
480
481
        while (true) {
482
            $repositoryReflection = new \ReflectionObject($repository);
483
            // If the repository is decorated, we need to recurse in the "repository" property
484
            if (!$repositoryReflection->hasProperty('repository')) {
485
                break;
486
            }
487
488
            $repositoryProperty = $repositoryReflection->getProperty('repository');
489
            $repositoryProperty->setAccessible(true);
490
            $repository = $repositoryProperty->getValue($repository);
491
        }
492
493
        $searchHandlerProperty = new \ReflectionProperty($repository, 'searchHandler');
494
        $searchHandlerProperty->setAccessible(true);
495
496
        /** @var \EzSystems\EzPlatformSolrSearchEngine\Handler $searchHandler */
497
        $searchHandler = $searchHandlerProperty->getValue($repository);
498
499
        $searchHandler->commit();
500
    }
501
}
502