From 2c6b4783baa2b22e4bb633007ba0828d455aa0be Mon Sep 17 00:00:00 2001 From: eileen Date: Thu, 4 Aug 2016 20:27:17 +1200 Subject: [PATCH] CRM-19170 preliminary tidy up on top donor report for testability --- CRM/Report/Form/Contribute/TopDonor.php | 4 +- tests/phpunit/api/v3/ReportTemplateTest.php | 267 +++++++++++++++++++- 2 files changed, 266 insertions(+), 5 deletions(-) diff --git a/CRM/Report/Form/Contribute/TopDonor.php b/CRM/Report/Form/Contribute/TopDonor.php index 2481484ea6..72d074efd0 100644 --- a/CRM/Report/Form/Contribute/TopDonor.php +++ b/CRM/Report/Form/Contribute/TopDonor.php @@ -277,7 +277,7 @@ class CRM_Report_Form_Contribute_TopDonor extends CRM_Report_Form { } $this->_selectClauses = $select; - $this->_select = " SELECT * FROM ( SELECT " . implode(', ', $select) . " "; + $this->_select = " SELECT " . implode(', ', $select) . " "; } /** @@ -391,7 +391,7 @@ class CRM_Report_Form_Contribute_TopDonor extends CRM_Report_Form { $setVariable = " SET @rows:=0, @rank=0 "; CRM_Core_DAO::singleValueQuery($setVariable); - $sql = " {$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} + $sql = "SELECT * FROM ( {$this->_select} {$this->_from} {$this->_where} {$this->_groupBy} ORDER BY civicrm_contribution_total_amount_sum DESC ) as abc {$this->_outerCluase} $this->_limit "; diff --git a/tests/phpunit/api/v3/ReportTemplateTest.php b/tests/phpunit/api/v3/ReportTemplateTest.php index ed3e3af0a9..2e26a2710d 100644 --- a/tests/phpunit/api/v3/ReportTemplateTest.php +++ b/tests/phpunit/api/v3/ReportTemplateTest.php @@ -35,9 +35,15 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase { protected $_apiversion = 3; - public function setUp() { - parent::setUp(); - $this->useTransaction(TRUE); + /** + * Our group reports use an alter so transaction cleanup won't work. + * + * @throws \Exception + */ + public function tearDown() { + $this->quickCleanUpFinancialEntities(); + $this->quickCleanup(array('civicrm_group', 'civicrm_saved_search', 'civicrm_group_contact')); + parent::tearDown(); } public function testReportTemplate() { @@ -203,6 +209,15 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase { return $reportTemplates; } + /** + * Get contribution templates that work with basic filter tests. + * + * These templates require minimal data config. + */ + public static function getContributionReportTemplates() { + return array(array('contribute/summary'), array('contribute/detail'), array('contribute/repeat'), array('contribute/topDonor')); + } + /** * Test Lybunt report to check basic inclusion of a contact who gave in the year before the chosen year. */ @@ -271,4 +286,250 @@ class api_v3_ReportTemplateTest extends CiviUnitTestCase { $this->assertEquals(2, $rows['count'], "Report failed - the sql used to generate the results was " . print_r($rows['metadata']['sql'], TRUE)); } + /** + * Test the group filter works on the contribution summary (with a smart group). + */ + public function testContributionSummaryWithSmartGroupFilter() { + $groupID = $this->setUpPopulatedSmartGroup(); + $rows = $this->callAPISuccess('report_template', 'getrows', array( + 'report_id' => 'contribute/summary', + 'gid_value' => $groupID, + 'gid_op' => 'in', + 'options' => array('metadata' => array('sql')), + )); + $this->assertEquals(3, $rows['values'][0]['civicrm_contribution_total_amount_count']); + + } + + /** + * Test the group filter works on the contribution summary (with a smart group). + */ + public function testContributionSummaryWithNotINSmartGroupFilter() { + $groupID = $this->setUpPopulatedSmartGroup(); + $rows = $this->callAPISuccess('report_template', 'getrows', array( + 'report_id' => 'contribute/summary', + 'gid_value' => $groupID, + 'gid_op' => 'not in', + 'options' => array('metadata' => array('sql')), + )); + $this->assertEquals(2, $rows['values'][0]['civicrm_contribution_total_amount_count']); + + } + + /** + * Test the group filter works on the contribution summary (with a smart group). + * + * @dataProvider getContributionReportTemplates + * + * @param string $template + * Report template unique identifier. + */ + public function testContributionSummaryWithNonSmartGroupFilter($template) { + $groupID = $this->setUpPopulatedGroup(); + $rows = $this->callAPISuccess('report_template', 'getrows', array( + 'report_id' => $template, + 'gid_value' => array($groupID), + 'gid_op' => 'in', + 'options' => array('metadata' => array('sql')), + )); + $this->assertNumberOfContactsInResult(1, $rows, $template); + } + + /** + * Assert the included results match the expected. + * + * There may or may not be a group by in play so the assertion varies a little. + * + * @param int $numberExpected + * @param array $rows + * Rows returned from the report. + * @param string $template + */ + protected function assertNumberOfContactsInResult($numberExpected, $rows, $template) { + if (isset($rows['values'][0]['civicrm_contribution_total_amount_count'])) { + $this->assertEquals($numberExpected, $rows['values'][0]['civicrm_contribution_total_amount_count'], 'wrong row count in ' . $template); + } + else { + $this->assertEquals($numberExpected, count($rows['values']), 'wrong row count in ' . $template); + } + } + + /** + * Test the group filter works on the contribution summary when 2 groups are involved. + */ + public function testContributionSummaryWithTwoGroups() { + $groupID = $this->setUpPopulatedGroup(); + $groupID2 = $this->setUpPopulatedSmartGroup(); + $rows = $this->callAPISuccess('report_template', 'getrows', array( + 'report_id' => 'contribute/summary', + 'gid_value' => array($groupID, $groupID2), + 'gid_op' => 'in', + 'options' => array('metadata' => array('sql')), + )); + $this->assertEquals(4, $rows['values'][0]['civicrm_contribution_total_amount_count']); + } + + /** + * Test the group filter works on the contribution summary when 2 groups are involved. + */ + public function testContributionSummaryWithTwoGroupsWithIntersection() { + $groups = $this->setUpIntersectingGroups(); + + $rows = $this->callAPISuccess('report_template', 'getrows', array( + 'report_id' => 'contribute/summary', + 'gid_value' => $groups, + 'gid_op' => 'in', + 'options' => array('metadata' => array('sql')), + )); + $this->assertEquals(7, $rows['values'][0]['civicrm_contribution_total_amount_count']); + } + + /** + * Set up a smart group for testing. + * + * The smart group includes all Households by filter. In addition an individual + * is created and hard-added and an individual is created that is not added. + * + * One household is hard-added as well as being in the filter. + * + * This gives us a range of scenarios for testing contacts are included only once + * whenever they are hard-added or in the criteria. + * + * @return int + */ + public function setUpPopulatedSmartGroup() { + $household1ID = $this->householdCreate(); + $individual1ID = $this->individualCreate(); + $householdID = $this->householdCreate(); + $individualID = $this->individualCreate(); + $individualIDRemoved = $this->individualCreate(); + $groupID = $this->smartGroupCreate(array(), array('name' => uniqid(), 'title' => uniqid())); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $individualIDRemoved, + 'status' => 'Removed', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $individualID, + 'status' => 'Added', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $householdID, + 'status' => 'Added', + )); + foreach (array($household1ID, $individual1ID, $householdID, $individualID, $individualIDRemoved) as $contactID) { + $this->contributionCreate(array('contact_id' => $contactID, 'invoice_id' => '', 'trxn_id' => '')); + } + + // Refresh the cache for test purposes. It would be better to alter to alter the GroupContact add function to add contacts to the cache. + CRM_Contact_BAO_GroupContactCache::remove($groupID, FALSE); + return $groupID; + } + + /** + * Set up a smart group for testing. + * + * The smart group includes all Households by filter. In addition an individual + * is created and hard-added and an individual is created that is not added. + * + * One household is hard-added as well as being in the filter. + * + * This gives us a range of scenarios for testing contacts are included only once + * whenever they are hard-added or in the criteria. + * + * @return int + */ + public function setUpPopulatedGroup() { + $individual1ID = $this->individualCreate(); + $individualID = $this->individualCreate(); + $individualIDRemoved = $this->individualCreate(); + $groupID = $this->groupCreate(array('name' => uniqid(), 'title' => uniqid())); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $individualIDRemoved, + 'status' => 'Removed', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $individualID, + 'status' => 'Added', + )); + + foreach (array($individual1ID, $individualID, $individualIDRemoved) as $contactID) { + $this->contributionCreate(array('contact_id' => $contactID, 'invoice_id' => '', 'trxn_id' => '')); + } + + // Refresh the cache for test purposes. It would be better to alter to alter the GroupContact add function to add contacts to the cache. + CRM_Contact_BAO_GroupContactCache::remove($groupID, FALSE); + return $groupID; + } + + /** + * @return array + */ + public function setUpIntersectingGroups() { + $groupID = $this->setUpPopulatedGroup(); + $groupID2 = $this->setUpPopulatedSmartGroup(); + $addedToBothIndividualID = $this->individualCreate(); + $removedFromBothIndividualID = $this->individualCreate(); + $addedToSmartGroupRemovedFromOtherIndividualID = $this->individualCreate(); + $removedFromSmartGroupAddedToOtherIndividualID = $this->individualCreate(); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $addedToBothIndividualID, + 'status' => 'Added', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID2, + 'contact_id' => $addedToBothIndividualID, + 'status' => 'Added', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $removedFromBothIndividualID, + 'status' => 'Removed', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID2, + 'contact_id' => $removedFromBothIndividualID, + 'status' => 'Removed', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID2, + 'contact_id' => $addedToSmartGroupRemovedFromOtherIndividualID, + 'status' => 'Added', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $addedToSmartGroupRemovedFromOtherIndividualID, + 'status' => 'Removed', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID, + 'contact_id' => $removedFromSmartGroupAddedToOtherIndividualID, + 'status' => 'Added', + )); + $this->callAPISuccess('GroupContact', 'create', array( + 'group_id' => $groupID2, + 'contact_id' => $removedFromSmartGroupAddedToOtherIndividualID, + 'status' => 'Removed', + )); + + foreach (array( + $addedToBothIndividualID, + $removedFromBothIndividualID, + $addedToSmartGroupRemovedFromOtherIndividualID, + $removedFromSmartGroupAddedToOtherIndividualID, + ) as $contactID) { + $this->contributionCreate(array( + 'contact_id' => $contactID, + 'invoice_id' => '', + 'trxn_id' => '', + )); + } + return array($groupID, $groupID2); + } + } -- 2.25.1