- <?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());
- }
- }