From eae8821b9717b6b06796751f828418e4092a2b44 Mon Sep 17 00:00:00 2001 From: nathangray Date: Thu, 2 Feb 2017 09:22:54 -0700 Subject: [PATCH] Fix some remaining bugs in set/clear project, add some automatic tests --- infolog/inc/class.infolog_bo.inc.php | 17 +- infolog/test/SetProjectManagerTest.php | 415 +++++++++++++++++++++++++ 2 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 infolog/test/SetProjectManagerTest.php diff --git a/infolog/inc/class.infolog_bo.inc.php b/infolog/inc/class.infolog_bo.inc.php index 7a81ef2960..2758703d6f 100644 --- a/infolog/inc/class.infolog_bo.inc.php +++ b/infolog/inc/class.infolog_bo.inc.php @@ -1066,7 +1066,7 @@ class infolog_bo // if project has been removed, but is still info_contact --> also remove it if ($app == 'projectmanager' && $id && $id == $values['old_pm_id'] && !$values['pm_id']) { - unset($values['info_link_id'], $id, $values['info_contact']['id']); + unset($values['info_link_id'], $id, $values['info_contact']); } elseif ($app && $id) { @@ -1085,6 +1085,21 @@ class infolog_bo unset($values['info_link_id']); } } + else if ($values['pm_id'] && $values['info_id'] && !$values['old_pm_id']) + { + // Set for new entry with no contact + $app = 'projectmanager'; + $id = $values['pm_id']; + $values['info_link_id'] = (int)($info_link_id = Link::link( + 'infolog', + $values['info_id'], + $app,$id + )); + } + else + { + unset($values['info_link_id']); + } if ($old_link_id && $old_link_id != $values['info_link_id']) { $link = Link::get_link($old_link_id); diff --git a/infolog/test/SetProjectManagerTest.php b/infolog/test/SetProjectManagerTest.php new file mode 100644 index 0000000000..3c094d16b0 --- /dev/null +++ b/infolog/test/SetProjectManagerTest.php @@ -0,0 +1,415 @@ +ui = new \infolog_ui(); + + + $this->ui->tmpl = $this->getMockBuilder('\\Egroupware\\Api\\Etemplate') + ->disableOriginalConstructor() + ->setMethods(array('exec', 'read')) + ->getMock($this->ui); + + $this->bo = $this->ui->bo; + $this->pm_bo = new \projectmanager_bo(); + + $this->mockTracking($this->bo, 'infolog_tracking'); + + $this->makeProject(); + } + + public function tearDown() + { + // Remove infolog under test + if($this->info_id) + { + $this->bo->delete($this->info_id, False, False, True); + } + + // Remove the test project + $this->deleteProject(); + + $this->bo = null; + $this->pm_bo = null; + } + + /** + * Create a new infolog entry, with project set + * + * This one goes via the ui, mostly to see how it would work + */ + public function testAddProjectToNew() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->atLeastOnce()) + ->method('track') + ->with($this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})); + + // Mock the etemplate call to check the results + $this->ui->tmpl->expects($this->once()) + ->method('exec') + ->with($this->stringContains('infolog.infolog_ui.edit'), + $this->callback(function($info) { + $this->assertNotNull($info['info_id']); + $this->info_id = $info['info_id']; + return $info['pm_id'] == $this->pm_id; + }) + ); + + $info = $this->getTestInfolog(); + + // Set up the test - just set pm_id + $info['pm_id'] = $this->pm_id; + + // Set button 'apply' to save, but not try to close the window since + // that would fail + $info['button'] = array('apply' => true); + + // Make a call to edit, looks like user set pm_id and clicked Apply + $this->ui->edit($info); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Check project + $this->checkElements(); + } + + public function testAddProjectToExisting() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->exactly(2)) + ->method('track') + ->withConsecutive( + // First call - creation + [$this->callback(function($subject) { return is_null($subject['pm_status']);})], + // Second call - after setting project + [$this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})] + ); + + $info = $this->getTestInfolog(); + + $this->info_id = $this->bo->write($info); + $this->assertThat($this->info_id, + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Set project by pm_id + $info['pm_id'] = $this->pm_id; + $this->bo->write($info); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Check pm_id is there + $this->assertNotNull($info['pm_id'], 'Project was not set'); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Check project + $this->checkElements(); + } + + /** + * Create a new infolog entry, set project via info_contact + */ + public function testContact() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->once()) + ->method('track') + ->with($this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})); + + $info = $this->getTestInfolog(); + + // Set up the test - just set info_contact + $info['info_contact'] = 'projectmanager:'.$this->pm_id; + + $this->info_id = $this->bo->write($info); + $this->assertArrayHasKey('info_id', $info, 'Could not make test project'); + $this->assertThat($this->info_id, + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + + // Check infolog has pm_id properly set + $this->assertEquals($this->pm_id, $info['pm_id']); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Check project + $this->checkElements(); + } + + public function testLoadWithProject() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->once()) + ->method('track') + ->with($this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})); + + $info = $this->getTestInfolog(); + + // Set up the test - just set info_contact + $info['info_contact'] = 'projectmanager:'.$this->pm_id; + + $this->info_id = $this->bo->write($info); + $this->assertThat($this->info_id, + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + + // Check infolog has pm_id properly set + $this->assertEquals($this->pm_id, $info['pm_id']); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Check infolog still has pm_id + $this->assertEquals($this->pm_id, $info['pm_id'], 'Project went missing'); + + // Check project + $this->checkElements(); + } + + public function testClearProject() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->exactly(2)) + ->method('track') + ->withConsecutive( + // First call - set the project + [$this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})], + // Second call - clear the project + [$this->callback(function($subject) { return is_null($subject['pm_status']);})] + ); + + $info = $this->getTestInfolog(); + + // Set up the test - just set info_contact + $info['info_contact'] = 'projectmanager:'.$this->pm_id; + + $this->info_id = $this->bo->write($info); + $this->assertThat($this->info_id, + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Clear it + unset($info['pm_id']); + $this->bo->write($info); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Check pm_id is gone + $this->assertNull($info['pm_id'], 'Project was not removed'); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Check project + $this->checkElements(0); + } + + /** + * If the contact is set to a project, and the contact is cleared, that + * will also clear the project + */ + public function testClearContact() + { + // Saving the infolog should try to send a notification + $this->bo->tracking->expects($this->exactly(2)) + ->method('track') + ->withConsecutive( + // First call - set the project + [$this->callback(function($subject) { return $subject['pm_id'] == $this->pm_id;})], + // Second call - clear the project + [$this->callback(function($subject) { return is_null($subject['pm_status']);})] + ); + + $info = $this->getTestInfolog(); + + // Set up the test - just set info_contact + $info['info_contact'] = 'projectmanager:'.$this->pm_id; + + $this->info_id = $this->bo->write($info); + $this->assertThat($this->info_id, + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Clear it + unset($info['info_contact']); + $this->bo->write($info); + + // Now load it again + $info = $this->bo->read($this->info_id); + + // Check contact was cleared + $this->assertNull($info['info_contact'], 'Contact was not cleared'); + + // Check pm_id is gone + $this->assertNull($info['pm_id'], 'Project was not removed'); + + // Force links to run notification now so we get valid testing - it + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Check project + $this->checkElements(0); + } + + protected function getTestInfolog() + { + return array( + 'info_subject' => 'Test Infolog Entry for ' . $this->getName() + ); + } + + /** + * Make a project so we can test deleting it + */ + protected function makeProject() + { + $project = array( + 'pm_number' => 'TEST', + 'pm_title' => 'Auto-test for ' . $this->getName(), + 'pm_status' => 'active', + 'pm_description' => 'Test project for ' . $this->getName() + ); + + // Save & set modifier, no notifications + try + { + $result = true; + $result = $this->pm_bo->save($project, true, false); + } + catch (\Exception $e) + { + // Something went wrong, we'll just fail + $this->fail($e); + } + + $this->assertFalse((boolean)$result, 'Error making test project'); + $this->assertArrayHasKey('pm_id', $this->pm_bo->data, 'Could not make test project'); + $this->assertThat($this->pm_bo->data['pm_id'], + $this->logicalAnd( + $this->isType('integer'), + $this->greaterThan(0) + ) + ); + $this->pm_id = $this->pm_bo->data['pm_id']; + } + + /** + * Check that the project element is present + * + */ + protected function checkElements($expected_count = 1) + { + $element_bo = new \projectmanager_elements_bo(); + $element_count = 0; + + foreach($element_bo->search(array('pm_id' => $this->pm_id), false) as $element) + { + $element_count++; + $this->assertEquals($this->info_id, $element['pe_app_id']); + } + + $this->assertEquals($expected_count, $element_count, "Incorrect number of elements"); + } + + /** + * Fully delete a project and its elements, no matter what state or settings + */ + protected function deleteProject() + { + // Force links to run notification now, or elements might stay + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + + // Force to ignore setting + $this->pm_bo->history = ''; + $this->pm_bo->delete($this->pm_id, true); + + // Force links to run notification now, or elements might stay + // usually waits until Egw::on_shutdown(); + Api\Link::run_notifies(); + } + +} \ No newline at end of file