JobTest.php #1

  • //
  • guest/
  • thomas_gray/
  • jambox/
  • main/
  • swarm/
  • tests/
  • phpunit/
  • P4Test/
  • Spec/
  • JobTest.php
  • View
  • Commits
  • Open Download .zip Download (27 KB)
<?php
/**
 * Test methods for the P4 Job 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\Job;
use P4\Spec\User;
use P4\Log\Logger;
use P4\Spec\Client;
use P4\Spec\Exception\NotFoundException;
use Zend\Log\Logger as ZendLogger;
use Zend\Log\Writer\Mock as MockLog;

class JobTest extends TestCase
{
    /**
     * Test fetching a job.
     */
    public function testFetch()
    {
        // ensure fetch fails for a non-existant job.
        $jobId = 'alskdfj2134';
        try {
            Job::fetch($jobId);
            $this->fail('Fetch should fail for a non-existant job.');
        } catch (NotFoundException $e) {
            $this->assertSame(
                "Cannot fetch job $jobId. Record does not exist.",
                $e->getMessage(),
                'Expected error fetching a non-existant job.'
            );
        } catch (\Exception $e) {
            $this->fail('Unexpected exception fetching a non-existant job.');
        }

        // ensure fetch fails with an empty id
        $jobId = '';
        try {
            Job::fetch($jobId);
            $this->fail('Unexpected success fetching an empty job id.');
        } catch (\InvalidArgumentException $e) {
            $this->assertSame(
                'Must supply a valid id to fetch.',
                $e->getMessage(),
                'Expected error fetching an empty job id.'
            );
        } catch (\Exception $e) {
            $this->fail('Unexpected exception fetching an empty job id.');
        }
    }

    /**
     * Verify one command populates a job.
     */
    public function testFetchOneCommand()
    {
        $job = new Job;
        $description = "test job for fetching\n";
        $job->set('Description', $description)->save();
        try {
            $job = Job::fetch('job000001');
            $this->assertSame($description, $job->getDescription());
        } catch (\Exception $e) {
            $this->fail("Unexpected exception fetching a job.");
        }

        // ensure it only takes one command to fetch a job and read
        // basic values from it -- we verify this by peeking at the log
        $original = Logger::hasLogger() ? Logger::getLogger() : null;
        $logger   = new ZendLogger;
        $mock     = new MockLog;
        $logger->addWriter($mock);
        Logger::setLogger($logger);

        $fetched = Job::fetch('job000001');
        $fetched->get();
        $this->assertSame(1, count($mock->events));

        // restore original logger if there is one.
        Logger::setLogger($original);
    }

    /**
     * Test exists.
     */
    public function testExists()
    {
        // ensure id-exists returns false for non-existant job
        $this->assertFalse(Job::exists('alsdjf'), 'Given job id should not exist.');

        // ensure id-exists returns false for invalid job
        $this->assertFalse(Job::exists('-job1'), 'Invalid job id should not exist.');

        // create job and ensure it exists.
        $job = new Job;
        $job->set('Description', 'test')->save();
        $this->assertTrue(Job::exists('job000001'), 'Given job id should exist.');
    }

    /**
     * Test saving a job.
     */
    public function testSave()
    {
        $job = new Job;
        $description = 'test!';
        $job->set('Description', $description);

        // demonstrate that pre-save description is unmodified.
        $this->assertSame(
            $description,
            $job->get('Description'),
            'Expected pre-fetch description'
        );

        $job->save();
        $firstId = 'job000001';
        $this->assertSame($firstId, $job->getId(), 'Expected id');

        $job = Job::fetch($firstId);
        $this->assertSame($firstId, $job->getId(), 'Expected id');

        // demonstrate that post-save description has had whitespace
        // management performed by the server.
        $this->assertSame(
            "$description\n",
            $job->get('Description'),
            'Expected post-fetch description'
        );
    }

    /**
     * Test deleting a job.
     */
    public function testDelete()
    {
        // make a few jobs
        $expectedIds = array();
        $expectedDescriptions = array();
        for ($i = 0; $i < 5; $i++) {
            $job = new Job;
            $description = "job $i\n";
            $job->set('Description', $description);
            $job->save();
            $expectedIds[] = $job->getId();
            $expectedDescriptions[] = $description;
        }

        $jobs = Job::fetchAll();
        $this->assertTrue($jobs->count() == 5, 'Expected job count');
        $jobIds = array();
        $descriptions = array();
        foreach ($jobs as $job) {
            $jobIds[] = $job->getId();
            $descriptions[] = $job->get('Description');
        }
        $this->assertSame(
            $expectedIds,
            $jobIds,
            'Expected job ids'
        );
        $this->assertSame(
            $expectedDescriptions,
            $descriptions,
            'Expected job descriptions'
        );
        $theId = $jobs->nth(2)->getId();
        $this->assertTrue(
            Job::exists($theId),
            'Given job id should exist.'
        );

        // now delete a job
        $job = $jobs->nth(2);
        $job->delete();

        // adjust expectations
        array_splice($expectedIds, 2, 1);
        array_splice($expectedDescriptions, 2, 1);

        // refetch and test that the deleted job no longer exists
        // and that the non-deleted jobs still exist
        $jobs = Job::fetchAll();
        $this->assertTrue($jobs->count() == 4, 'Expected job count');
        $jobIds = array();
        $descriptions = array();
        foreach ($jobs as $job) {
            $jobIds[] = $job->getId();
            $descriptions[] = $job->get('Description');
        }
        $this->assertSame(
            $expectedIds,
            $jobIds,
            'Expected job ids'
        );
        $this->assertSame(
            $expectedDescriptions,
            $descriptions,
            'Expected job descriptions'
        );
        $this->assertFalse(
            Job::exists($theId),
            'Given job id should not exist.'
        );
    }

    /**
     * Test fetchAll.
     */
    public function testFetchAll()
    {
        $expectedJobIds = array();
        $expectedDescriptions = array();
        for ($i = 0; $i < 10; $i++) {
            $job = new Job;
            $description = "test job $i";
            $job->set('Description', $description);
            $job->save();
            $expectedDescriptions[] = "$description\n";
            $expectedJobIds[] = $job->getId();
        }

        $jobs = Job::fetchAll();
        $this->assertTrue($jobs->count() == 10, 'Expected job count');
        $jobIds = array();
        $descriptions = array();
        foreach ($jobs as $job) {
            $jobIds[] = $job->getId();
            $descriptions[] = $job->get('Description');
        }
        $this->assertSame(
            $expectedJobIds,
            $jobIds,
            'Expected job ids'
        );
        $this->assertSame(
            $expectedDescriptions,
            $descriptions,
            'Expected job descriptions'
        );
    }

    /**
     * get/set value are tested already for code indexed mutators. Test them for
     * fields without mutator/accessors.
     */
    public function testGetSet()
    {
        // add the field 'NewField' to do our testing on.
        $fields = \P4\Spec\Definition::fetch('job')->getFields();
        $fields['NewField'] = array (
            'code' => '110',
            'dataType' => 'word',
            'displayLength' => '32',
            'fieldType' => 'required',
        );
        \P4\Spec\Definition::fetch('job')->setFields($fields)->save();

        // test in memory object
        $job = new Job;
        $job->setDescription('test');

        $this->assertSame(
            null,
            $job->get('NewField'),
            'Expected matching starting value'
        );

        $job->set('NewField', 'test');

        $this->assertSame(
            'test',
            $job->get('NewField'),
            'Expected matching value after set'
        );

        // save it and refetch to verify it is still good
        $job->save();
        $job = Job::fetch($job->getId());

        $this->assertSame(
            'test',
            $job->get('NewField'),
            'Expected matching value after save/fetch'
        );
    }

    /**
     * Test setting invalid inputs for Status/User/Description
     */
    public function testBadSetStatusUserDescription()
    {
        $methods = array(
            'setStatus'      => 'Status must be a string or null',
            'setUser'        => 'User must be a string, P4\Spec\User or null',
            'setDescription' => 'Description must be a string or null',
        );

        $tests = array(
            array(
                'title' => __LINE__.' int',
                'value' => 10
            ),
            array(
                'title' => __LINE__.' bool',
                'value' => true
            ),
            array(
                'title' => __LINE__.' float',
                'value' => 10.0
            ),
            array(
                'title' => __LINE__.' P4\Spec\Client',
                'value' => Client::fetchAll(array(Client::FETCH_MAXIMUM => 1))
            ),
        );

        foreach ($methods as $method => $expectedError) {
            foreach ($tests as $test) {
                try {
                    $job = new Job;

                    $job->{$method}($test['value']);

                    $this->fail(
                        $method.' '.$test['title'].': Unexpected success'
                    );
                } catch (\PHPUnit\Framework\AssertionFailedError $e) {
                    $this->fail($e->getMessage());
                } catch (\InvalidArgumentException $e) {
                    $this->assertSame(
                        $expectedError,
                        $e->getMessage(),
                        $method.' '.$test['title'].': unexpected exception message'
                    );
                } catch (\Exception $e) {
                    $this->fail(
                        $method.' '.$test['title'].
                        ': unexpected exception ('. get_class($e) .') '.
                        $e->getMessage()
                    );
                }
            }
        }
    }

    /**
     * Test setting valid inputs for Status
     */
    public function testGoodSetStatus()
    {
        $tests = array(
            array(
                'title' => __LINE__.' empty string',
                'value' => ''
            ),
            array(
                'title' => __LINE__.' null',
                'value' => null
            ),
            array(
                'title' => __LINE__.' valid string',
                'value' => 'closed',
                'canSave' => true,
            ),
            array(
                'title' => __LINE__.' valid string',
                'value' => 'suspended',
                'canSave' => true,
            ),
            array(
                'title' => __LINE__.' valid string',
                'value' => 'open',
                'canSave' => true,
            ),
        );

        foreach ($tests as $test) {
            $title = $test['title'];
            $value = $test['value'];
            $out   = array_key_exists('out', $test) ? $test['out'] : $test['value'];

            $job = new Job;

            // in memory test via setStatus
            $job->setStatus($value);
            $this->assertSame(
                $out,
                $job->getStatus(),
                $title.': expected to match set value'
            );

            $this->assertSame(
                $out,
                $job->get('Status'),
                $title.': Expected get() to match'
            );

            // via set comparison
            $job = new Job;
            $job->set('Status', $value);
            $this->assertSame(
                $out,
                $job->get('Status'),
                $title.': Expected getStatus to match get'
            );

            $this->assertSame(
                $out,
                $job->getStatus(),
                $title.': Expected set to match getStatus'
            );

            if (array_key_exists('canSave', $test)) {
                // post save test
                $job->setDescription('blah')->setUser('user1')->save();
                $this->assertSame(
                    $out,
                    $job->getStatus(),
                    'Expected getStatus to match post save'
                );

                $this->assertSame(
                    $out,
                    $job->get('Status'),
                    'Expected get(Status) to match post save'
                );

                // post fetch test
                $job = Job::fetch($job->getId());
                $this->assertSame(
                    $out,
                    $job->getStatus(),
                    'Expected getStatus to match post fetch'
                );

                $this->assertSame(
                    $out,
                    $job->get('Status'),
                    'Expected get(Status) to match post fetch'
                );
            }
        }
    }

    /**
     * Test setting valid inputs for User
     */
    public function testGoodSetUser()
    {
        $user = new User;
        $user->setId('bob');
        $tests = array(
            array(
                'title' => __LINE__.' empty string',
                'value' => ''
            ),
            array(
                'title' => __LINE__.' null',
                'value' => null
            ),
            array(
                'title' => __LINE__.' valid string',
                'value' => 'user1',
                'canSave' => true,
            ),
            array(
                'title' => __LINE__.' valid object',
                'value' => $user,
                'out'   => $user->getId(),
                'canSave' => true,
            ),
        );

        foreach ($tests as $test) {
            $title = $test['title'];
            $value = $test['value'];
            $out   = array_key_exists('out', $test) ? $test['out'] : $test['value'];

            $job = new Job;

            // in memory test via setField
            $job->setUser($value);
            $this->assertSame(
                $out,
                $job->getUser(),
                $title.': expected to match set value'
            );

            $this->assertSame(
                $out,
                $job->get('User'),
                $title.': Expected get() to match'
            );

            // via set comparison
            $job = new Job;
            $job->set('User', $value);
            $this->assertSame(
                $out,
                $job->get('User'),
                $title.': Expected to match get'
            );

            $this->assertSame(
                $out,
                $job->getUser(),
                $title.': Expected set to match getUser'
            );

            if (array_key_exists('canSave', $test)) {
                // post save test
                $job->setDescription('blah')->setStatus('open')->save();
                $this->assertSame(
                    $out,
                    $job->getUser(),
                    'Expected getUser to match post save'
                );

                $this->assertSame(
                    $out,
                    $job->get('User'),
                    'Expected get(User) to match post save'
                );

                // post fetch test
                $job = Job::fetch($job->getId());
                $this->assertSame(
                    $out,
                    $job->getUser(),
                    'Expected getUser to match post fetch'
                );

                $this->assertSame(
                    $out,
                    $job->get('User'),
                    'Expected get(User) to match post fetch'
                );
            }
        }
    }

    /**
     * Test setting valid inputs for Description
     */
    public function testGoodSetDescription()
    {
        $tests = array(
            array(
                'title' => __LINE__.' empty string',
                'value' => ''
            ),
            array(
                'title' => __LINE__.' null',
                'value' => null
            ),
            array(
                'title' => __LINE__.' valid string',
                'value' => "test description\n",
                'canSave' => true,
            ),
            array(
                'title' => __LINE__.' valid multi-line string',
                'value' => "test of\nmultiline\ndescriptoin!\n",
                'canSave' => true,
            ),
        );

        foreach ($tests as $test) {
            $title = $test['title'];
            $value = $test['value'];
            $out   = array_key_exists('out', $test) ? $test['out'] : $test['value'];

            $job = new Job;

            // in memory test via setField
            $job->setDescription($value);
            $this->assertSame(
                $out,
                $job->getDescription(),
                $title.': expected to match set value'
            );

            $this->assertSame(
                $out,
                $job->get('Description'),
                $title.': Expected get() to match'
            );

            // via set comparison
            $job = new Job;
            $job->set('Description', $value);
            $this->assertSame(
                $out,
                $job->get('Description'),
                $title.': Expected to match get'
            );

            $this->assertSame(
                $out,
                $job->getDescription(),
                $title.': Expected set to match getDescription'
            );

            if (array_key_exists('canSave', $test)) {
                // post save test
                $job->setUser('user1')->setStatus('open')->save();
                $this->assertSame(
                    $out,
                    $job->getDescription(),
                    'Expected getDescription to match post save'
                );

                $this->assertSame(
                    $out,
                    $job->get('Description'),
                    'Expected get(Description) to match post save'
                );

                // post fetch test
                $job = Job::fetch($job->getId());

                $this->assertSame(
                    $out,
                    $job->getDescription(),
                    'Expected getDescription to match post fetch'
                );

                $this->assertSame(
                    $out,
                    $job->get('Description'),
                    'Expected get(Description) to match post fetch'
                );
            }
        }
    }

    /**
     * test the get date function
     */
    public function testGetDate()
    {
        $job = new Job;

        $this->assertSame(
            null,
            $job->getDate(),
            'Expected starting date to match'
        );

        $job->setUser('user1')->setStatus('open')->setDescription('blah')->save();

        // convert to unix time (accounting for timezone) and verify it looks ok
        $dateTime = \DateTime::createFromFormat('Y/m/d H:i:s', $job->getDate(), $this->p4->getTimeZone());
        $this->assertLessThan(
            2,
            abs((int) $dateTime->format('U') - time()),
            'Expected converted data/time to be within range post save'
        );

        // also confirm the built-in conversion on the job object spits out a good unixtime
        $this->assertSame(
            (int) $dateTime->format('U'),
            $job->getTime(),
            'Expected time to be within range post save'
        );
    }

    /**
     * Tests invalid options and option combos
     */
    public function testFetchAllBadOptions()
    {
        $tests = array(
            array(
                'title'     => __LINE__.' integer filter',
                'options'   => array(Job::FETCH_BY_FILTER => 0),
                'exception' => 'Fetch by Filter expects a non-empty string as input'
            ),
            array(
                'title'     => __LINE__.' empty string filter',
                'options'   => array(Job::FETCH_BY_FILTER => ""),
                'exception' => 'Fetch by Filter expects a non-empty string as input'
            ),
            array(
                'title'     => __LINE__.' empty string filter w/whitespace',
                'options'   => array(Job::FETCH_BY_FILTER => "     "),
                'exception' => 'Fetch by Filter expects a non-empty string as input'
            ),
            array(
                'title'     => __LINE__.' integer filter',
                'options'   => array(Job::FETCH_BY_FILTER => 10),
                'exception' => 'Fetch by Filter expects a non-empty string as input'
            ),
        );

        foreach ($tests as $test) {
            try {
                Job::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 fetchAll with FETCH_DESCRIPTION = false and = true
     */
    public function testFetchAllDescriptions()
    {
        for ($i=0; $i<4; $i++) {
            $job = new Job;
            $job->setId((string)$i)->setUser('user'.$i)->setStatus('open')
                ->setDescription('test: '.$i."\n")->save();
        }

        // eval a mock object into existence which adds a 'getRawValues' function
        $mockCode = 'class P4_JobMock extends \\P4\\Spec\\Job {
                        public function getRawValues()
                        {
                            return $this->values;
                        }
                    }';

        if (!class_exists('P4_JobMock')) {
            eval($mockCode);
        }

        // Test with FETCH_DESCRIPTION off
        $jobs = \P4_JobMock::fetchAll(array(Job::FETCH_DESCRIPTION => false));
        foreach ($jobs as $job) {
            $this->assertFalse(
                array_key_exists('Description', $job->getRawValues()),
                'Job: '.$job->getId().' expected Description to be non-existent'
            );

            $this->assertSame(
                "test: ".$job->getId()."\n",
                $job->getDescription(),
                'Job: '.$job->getId().' expected Description to autoload'
            );
        }

        // Test with FETCH_DESCRIPTION on
        $jobs = \P4_JobMock::fetchAll(array(Job::FETCH_DESCRIPTION => true));
        foreach ($jobs as $job) {
            $this->assertTrue(
                array_key_exists('Description', $job->getRawValues()),
                'Job: '.$job->getId().' expected Description to exist'
            );

            $values = $job->getRawValues();
            $this->assertSame(
                "test: ".$job->getId()."\n",
                $values['Description'],
                'Job: '.$job->getId().' expected Description to match'
            );

            $this->assertSame(
                "test: ".$job->getId()."\n",
                $job->getDescription(),
                'Job: '.$job->getId().' expected Description to match via accessor'
            );
        }

        // Test default is FETCH_DESCRIPTION on
        $explicitJobs = \P4_JobMock::fetchAll(array(Job::FETCH_DESCRIPTION => true));
        $defaultJobs  = \P4_JobMock::fetchAll();

        foreach ($explicitJobs as $key => $job) {
            $this->assertSame(
                $job->getRawValues(),
                $defaultJobs[$key]->getRawValues(),
                'Expeted default to be fetch description = true'
            );
        }
    }

    /**
     * Verify a variety of unusual ids don't cause trouble
     */
    public function testCrazyIds()
    {
        $ids = array(
            '!bang', '$test', '%percent', '&and', '\'', '(open', ')closed', ',comma', '.dot',
            '042709', '30387b', '3spaces', '<ab>', '<abc>', '<open', '>new', '?question', '[open',
            ']closed', '^carrot', '^new', '_Myjob001', '__job_w/_leading_and_trailing_white_space_',
            '_underscore', 'www.hello'
        );

        foreach ($ids as $id) {
            $job = new Job;
            $job->setId($id)
                ->setDescription($id)
                ->save();
        }
    }

    /**
     * Verify ID's with - don't cause erroneous fetch.
     */
    public function testDashFetches()
    {
        $ids = array('foo', 'foo2', 'foo-bar', 'foo-biz', 'bar-foo', 'biz-foo');
        foreach ($ids as $id) {
            $job = new Job;
            $job->setId($id)
                ->setDescription($id)
                ->save();
        }

        $this->assertSame(
            array('foo'),
            Job::fetchAll(array(Job::FETCH_BY_IDS => 'foo'))->invoke('getId'),
            'expected fetch by ids to work'
        );
    }

    public function testCreatedModifiedFieldMethods()
    {
        $job = new Job;

        // should have mod-date field by default
        $this->assertTrue($job->hasModifiedDateField());
        $this->assertSame('Date', $job->getModifiedDateField());

        // should NOT have create-date field
        $this->assertFalse($job->hasCreatedDateField());
        try {
            $job->getCreatedDateField();
            $this->fail();
        } catch (\P4\Spec\Exception\Exception $e) {
            $this->assertTrue(true);
        }

        // add a created date field
        $spec   = $job->getSpecDefinition();
        $fields = $spec->getFields();
        $fields['CreatedDate'] = array(
            'code'          => 106,
            'dataType'      => 'date',
            'displayLength' => 20,
            'fieldType'     => 'once',
            'default'       => '$now'
        );
        $spec->setFields($fields)->save();

        // should now have create-date field
        $this->assertTrue($job->hasCreatedDateField());
        $this->assertSame('CreatedDate', $job->getCreatedDateField());

        // should have created by field.
        $this->assertTrue($job->hasCreatedByField());
        $this->assertSame('User', $job->getCreatedByField());

        // should NOT have modified by field.
        $this->assertFalse($job->hasModifiedByField());
        try {
            $job->getModifiedByField();
            $this->fail();
        } catch (\P4\Spec\Exception\Exception $e) {
            $this->assertTrue(true);
        }

        // add a modified by field
        $spec   = $job->getSpecDefinition();
        $fields = $spec->getFields();
        $fields['ModifiedBy'] = array(
            'code'          => 107,
            'dataType'      => 'word',
            'displayLength' => 20,
            'fieldType'     => 'always',
            'default'       => '$user'
        );
        $spec->setFields($fields)->save();

        // should have mod-date field by default
        $this->assertTrue($job->hasModifiedByField());
        $this->assertSame('ModifiedBy', $job->getModifiedByField());
    }
}
# Change User Description Committed
#1 18730 Liz Lam clean up code and move things around