GroupTest.php #1

  • //
  • guest/
  • thomas_gray/
  • jambox/
  • main/
  • swarm/
  • tests/
  • phpunit/
  • P4Test/
  • Spec/
  • GroupTest.php
  • View
  • Commits
  • Open Download .zip Download (29 KB)
<?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('[email protected]')
             ->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'));
    }
}
# Change User Description Committed
#1 18730 Liz Lam clean up code and move things around