CRM-19029 Additional tests for merge function
authoreileen <emcnaughton@wikimedia.org>
Wed, 29 Jun 2016 08:19:41 +0000 (20:19 +1200)
committereileen <emcnaughton@wikimedia.org>
Sun, 17 Jul 2016 22:25:01 +0000 (10:25 +1200)
tests/phpunit/CiviTest/CiviUnitTestCase.php
tests/phpunit/api/v3/JobTest.php
tests/phpunit/api/v3/MembershipTest.php

index f0beda43de4164e385612e302f8c6475fe845eb4..fa833485124f48e71da5adc8c90fc141f907d6b1 100644 (file)
@@ -1165,16 +1165,17 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase {
    * @return mixed
    */
   public function contactMembershipCreate($params) {
-    $pre = array(
+    $params = array_merge(array(
       'join_date' => '2007-01-21',
       'start_date' => '2007-01-21',
       'end_date' => '2007-12-21',
       'source' => 'Payment',
-    );
-
-    foreach ($pre as $key => $val) {
-      if (!isset($params[$key])) {
-        $params[$key] = $val;
+      'membership_type_id' => 'General',
+    ), $params);
+    if (!is_numeric($params['membership_type_id'])) {
+      $membershipTypes = $this->callAPISuccess('Membership', 'getoptions', array('action' => 'create', 'field' => 'membership_type_id'));
+      if (!in_array($params['membership_type_id'], $membershipTypes['values'])) {
+        $this->membershipTypeCreate(array('name' => $params['membership_type_id']));
       }
     }
 
@@ -1957,40 +1958,37 @@ class CiviUnitTestCase extends PHPUnit_Extensions_Database_TestCase {
    * @param array $params
    * @return array|int
    */
-  public function activityCreate($params = NULL) {
-
-    if ($params === NULL) {
-      $individualSourceID = $this->individualCreate();
-
-      $contactParams = array(
+  public function activityCreate($params = array()) {
+    $params = array_merge(array(
+      'subject' => 'Discussion on warm beer',
+      'activity_date_time' => date('Ymd'),
+      'duration_hours' => 30,
+      'duration_minutes' => 20,
+      'location' => 'Baker Street',
+      'details' => 'Lets schedule a meeting',
+      'status_id' => 1,
+      'activity_name' => 'Meeting',
+    ), $params);
+    if (!isset($params['source_contact_id'])) {
+      $params['source_contact_id'] = $this->individualCreate();
+    }
+    if (!isset($params['target_contact_id'])) {
+      $params['target_contact_id'] = $this->individualCreate(array(
         'first_name' => 'Julia',
         'Last_name' => 'Anderson',
         'prefix' => 'Ms.',
         'email' => 'julia_anderson@civicrm.org',
         'contact_type' => 'Individual',
-      );
-
-      $individualTargetID = $this->individualCreate($contactParams);
-
-      $params = array(
-        'source_contact_id' => $individualSourceID,
-        'target_contact_id' => array($individualTargetID),
-        'assignee_contact_id' => array($individualTargetID),
-        'subject' => 'Discussion on warm beer',
-        'activity_date_time' => date('Ymd'),
-        'duration_hours' => 30,
-        'duration_minutes' => 20,
-        'location' => 'Baker Street',
-        'details' => 'Lets schedule a meeting',
-        'status_id' => 1,
-        'activity_name' => 'Meeting',
-      );
+      ));
+    }
+    if (!isset($params['assignee_contact_id'])) {
+      $params['assignee_contact_id'] = $params['target_contact_id'];
     }
 
     $result = $this->callAPISuccess('Activity', 'create', $params);
 
-    $result['target_contact_id'] = $individualTargetID;
-    $result['assignee_contact_id'] = $individualTargetID;
+    $result['target_contact_id'] = $params['target_contact_id'];
+    $result['assignee_contact_id'] = $params['assignee_contact_id'];
     return $result;
   }
 
index fe4f3a08712f0699a33ac34aed16d291581b578a..975b44ee2992d19f67903d30564a104898fd6430 100644 (file)
@@ -46,9 +46,18 @@ class api_v3_JobTest extends CiviUnitTestCase {
   public $DBResetRequired = FALSE;
   public $_entity = 'Job';
   public $_params = array();
+  /**
+   * Created membership type.
+   *
+   * Must be created outside the transaction due to it breaking the transaction.
+   *
+   * @var
+   */
+  public $membershipTypeID;
 
   public function setUp() {
     parent::setUp();
+    $this->membershipTypeID = $this->membershipTypeCreate(array('name' => 'General'));
     $this->useTransaction(TRUE);
     $this->_params = array(
       'sequential' => 1,
@@ -62,6 +71,11 @@ class api_v3_JobTest extends CiviUnitTestCase {
     );
   }
 
+  public function tearDown() {
+    parent::tearDown();
+    $this->membershipTypeDelete(array('id' => $this->membershipTypeID));
+  }
+
   /**
    * Check with no name.
    */
@@ -344,15 +358,123 @@ class api_v3_JobTest extends CiviUnitTestCase {
     $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => $dataSet['mode']));
     $this->assertEquals($dataSet['skipped'], count($result['values']['skipped']), 'Failed to skip the right number:' . $dataSet['skipped']);
     $this->assertEquals($dataSet['merged'], count($result['values']['merged']));
-    $result = $this->callAPISuccess('Contact', 'get', array('contact_sub_type' => 'Student', 'sequential' => 1));
+    $result = $this->callAPISuccess('Contact', 'get', array(
+      'contact_sub_type' => 'Student',
+      'sequential' => 1,
+      'options' => array('sort' => 'id ASC'),
+    ));
     $this->assertEquals(count($dataSet['expected']), $result['count']);
     foreach ($dataSet['expected'] as $index => $contact) {
       foreach ($contact as $key => $value) {
+        // Handle the fact it's in a different field in the return value.
+        if ($key == 'gender_id') {
+          $key = 'gender';
+        }
         $this->assertEquals($value, $result['values'][$index][$key]);
       }
     }
   }
 
+  /**
+   * Check that the merge carries across various related entities.
+   *
+   * Note the group combinations & expected results:
+   */
+  public function testBatchMergeWithAssets() {
+    $contactID = $this->individualCreate();
+    $contact2ID = $this->individualCreate();
+    $this->contributionCreate(array('contact_id' => $contactID));
+    $this->contributionCreate(array('contact_id' => $contact2ID, 'invoice_id' => '2', 'trxn_id' => 2));
+    $this->contactMembershipCreate(array('contact_id' => $contactID));
+    $this->contactMembershipCreate(array('contact_id' => $contact2ID));
+    $this->activityCreate(array('source_contact_id' => $contactID, 'target_contact_id' => $contactID, 'assignee_contact_id' => $contactID));
+    $this->activityCreate(array('source_contact_id' => $contact2ID, 'target_contact_id' => $contact2ID, 'assignee_contact_id' => $contact2ID));
+    $this->tagCreate(array('name' => 'Tall'));
+    $this->tagCreate(array('name' => 'Short'));
+    $this->entityTagAdd(array('contact_id' => $contactID, 'tag_id' => 'Tall'));
+    $this->entityTagAdd(array('contact_id' => $contact2ID, 'tag_id' => 'Short'));
+    $this->entityTagAdd(array('contact_id' => $contact2ID, 'tag_id' => 'Tall'));
+    $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => 'safe'));
+    $this->assertEquals(0, count($result['values']['skipped']));
+    $this->assertEquals(1, count($result['values']['merged']));
+    $this->callAPISuccessGetCount('Contribution', array('contact_id' => $contactID), 2);
+    $this->callAPISuccessGetCount('Contribution', array('contact_id' => $contact2ID), 0);
+    $this->callAPISuccessGetCount('FinancialItem', array('contact_id' => $contactID), 2);
+    $this->callAPISuccessGetCount('FinancialItem', array('contact_id' => $contact2ID), 0);
+    $this->callAPISuccessGetCount('Membership', array('contact_id' => $contactID), 2);
+    $this->callAPISuccessGetCount('Membership', array('contact_id' => $contact2ID), 0);
+    $this->callAPISuccessGetCount('EntityTag', array('contact_id' => $contactID), 2);
+    $this->callAPISuccessGetCount('EntityTag', array('contact_id' => $contact2ID), 0);
+    // 12 activities is one for each contribution (2), one for each membership (+2 = 4)
+    // 3 for each of the added activities as there are 3 roles (+6 = 10
+    // 2 for the (source & target) contact merged activity (+2 = 12)
+    $this->callAPISuccessGetCount('ActivityContact', array('contact_id' => $contactID), 12);
+    // 2 for the connection to the deleted by merge activity (source & target)
+    $this->callAPISuccessGetCount('ActivityContact', array('contact_id' => $contact2ID), 2);
+  }
+
+  /**
+   * Check that the merge carries across various related entities.
+   *
+   * Note the group combinations 'expected' results:
+   *
+   * Group 0  Added  null  Added
+   * Group 1  Added  Added  Added
+   * Group 2  Added  Removed  ****  Added
+   * Group 3  Removed  null  **** null
+   * Group 4  Removed  Added  **** Added
+   * Group 5  Removed  Removed **** null
+   * Group 6  null  Added  Added
+   * Group 7  null  Removed  **** null
+   *
+   * The ones with **** are the ones where I think a case could be made to change the behaviour.
+   */
+  public function testBatchMergeMergesGroups() {
+    $contactID = $this->individualCreate();
+    $contact2ID = $this->individualCreate();
+    $groups = array();
+    for ($i = 0; $i < 8; $i++) {
+      $groups[] = $this->groupCreate(array('name' => 'mergeGroup' . $i, 'title' => 'merge group' . $i));
+    }
+
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[0]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[1]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[2]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[3], 'status' => 'Removed'));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[4], 'status' => 'Removed'));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contactID, 'group_id' => $groups[5], 'status' => 'Removed'));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[1]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[2], 'status' => 'Removed'));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[4]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[5], 'status' => 'Removed'));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[6]));
+    $this->callAPISuccess('GroupContact', 'create', array('contact_id' => $contact2ID, 'group_id' => $groups[7], 'status' => 'Removed'));
+    $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => 'safe'));
+    $this->assertEquals(0, count($result['values']['skipped']));
+    $this->assertEquals(1, count($result['values']['merged']));
+    $groupResult = $this->callAPISuccess('GroupContact', 'get', array());
+    $this->assertEquals(5, $groupResult['count']);
+    $expectedGroups = array($groups[0], $groups[1], $groups[2], $groups[4], $groups[6]);
+    foreach ($groupResult['values'] as $groupValues) {
+      $this->assertEquals($contactID, $groupValues['contact_id']);
+      $this->assertEquals('Added', $groupValues['status']);
+      $this->assertTrue(in_array($groupValues['group_id'], $expectedGroups));
+    }
+  }
+
+  /**
+   * Test the organization will not be matched to an individual.
+   */
+  public function testBatchMergeWillNotMergeOrganizationToIndividual() {
+    $individual = $this->callAPISuccess('Contact', 'create', array('contact_type' => 'Individual', 'organization_name' => 'Anon', 'email' => 'anonymous@hacker.com'));
+    $organization = $this->callAPISuccess('Contact', 'create', array('contact_type' => 'Organization', 'organization_name' => 'Anon', 'email' => 'anonymous@hacker.com'));
+    $result = $this->callAPISuccess('Job', 'process_batch_merge', array('mode' => 'aggressive'));
+    $this->assertEquals(0, count($result['values']['skipped']));
+    $this->assertEquals(0, count($result['values']['merged']));
+    $this->callAPISuccessGetSingle('Contact', array('id' => $individual['id']));
+    $this->callAPISuccessGetSingle('Contact', array('id' => $organization['id']));
+  }
+
   /**
    * Test the batch merge does not create duplicate emails.
    *
@@ -755,6 +877,42 @@ class api_v3_JobTest extends CiviUnitTestCase {
         ),
       ),
     );
+
+    $conflictPairs = array(
+      'first_name' => 'Dianna',
+      'last_name' => 'McAndrew',
+      'middle_name' => 'Prancer',
+      'birth_date' => '2015-12-25',
+      'gender_id' => 'Female',
+      'job_title' => 'Thriller',
+    );
+
+    foreach ($conflictPairs as $key => $value) {
+      $contactParams = array(
+        'first_name' => 'Michael',
+        'middle_name' => 'Dancer',
+        'last_name' => 'Jackson',
+        'birth_date' => '2015-02-25',
+        'email' => 'michael@neverland.com',
+        'contact_type' => 'Individual',
+        'contact_sub_type' => array('Student'),
+        'gender_id' => 'Male',
+        'job_title' => 'Entertainer',
+      );
+      $contact2 = $contactParams;
+
+      $contact2[$key] = $value;
+      $data[$key . '_conflict'] = array(
+        array(
+          'mode' => 'safe',
+          'contacts' => array($contactParams, $contact2),
+          'skipped' => 1,
+          'merged' => 0,
+          'expected' => array($contactParams, $contact2),
+        ),
+      );
+    }
+
     return $data;
   }
 
index dbc4a5458cda22cc9c714af7ecea7ecd1c4730ae..9132aa3563fabbb4e569ce51f99e90646f01466d 100644 (file)
@@ -62,6 +62,7 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
       'fixed_period_start_day' => '301',
       // Ie. 11 Nov.
       'fixed_period_rollover_day' => '1111',
+      'name' => 'Another one',
     ));
     $this->_membershipStatusID = $this->membershipStatusCreate('test status');
 
@@ -531,7 +532,7 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
       'id' => $OrganizationMembershipID,
       'max_related' => 3,
     );
-    $this->contactMembershipCreate($params);
+    $this->callAPISuccess('Membership', 'create', $params);
 
     // Check that the employee inherited the membership
     $params = array(
@@ -1398,7 +1399,7 @@ class api_v3_MembershipTest extends CiviUnitTestCase {
    */
   public function testGetOptionsMembershipTypeID() {
     $options = $this->callAPISuccess('Membership', 'getoptions', array('field' => 'membership_type_id'));
-    $this->assertEquals('General', array_pop($options['values']));
+    $this->assertEquals('Another one', array_pop($options['values']));
     $this->assertEquals('General', array_pop($options['values']));
     $this->assertEquals(NULL, array_pop($options['values']));
   }