Completed
Push — 7.0 ( 7b47bc...b7670c )
by André
132:42 queued 114:32
created

BaseTest::assertValidationErrorOccurs()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 8
rs 9.4285
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 eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException;
12
use eZ\Publish\API\Repository\Tests\PHPUnitConstraint\ValidationErrorOccurs as PHPUnitConstraintValidationErrorOccurs;
13
use EzSystems\EzPlatformSolrSearchEngine\Tests\SetupFactory\LegacySetupFactory as LegacySolrSetupFactory;
14
use PHPUnit\Framework\TestCase;
15
use eZ\Publish\API\Repository\Repository;
16
use eZ\Publish\API\Repository\Values\ValueObject;
17
use eZ\Publish\API\Repository\Values\User\Limitation\RoleLimitation;
18
use eZ\Publish\API\Repository\Values\User\Limitation\SubtreeLimitation;
19
use eZ\Publish\API\Repository\Values\User\UserGroup;
20
use eZ\Publish\Core\REST\Client\Sessionable;
21
use DateTime;
22
use ArrayObject;
23
use Exception;
24
use PDOException;
25
26
/**
27
 * Base class for api specific tests.
28
 */
29
abstract class BaseTest extends TestCase
30
{
31
    /**
32
     * Maximum integer number accepted by the different backends.
33
     */
34
    const DB_INT_MAX = 2147483647;
35
36
    /**
37
     * @var \eZ\Publish\API\Repository\Tests\SetupFactory
38
     */
39
    private $setupFactory;
40
41
    /**
42
     * @var \eZ\Publish\API\Repository\Repository
43
     */
44
    private $repository;
45
46
    protected function setUp()
47
    {
48
        parent::setUp();
49
50
        try {
51
            // Use setup factory instance here w/o clearing data in case test don't need to
52
            $repository = $this->getSetupFactory()->getRepository(false);
53
54
            // Set session if we are testing the REST backend to make it
55
            // possible to persist data in the memory backend during multiple
56
            // requests.
57
            if ($repository instanceof Sessionable) {
58
                $repository->setSession($id = md5(microtime()));
59
            }
60
        } catch (PDOException $e) {
61
            $this->fail(
62
                'The communication with the database cannot be established. ' .
63
                "This is required in order to perform the tests.\n\n" .
64
                'Exception: ' . $e
65
            );
66
        } catch (Exception $e) {
67
            $this->fail(
68
                'Cannot create a repository with predefined user. ' .
69
                'Check the UserService or RoleService implementation. ' .
70
                PHP_EOL . PHP_EOL .
71
                'Exception: ' . $e
72
            );
73
        }
74
    }
75
76
    /**
77
     * Resets the temporary used repository between each test run.
78
     */
79
    protected function tearDown()
80
    {
81
        $this->repository = null;
82
        parent::tearDown();
83
    }
84
85
    /**
86
     * Returns the ID generator, fitting to the repository implementation.
87
     *
88
     * @return \eZ\Publish\API\Repository\Tests\IdManager
89
     */
90
    protected function getIdManager()
91
    {
92
        return $this->getSetupFactory()->getIdManager();
93
    }
94
95
    /**
96
     * Generates a repository specific ID value.
97
     *
98
     * @param string $type
99
     * @param mixed $rawId
100
     *
101
     * @return mixed
102
     */
103
    protected function generateId($type, $rawId)
104
    {
105
        return $this->getIdManager()->generateId($type, $rawId);
106
    }
107
108
    /**
109
     * Parses a repository specific ID value.
110
     *
111
     * @param string $type
112
     * @param mixed $id
113
     *
114
     * @return mixed
115
     */
116
    protected function parseId($type, $id)
117
    {
118
        return $this->getIdManager()->parseId($type, $id);
119
    }
120
121
    /**
122
     * Returns a config setting provided by the setup factory.
123
     *
124
     * @param string $configKey
125
     *
126
     * @return mixed
127
     */
128
    protected function getConfigValue($configKey)
129
    {
130
        return $this->getSetupFactory()->getConfigValue($configKey);
131
    }
132
133
    /**
134
     * Tests if the currently tested api is based on a V4 implementation.
135
     *
136
     * @return bool
137
     */
138
    protected function isVersion4()
139
    {
140
        return isset($_ENV['backendVersion']) && '4' === $_ENV['backendVersion'];
141
    }
142
143
    /**
144
     * @param bool $initialInitializeFromScratch Only has an effect if set in first call within a test
145
     *
146
     * @return \eZ\Publish\API\Repository\Repository
147
     */
148
    protected function getRepository($initialInitializeFromScratch = true)
149
    {
150
        if (null === $this->repository) {
151
            $this->repository = $this->getSetupFactory()->getRepository($initialInitializeFromScratch);
152
        }
153
154
        return $this->repository;
155
    }
156
157
    /**
158
     * @return \eZ\Publish\API\Repository\Tests\SetupFactory
159
     */
160
    protected function getSetupFactory()
161
    {
162
        if (null === $this->setupFactory) {
163
            if (false === isset($_ENV['setupFactory'])) {
164
                throw new \ErrorException(
165
                    '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'
166
                );
167
            }
168
169
            $setupClass = $_ENV['setupFactory'];
170
            if (false === class_exists($setupClass)) {
171
                throw new \ErrorException(
172
                    sprintf(
173
                        '$_ENV["setupFactory"] does not reference an existing class: %s. Did you forget to install an package dependency?',
174
                        $setupClass
175
                    )
176
                );
177
            }
178
179
            $this->setupFactory = new $setupClass();
180
        }
181
182
        return $this->setupFactory;
183
    }
184
185
    /**
186
     * Asserts that properties given in $expectedValues are correctly set in
187
     * $actualObject.
188
     *
189
     * @param mixed[] $expectedValues
190
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
191
     */
192
    protected function assertPropertiesCorrect(array $expectedValues, ValueObject $actualObject)
193
    {
194
        foreach ($expectedValues as $propertyName => $propertyValue) {
195
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
196
        }
197
    }
198
199
    /**
200
     * Asserts that properties given in $expectedValues are correctly set in
201
     * $actualObject.
202
     *
203
     * If the property type is array, it will be sorted before comparison.
204
     *
205
     * @TODO: introduced because of randomly failing tests, ref: https://jira.ez.no/browse/EZP-21734
206
     *
207
     * @param mixed[] $expectedValues
208
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
209
     */
210
    protected function assertPropertiesCorrectUnsorted(array $expectedValues, ValueObject $actualObject)
211
    {
212
        foreach ($expectedValues as $propertyName => $propertyValue) {
213
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName, true);
214
        }
215
    }
216
217
    /**
218
     * Asserts all properties from $expectedValues are correctly set in
219
     * $actualObject. Additional (virtual) properties can be asserted using
220
     * $additionalProperties.
221
     *
222
     * @param \eZ\Publish\API\Repository\Values\ValueObject $expectedValues
223
     * @param \eZ\Publish\API\Repository\Values\ValueObject $actualObject
224
     * @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...
225
     */
226
    protected function assertStructPropertiesCorrect(ValueObject $expectedValues, ValueObject $actualObject, array $additionalProperties = array())
227
    {
228
        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...
229
            $this->assertPropertiesEqual($propertyName, $propertyValue, $actualObject->$propertyName);
230
        }
231
232
        foreach ($additionalProperties as $propertyName) {
233
            $this->assertPropertiesEqual($propertyName, $expectedValues->$propertyName, $actualObject->$propertyName);
234
        }
235
    }
236
237
    /**
238
     * @see \eZ\Publish\API\Repository\Tests\BaseTest::assertPropertiesCorrectUnsorted()
239
     *
240
     * @param array $items An array of scalar values
241
     */
242
    private function sortItems(array &$items)
243
    {
244
        $sorter = function ($a, $b) {
245
            if (!is_scalar($a) || !is_scalar($b)) {
246
                $this->fail('Wrong usage: method ' . __METHOD__ . ' accepts only an array of scalar values');
247
            }
248
249
            return strcmp($a, $b);
250
        };
251
        usort($items, $sorter);
252
    }
253
254
    private function assertPropertiesEqual($propertyName, $expectedValue, $actualValue, $sortArray = false)
255
    {
256
        if ($expectedValue instanceof ArrayObject) {
257
            $expectedValue = $expectedValue->getArrayCopy();
258
        } elseif ($expectedValue instanceof DateTime) {
259
            $expectedValue = $expectedValue->format(DateTime::RFC850);
260
        }
261
        if ($actualValue instanceof ArrayObject) {
262
            $actualValue = $actualValue->getArrayCopy();
263
        } elseif ($actualValue instanceof DateTime) {
264
            $actualValue = $actualValue->format(DateTime::RFC850);
265
        }
266
267
        if ($sortArray && is_array($actualValue) && is_array($expectedValue)) {
268
            $this->sortItems($actualValue);
269
            $this->sortItems($expectedValue);
270
        }
271
272
        $this->assertEquals(
273
            $expectedValue,
274
            $actualValue,
275
            sprintf('Object property "%s" incorrect.', $propertyName)
276
        );
277
    }
278
279
    /**
280
     * Create a user in editor user group.
281
     *
282
     * @param string $login
283
     *
284
     * @return \eZ\Publish\API\Repository\Values\User\User
285
     */
286
    protected function createUserVersion1($login = 'user')
287
    {
288
        $repository = $this->getRepository();
289
290
        /* BEGIN: Inline */
291
        // ID of the "Editors" user group in an eZ Publish demo installation
292
        $editorsGroupId = 13;
293
294
        $userService = $repository->getUserService();
295
296
        // Instantiate a create struct with mandatory properties
297
        $userCreate = $userService->newUserCreateStruct(
298
            $login,
299
            "{$login}@example.com",
300
            'secret',
301
            'eng-US'
302
        );
303
        $userCreate->enabled = true;
304
305
        // Set some fields required by the user ContentType
306
        $userCreate->setField('first_name', 'Example');
307
        $userCreate->setField('last_name', 'User');
308
309
        // Load parent group for the user
310
        $group = $userService->loadUserGroup($editorsGroupId);
311
312
        // Create a new user instance.
313
        $user = $userService->createUser($userCreate, array($group));
314
        /* END: Inline */
315
316
        return $user;
317
    }
318
319
    /**
320
     * Create a user in new user group with editor rights limited to Media Library (/1/48/).
321
     *
322
     * @uses ::createCustomUserVersion1()
323
     *
324
     * @return \eZ\Publish\API\Repository\Values\User\User
325
     */
326
    protected function createMediaUserVersion1()
327
    {
328
        return $this->createCustomUserVersion1(
329
            'Media Editor',
330
            'Editor',
331
            new SubtreeLimitation(array('limitationValues' => array('/1/43/')))
332
        );
333
    }
334
335
    /**
336
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
337
     *
338
     * @param string $userGroupName Name of the new user group to create
339
     * @param string $roleIdentifier Role identifier to assign to the new group
340
     * @param RoleLimitation|null $roleLimitation
341
     *
342
     * @return \eZ\Publish\API\Repository\Values\User\User
343
     */
344
    protected function createCustomUserVersion1($userGroupName, $roleIdentifier, RoleLimitation $roleLimitation = null)
345
    {
346
        return $this->createCustomUserWithLogin(
347
            'user',
348
            '[email protected]',
349
            $userGroupName,
350
            $roleIdentifier,
351
            $roleLimitation
352
        );
353
    }
354
355
    /**
356
     * Create a user with new user group and assign a existing role (optionally with RoleLimitation).
357
     *
358
     * @param string $login User login
359
     * @param string $email User e-mail
360
     * @param string $userGroupName Name of the new user group to create
361
     * @param string $roleIdentifier Role identifier to assign to the new group
362
     * @param RoleLimitation|null $roleLimitation
363
     * @return \eZ\Publish\API\Repository\Values\User\User
364
     */
365
    protected function createCustomUserWithLogin(
366
        $login,
367
        $email,
368
        $userGroupName,
369
        $roleIdentifier,
370
        RoleLimitation $roleLimitation = null
371
    ) {
372
        $repository = $this->getRepository();
373
374
        /* BEGIN: Inline */
375
        // ID of the "Users" user group in an eZ Publish demo installation
376
        $rootUsersGroupId = $this->generateId('location', 4);
377
378
        $roleService = $repository->getRoleService();
379
        $userService = $repository->getUserService();
380
381
        // Get a group create struct
382
        $userGroupCreate = $userService->newUserGroupCreateStruct('eng-US');
383
        $userGroupCreate->setField('name', $userGroupName);
384
385
        // Create new group with media editor rights
386
        $userGroup = $userService->createUserGroup(
387
            $userGroupCreate,
388
            $userService->loadUserGroup($rootUsersGroupId)
389
        );
390
        $roleService->assignRoleToUserGroup(
391
            $roleService->loadRoleByIdentifier($roleIdentifier),
392
            $userGroup,
393
            $roleLimitation
394
        );
395
396
        // Instantiate a create struct with mandatory properties
397
        $userCreate = $userService->newUserCreateStruct(
398
            $login,
399
            $email,
400
            'secret',
401
            'eng-US'
402
        );
403
        $userCreate->enabled = true;
404
405
        // Set some fields required by the user ContentType
406
        $userCreate->setField('first_name', 'Example');
407
        $userCreate->setField('last_name', ucfirst($login));
408
409
        // Create a new user instance.
410
        $user = $userService->createUser($userCreate, array($userGroup));
411
        /* END: Inline */
412
413
        return $user;
414
    }
415
416
    /**
417
     * Create a user using given data.
418
     *
419
     * @param string $login
420
     * @param string $firstName
421
     * @param string $lastName
422
     * @param \eZ\Publish\API\Repository\Values\User\UserGroup|null $userGroup optional user group, Editor by default
423
     *
424
     * @return \eZ\Publish\API\Repository\Values\User\User
425
     */
426
    protected function createUser($login, $firstName, $lastName, UserGroup $userGroup = null)
427
    {
428
        $repository = $this->getRepository();
429
430
        $userService = $repository->getUserService();
431
        if (null === $userGroup) {
432
            $userGroup = $userService->loadUserGroup(13);
433
        }
434
435
        // Instantiate a create struct with mandatory properties
436
        $userCreate = $userService->newUserCreateStruct(
437
            $login,
438
            "{$login}@example.com",
439
            'secret',
440
            'eng-US'
441
        );
442
        $userCreate->enabled = true;
443
444
        // Set some fields required by the user ContentType
445
        $userCreate->setField('first_name', $firstName);
446
        $userCreate->setField('last_name', $lastName);
447
448
        // Create a new user instance.
449
        $user = $userService->createUser($userCreate, array($userGroup));
450
451
        return $user;
452
    }
453
454
    /**
455
     * Only for internal use.
456
     *
457
     * Creates a \DateTime object for $timestamp in the current time zone
458
     *
459
     * @param int $timestamp
460
     *
461
     * @return \DateTime
462
     */
463
    public function createDateTime($timestamp = null)
464
    {
465
        $dateTime = new \DateTime();
466
        if ($timestamp !== null) {
467
            $dateTime->setTimestamp($timestamp);
468
        }
469
470
        return $dateTime;
471
    }
472
473
    /**
474
     * Calls given Repository's aggregated SearchHandler::refresh().
475
     *
476
     * Currently implemented only in Solr search engine.
477
     *
478
     * @param \eZ\Publish\API\Repository\Repository $repository
479
     */
480
    protected function refreshSearch(Repository $repository)
481
    {
482
        $setupFactory = $this->getSetupFactory();
483
484
        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...
485
            return;
486
        }
487
488
        while (true) {
489
            $repositoryReflection = new \ReflectionObject($repository);
490
            // If the repository is decorated, we need to recurse in the "repository" property
491
            if (!$repositoryReflection->hasProperty('repository')) {
492
                break;
493
            }
494
495
            $repositoryProperty = $repositoryReflection->getProperty('repository');
496
            $repositoryProperty->setAccessible(true);
497
            $repository = $repositoryProperty->getValue($repository);
498
        }
499
500
        $searchHandlerProperty = new \ReflectionProperty($repository, 'searchHandler');
501
        $searchHandlerProperty->setAccessible(true);
502
503
        /** @var \EzSystems\EzPlatformSolrSearchEngine\Handler $searchHandler */
504
        $searchHandler = $searchHandlerProperty->getValue($repository);
505
506
        $searchHandler->commit();
507
    }
508
509
    /**
510
     * Create role of a given name with the given policies described by an array.
511
     *
512
     * @param $roleName
513
     * @param array $policiesData [['module' => 'content', 'function' => 'read', 'limitations' => []]
514
     *
515
     * @return \eZ\Publish\API\Repository\Values\User\Role
516
     *
517
     * @throws \eZ\Publish\API\Repository\Exceptions\InvalidArgumentException
518
     * @throws \eZ\Publish\API\Repository\Exceptions\LimitationValidationException
519
     * @throws \eZ\Publish\API\Repository\Exceptions\NotFoundException
520
     * @throws \eZ\Publish\API\Repository\Exceptions\UnauthorizedException
521
     */
522
    public function createRoleWithPolicies($roleName, array $policiesData)
523
    {
524
        $repository = $this->getRepository(false);
525
        $roleService = $repository->getRoleService();
526
527
        $roleCreateStruct = $roleService->newRoleCreateStruct($roleName);
528
        foreach ($policiesData as $policyData) {
529
            $policyCreateStruct = $roleService->newPolicyCreateStruct(
530
                $policyData['module'],
531
                $policyData['function']
532
            );
533
534
            if (isset($policyData['limitations'])) {
535
                foreach ($policyData['limitations'] as $limitation) {
536
                    $policyCreateStruct->addLimitation($limitation);
537
                }
538
            }
539
540
            $roleCreateStruct->addPolicy($policyCreateStruct);
541
        }
542
543
        $roleDraft = $roleService->createRole($roleCreateStruct);
544
545
        $roleService->publishRoleDraft($roleDraft);
546
547
        return $roleService->loadRole($roleDraft->id);
548
    }
549
550
    /**
551
     * Traverse all errors for all fields in all Translations to find expected one.
552
     *
553
     * @param \eZ\Publish\API\Repository\Exceptions\ContentFieldValidationException $exception
554
     * @param string $expectedValidationErrorMessage
555
     */
556
    protected function assertValidationErrorOccurs(
557
        ContentFieldValidationException $exception,
558
        $expectedValidationErrorMessage
559
    ) {
560
        $constraint = new PHPUnitConstraintValidationErrorOccurs($expectedValidationErrorMessage);
561
562
        self::assertThat($exception, $constraint);
563
    }
564
}
565