Simplify apiv4 conformance test
authorEileen McNaughton <emcnaughton@wikimedia.org>
Wed, 19 Jan 2022 23:34:26 +0000 (12:34 +1300)
committerEileen McNaughton <emcnaughton@wikimedia.org>
Thu, 20 Jan 2022 06:20:02 +0000 (19:20 +1300)
The use of services meant this test failed if you didn't do
something or other (maybe some flushing - I never did figure it
out) & is an unnecessary complexity.

CRM/Api4/Services.php
Civi/Api4/Service/Spec/SpecGatherer.php
tests/phpunit/api/v4/Entity/ConformanceTest.php
tests/phpunit/api/v4/Service/TestCreationParameterProvider.php
tests/phpunit/api/v4/services.xml [deleted file]

index 18bab2f7ad8d747f0344bc0ffbde943a09f686cd..f5581efd0fadc7cce6289f6ee9c1e65624867e81 100644 (file)
@@ -57,12 +57,6 @@ class CRM_Api4_Services {
         [new Reference($provider)]
       );
     }
-
-    if (defined('CIVICRM_UF') && CIVICRM_UF === 'UnitTests'
-      && file_exists('tests/phpunit/api/v4/services.xml')
-    ) {
-      $loader->load('tests/phpunit/api/v4/services.xml');
-    }
   }
 
   /**
index 51a36fc82bdccc12073c744312655b1e4a8e1277..c4f49b7c9b53afaf814f13a946059258032c32db 100644 (file)
@@ -55,7 +55,7 @@ class SpecGatherer {
     }
 
     // Default value only makes sense for create actions
-    if ($action != 'create') {
+    if ($action !== 'create') {
       foreach ($specification->getFields() as $field) {
         $field->setDefaultValue(NULL);
       }
index 7194f288ec72cf4bfe13caa5e5afd5d500882e69..e8fb646de784fbc2889fa9ed630eac7ce4672f31 100644 (file)
@@ -16,9 +16,9 @@
  * @copyright CiviCRM LLC https://civicrm.org/licensing
  */
 
-
 namespace api\v4\Entity;
 
+use api\v4\Service\TestCreationParameterProvider;
 use api\v4\Traits\CheckAccessTrait;
 use api\v4\Traits\OptionCleanupTrait;
 use api\v4\Traits\TableDropperTrait;
@@ -30,6 +30,7 @@ use api\v4\UnitTestCase;
 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;
@@ -53,6 +54,8 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
 
   /**
    * Set up baseline for testing
+   *
+   * @throws \CRM_Core_Exception
    */
   public function setUp(): void {
     // Enable all components
@@ -60,7 +63,8 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
     $this->setUpOptionCleanup();
     $this->loadDataSet('CaseType');
     $this->loadDataSet('ConformanceTest');
-    $this->creationParamProvider = \Civi::container()->get('test.param_provider');
+    $gatherer = new SpecGatherer();
+    $this->creationParamProvider = new TestCreationParameterProvider($gatherer);
     parent::setUp();
     $this->resetCheckAccess();
   }
@@ -94,9 +98,9 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
    * @return array
    *
    * @throws \API_Exception
-   * @throws \Civi\API\Exception\UnauthorizedException
+   * @throws \CRM_Core_Exception
    */
-  public function getEntitiesHitech() {
+  public function getEntitiesHitech(): array {
     // Ensure all components are enabled so their entities show up
     foreach (array_keys(\CRM_Core_Component::getComponents()) as $component) {
       \CRM_Core_BAO_ConfigSetting::enableComponent($component);
@@ -113,7 +117,7 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
    *
    * @return array
    */
-  public function getEntitiesLotech() {
+  public function getEntitiesLotech(): array {
     $manual['add'] = [];
     $manual['remove'] = ['CustomValue'];
     $manual['transform'] = ['CiviCase' => 'Case'];
@@ -137,7 +141,7 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
    * Ensure that "getEntitiesLotech()" (which is the 'dataProvider') is up to date
    * with "getEntitiesHitech()" (which is a live feed available entities).
    */
-  public function testEntitiesProvider() {
+  public function testEntitiesProvider(): void {
     $this->assertEquals($this->getEntitiesHitech(), $this->getEntitiesLotech(), "The lo-tech list of entities does not match the hi-tech list. You probably need to update getEntitiesLotech().");
   }
 
@@ -286,10 +290,8 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
   /**
    * @param string $entity
    * @param \Civi\Api4\Generic\AbstractEntity|string $entityClass
-   *
-   * @return mixed
    */
-  protected function checkCreationDenied($entity, $entityClass) {
+  protected function checkCreationDenied(string $entity, $entityClass): void {
     $this->setCheckAccessGrants(["{$entity}::create" => FALSE]);
     $this->assertEquals(0, $this->checkAccessCounts["{$entity}::create"]);
 
@@ -316,7 +318,7 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
    * @param \Civi\Api4\Generic\AbstractEntity|string $entityClass
    * @param int $id
    */
-  protected function checkUpdateFailsFromCreate($entityClass, $id): void {
+  protected function checkUpdateFailsFromCreate($entityClass, int $id): void {
     $exceptionThrown = '';
     try {
       $entityClass::create(FALSE)
@@ -334,7 +336,7 @@ class ConformanceTest extends UnitTestCase implements HookInterface {
    * @param int $id
    * @param string $entity
    */
-  protected function checkGet($entityClass, $id, $entity) {
+  protected function checkGet($entityClass, int $id, string $entity): void {
     $getResult = $entityClass::get(FALSE)
       ->addWhere('id', '=', $id)
       ->execute();
index 92bb30428c040ece3c34284b2a49955c224becfb..5bdc2ce7cea7e72294a369e651feba99bc4d30c7 100644 (file)
@@ -38,17 +38,25 @@ class TestCreationParameterProvider {
   }
 
   /**
-   * @param $entity
+   * Get the required fields for the api entity + action.
+   *
+   * @param string $entity
    *
    * @return array
+   * @throws \API_Exception
    */
-  public function getRequired($entity) {
-    $createSpec = $this->gatherer->getSpec($entity, 'create', FALSE);
-    $requiredFields = array_merge($createSpec->getRequiredFields(), $createSpec->getConditionalRequiredFields());
+  public function getRequired(string $entity) {
+    $requiredFields = civicrm_api4($entity, 'getfields', [
+      'action' => 'create',
+      'loadOptions' => TRUE,
+      'where' => [
+        ['OR', [['required', '=', TRUE], ['required_if', 'IS NOT EMPTY']]],
+      ],
+    ], 'name');
 
     $requiredParams = [];
-    foreach ($requiredFields as $requiredField) {
-      $requiredParams[$requiredField->getName()] = $this->getRequiredValue($requiredField);
+    foreach ($requiredFields as $fieldName => $requiredField) {
+      $requiredParams[$fieldName] = $this->getRequiredValue($requiredField);
     }
 
     // This is a ruthless hack to avoid peculiar constraints - but
@@ -77,43 +85,43 @@ class TestCreationParameterProvider {
    * Attempt to get a value using field option, defaults, FKEntity, or a random
    * value based on the data type.
    *
-   * @param \Civi\Api4\Service\Spec\FieldSpec $field
+   * @param array $field
    *
    * @return mixed
    * @throws \Exception
    */
-  private function getRequiredValue(FieldSpec $field) {
+  private function getRequiredValue(array $field) {
 
-    if ($field->getOptions()) {
-      return $this->getOption($field);
+    if (!empty($field['options'])) {
+      return key($field['options']);
     }
-    elseif ($field->getFkEntity()) {
-      return $this->getFkID($field, $field->getFkEntity());
+    if (!empty($field['fk_entity'])) {
+      return $this->getFkID($field['fk_entity']);
     }
-    elseif ($field->getDefaultValue()) {
-      return $field->getDefaultValue();
+    if (isset($field['default_value'])) {
+      return $field['default_value'];
     }
-    elseif ($field->getName() === 'contact_id') {
-      return $this->getFkID($field, 'Contact');
+    if ($field['name'] === 'contact_id') {
+      return $this->getFkID('Contact');
     }
-    elseif ($field->getName() === 'entity_id') {
+    if ($field['name'] === 'entity_id') {
       // What could possibly go wrong with this?
-      switch ($field->getTableName()) {
+      switch ($field['table_name']) {
         case 'civicrm_financial_item':
-          return $this->getFkID($field, FinancialItemCreationSpecProvider::DEFAULT_ENTITY);
+          return $this->getFkID(FinancialItemCreationSpecProvider::DEFAULT_ENTITY);
 
         default:
-          return $this->getFkID($field, 'Contact');
+          return $this->getFkID('Contact');
       }
     }
 
-    $randomValue = $this->getRandomValue($field->getDataType());
+    $randomValue = $this->getRandomValue($field['data_type']);
 
     if ($randomValue) {
       return $randomValue;
     }
 
-    throw new \Exception('Could not provide default value');
+    throw new \API_Exception('Could not provide default value');
   }
 
   /**
@@ -127,13 +135,15 @@ class TestCreationParameterProvider {
   }
 
   /**
-   * @param \Civi\Api4\Service\Spec\FieldSpec $field
+   * Get an ID for the appropriate entity.
+   *
    * @param string $fkEntity
    *
    * @return mixed
-   * @throws \Exception
+   *
+   * @throws \API_Exception
    */
-  private function getFkID(FieldSpec $field, $fkEntity) {
+  private function getFkID(string $fkEntity) {
     $params = ['checkPermissions' => FALSE];
     // Be predictable about what type of contact we select
     if ($fkEntity === 'Contact') {
@@ -142,7 +152,7 @@ class TestCreationParameterProvider {
     $entityList = civicrm_api4($fkEntity, 'get', $params);
     if ($entityList->count() < 1) {
       $msg = sprintf('At least one %s is required in test', $fkEntity);
-      throw new \Exception($msg);
+      throw new \API_Exception($msg);
     }
 
     return $entityList->last()['id'];
@@ -159,7 +169,7 @@ class TestCreationParameterProvider {
         return TRUE;
 
       case 'Integer':
-        return rand(1, 2000);
+        return random_int(1, 2000);
 
       case 'String':
         return \CRM_Utils_String::createRandom(10, implode('', range('a', 'z')));
diff --git a/tests/phpunit/api/v4/services.xml b/tests/phpunit/api/v4/services.xml
deleted file mode 100644 (file)
index e5e9c69..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<container xmlns="http://symfony.com/schema/dic/services"
-           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-           xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
-
-    <services>
-        <service id="test.param_provider" class="api\v4\Service\TestCreationParameterProvider" public="true">
-            <argument type="service" id="spec_gatherer"/>
-        </service>
-    </services>
-</container>