From: Coleman Watts Date: Wed, 11 May 2022 11:19:29 +0000 (-0400) Subject: APIv4 - Simplify entity creation in test suite X-Git-Url: https://vcs.fsf.org/?a=commitdiff_plain;h=3df12dac61df30491701020f542909a5f63165da;p=civicrm-core.git APIv4 - Simplify entity creation in test suite Removes the old v3 creation and hardcoded sample data in favor of new `createTestRecord` and `saveTestRecords` methods which automatically handle cleanup during tearDown. --- diff --git a/CRM/Core/BAO/CustomGroup.php b/CRM/Core/BAO/CustomGroup.php index d53aac1c70..3b6e9269cf 100644 --- a/CRM/Core/BAO/CustomGroup.php +++ b/CRM/Core/BAO/CustomGroup.php @@ -40,6 +40,8 @@ class CRM_Core_BAO_CustomGroup extends CRM_Core_DAO_CustomGroup implements \Civi * @throws \Exception */ public static function create(&$params) { + // This is the database default + $params += ['extends' => 'Contact']; // create custom group dao, populate fields and then save. $group = new CRM_Core_DAO_CustomGroup(); if (isset($params['title'])) { diff --git a/Civi/Api4/Service/Spec/Provider/CustomGroupSpecProvider.php b/Civi/Api4/Service/Spec/Provider/CustomGroupSpecProvider.php index 86498fc6fe..a49febd215 100644 --- a/Civi/Api4/Service/Spec/Provider/CustomGroupSpecProvider.php +++ b/Civi/Api4/Service/Spec/Provider/CustomGroupSpecProvider.php @@ -23,7 +23,6 @@ class CustomGroupSpecProvider implements Generic\SpecProviderInterface { $action = $spec->getAction(); $spec->getFieldByName('extends') - ->setRequired($action === 'create') ->setSuffixes(['name', 'label', 'grouping']); } diff --git a/Civi/Api4/Service/Spec/Provider/MembershipTypeCreationSpecProvider.php b/Civi/Api4/Service/Spec/Provider/MembershipTypeCreationSpecProvider.php new file mode 100644 index 0000000000..617d707206 --- /dev/null +++ b/Civi/Api4/Service/Spec/Provider/MembershipTypeCreationSpecProvider.php @@ -0,0 +1,38 @@ +getFieldByName('duration_interval')->setDefaultValue(1); + } + + /** + * When does this apply. + * + * @param string $entity + * @param string $action + * + * @return bool + */ + public function applies($entity, $action): bool { + return $entity === 'MembershipType' && $action === 'create'; + } + +} diff --git a/tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php b/tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php index 71efdb46f8..afaa596115 100644 --- a/tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php +++ b/tests/phpunit/CRM/Core/BAO/ActionScheduleTest.php @@ -889,7 +889,7 @@ class CRM_Core_BAO_ActionScheduleTest extends CiviUnitTestCase { 'period_type' => 'rolling', 'member_of_contact_id' => 1, 'financial_type_id:name' => 'Member Dues', - 'duration_unit' => 1, + 'duration_unit' => 'month', ] )->execute()->first()['id']; } diff --git a/tests/phpunit/api/v4/Action/ComplexQueryTest.php b/tests/phpunit/api/v4/Action/ComplexQueryTest.php deleted file mode 100644 index 955377382f..0000000000 --- a/tests/phpunit/api/v4/Action/ComplexQueryTest.php +++ /dev/null @@ -1,129 +0,0 @@ -loadDataSet('DefaultDataSet'); - return parent::setUpHeadless(); - } - - public function tearDown(): void { - $relatedTables = [ - 'civicrm_activity', - 'civicrm_activity_contact', - ]; - $this->cleanup(['tablesToTruncate' => $relatedTables]); - parent::tearDown(); - } - - /** - * Fetch all phone call activities - * Expects at least one activity loaded from the data set. - * - * @throws \API_Exception - */ - public function testGetAllHousingSupportActivities(): void { - $results = Activity::get(FALSE) - ->addWhere('activity_type_id:name', '=', 'Phone Call') - ->execute(); - - $this->assertGreaterThan(0, count($results)); - } - - /** - * - */ - public function testGetWithCount() { - $myName = uniqid('count'); - for ($i = 1; $i <= 20; ++$i) { - Contact::create() - ->addValue('first_name', "Contact $i") - ->addValue('last_name', $myName) - ->setCheckPermissions(FALSE)->execute(); - } - - $get1 = Contact::get() - ->addWhere('last_name', '=', $myName) - ->selectRowCount() - ->addSelect('first_name') - ->setLimit(10) - ->setDebug(TRUE) - ->setCheckPermissions(FALSE)->execute(); - - $this->assertEquals(20, $get1->count()); - $this->assertCount(10, (array) $get1); - - } - - /** - * Fetch contacts named 'Bob' and all of their blue activities - */ - public function testGetAllBlueActivitiesForBobs() { - - } - - /** - * Get all contacts in a zipcode and return their Home or Work email addresses - */ - public function testGetHomeOrWorkEmailsForContactsWithZipcode() { - - } - - /** - * Fetch all activities where Bob is the assignee or source - */ - public function testGetActivitiesWithBobAsAssigneeOrSource() { - - } - - /** - * Get all contacts which - * (a) have address in zipcode 94117 or 94118 or in city "San Francisco","LA" - * and - * (b) are not deceased and - * (c) have a custom-field "most_important_issue=Environment". - */ - public function testAWholeLotOfConditions() { - - } - - /** - * Get participants who attended CiviCon 2012 but not CiviCon 2013. - * Return their name and email. - */ - public function testGettingNameAndEmailOfAttendeesOfCiviCon2012Only() { - - } - -} diff --git a/tests/phpunit/api/v4/Action/ContactGetTest.php b/tests/phpunit/api/v4/Action/ContactGetTest.php index e02827bf50..6e4a722985 100644 --- a/tests/phpunit/api/v4/Action/ContactGetTest.php +++ b/tests/phpunit/api/v4/Action/ContactGetTest.php @@ -330,9 +330,7 @@ class ContactGetTest extends Api4TestBase implements TransactionalInterface { ['first_name' => 'abc', 'last_name' => $lastName, 'birth_date' => 'now - 1 year - 1 month'], ['first_name' => 'def', 'last_name' => $lastName, 'birth_date' => 'now - 21 year - 6 month'], ]; - Contact::save(FALSE) - ->setRecords($sampleData) - ->execute(); + $this->saveTestRecords('Contact', ['records' => $sampleData]); $result = Contact::get(FALSE) ->addWhere('last_name', '=', $lastName) @@ -347,4 +345,28 @@ class ContactGetTest extends Api4TestBase implements TransactionalInterface { ->execute()->single(); } + /** + * + */ + public function testGetWithCount() { + $myName = uniqid('count'); + for ($i = 1; $i <= 20; ++$i) { + $this->createTestRecord('Contact', [ + 'first_name' => "Contact $i", + 'last_name' => $myName, + ]); + } + + $get1 = Contact::get(FALSE) + ->addWhere('last_name', '=', $myName) + ->selectRowCount() + ->addSelect('first_name') + ->setLimit(10) + ->execute(); + + $this->assertEquals(20, $get1->count()); + $this->assertCount(10, (array) $get1); + + } + } diff --git a/tests/phpunit/api/v4/Action/FkJoinTest.php b/tests/phpunit/api/v4/Action/FkJoinTest.php index bde62072da..74a79473c5 100644 --- a/tests/phpunit/api/v4/Action/FkJoinTest.php +++ b/tests/phpunit/api/v4/Action/FkJoinTest.php @@ -21,11 +21,9 @@ namespace api\v4\Action; use api\v4\Api4TestBase; use Civi\Api4\Activity; -use Civi\Api4\CiviCase; use Civi\Api4\Contact; use Civi\Api4\Email; use Civi\Api4\EntityTag; -use Civi\Api4\Phone; use Civi\Api4\Relationship; use Civi\Api4\Tag; use Civi\Test\TransactionalInterface; @@ -35,12 +33,6 @@ use Civi\Test\TransactionalInterface; */ class FkJoinTest extends Api4TestBase implements TransactionalInterface { - public function setUpHeadless() { - $this->loadDataSet('DefaultDataSet'); - - return parent::setUpHeadless(); - } - public function tearDown(): void { $relatedTables = [ 'civicrm_activity', @@ -60,6 +52,10 @@ class FkJoinTest extends Api4TestBase implements TransactionalInterface { * loaded from the data set. */ public function testThreeLevelJoin() { + $this->createTestRecord('Activity', [ + 'activity_type_id:name' => 'Phone Call', + ]); + $results = Activity::get(FALSE) ->addWhere('activity_type_id:name', '=', 'Phone Call') ->execute(); @@ -68,50 +64,80 @@ class FkJoinTest extends Api4TestBase implements TransactionalInterface { } public function testOptionalJoin() { - // DefaultDataSet includes 2 phones for contact 1, 0 for contact 2. + $contact1 = $this->createTestRecord('Contact'); + $contact2 = $this->createTestRecord('Contact'); + + $this->createTestRecord('Phone', [ + 'location_type_id:name' => 'Home', + 'contact_id' => $contact1['id'], + ]); + $this->createTestRecord('Phone', [ + 'location_type_id:name' => 'Work', + 'contact_id' => $contact1['id'], + ]); + // We'll add one for contact 2 as a red herring to make sure we only get back the correct ones. - Phone::create(FALSE) - ->setValues(['contact_id' => $this->getReference('test_contact_2')['id'], 'phone' => '123456']) - ->execute(); + $this->createTestRecord('Phone', [ + 'contact_id' => $contact2['id'], + ]); $contacts = Contact::get(FALSE) ->addJoin('Phone', FALSE) ->addSelect('id', 'phone.phone') - ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id']]) + ->addWhere('id', 'IN', [$contact1['id']]) ->addOrderBy('phone.id') ->execute(); $this->assertCount(2, $contacts); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[1]['id']); + $this->assertEquals($contact1['id'], $contacts[0]['id']); + $this->assertEquals($contact1['id'], $contacts[1]['id']); } public function testRequiredJoin() { + $contact1 = $this->createTestRecord('Contact'); + $contact2 = $this->createTestRecord('Contact'); + + $this->createTestRecord('Phone', [ + 'location_type_id:name' => 'Home', + 'contact_id' => $contact1['id'], + 'phone' => '+35355439483', + ]); + $this->createTestRecord('Phone', [ + 'location_type_id:name' => 'Work', + 'contact_id' => $contact1['id'], + ]); + // Joining with no condition $contacts = Contact::get(FALSE) ->addSelect('id', 'phone.phone') ->addJoin('Phone', TRUE) - ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']]) + ->addWhere('id', 'IN', [$contact1['id'], $contact2['id']]) ->addOrderBy('phone.id') ->execute(); $this->assertCount(2, $contacts); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[1]['id']); + $this->assertEquals($contact1['id'], $contacts[0]['id']); + $this->assertEquals($contact1['id'], $contacts[1]['id']); // Add is_primary condition, should result in only one record $contacts = Contact::get(FALSE) ->addSelect('id', 'phone.phone', 'phone.location_type_id') ->addJoin('Phone', TRUE, ['phone.is_primary', '=', TRUE]) - ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']]) + ->addWhere('id', 'IN', [$contact1['id'], $contact2['id']]) ->addOrderBy('phone.id') ->execute(); $this->assertCount(1, $contacts); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']); + $this->assertEquals($contact1['id'], $contacts[0]['id']); $this->assertEquals('+35355439483', $contacts[0]['phone.phone']); $this->assertEquals('1', $contacts[0]['phone.location_type_id']); } public function testImplicitJoinOnExplicitJoin() { + $contact1 = $this->createTestRecord('Contact'); + $this->createTestRecord('Address', [ + 'contact_id' => $contact1['id'], + 'country_id' => 1228, + ]); + $contacts = Contact::get(FALSE) - ->addWhere('id', '=', $this->getReference('test_contact_1')['id']) + ->addWhere('id', '=', $contact1['id']) ->addJoin('Address AS address', TRUE, ['id', '=', 'address.contact_id'], ['address.location_type_id', '=', 1]) ->addSelect('id', 'address.country_id.iso_code') ->execute(); @@ -120,11 +146,16 @@ class FkJoinTest extends Api4TestBase implements TransactionalInterface { } public function testExcludeJoin() { + $contact1 = $this->createTestRecord('Contact'); + $this->createTestRecord('Address', [ + 'contact_id' => $contact1['id'], + 'country_id' => 1228, + ]); $contacts = Contact::get(FALSE) ->addJoin('Address AS address', 'EXCLUDE', ['id', '=', 'address.contact_id'], ['address.location_type_id', '=', 1]) ->addSelect('id') ->execute()->column('id'); - $this->assertNotContains($this->getReference('test_contact_1')['id'], $contacts); + $this->assertNotContains($contact1['id'], $contacts); } public function testInvalidJoinAlias() { @@ -433,36 +464,39 @@ class FkJoinTest extends Api4TestBase implements TransactionalInterface { } public function testJoinWithExpression() { - Phone::create(FALSE) - ->setValues(['contact_id' => $this->getReference('test_contact_1')['id'], 'phone' => '654321']) - ->execute(); + + $contact1 = $this->createTestRecord('Contact'); + $contact2 = $this->createTestRecord('Contact'); + $this->createTestRecord('Phone', [ + 'contact_id' => $contact1['id'], + 'phone' => '654321', + ]); + $contacts = Contact::get(FALSE) ->addSelect('id', 'phone.phone') ->addJoin('Phone', 'INNER', ['LOWER(phone.phone)', '=', "CONCAT('6', '5', '4', '3', '2', '1')"]) - ->addWhere('id', 'IN', [$this->getReference('test_contact_1')['id'], $this->getReference('test_contact_2')['id']]) + ->addWhere('id', 'IN', [$contact1['id'], $contact2['id']]) ->addOrderBy('phone.id') ->execute(); $this->assertCount(1, $contacts); - $this->assertEquals($this->getReference('test_contact_1')['id'], $contacts[0]['id']); + $this->assertEquals($contact1['id'], $contacts[0]['id']); $this->assertEquals('654321', $contacts[0]['phone.phone']); } public function testJoinCaseRoles() { \CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase'); - $this->loadDataSet('CaseType'); - $contactID = $this->createEntity(['type' => 'Individual'])['id']; - $managerID = $this->createEntity(['type' => 'Individual'])['id']; + $contactID = $this->createTestRecord('Contact')['id']; + $managerID = $this->createTestRecord('Contact')['id']; - $case = CiviCase::create(FALSE) - ->addValue('case_type_id', $this->getReference('test_case_type_1')['id']) - ->addValue('status_id', 1) - ->addValue('creator_id', $managerID) - ->addValue('contact_id', $contactID) - ->execute() - ->first(); + $caseType = $this->createTestRecord('CaseType'); + $case = $this->createTestRecord('Case', [ + 'creator_id' => $managerID, + 'contact_id' => $contactID, + 'case_type_id' => $caseType['id'], + ]); - $contacts = \Civi\Api4\Contact::get() + $contacts = Contact::get(FALSE) ->addSelect('*', 'case.*') ->addJoin('Case AS case', 'INNER', 'RelationshipCache', ['id', '=', 'case.far_contact_id'], ['case.far_relation', '=', '"Parent of"']) ->addWhere('case.id', '=', $case['id']) diff --git a/tests/phpunit/api/v4/Action/IsPrimaryTest.php b/tests/phpunit/api/v4/Action/IsPrimaryTest.php index a2dae2075d..66551102a0 100644 --- a/tests/phpunit/api/v4/Action/IsPrimaryTest.php +++ b/tests/phpunit/api/v4/Action/IsPrimaryTest.php @@ -36,7 +36,7 @@ class IsPrimaryTest extends Api4TestBase implements TransactionalInterface { * Test that creating a location entity or deleting one re-assigns is_primary correctly. */ public function testPrimaryHandling() { - $contactID = self::createEntity(['type' => 'Individual'])['id']; + $contactID = $this->createTestRecord('Contact')['id']; // Create an entity of each type. Email::create()->setValues(['email' => 'b@example.com', 'contact_id' => $contactID])->execute(); Phone::create()->setValues(['phone' => '123', 'contact_id' => $contactID])->execute(); diff --git a/tests/phpunit/api/v4/Api4TestBase.php b/tests/phpunit/api/v4/Api4TestBase.php index 7078895133..07a1e6f22e 100644 --- a/tests/phpunit/api/v4/Api4TestBase.php +++ b/tests/phpunit/api/v4/Api4TestBase.php @@ -19,8 +19,8 @@ namespace api\v4; -use api\v4\Traits\TestDataLoaderTrait; use Civi\Api4\UFMatch; +use Civi\Api4\Utils\CoreUtil; use Civi\Test\HeadlessInterface; require_once 'api/Exception.php'; @@ -30,7 +30,12 @@ require_once 'api/Exception.php'; */ class Api4TestBase extends \PHPUnit\Framework\TestCase implements HeadlessInterface { - use TestDataLoaderTrait; + /** + * Records created which will be deleted during tearDown + * + * @var array + */ + public $testRecords = []; /** * @see CiviUnitTestCase @@ -48,6 +53,15 @@ class Api4TestBase extends \PHPUnit\Framework\TestCase implements HeadlessInterf return \Civi\Test::headless()->apply(); } + /** + */ + public function tearDown(): void { + // Delete all test records in reverse order to prevent fk constraints + foreach (array_reverse($this->testRecords) as $record) { + civicrm_api4($record[0], 'delete', ['checkPermissions' => FALSE, 'where' => $record[1]]); + } + } + /** * Quick clean by emptying tables created for the test. * @@ -66,17 +80,6 @@ class Api4TestBase extends \PHPUnit\Framework\TestCase implements HeadlessInterf \CRM_Core_DAO::executeQuery("SET FOREIGN_KEY_CHECKS = 1;"); } - /** - * Quick record counter - * - * @param string $table_name - * @returns int record count - */ - public function getRowCount($table_name) { - $sql = "SELECT count(id) FROM $table_name"; - return (int) \CRM_Core_DAO::singleValueQuery($sql); - } - /** * Emulate a logged in user since certain functions use that. * value to store a record in the DB (like activity) @@ -86,13 +89,13 @@ class Api4TestBase extends \PHPUnit\Framework\TestCase implements HeadlessInterf * Contact ID of the created user. */ public function createLoggedInUser() { - $contactID = $this->createEntity(['type' => 'Individual'])['id']; + $contactID = $this->createTestRecord('Contact')['id']; UFMatch::delete(FALSE)->addWhere('uf_id', '=', 6)->execute(); - UFMatch::create(FALSE)->setValues([ + $this->createTestRecord('UFMatch', [ 'contact_id' => $contactID, 'uf_name' => 'superman', 'uf_id' => 6, - ])->execute(); + ]); $session = \CRM_Core_Session::singleton(); $session->set('userID', $contactID); @@ -100,177 +103,260 @@ class Api4TestBase extends \PHPUnit\Framework\TestCase implements HeadlessInterf } /** - * Create sample entities (using V3 for now). + * Inserts a test record, supplying all required values if not provided. * - * @param array $params - * (type, seq, overrides, count) - * @return array - * (either single, or array of array if count >1) - * @throws \CiviCRM_API3_Exception - * @throws \Exception + * Test records will be automatically deleted during tearDown. + * + * @param string $entityName + * @param array $values + * @return array|null + * @throws \API_Exception + * @throws \Civi\API\Exception\NotImplementedException */ - public static function createEntity($params) { - $params += [ - 'count' => 1, - 'seq' => 0, + public function createTestRecord(string $entityName, array $values = []) { + return $this->saveTestRecords($entityName, ['records' => [$values]])->first(); + } + + /** + * Saves one or more test records, supplying default values. + * + * Test records will be automatically deleted during tearDown. + * + * @param string $entityName + * @param array $saveParams + * @return \Civi\Api4\Generic\Result + * @throws \API_Exception + * @throws \Civi\API\Exception\NotImplementedException + */ + public function saveTestRecords(string $entityName, array $saveParams) { + $saveParams += [ + 'checkPermissions' => FALSE, + 'defaults' => [], ]; - $entities = []; - $entity = NULL; - for ($i = 0; $i < $params['count']; $i++) { - $params['seq']++; - $data = self::sample($params); - $api_params = ['sequential' => 1] + $data['sample_params']; - $result = civicrm_api3($data['entity'], 'create', $api_params); - if ($result['is_error']) { - throw new \Exception("creating $data[entity] failed"); - } - $entity = $result['values'][0]; - if (!($entity['id'] > 0)) { - throw new \Exception("created entity is malformed"); + $idField = CoreUtil::getIdFieldName($entityName); + foreach ($saveParams['records'] as &$record) { + $record += $saveParams['defaults']; + if (empty($record[$idField])) { + $this->getRequiredValuesToCreate($entityName, $record); } - $entities[] = $entity; } - return $params['count'] == 1 ? $entity : $entities; + $saved = civicrm_api4($entityName, 'save', $saveParams); + foreach ($saved as $item) { + $this->testRecords[] = [$entityName, [[$idField, '=', $item[$idField]]]]; + } + return $saved; } /** - * Helper function for creating sample entities. - * - * Depending on the supplied sequence integer, plucks values from the dummy data. - * Constructs a foreign entity when an ID is required but isn't supplied in the overrides. + * Get the required fields for the api entity + action. * - * Inspired by CiviUnitTestCase:: - * @todo - extract this function to own class and share with CiviUnitTestCase? - * @param array $params - * - type: string roughly matching entity type - * - seq: (optional) int sequence number for the values of this type - * - overrides: (optional) array of fill in parameters + * @param string $entity + * @param array $values * * @return array - * - entity: string API entity type (usually the type supplied except for contact subtypes) - * - sample_params: array API sample_params properties of sample entity + * @throws \API_Exception */ - public static function sample($params) { - $params += [ - 'seq' => 0, - 'overrides' => [], - ]; - $type = $params['type']; - // sample data - if field is array then chosed based on `seq` - $sample_params = []; - if (in_array($type, ['Individual', 'Organization', 'Household'])) { - $sample_params['contact_type'] = $type; - $entity = 'Contact'; + public function getRequiredValuesToCreate(string $entity, &$values = []) { + $requiredFields = civicrm_api4($entity, 'getfields', [ + 'action' => 'create', + 'loadOptions' => TRUE, + 'where' => [ + ['type', 'IN', ['Field', 'Extra']], + ['OR', + [ + ['required', '=', TRUE], + // Include contitionally-required fields only if they don't create a circular FK reference + ['AND', [['required_if', 'IS NOT EMPTY'], ['fk_entity', '!=', $entity]]], + ], + ], + ['default_value', 'IS EMPTY'], + ['readonly', 'IS EMPTY'], + ], + ], 'name'); + + $extraValues = []; + foreach ($requiredFields as $fieldName => $requiredField) { + if (!isset($values[$fieldName])) { + $extraValues[$fieldName] = $this->getRequiredValue($requiredField); + } } - else { - $entity = $type; + + // Hack in some extra per-entity values that couldn't be determined by metadata. + // Try to keep this to a minimum and improve metadata as a first-resort. + + switch ($entity) { + case 'UFField': + $extraValues['field_name'] = 'activity_campaign_id'; + break; + + case 'Translation': + $extraValues['entity_table'] = 'civicrm_event'; + $extraValues['entity_field'] = 'description'; + $extraValues['entity_id'] = $this->getFkID('Event'); + break; + + case 'Case': + $extraValues['creator_id'] = $this->getFkID('Contact'); + break; + + case 'CaseContact': + // Prevent "already exists" error from using an existing contact id + $extraValues['contact_id'] = $this->createTestRecord('Contact')['id']; + break; + + case 'CaseType': + $extraValues['definition'] = [ + "activityTypes" => [ + [ + "name" => "Open Case", + "max_instances" => "1", + ], + [ + "name" => "Follow up", + ], + ], + "activitySets" => [ + [ + "name" => "standard_timeline", + "label" => "Standard Timeline", + "timeline" => 1, + "activityTypes" => [ + [ + "name" => "Open Case", + "status" => "Completed", + ], + [ + "name" => "Follow up", + "reference_activity" => "Open Case", + "reference_offset" => "3", + "reference_select" => "newest", + ], + ], + ], + ], + "timelineActivityTypes" => [ + [ + "name" => "Open Case", + "status" => "Completed", + ], + [ + "name" => "Follow up", + "reference_activity" => "Open Case", + "reference_offset" => "3", + "reference_select" => "newest", + ], + ], + "caseRoles" => [ + [ + "name" => "Parent of", + "creator" => "1", + "manager" => "1", + ], + ], + ]; + break; } - // use the seq to pluck a set of params out - foreach (self::sampleData($type) as $key => $value) { - if (is_array($value)) { - $sample_params[$key] = $value[$params['seq'] % count($value)]; - } - else { - $sample_params[$key] = $value; - } + + $values += $extraValues; + return $values; + } + + /** + * Attempt to get a value using field option, defaults, FKEntity, or a random + * value based on the data type. + * + * @param array $field + * + * @return mixed + * @throws \Exception + */ + private function getRequiredValue(array $field) { + if (!empty($field['options'])) { + return key($field['options']); + } + if (!empty($field['fk_entity'])) { + return $this->getFkID($field['fk_entity']); } - if ($type == 'Individual') { - $sample_params['email'] = strtolower( - $sample_params['first_name'] . '_' . $sample_params['last_name'] . '@civicrm.org' - ); - $sample_params['prefix_id'] = 3; - $sample_params['suffix_id'] = 3; + if (isset($field['default_value'])) { + return $field['default_value']; } - if (!count($sample_params)) { - throw new \Exception("unknown sample type: $type"); + if ($field['name'] === 'contact_id') { + return $this->getFkID('Contact'); } - $sample_params = $params['overrides'] + $sample_params; - // make foreign enitiies if they haven't been supplied - foreach ($sample_params as $key => $value) { - if (substr($value, 0, 6) === 'dummy.') { - $foreign_entity = self::createEntity([ - 'type' => substr($value, 6), - 'seq' => $params['seq'], - ]); - $sample_params[$key] = $foreign_entity['id']; + if ($field['name'] === 'entity_id') { + // What could possibly go wrong with this? + switch ($field['table_name'] ?? NULL) { + case 'civicrm_financial_item': + return $this->getFkID(\Civi\Api4\Service\Spec\Provider\FinancialItemCreationSpecProvider::DEFAULT_ENTITY); + + default: + return $this->getFkID('Contact'); } } - return compact("entity", "sample_params"); + + $randomValue = $this->getRandomValue($field['data_type']); + + if ($randomValue) { + return $randomValue; + } + + throw new \API_Exception('Could not provide default value'); } /** - * Provider of sample data. + * Get an ID for the appropriate entity. * - * @return array - * Array values represent a set of allowable items. - * Strings in the form "dummy.Entity" require creating a foreign entity first. + * @param string $fkEntity + * + * @return int + * + * @throws \API_Exception */ - public static function sampleData($type) { - $data = [ - 'Individual' => [ - // The number of values in each list need to be coprime numbers to not have duplicates - 'first_name' => ['Anthony', 'Joe', 'Terrence', 'Lucie', 'Albert', 'Bill', 'Kim'], - 'middle_name' => ['J.', 'M.', 'P', 'L.', 'K.', 'A.', 'B.', 'C.', 'D', 'E.', 'Z.'], - 'last_name' => ['Anderson', 'Miller', 'Smith', 'Collins', 'Peterson'], - 'contact_type' => 'Individual', - ], - 'Organization' => [ - 'organization_name' => [ - 'Unit Test Organization', - 'Acme', - 'Roberts and Sons', - 'Cryo Space Labs', - 'Sharper Pens', - ], - ], - 'Household' => [ - 'household_name' => ['Unit Test household'], - ], - 'Event' => [ - 'title' => 'Annual CiviCRM meet', - 'summary' => 'If you have any CiviCRM related issues or want to track where CiviCRM is heading, Sign up now', - 'description' => 'This event is intended to give brief idea about progess of CiviCRM and giving solutions to common user issues', - 'event_type_id' => 1, - 'is_public' => 1, - 'start_date' => 20081021, - 'end_date' => 20081023, - 'is_online_registration' => 1, - 'registration_start_date' => 20080601, - 'registration_end_date' => 20081015, - 'max_participants' => 100, - 'event_full_text' => 'Sorry! We are already full', - 'is_monetary' => 0, - 'is_active' => 1, - 'is_show_location' => 0, - ], - 'Participant' => [ - 'event_id' => 'dummy.Event', - 'contact_id' => 'dummy.Individual', - 'status_id' => 2, - 'role_id' => 1, - 'register_date' => 20070219, - 'source' => 'Wimbeldon', - 'event_level' => 'Payment', - ], - 'Contribution' => [ - 'contact_id' => 'dummy.Individual', - // donation, 2 = member, 3 = campaign contribution, 4=event - 'financial_type_id' => 1, - 'total_amount' => 7.3, - ], - 'Activity' => [ - //'activity_type_id' => 1, - 'subject' => 'unit testing', - 'source_contact_id' => 'dummy.Individual', - ], - 'Group' => [ - 'title' => 'unit testing', - ], - ]; - if ($type == 'Contact') { - $type = 'Individual'; + private function getFkID(string $fkEntity) { + $params = ['checkPermissions' => FALSE]; + // Be predictable about what type of contact we select + if ($fkEntity === 'Contact') { + $params['where'] = [['contact_type', '=', 'Individual']]; } - return $data[$type]; + $entityList = civicrm_api4($fkEntity, 'get', $params); + // If no existing entities, create one + if ($entityList->count() < 1) { + return $this->createTestRecord($fkEntity)['id']; + } + + return $entityList->last()['id']; + } + + /** + * @param $dataType + * + * @return int|null|string + */ + private function getRandomValue($dataType) { + switch ($dataType) { + case 'Boolean': + return TRUE; + + case 'Integer': + return random_int(1, 2000); + + case 'String': + return \CRM_Utils_String::createRandom(10, implode('', range('a', 'z'))); + + case 'Text': + return \CRM_Utils_String::createRandom(100, implode('', range('a', 'z'))); + + case 'Money': + return sprintf('%d.%2d', rand(0, 2000), rand(10, 99)); + + case 'Date': + return '20100102'; + + case 'Timestamp': + return 'now'; + } + + return NULL; } } diff --git a/tests/phpunit/api/v4/Custom/CreateCustomValueTest.php b/tests/phpunit/api/v4/Custom/CreateCustomValueTest.php index 4407e8ca14..56b5fff6ab 100644 --- a/tests/phpunit/api/v4/Custom/CreateCustomValueTest.php +++ b/tests/phpunit/api/v4/Custom/CreateCustomValueTest.php @@ -104,7 +104,7 @@ class CreateCustomValueTest extends CustomTestBase { ->addValue('time_format', 2) ->execute(); - $contactID = $this->createEntity(['type' => 'Individual'])['id']; + $contactID = $this->createTestRecord('Contact')['id']; CustomValue::create('MyContactDateFields', FALSE) ->addValue('date_field', '2022-02-02') diff --git a/tests/phpunit/api/v4/Custom/CustomFieldAlterTest.php b/tests/phpunit/api/v4/Custom/CustomFieldAlterTest.php index 1faabe10be..7d681b3b40 100644 --- a/tests/phpunit/api/v4/Custom/CustomFieldAlterTest.php +++ b/tests/phpunit/api/v4/Custom/CustomFieldAlterTest.php @@ -29,7 +29,7 @@ use Civi\Api4\CustomGroup; class CustomFieldAlterTest extends CustomTestBase { public function testChangeSerialize() { - $contact = $this->createEntity(['type' => 'Individual']); + $contact = $this->createTestRecord('Contact'); $customGroup = CustomGroup::create(FALSE) ->addValue('title', 'MyFieldsToAlter') diff --git a/tests/phpunit/api/v4/Custom/PseudoconstantTest.php b/tests/phpunit/api/v4/Custom/PseudoconstantTest.php index 8f006dfe66..358d8192b3 100644 --- a/tests/phpunit/api/v4/Custom/PseudoconstantTest.php +++ b/tests/phpunit/api/v4/Custom/PseudoconstantTest.php @@ -276,13 +276,13 @@ class PseudoconstantTest extends CustomTestBase { } public function testParticipantRole() { - $event = $this->createEntity(['type' => 'Event']); - $contact = $this->createEntity(['type' => 'Individual']); - $participant = Participant::create() - ->addValue('contact_id', $contact['id']) - ->addValue('event_id', $event['id']) - ->addValue('role_id:label', ['Attendee', 'Volunteer']) - ->execute()->first(); + $event = $this->createTestRecord('Event'); + $contact = $this->createTestRecord('Contact'); + $participant = $this->createTestRecord('Participant', [ + 'contact_id' => $contact['id'], + 'event_id' => $event['id'], + 'role_id:label' => ['Attendee', 'Volunteer'], + ]); $search1 = Participant::get() ->addSelect('role_id', 'role_id:label') @@ -304,7 +304,7 @@ class PseudoconstantTest extends CustomTestBase { \CRM_Core_BAO_ConfigSetting::enableComponent('CiviContribute'); \CRM_Core_BAO_ConfigSetting::enableComponent('CiviCampaign'); - $contact = $this->createEntity(['type' => 'Individual']); + $contact = $this->createTestRecord('Contact'); $campaignTitle = uniqid('Test '); diff --git a/tests/phpunit/api/v4/DataSets/CaseType.json b/tests/phpunit/api/v4/DataSets/CaseType.json deleted file mode 100644 index dd1c084386..0000000000 --- a/tests/phpunit/api/v4/DataSets/CaseType.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "CaseType": [ - { - "name": "test_case_type", - "title": "Test Case Type", - "definition": { - "activityTypes": [ - { - "name": "Open Case", - "max_instances": "1" - }, - { - "name": "Follow up" - } - ], - "activitySets": [ - { - "name": "standard_timeline", - "label": "Standard Timeline", - "timeline": 1, - "activityTypes": [ - { - "name": "Open Case", - "status": "Completed" - }, - { - "name": "Follow up", - "reference_activity": "Open Case", - "reference_offset": "3", - "reference_select": "newest" - } - ] - } - ], - "timelineActivityTypes": [ - { - "name": "Open Case", - "status": "Completed" - }, - { - "name": "Follow up", - "reference_activity": "Open Case", - "reference_offset": "3", - "reference_select": "newest" - } - ], - "caseRoles": [ - { - "name": "Parent of", - "creator": "1", - "manager": "1" - } - ] - }, - "@ref": "test_case_type_1" - } - ] -} diff --git a/tests/phpunit/api/v4/DataSets/ConformanceTest.json b/tests/phpunit/api/v4/DataSets/ConformanceTest.json deleted file mode 100644 index 0b5bf5597c..0000000000 --- a/tests/phpunit/api/v4/DataSets/ConformanceTest.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "Contact": [ - { - "first_name": "Janice", - "last_name": "Voss", - "contact_type": "Individual", - "@ref": "test_contact_1" - }, - { - "first_name": "Jim", - "last_name": "Henson", - "contact_type": "Individual", - "@ref": "test_contact_2" - } - ], - "Case": [ - { - "case_type_id": "@ref test_case_type_1.id", - "status_id": 1, - "contact_id": "@ref test_contact_1.id", - "creator_id": "@ref test_contact_1.id" - } - ], - "CustomGroup": [ - { - "name": "MyFavoriteThings", - "title": "MyFavoriteThings", - "extends": "Contact" - } - ], - "Event": [ - { - "start_date": "20401010000000", - "title": "The Singularity", - "event_type_id": "major_historical_event" - } - ], - "Group": [ - { - "name": "the_group", - "title": "The Group" - } - ], - "Mapping": [ - { - "name": "the_mapping", - "mapping_type_id": "1" - } - ], - "Activity": [ - { - "subject": "Test A Phone Activity", - "activity_type_id:name": "Phone Call", - "source_contact_id": "@ref test_contact_1.id" - } - ], - "Contribution": [ - { - "total_amount": 999.89, - "financial_type_id:name": "Donation", - "contact_id": "@ref test_contact_1.id" - } - ], - "Pledge" : [ - { - "contact_id": "@ref test_contact_1.id", - "original_installment_amount" : 10, - "amount" : 10, - "start_date" : "now", - "create_date" : "now", - "status_id:name" : "Pending" - } - ], - "PaymentProcessor" : [ - { - "payment_processor_type_id:name": "Dummy" - } - ], - "Batch": [ - { - "title": "Batch 433397", - "name": "Batch_433397", - "status_id": "1" - } - ], - "Product": [ - { - "name": "Test Product", - "price": "10.00", - "sku": "Test SKU", - "financial_type_id:name": "Donation", - "min_contribution": "10.00" - } - ], - "MembershipType": [ - { - "name": "General", - "period_type" : "fixed", - "financial_type_id:name": "Donation", - "duration_unit" : "month", - "member_of_contact_id" : "@ref test_contact_1.id" - } - ], - "ContributionPage": [ - { - "name": "General" - } - ], - "MembershipType": [ - { - "domain_id": "1", - "name": "General", - "description": "Regular annual membership.", - "member_of_contact_id": "1", - "financial_type_id": "2", - "minimum_fee": "100.000000000", - "duration_unit": "year", - "duration_interval": "2", - "period_type": "rolling", - "relationship_type_id": [ - "7" - ], - "relationship_direction": [ - "b_a" - ], - "visibility": "Public", - "weight": "1", - "auto_renew": "0", - "is_active": "1" - } - ], - "Membership": [ - { - "membership_type_id:name": "General", - "contact_id" : "@ref test_contact_1.id", - "status_id:name" : "Pending" - } - ] -} diff --git a/tests/phpunit/api/v4/DataSets/DefaultDataSet.json b/tests/phpunit/api/v4/DataSets/DefaultDataSet.json deleted file mode 100644 index 17a0a297df..0000000000 --- a/tests/phpunit/api/v4/DataSets/DefaultDataSet.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "Contact": [ - { - "first_name": "Phoney", - "last_name": "Contact", - "contact_type": "Individual", - "@ref": "test_contact_1" - }, - { - "first_name": "Second", - "last_name": "Test", - "contact_type": "Individual", - "@ref": "test_contact_2" - } - ], - "Activity": [ - { - "subject": "Test Phone Activity", - "activity_type_id:name": "Phone Call", - "source_contact_id": "@ref test_contact_1.id" - }, - { - "subject": "Another Activity", - "activity_type_id:name": "Meeting", - "source_contact_id": "@ref test_contact_1.id", - "assignee_contact_id": [ - "@ref test_contact_1.id", - "@ref test_contact_2.id" - ] - } - ], - "Phone": [ - { - "contact_id": "@ref test_contact_1.id", - "phone": "+35355439483", - "location_type_id": "1", - "@ref": "test_phone_1" - }, - { - "contact_id": "@ref test_contact_1.id", - "phone": "+3538733439483", - "location_type_id": "2" - } - ], - "Address": [ - { - "contact_id": "@ref test_contact_1.id", - "street_address": "123 Sesame St.", - "country_id": "1228", - "location_type_id": "1", - "@ref": "test_address_1" - } - ] -} diff --git a/tests/phpunit/api/v4/DataSets/MultiContactMultiEmail.json b/tests/phpunit/api/v4/DataSets/MultiContactMultiEmail.json deleted file mode 100644 index ce3fbcaf92..0000000000 --- a/tests/phpunit/api/v4/DataSets/MultiContactMultiEmail.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "Contact": [ - { - "first_name": "First", - "last_name": "Contact", - "contact_type": "Individual", - "@ref": "test_contact_1" - }, - { - "first_name": "Second", - "last_name": "Contact", - "contact_type": "Individual", - "@ref": "test_contact_2" - } - ], - "Email": [ - { - "contact_id": "@ref test_contact_1.id", - "email": "test_contact_one_home@fakedomain.com", - "location_type_id": 1, - "@ref": "test_email_1" - }, - { - "contact_id": "@ref test_contact_1.id", - "email": "test_contact_one_work@fakedomain.com", - "location_type_id": 2, - "@ref": "test_email_2" - }, - { - "contact_id": "@ref test_contact_2.id", - "email": "test_contact_two_home@fakedomain.com", - "location_type_id": 1, - "@ref": "test_email_3" - }, - { - "contact_id": "@ref test_contact_2.id", - "email": "test_contact_two_work@fakedomain.com", - "location_type_id": 2, - "@ref": "test_email_4" - } - ] -} diff --git a/tests/phpunit/api/v4/DataSets/SingleContact.json b/tests/phpunit/api/v4/DataSets/SingleContact.json deleted file mode 100644 index 41553368d6..0000000000 --- a/tests/phpunit/api/v4/DataSets/SingleContact.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "Contact": [ - { - "first_name": "Single", - "last_name": "Contact", - "contact_type": "Individual", - "preferred_communication_method": "1", - "@ref": "test_contact_1" - } - ], - "Activity": [ - { - "subject": "Won A Nobel Prize", - "activity_type_id:name": "Meeting", - "source_contact_id": "@ref test_contact_1.id", - "@ref": "test_activity_1" - }, - { - "subject": "Cleaned The House", - "activity_type_id:name": "Meeting", - "source_contact_id": "@ref test_contact_1.id", - "assignee_contact_id": [ - "@ref test_contact_1.id" - ], - "@ref": "test_activity_2" - } - ], - "Phone": [ - { - "contact_id": "@ref test_contact_1.id", - "phone": "+1111111111111", - "location_type_id": 1 - }, - { - "contact_id": "@ref test_contact_1.id", - "phone": "+2222222222222", - "location_type_id": 2 - } - ], - "Email": [ - { - "contact_id": "@ref test_contact_1.id", - "email": "test_contact_home@fakedomain.com", - "location_type_id": 1 - }, - { - "contact_id": "@ref test_contact_1.id", - "email": "test_contact_work@fakedomain.com", - "location_type_id": 2 - } - ], - "Address": [ - { - "contact_id": "@ref test_contact_1.id", - "street_address": "123 Sesame St.", - "location_type_id": 1 - } - ], - "Website": [ - { - "contact_id": "@ref test_contact_1.id", - "url": "http://test.com", - "website_id": 1 - } - ], - "OpenID": [ - { - "contact_id": "@ref test_contact_1.id", - "openid": "123", - "allowed_to_login": 1, - "location_type_id": 1 - } - ], - "IM": [ - { - "contact_id": "@ref test_contact_1.id", - "name": "123", - "location_type_id": 1 - } - ] -} diff --git a/tests/phpunit/api/v4/Entity/CaseTest.php b/tests/phpunit/api/v4/Entity/CaseTest.php index ac92b4c3d0..6bf8c07b3b 100644 --- a/tests/phpunit/api/v4/Entity/CaseTest.php +++ b/tests/phpunit/api/v4/Entity/CaseTest.php @@ -19,47 +19,28 @@ namespace api\v4\Entity; -use Civi\Api4\CiviCase; use api\v4\Api4TestBase; use Civi\Api4\Relationship; -use Civi\Test\TransactionalInterface; /** * @group headless */ -class CaseTest extends Api4TestBase implements TransactionalInterface { +class CaseTest extends Api4TestBase { public function setUp(): void { parent::setUp(); \CRM_Core_BAO_ConfigSetting::enableComponent('CiviCase'); - $this->loadDataSet('CaseType'); - } - - public function tearDown(): void { - $relatedTables = [ - 'civicrm_activity', - 'civicrm_activity_contact', - 'civicrm_relationship', - 'civicrm_case_contact', - 'civicrm_case_type', - 'civicrm_case', - ]; - $this->cleanup(['tablesToTruncate' => $relatedTables]); - parent::tearDown(); } public function testCreateUsingLoggedInUser() { $uid = $this->createLoggedInUser(); - $contactID = $this->createEntity(['type' => 'Individual'])['id']; + $contactID = $this->createTestRecord('Contact')['id']; - $case = CiviCase::create(FALSE) - ->addValue('case_type_id', $this->getReference('test_case_type_1')['id']) - ->addValue('creator_id', 'user_contact_id') - ->addValue('status_id', 1) - ->addValue('contact_id', $contactID) - ->execute() - ->first(); + $case = $this->createTestRecord('Case', [ + 'creator_id' => 'user_contact_id', + 'contact_id' => $contactID, + ]); $relationships = Relationship::get(FALSE) ->addWhere('case_id', '=', $case['id']) @@ -71,6 +52,11 @@ class CaseTest extends Api4TestBase implements TransactionalInterface { } public function testCgExtendsObjects() { + $this->createTestRecord('CaseType', [ + 'title' => 'Test Case Type', + 'name' => 'test_case_type1', + ]); + $field = \Civi\Api4\CustomGroup::getFields(FALSE) ->setLoadOptions(TRUE) ->addValue('extends', 'Case') diff --git a/tests/phpunit/api/v4/Entity/ConformanceTest.php b/tests/phpunit/api/v4/Entity/ConformanceTest.php index c85ace355e..f7b43a04cd 100644 --- a/tests/phpunit/api/v4/Entity/ConformanceTest.php +++ b/tests/phpunit/api/v4/Entity/ConformanceTest.php @@ -18,7 +18,6 @@ namespace api\v4\Entity; -use api\v4\Service\TestCreationParameterProvider; use api\v4\Traits\CheckAccessTrait; use api\v4\Traits\TableDropperTrait; use Civi\API\Exception\UnauthorizedException; @@ -29,7 +28,6 @@ use api\v4\Api4TestBase; use Civi\Api4\Event\ValidateValuesEvent; use Civi\Api4\Service\Spec\CustomFieldSpec; use Civi\Api4\Service\Spec\FieldSpec; -use Civi\Api4\Service\Spec\SpecGatherer; use Civi\Api4\Utils\CoreUtil; use Civi\Core\Event\PostEvent; use Civi\Core\Event\PreEvent; @@ -43,11 +41,6 @@ class ConformanceTest extends Api4TestBase implements HookInterface { use CheckAccessTrait; use TableDropperTrait; - /** - * @var \api\v4\Service\TestCreationParameterProvider - */ - protected $creationParamProvider; - /** * Set up baseline for testing * @@ -56,10 +49,6 @@ class ConformanceTest extends Api4TestBase implements HookInterface { public function setUp(): void { // Enable all components \CRM_Core_BAO_ConfigSetting::enableAllComponents(); - $this->loadDataSet('CaseType'); - $this->loadDataSet('ConformanceTest'); - $gatherer = new SpecGatherer(); - $this->creationParamProvider = new TestCreationParameterProvider($gatherer); parent::setUp(); $this->resetCheckAccess(); } @@ -261,7 +250,7 @@ class ConformanceTest extends Api4TestBase implements HookInterface { $this->setCheckAccessGrants(["{$entity}::create" => TRUE]); $this->assertEquals(0, $this->checkAccessCounts["{$entity}::create"]); - $requiredParams = $this->creationParamProvider->getRequired($entity); + $requiredParams = $this->getRequiredValuesToCreate($entity); $createResult = $entityClass::create() ->setValues($requiredParams) ->setCheckPermissions(!$isReadOnly) @@ -293,7 +282,7 @@ class ConformanceTest extends Api4TestBase implements HookInterface { $this->setCheckAccessGrants(["{$entity}::create" => FALSE]); $this->assertEquals(0, $this->checkAccessCounts["{$entity}::create"]); - $requiredParams = $this->creationParamProvider->getRequired($entity); + $requiredParams = $this->getRequiredValuesToCreate($entity); try { $entityClass::create() diff --git a/tests/phpunit/api/v4/Entity/ContactJoinTest.php b/tests/phpunit/api/v4/Entity/ContactJoinTest.php index a2adafbb0d..40fadf38e0 100644 --- a/tests/phpunit/api/v4/Entity/ContactJoinTest.php +++ b/tests/phpunit/api/v4/Entity/ContactJoinTest.php @@ -22,36 +22,23 @@ namespace api\v4\Entity; use Civi\Api4\Contact; use Civi\Api4\OptionValue; use api\v4\Api4TestBase; -use Civi\Test\TransactionalInterface; /** * @group headless */ -class ContactJoinTest extends Api4TestBase implements TransactionalInterface { - - public function setUpHeadless() { - $relatedTables = [ - 'civicrm_address', - 'civicrm_email', - 'civicrm_phone', - 'civicrm_openid', - 'civicrm_im', - 'civicrm_website', - 'civicrm_activity', - 'civicrm_activity_contact', - ]; - - $this->cleanup(['tablesToTruncate' => $relatedTables]); - $this->loadDataSet('SingleContact'); - - return parent::setUpHeadless(); - } +class ContactJoinTest extends Api4TestBase { public function testContactJoin() { - $contact = $this->getReference('test_contact_1'); + $contact = $this->createTestRecord('Contact', [ + 'first_name' => uniqid(), + 'last_name' => uniqid(), + ]); $entitiesToTest = ['Address', 'OpenID', 'IM', 'Website', 'Email', 'Phone']; foreach ($entitiesToTest as $entity) { + $this->createTestRecord($entity, [ + 'contact_id' => $contact['id'], + ]); $results = civicrm_api4($entity, 'get', [ 'where' => [['contact_id', '=', $contact['id']]], 'select' => ['contact_id.*_name', 'contact_id.id'], @@ -64,12 +51,12 @@ class ContactJoinTest extends Api4TestBase implements TransactionalInterface { } public function testJoinToPCMWillReturnArray() { - $contact = Contact::create()->setValues([ + $contact = $this->createTestRecord('Contact', [ 'preferred_communication_method' => [1, 2, 3], 'contact_type' => 'Individual', 'first_name' => 'Test', 'last_name' => 'PCM', - ])->execute()->first(); + ]); $fetchedContact = Contact::get() ->addWhere('id', '=', $contact['id']) @@ -89,19 +76,19 @@ class ContactJoinTest extends Api4TestBase implements TransactionalInterface { $optionValues = array_column($options, 'value'); $labels = array_column($options, 'label'); - $contact = Contact::create()->setValues([ + $contact = $this->createTestRecord('Contact', [ 'preferred_communication_method' => $optionValues, 'contact_type' => 'Individual', 'first_name' => 'Test', 'last_name' => 'PCM', - ])->execute()->first(); + ]); - $contact2 = Contact::create()->setValues([ + $contact2 = $this->createTestRecord('Contact', [ 'preferred_communication_method' => $optionValues, 'contact_type' => 'Individual', 'first_name' => 'Test', 'last_name' => 'PCM2', - ])->execute()->first(); + ]); $contactIds = array_column([$contact, $contact2], 'id'); diff --git a/tests/phpunit/api/v4/Entity/GroupContactTest.php b/tests/phpunit/api/v4/Entity/GroupContactTest.php index 1b97a61ce0..7921506976 100644 --- a/tests/phpunit/api/v4/Entity/GroupContactTest.php +++ b/tests/phpunit/api/v4/Entity/GroupContactTest.php @@ -20,22 +20,19 @@ namespace api\v4\Entity; use api\v4\Api4TestBase; -use Civi\Api4\GroupContact; -use Civi\Test\TransactionalInterface; /** * @group headless */ -class GroupContactTest extends Api4TestBase implements TransactionalInterface { +class GroupContactTest extends Api4TestBase { public function testCreate() { - $contact = $this->createEntity(['type' => 'Individual']); - $group = $this->createEntity(['type' => 'Group']); - $result = GroupContact::create(FALSE) - ->addValue('group_id', $group['id']) - ->addValue('contact_id', $contact['id']) - ->execute() - ->first(); + $contact = $this->createTestRecord('Contact'); + $group = $this->createTestRecord('Group'); + $result = $this->createTestRecord('GroupContact', [ + 'group_id' => $group['id'], + 'contact_id' => $contact['id'], + ]); $this->assertEquals('Added', $result['status']); } diff --git a/tests/phpunit/api/v4/Entity/NoteTest.php b/tests/phpunit/api/v4/Entity/NoteTest.php index 212a481f50..31bdacfb33 100644 --- a/tests/phpunit/api/v4/Entity/NoteTest.php +++ b/tests/phpunit/api/v4/Entity/NoteTest.php @@ -28,7 +28,7 @@ use Civi\Test\TransactionalInterface; class NoteTest extends Api4TestBase implements TransactionalInterface { public function testDeleteWithChildren() { - $c1 = $this->createEntity(['type' => 'Individual']); + $c1 = $this->createTestRecord('Contact'); $text = uniqid(__FUNCTION__, TRUE); diff --git a/tests/phpunit/api/v4/Entity/ParticipantTest.php b/tests/phpunit/api/v4/Entity/ParticipantTest.php index 7ff6740842..f7e91c841b 100644 --- a/tests/phpunit/api/v4/Entity/ParticipantTest.php +++ b/tests/phpunit/api/v4/Entity/ParticipantTest.php @@ -54,7 +54,7 @@ class ParticipantTest extends Api4TestBase implements TransactionalInterface { public function testGet() { $rows = $this->getRowCount('civicrm_participant'); if ($rows > 0) { - $this->markTestSkipped('Participant table must be empty'); + $this->fail('Participant table must be empty'); } // With no records: @@ -76,36 +76,34 @@ class ParticipantTest extends Api4TestBase implements TransactionalInterface { $expectedFirstEventCount = ceil($participantCount / $eventCount); $dummy = [ - 'contacts' => $this->createEntity([ - 'type' => 'Individual', - 'count' => $contactCount, - 'seq' => 1, + 'contacts' => $this->saveTestRecords('Contact', [ + 'records' => array_fill(0, $contactCount, []), ]), - 'events' => $this->createEntity([ - 'type' => 'Event', - 'count' => $eventCount, - 'seq' => 1, + 'events' => $this->saveTestRecords('Event', [ + 'records' => array_fill(0, $eventCount, []), ]), 'sources' => ['Paddington', 'Springfield', 'Central'], ]; // - create dummy participants record + $records = []; for ($i = 0; $i < $participantCount; $i++) { - $dummy['participants'][$i] = $this->sample([ - 'type' => 'Participant', - 'overrides' => [ - 'event_id' => $dummy['events'][$i % $eventCount]['id'], - 'contact_id' => $dummy['contacts'][$i % $contactCount]['id'], - // 3 = number of sources - 'source' => $dummy['sources'][$i % 3], - ], - ])['sample_params']; - - Participant::create() - ->setValues($dummy['participants'][$i]) - ->setCheckPermissions(FALSE) - ->execute(); + $records[] = [ + 'event_id' => $dummy['events'][$i % $eventCount]['id'], + 'contact_id' => $dummy['contacts'][$i % $contactCount]['id'], + // 3 = number of sources + 'source' => $dummy['sources'][$i % 3], + ]; } + $this->saveTestRecords('Participant', [ + 'records' => $records, + 'defaults' => [ + 'status_id' => 2, + 'role_id' => 1, + 'register_date' => 20070219, + 'event_level' => 'Payment', + ], + ]); $sqlCount = $this->getRowCount('civicrm_participant'); $this->assertEquals($participantCount, $sqlCount, "Unexpected count"); @@ -253,4 +251,15 @@ class ParticipantTest extends Api4TestBase implements TransactionalInterface { $this->assertCount(1, Participant::get()->selectRowCount()->addWhere('id', '=', $testParticipants->first()['id'])->execute()); } + /** + * Quick record counter + * + * @param string $table_name + * @returns int record count + */ + private function getRowCount($table_name) { + $sql = "SELECT count(id) FROM $table_name"; + return (int) \CRM_Core_DAO::singleValueQuery($sql); + } + } diff --git a/tests/phpunit/api/v4/Entity/ValidateValuesTest.php b/tests/phpunit/api/v4/Entity/ValidateValuesTest.php index ab1aab3db2..79255599e9 100644 --- a/tests/phpunit/api/v4/Entity/ValidateValuesTest.php +++ b/tests/phpunit/api/v4/Entity/ValidateValuesTest.php @@ -32,12 +32,12 @@ class ValidateValuesTest extends Api4TestBase implements TransactionalInterface private $lastValidator; - protected function setUp(): void { + public function setUp(): void { $this->lastValidator = NULL; parent::setUp(); } - protected function tearDown(): void { + public function tearDown(): void { $this->setValidator(NULL); parent::tearDown(); } diff --git a/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php b/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php index a47b022ff5..03f147b62d 100644 --- a/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php +++ b/tests/phpunit/api/v4/Query/Api4SelectQueryTest.php @@ -22,35 +22,23 @@ namespace api\v4\Query; use Civi\API\Request; use Civi\Api4\Query\Api4SelectQuery; use api\v4\Api4TestBase; -use Civi\Test\TransactionalInterface; /** * @group headless */ -class Api4SelectQueryTest extends Api4TestBase implements TransactionalInterface { - - public function setUpHeadless() { - $relatedTables = [ - 'civicrm_address', - 'civicrm_email', - 'civicrm_phone', - 'civicrm_openid', - 'civicrm_im', - 'civicrm_website', - 'civicrm_activity', - 'civicrm_activity_contact', - ]; - $this->cleanup(['tablesToTruncate' => $relatedTables]); - $this->loadDataSet('DefaultDataSet'); - $displayNameFormat = '{contact.first_name}{ }{contact.last_name}'; - \Civi::settings()->set('display_name_format', $displayNameFormat); - - return parent::setUpHeadless(); - } +class Api4SelectQueryTest extends Api4TestBase { public function testManyToOneJoin() { - $phoneNum = $this->getReference('test_phone_1')['phone']; - $contact = $this->getReference('test_contact_1'); + $contact = $this->createTestRecord('Contact', [ + 'first_name' => uniqid(), + 'last_name' => uniqid(), + ]); + $phone = $this->createTestRecord('Phone', [ + 'contact_id' => $contact['id'], + 'phone' => uniqid(), + ]); + + $phoneNum = $phone['phone']; $api = Request::create('Phone', 'get', [ 'version' => 4, diff --git a/tests/phpunit/api/v4/Query/OptionValueJoinTest.php b/tests/phpunit/api/v4/Query/OptionValueJoinTest.php index 0c8161617d..3b3342ce12 100644 --- a/tests/phpunit/api/v4/Query/OptionValueJoinTest.php +++ b/tests/phpunit/api/v4/Query/OptionValueJoinTest.php @@ -21,32 +21,17 @@ namespace api\v4\Query; use Civi\Api4\Query\Api4SelectQuery; use api\v4\Api4TestBase; -use Civi\Test\TransactionalInterface; /** * @group headless */ -class OptionValueJoinTest extends Api4TestBase implements TransactionalInterface { - - public function setUpHeadless() { - $relatedTables = [ - 'civicrm_address', - 'civicrm_email', - 'civicrm_phone', - 'civicrm_openid', - 'civicrm_im', - 'civicrm_website', - 'civicrm_activity', - 'civicrm_activity_contact', - ]; - - $this->cleanup(['tablesToTruncate' => $relatedTables]); - $this->loadDataSet('SingleContact'); - - return parent::setUpHeadless(); - } +class OptionValueJoinTest extends Api4TestBase { public function testCommunicationMethodJoin() { + $this->createTestRecord('Contact', [ + 'preferred_communication_method' => 1, + ]); + $api = \Civi\API\Request::create('Contact', 'get', [ 'version' => 4, 'checkPermissions' => FALSE, diff --git a/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php b/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php index 73fdb03ccf..f3b2ce370c 100644 --- a/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php +++ b/tests/phpunit/api/v4/Query/SelectQueryMultiJoinTest.php @@ -21,31 +21,46 @@ namespace api\v4\Query; use Civi\Api4\Email; use api\v4\Api4TestBase; -use Civi\Test\TransactionalInterface; /** * Class SelectQueryMultiJoinTest * @package api\v4\Query * @group headless */ -class SelectQueryMultiJoinTest extends Api4TestBase implements TransactionalInterface { - - public function setUpHeadless() { - $this->cleanup(['tablesToTruncate' => ['civicrm_contact', 'civicrm_email']]); - $this->loadDataSet('MultiContactMultiEmail'); - return parent::setUpHeadless(); - } +class SelectQueryMultiJoinTest extends Api4TestBase { public function testManyToOneSelect() { + + $contact1 = $this->createTestRecord('Contact', [ + 'first_name' => 'First', + 'last_name' => 'Contact', + ]); + $firstEmail = $this->createTestRecord('Email', [ + 'contact_id' => $contact1['id'], + 'location_type_id:name' => 'Home', + ]); + $secondEmail = $this->createTestRecord('Email', [ + 'contact_id' => $contact1['id'], + 'location_type_id:name' => 'Work', + ]); + $contact2 = $this->createTestRecord('Contact', [ + 'first_name' => 'Second', + 'last_name' => 'Contact', + ]); + $thirdEmail = $this->createTestRecord('Email', [ + 'contact_id' => $contact2['id'], + 'location_type_id:name' => 'Home', + ]); + $fourthEmail = $this->createTestRecord('Email', [ + 'contact_id' => $contact2['id'], + 'location_type_id:name' => 'Work', + ]); + $results = Email::get() ->addSelect('contact_id.display_name') ->execute() ->indexBy('id'); - $firstEmail = $this->getReference('test_email_1'); - $secondEmail = $this->getReference('test_email_2'); - $thirdEmail = $this->getReference('test_email_3'); - $fourthEmail = $this->getReference('test_email_4'); $firstContactEmailIds = [$firstEmail['id'], $secondEmail['id']]; $secondContactEmailIds = [$thirdEmail['id'], $fourthEmail['id']]; diff --git a/tests/phpunit/api/v4/Service/TestCreationParameterProvider.php b/tests/phpunit/api/v4/Service/TestCreationParameterProvider.php deleted file mode 100644 index 7d016aacc9..0000000000 --- a/tests/phpunit/api/v4/Service/TestCreationParameterProvider.php +++ /dev/null @@ -1,195 +0,0 @@ -gatherer = $gatherer; - } - - /** - * Get the required fields for the api entity + action. - * - * @param string $entity - * - * @return array - * @throws \API_Exception - */ - public function getRequired(string $entity) { - $requiredFields = civicrm_api4($entity, 'getfields', [ - 'action' => 'create', - 'loadOptions' => TRUE, - 'where' => [ - ['OR', [['required', '=', TRUE], ['required_if', 'IS NOT EMPTY']]], - ['readonly', 'IS EMPTY'], - ], - ], 'name'); - - $requiredParams = []; - foreach ($requiredFields as $fieldName => $requiredField) { - $requiredParams[$fieldName] = $this->getRequiredValue($requiredField); - } - - // This is a ruthless hack to avoid peculiar constraints - but - // it's also a test class & hard to care enough to do something - // better - $overrides = []; - $overrides['UFField'] = [ - 'field_name' => 'activity_campaign_id', - ]; - $overrides['Translation'] = [ - 'entity_table' => 'civicrm_event', - 'entity_field' => 'description', - 'entity_id' => \CRM_Core_DAO::singleValueQuery('SELECT min(id) FROM civicrm_event'), - ]; - - if (isset($overrides[$entity])) { - $requiredParams = array_merge($requiredParams, $overrides[$entity]); - } - - return $requiredParams; - } - - /** - * Attempt to get a value using field option, defaults, FKEntity, or a random - * value based on the data type. - * - * @param array $field - * - * @return mixed - * @throws \Exception - */ - private function getRequiredValue(array $field) { - - if (!empty($field['options'])) { - return key($field['options']); - } - if (!empty($field['fk_entity'])) { - return $this->getFkID($field['fk_entity']); - } - if (isset($field['default_value'])) { - return $field['default_value']; - } - if ($field['name'] === 'contact_id') { - return $this->getFkID('Contact'); - } - if ($field['name'] === 'entity_id') { - // What could possibly go wrong with this? - switch ($field['table_name'] ?? NULL) { - case 'civicrm_financial_item': - return $this->getFkID(FinancialItemCreationSpecProvider::DEFAULT_ENTITY); - - default: - return $this->getFkID('Contact'); - } - } - - $randomValue = $this->getRandomValue($field['data_type']); - - if ($randomValue) { - return $randomValue; - } - - throw new \API_Exception('Could not provide default value'); - } - - /** - * @param \Civi\Api4\Service\Spec\FieldSpec $field - * - * @return mixed - */ - private function getOption(FieldSpec $field) { - $options = array_column($field->getOptions(), 'label', 'id'); - return key($options); - } - - /** - * Get an ID for the appropriate entity. - * - * @param string $fkEntity - * - * @return mixed - * - * @throws \API_Exception - */ - private function getFkID(string $fkEntity) { - $params = ['checkPermissions' => FALSE]; - // Be predictable about what type of contact we select - if ($fkEntity === 'Contact') { - $params['where'] = [['contact_type', '=', 'Individual']]; - } - $entityList = civicrm_api4($fkEntity, 'get', $params); - // If no existing entities, create one - if ($entityList->count() < 1) { - $entityList = civicrm_api4($fkEntity, 'create', [ - 'checkPermissions' => FALSE, - 'values' => $this->getRequired($fkEntity), - ]); - } - - return $entityList->last()['id']; - } - - /** - * @param $dataType - * - * @return int|null|string - */ - private function getRandomValue($dataType) { - switch ($dataType) { - case 'Boolean': - return TRUE; - - case 'Integer': - return random_int(1, 2000); - - case 'String': - return \CRM_Utils_String::createRandom(10, implode('', range('a', 'z'))); - - case 'Text': - return \CRM_Utils_String::createRandom(100, implode('', range('a', 'z'))); - - case 'Money': - return sprintf('%d.%2d', rand(0, 2000), rand(10, 99)); - - case 'Date': - return '20100102'; - - case 'Timestamp': - return 'now'; - } - - return NULL; - } - -} diff --git a/tests/phpunit/api/v4/Traits/TestDataLoaderTrait.php b/tests/phpunit/api/v4/Traits/TestDataLoaderTrait.php deleted file mode 100644 index ce8d63254d..0000000000 --- a/tests/phpunit/api/v4/Traits/TestDataLoaderTrait.php +++ /dev/null @@ -1,86 +0,0 @@ - $entities) { - foreach ($entities as $entityValues) { - - $entityValues = $this->replaceReferences($entityValues); - - $params = ['values' => $entityValues, 'checkPermissions' => FALSE]; - $result = civicrm_api4($entityName, 'create', $params); - if (isset($entityValues['@ref'])) { - $this->references[$entityValues['@ref']] = $result->first(); - } - } - } - } - - /** - * @param $name - * - * @return null|mixed - */ - protected function getReference($name) { - return $this->references[$name] ?? NULL; - } - - /** - * @param array $entityValues - * - * @return array - */ - private function replaceReferences($entityValues) { - foreach ($entityValues as $name => $value) { - if (is_array($value)) { - $entityValues[$name] = $this->replaceReferences($value); - } - elseif (substr($value, 0, 4) === '@ref') { - $referenceName = substr($value, 5); - list ($reference, $property) = explode('.', $referenceName); - $entityValues[$name] = $this->references[$reference][$property]; - } - } - return $entityValues; - } - -}