- <?php
- /**
- * Test methods for the P4 Group class.
- *
- * @copyright 2012 Perforce Software. All rights reserved.
- * @license Please see LICENSE.txt in top-level folder of this distribution.
- * @version <release>/<patch>
- */
-
- namespace P4Test\Spec;
-
- use P4Test\TestCase;
- use P4\Spec\User;
- use P4\Spec\Group;
- use P4\Connection\Connection;
- use P4\Spec\Exception\NotFoundException;
- use P4\Spec\Exception\Exception as SpecException;
-
- class GroupTest extends TestCase
- {
- /**
- * Test fetchAll method
- */
- public function testFetchAll()
- {
- $group = new Group;
- $group->setId('test1')->addUser('user1')->save();
- $group = new Group;
- $group->setId('test2')->addUser('user1')->save();
- $group = new Group;
- $group->setId('test3')->addUser('user2')->addSubgroup('test2')->save();
- $group = new Group;
- $group->setId('test4')->addUser('user3')->addSubgroup('test3')->save();
- $group = new Group;
- $group->setId('test5')->addUser('user4')->addOwner('user5')->save();
- $group = new Group;
- $group->setId('test6')->addSubgroup('test7')->save();
- $group = new Group;
- $group->setId('test7%%')
- ->addSubgroup('test%%7')
- ->addUser('user1')
- ->addUser('user%%1')
- ->addOwner('user%%2')
- ->save();
- $names = array('test1', 'test2', 'test3', 'test4', 'test5', 'test6', 'test7%%');
-
- // Verify full fetchAll works ok
- $this->assertSame(
- $names,
- Group::fetchAll()->invoke('getId'),
- 'Expected fetch all to match'
- );
-
- // Verify fetch with made up option works
- $this->assertSame(
- $names,
- Group::fetchAll(
- array('fooBar' => true)
- )->invoke('getId'),
- 'Expected fetch all with made up option to match'
- );
-
- // Verify full FETCH_MAXIMUM works
- $this->assertSame(
- array_slice($names, 0, 3),
- Group::fetchAll(
- array(Group::FETCH_MAXIMUM => '3')
- )->invoke('getId'),
- 'Expected fetch all with Maximum to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for users
- $expected = array_slice($names, 0, 2);
- $expected[] = $names[6];
- $this->assertSame(
- $expected,
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user1')
- )->invoke('getId'),
- 'Expected fetch all with member filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for users with position specifiers
- $this->assertSame(
- array('test7%%'),
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user%%1')
- )->invoke('getId'),
- 'Expected fetch all with member %% filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for groups
- $this->assertSame(
- (array)'test6',
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'test7')
- )->invoke('getId'),
- 'Expected fetch all with sub-group member filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for groups with position specifiers
- $this->assertSame(
- (array)'test7%%',
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'test%%7')
- )->invoke('getId'),
- 'Expected fetch all with sub-group member %% filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for owners
- $this->assertSame(
- (array)'test5',
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user5')
- )->invoke('getId'),
- 'Expected fetch all with owner member filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER works for owners with position specifiers
- $this->assertSame(
- (array)'test7%%',
- Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user%%2')
- )->invoke('getId'),
- 'Expected fetch all with owner member %% filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER with FETCH_INDIRECT works
- $expected = array_slice($names, 0, 4);
- $expected[] = $names[6];
- $this->assertSame(
- $expected,
- Group::fetchAll(
- array(
- Group::FETCH_BY_MEMBER => 'user1',
- Group::FETCH_INDIRECT => true
- )
- )->invoke('getId'),
- 'Expected fetch all with indirect member filter to match'
- );
-
- // Verify full FETCH_BY_MEMBER with FETCH_INDIRECT and FETCH_MAXIMUM works
- $this->assertSame(
- array_slice($names, 0, 2),
- Group::fetchAll(
- array(
- Group::FETCH_BY_MEMBER => 'user1',
- Group::FETCH_INDIRECT => true,
- Group::FETCH_MAXIMUM => 2
- )
- )->invoke('getId'),
- 'Expected fetch all with indirect member filter and maximum to match'
- );
-
- // Verify FETCH_BY_USER works
- $this->assertSame(
- array('test1', 'test2', 'test7%%'),
- Group::fetchAll(
- array(
- Group::FETCH_BY_USER => 'user1',
- )
- )->invoke('getId'),
- 'expected simple fetch by user to work'
- );
-
- // Verify FETCH_BY_USER works with FETCH_INDIRECT
- $this->assertSame(
- array('test1', 'test2', 'test3', 'test4', 'test7%%'),
- Group::fetchAll(
- array(
- Group::FETCH_BY_USER => 'user1',
- Group::FETCH_INDIRECT => true
- )
- )->invoke('getId'),
- 'expected indirect fetch by user to work'
- );
-
- // Verify FETCH_BY_USER doesn't cover sub-groups
- $this->assertSame(
- array(),
- Group::fetchAll(
- array(
- Group::FETCH_BY_USER => 'test2',
- Group::FETCH_INDIRECT => true
- )
- )->invoke('getId'),
- 'expected fetch by user to ignore groups'
- );
-
- // Verify full FETCH_BY_NAME works
- $this->assertSame(
- array_slice($names, 0, 1),
- Group::fetchAll(
- array(Group::FETCH_BY_NAME => 'test1')
- )->invoke('getId'),
- 'Expected fetch all with name filter to match'
- );
- // Verify full FETCH_BY_NAME works with position specifiers
- $this->assertSame(
- array($names[6]),
- Group::fetchAll(
- array(Group::FETCH_BY_NAME => 'test7%%')
- )->invoke('getId'),
- 'Expected fetch all with name %% filter to match'
- );
- }
-
- /**
- * Test groups specs returned by fetchAll
- */
- public function testFetchAllSpecs()
- {
- $group = new Group;
- $group->setId('test1')
- ->addSubgroup('sg1')
- ->addUser('user1')
- ->addUser('user2')
- ->addUser('user3')
- ->addOwner('user0')
- ->save();
-
- $result = Group::fetchAll();
- $this->assertSame(
- 1,
- $result->count(),
- "Expected fetch all returns 1 result"
- );
-
- // prepare expected spec values
- $expectedUsers = array('user1', 'user2', 'user3');
- $expectedOwners = array('user0');
- $expectedSubgroups = array('sg1');
-
- // Verify result contains correct spec
- $group = $result->current();
- $this->assertSame(
- $expectedUsers,
- $group->getUsers(),
- "Expected fetch all users spec"
- );
- $this->assertSame(
- $expectedSubgroups,
- $group->getSubgroups(),
- "Expected fetch all subgroups spec"
- );
- $this->assertSame(
- $expectedOwners,
- $group->getOwners(),
- "Expected fetch all owners spec"
- );
-
- // Verify result contains correct specs for filter by name
- $result = Group::fetchAll(
- array(Group::FETCH_BY_NAME => 'test1')
- );
- $this->assertSame(
- 1,
- $result->count(),
- "Expected fetch all #2 returns 1 result"
- );
-
- // Verify result contains correct spec
- $group = $result->current();
- $this->assertSame(
- $expectedUsers,
- $group->getUsers(),
- "Expected fetch all #2 users spec"
- );
- $this->assertSame(
- $expectedSubgroups,
- $group->getSubgroups(),
- "Expected fetch all #2 subgroups spec"
- );
- $this->assertSame(
- $expectedOwners,
- $group->getOwners(),
- "Expected fetch all #2 owners spec"
- );
-
- // Verify result contains correct specs for filter by member
- $result = Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user2')
- );
- $this->assertSame(
- 1,
- $result->count(),
- "Expected fetch all #3 returns 1 result"
- );
-
- // Verify result contains correct spec
- $group = $result->current();
- $this->assertSame(
- $expectedUsers,
- $group->getUsers(),
- "Expected fetch all #3 users spec"
- );
- $this->assertSame(
- $expectedSubgroups,
- $group->getSubgroups(),
- "Expected fetch all #3 subgroups spec"
- );
- $this->assertSame(
- $expectedOwners,
- $group->getOwners(),
- "Expected fetch all #3 owners spec"
- );
-
- // Verify that saving partialy altered and unpopulated spec will save all values
- $group = Group::fetchAll(
- array(Group::FETCH_BY_MEMBER => 'user2')
- )->current();
-
- $group->setUsers(array('user4'))
- ->save();
-
- // Verify result contains correct spec
- $group = Group::fetch('test1');
- $this->assertSame(
- array('user4'),
- $group->getUsers(),
- "Expected fetch all #4 users spec"
- );
- $this->assertSame(
- $expectedSubgroups,
- $group->getSubgroups(),
- "Expected fetch all #4 subgroups spec"
- );
- $this->assertSame(
- $expectedOwners,
- $group->getOwners(),
- "Expected fetch all #4 owners spec"
- );
- }
-
- /**
- * Tests invalid options and option combos
- */
- public function testFetchAllBadOptions()
- {
- $tests = array(
- array(
- 'title' => __LINE__.' integer name filter',
- 'options' => array(Group::FETCH_BY_NAME => 0),
- 'exception' => 'Filter by Name expects a valid group id.'
- ),
- array(
- 'title' => __LINE__.' empty string name filter',
- 'options' => array(Group::FETCH_BY_NAME => ""),
- 'exception' => 'Filter by Name expects a valid group id.'
- ),
- array(
- 'title' => __LINE__.' invalid name filter',
- 'options' => array(Group::FETCH_BY_NAME => "-test"),
- 'exception' => 'Filter by Name expects a valid group id.'
- ),
- array(
- 'title' => __LINE__.' name filter with indirect option',
- 'options' => array(
- Group::FETCH_BY_NAME => "test",
- Group::FETCH_INDIRECT => true
- ),
- 'exception' => 'Filter by Name is not compatible with Fetch by Member or Fetch Indirect.'
- ),
- array(
- 'title' => __LINE__.' name filter with member option',
- 'options' => array(
- Group::FETCH_BY_NAME => "test",
- Group::FETCH_BY_MEMBER => "user"
- ),
- 'exception' => 'Filter by Name is not compatible with Fetch by Member or Fetch Indirect.'
- ),
- array(
- 'title' => __LINE__.' name filter with indirect and member options',
- 'options' => array(
- Group::FETCH_BY_NAME => "test",
- Group::FETCH_BY_MEMBER => "user",
- Group::FETCH_INDIRECT => true,
- ),
- 'exception' => 'Filter by Name is not compatible with Fetch by Member or Fetch Indirect.'
- ),
- array(
- 'title' => __LINE__.' empty string member filter',
- 'options' => array(Group::FETCH_BY_MEMBER => ""),
- 'exception' => 'Filter by Member expects a valid group or username.'
- ),
- array(
- 'title' => __LINE__.' integer member filter',
- 'options' => array(Group::FETCH_BY_MEMBER => 10),
- 'exception' => 'Filter by Member expects a valid group or username.'
- ),
- array(
- 'title' => __LINE__.' invalid member filter',
- 'options' => array(Group::FETCH_BY_MEMBER => "-test"),
- 'exception' => 'Filter by Member expects a valid group or username.'
- ),
- );
-
- foreach ($tests as $test) {
- try {
- Group::fetchAll($test['options']);
-
- $this->fail($test['title'].': unexpected success');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\InvalidArgumentException $e) {
- $this->assertSame(
- $test['exception'],
- $e->getMessage(),
- $test['title'].': unexpected exception message'
- );
- } catch (\Exception $e) {
- $this->fail(
- $test['title'].
- ': unexpected exception ('. get_class($e) .') '.
- $e->getMessage()
- );
- }
- }
- }
-
- /**
- * Test calling save without an ID
- */
- public function testSaveNoId()
- {
- try {
- $group = new Group;
- $group->save();
-
- $this->fail('unexpected success');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (SpecException $e) {
- $this->assertSame(
- 'Cannot save. Group is empty.',
- $e->getMessage(),
- 'unexpected exception message'
- );
- } catch (\Exception $e) {
- $this->fail(': unexpected exception ('. get_class($e) .') '. $e->getMessage());
- }
- }
-
- /**
- * Test fetch
- */
- public function testFetch()
- {
- // ensure fetch fails for a non-existant group.
- try {
- Group::fetch('alskdfj2134');
- $this->fail("Fetch should fail for a non-existant group.");
- } catch (NotFoundException $e) {
- $this->assertTrue(true);
- }
-
- // ensure fetch works for a just-created group
- $group = new Group;
- $group->setId('testers%%')
- ->addUser('tester')
- ->save();
-
- $group = Group::fetch('testers%%');
- $this->assertTrue($group->getId() == 'testers%%', "User id should be 'testers%%'.");
- }
-
- /**
- * Test id exists
- */
- public function testIdExists()
- {
- // ensure id-exists returns false for ill formatted group
- $this->assertFalse(Group::exists("-alsdjf"), "Invalid group id should not exist.");
-
- // ensure id-exists returns false for non-existant group
- $this->assertFalse(Group::exists("alsdjf"), "Given group id should not exist.");
-
- // create group and ensure it exists.
- $group = new Group;
- $group->setId('test')
- ->addUser('tester')
- ->save();
- $this->assertTrue(Group::exists("test"), 'Given group id should exist.');
-
- // check a group that contains position specifiers
- $group = new Group;
- $group->setId('testers%%')
- ->addUser('tester')
- ->save();
- $this->assertTrue(Group::exists('testers%%'), 'Given group id should exist.');
- }
-
- /**
- * test is empty
- */
- public function testIsEmpty()
- {
- $group = new Group;
- $this->assertTrue(
- $group->isEmpty(),
- 'Expected fresh group to be empty'
- );
-
- $group = new Group;
- $this->assertTrue(
- $group->setId('test')->isEmpty(),
- 'Expected group with ID to be empty'
- );
-
- $group = new Group;
- $this->assertTrue(
- $group->setId('test%%')->isEmpty(),
- 'Expected group with ID %% to be empty'
- );
-
- $group = new Group;
- $this->assertTrue(
- $group->setTimeout(100)->isEmpty(),
- 'Expected group with timeout to be empty'
- );
-
- $group = new Group;
- $this->assertFalse(
- $group->addSubgroup('test')->isEmpty(),
- 'Expected group with subgroup to not be empty'
- );
-
- $group = new Group;
- $this->assertFalse(
- $group->addOwner('test')->isEmpty(),
- 'Expected group with owner to not be empty'
- );
-
- $group = new Group;
- $this->assertFalse(
- $group->addUser('test')->isEmpty(),
- 'Expected group with user to not be empty'
- );
- }
-
- /**
- * test 'max' style fields with bad values
- */
- public function testBadMaxResultsMaxScanRowsMaxLockTimeTimeout()
- {
- $methods = array('MaxResults', 'MaxScanRows', 'MaxLockTime', 'Timeout');
- $tests = array(
- array(
- 'title' => __LINE__.' bool',
- 'value' => true,
- 'error' => 'Type of input must be one of: null, int, string'
- ),
- array(
- 'title' => __LINE__.' unsets',
- 'value' => 'unsets',
- 'error' => "For string input, only the values 'unlimited' and 'unset' are valid."
- ),
- array(
- 'title' => __LINE__.' blank string',
- 'value' => '',
- 'error' => "For string input, only the values 'unlimited' and 'unset' are valid."
- ),
- array(
- 'title' => __LINE__.' small negative number',
- 'value' => -2,
- 'error' => 'For integer input, only values greater than zero are valid.'
- ),
- array(
- 'title' => __LINE__.' big negative number',
- 'value' => -20000,
- 'error' => 'For integer input, only values greater than zero are valid.'
- )
- );
-
- foreach ($methods as $method) {
- foreach ($tests as $test) {
- $group = new Group;
-
- try {
- $group->{'set'.$method}($test['value']);
-
- $this->fail($test['title'].', '. $method .': unexpected success');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\InvalidArgumentException $e) {
- $this->assertSame(
- $test['error'],
- $e->getMessage(),
- $test['title'].', '. $method .': unexpected exception message'
- );
- } catch (\Exception $e) {
- $this->fail(
- $test['title'].', '. $method .
- ': unexpected exception ('. get_class($e) .') '.
- $e->getMessage()
- );
- }
- }
- }
- }
-
- /**
- * test 'max' style fields with good values
- */
- public function testGoodMaxResultsMaxScanRowsMaxLockTimeTimeout()
- {
- $methods = array('MaxResults', 'MaxScanRows', 'MaxLockTime', 'Timeout');
- $tests = array(
- array(
- 'title' => __LINE__.' small int',
- 'value' => 1,
- ),
- array(
- 'title' => __LINE__.' big int',
- 'value' => 10000,
- ),
- array(
- 'title' => __LINE__.' unset',
- 'value' => 'unset',
- 'out' => null
- ),
- array(
- 'title' => __LINE__.' null',
- 'value' => null,
- ),
- array(
- 'title' => __LINE__.' unlimited',
- 'value' => 'unlimited',
- ),
- );
-
- foreach ($methods as $method) {
- foreach ($tests as $test) {
- $group = new Group;
-
- $group->setId('test')->addUser('test');
- $group->{'set'.$method}($test['value']);
-
- $out = array_key_exists('out', $test) ? $test['out'] : $test['value'];
-
- // verify in-memory object matches up
- $this->assertSame(
- $out,
- $group->{'get'.$method}(),
- $test['title'].', '. $method .': expected matching return'
- );
-
- // save and verify it still matches
- $group->save();
- $this->assertSame(
- $out,
- $group->{'get'.$method}(),
- $test['title'].', '. $method .': expected matching return post save'
- );
-
- // fetch from storage and verify it still matches
- $group = Group::fetch('test');
- $this->assertSame(
- $out,
- $group->{'get'.$method}(),
- $test['title'].', '. $method .': expected matching return on fetched version'
- );
-
- }
- }
- }
-
- /**
- * Test behaviour when bad subgroups, owners, and users are specified.
- */
- public function testBadSubgroupsOwnersUsers()
- {
- $methods = array(
- 'setSubgroups', 'addSubgroup',
- 'setOwners', 'addOwner',
- 'setUsers', 'addUser',
- );
- $arrayError = '/^[^ ]+ must be specified as an array.$/';
- $elementError = '/^Individual [^ ]+ must be a valid ID in either string or [^ ]+ format.$/';
- $tests = array(
- array(
- 'title' => __LINE__.' int',
- 'value' => 10,
- 'setError' => $arrayError,
- 'addError' => $elementError
- ),
- array(
- 'title' => __LINE__.' bool',
- 'value' => true,
- 'setError' => $arrayError,
- 'addError' => $elementError
- ),
- array(
- 'title' => __LINE__.' null',
- 'value' => null,
- 'setError' => $arrayError,
- 'addError' => $elementError
- ),
- array(
- 'title' => __LINE__.' array of ints',
- 'value' => array(10, 9, 8),
- 'setError' => $elementError,
- 'addError' => $elementError
- ),
- );
-
-
- foreach ($methods as $method) {
- foreach ($tests as $test) {
- $group = new Group;
-
- try {
- $group->{$method}($test['value']);
-
- $this->fail($test['title'].', '. $method .': unexpected success');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\InvalidArgumentException $e) {
- $error = $test[substr($method, 0, 3).'Error'];
- $this->assertRegExp(
- $error,
- $e->getMessage(),
- $test['title'].', '. $method .': unexpected exception message'
- );
- } catch (\Exception $e) {
- $this->fail(
- $test['title'].', '. $method .
- ': unexpected exception ('. get_class($e) .') '.
- $e->getMessage()
- );
- }
- }
- }
- }
-
- /**
- * Test good set/add Subgroups, Owners, Users
- */
- public function testGoodSubgroupsOwnersUsers()
- {
- $group = new Group;
- $group->setId('test');
- $user = new User;
- $user->setId('test');
-
- $methods = array(
- 'Subgroup' => $group,
- 'Owner' => $user,
- 'User' => $user,
- );
-
- try {
- foreach ($methods as $method => $object) {
- // test 'set'
- $group = new Group;
- $group->setId('test');
- $group->{'set'.$method.'s'}(array($object));
-
- $this->assertSame(
- (array)$object->getId(),
- $group->{'get'.$method.'s'}(),
- $method.': expected matching return following set'
- );
-
- // test 'add'
- $group->{'add'.$method}('test2');
- $this->assertSame(
- array('test', 'test2'),
- $group->{'get'.$method.'s'}(),
- $method.': expected matching return following add'
- );
-
- // save and verify it still matches
- $group->save();
- $this->assertSame(
- array('test', 'test2'),
- $group->{'get'.$method.'s'}(),
- $method.': expected matching return following save'
- );
-
- // fetch from storage and verify it still matches
- $group = Group::fetch('test');
- $this->assertSame(
- array('test', 'test2'),
- $group->{'get'.$method.'s'}(),
- $method.': expected matching return following fetch'
- );
- }
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- $this->fail(
- $method.': unexpected exception ('. get_class($e) .') '. $e->getMessage()
- );
- }
- }
-
- /**
- * Test save as owner.
- */
- public function testSaveAsOwner()
- {
- $user = new User;
- $user->setId('owner-user')
- ->setFullName('Owner Of Group')
- ->setEmail('owner@domain.com')
- ->save();
-
- $group = new Group;
- $group->setId('test-group')
- ->setUsers(array($user->getId()))
- ->setOwners(array($user->getId()))
- ->save();
-
- // connect as 'owner-user'.
- $connection = Connection::factory(
- $this->p4->getPort(),
- $user->getId()
- );
-
- // save of group should fail w.out owner flag.
- try {
- $group = Group::fetch('test-group', $connection);
- $group->save();
- $this->fail('unexpected success');
- } catch (\Exception $e) {
- $this->assertTrue(true);
- }
-
- // now try to save the test-group w. owner flag.
- $group = Group::fetch('test-group', $connection);
- $group->save(true);
- }
-
- /**
- * Test fetch all captures all values (we had a bug where some fields were dropped).
- */
- public function testFetchAllGetsAllFields()
- {
- $values = array(
- 'Group' => 'test-group',
- 'MaxResults' => 1000,
- 'MaxScanRows' => 10000,
- 'MaxLockTime' => 30000,
- 'Timeout' => 3600,
- 'PasswordTimeout' => 'unlimited',
- 'Subgroups' => array('sub-group'),
- 'Owners' => array('tester'),
- 'Users' => array('tester')
- );
- $this->p4->run('group', array('-i'), $values);
-
- $groups = Group::fetchAll(array(), $this->p4);
- $this->assertSame(
- array('test-group' => $values),
- $groups->toArray()
- );
- }
-
- /**
- * Test fetch all with a filter callback
- */
- public function testFetchAllWithCallback()
- {
- for ($i = 0; $i < 10; $i++) {
- $this->p4->run('group', array('-i'), array('Group' => 'group' . $i, 'Owners' => array('tester')));
- }
-
- $groups = Group::fetchAll();
- $this->assertSame(10, $groups->count());
-
- $groups = Group::fetchAll(
- array(Group::FETCH_FILTER_CALLBACK => function ($group) {
- return filter_var($group['Group'], FILTER_SANITIZE_NUMBER_INT) % 2;
- })
- );
- $this->assertSame(5, $groups->count());
- $this->assertSame(array('group1', 'group3', 'group5', 'group7', 'group9'), $groups->invoke('getId'));
- }
- }