Civi\Test - Allow `headless()->apply()` (etc) to execute without setup.sh
authorTim Otten <totten@civicrm.org>
Mon, 27 Jan 2020 23:59:41 +0000 (15:59 -0800)
committerTim Otten <totten@civicrm.org>
Tue, 28 Jan 2020 22:22:22 +0000 (14:22 -0800)
Before
------

If you have a copy of the `git` codebase and wish to run any of the headless
test suites, you *must* run `setup.sh` aka `GenCode` beforehand.

This is because certain files - `sql/civicrm.mysql` and
`sql/civicrm_data.mysql` - are used in the headless suite.  As large
auto-generated files, they are not provided in git.

After
-----

The files `sql/civicrm.mysql` and `sql/civicrm_data.mysql` are no longer
required by the test suite -- the headless tests will directly use the
`GenCode` classes to produce the needful.

Comments
--------

The general thrust of this commit is to find spots which read an SQL file, e.g.

```php
\Civi\Test::execute(file_get_contents("foobar.mysql"));
```

and instead call the generator for that file, e.g.:

```php
$schema = new \CRM_Core_CodeGen_Schema(\Civi\Test::codeGen());
$result = $schema->generateFooBar();
\Civi\Test::execute($result['foobar.mysql']);
});
```

In doing so, we incorporate a couple tricks:

* The SQL content is cached for the duration of the test-run (`Civi\Test::$statics`).
  Generating the SQL is not super expensive... but `Civi\Test::headless()->...apply()`
  may be called thousands of times, so it could add-up. Just cache it.
* Most of the `generateFooBar()` functions depend in some fashion on `ts()`. This
  commit depends on a preceding commit to make `ts()` more amenable to execution
  during early stages of the test.
    * Related discussion: https://chat.civicrm.org/civicrm/pl/ehohytqkf7bd5prg9w75dq4qqw

CRM/Core/CodeGen/Main.php
Civi/Test.php
Civi/Test/CiviEnvBuilder.php
Civi/Test/CiviEnvBuilder/CoreSchemaStep.php [new file with mode: 0644]
Civi/Test/Data.php

index 4ea9ba89342b1794ba1ed83d3775db9184a33a02..88a31222d60ae531b8b2a853d4f3178ebfdd9ace 100644 (file)
@@ -151,13 +151,17 @@ Alternatively you can get a version of CiviCRM that matches your PHP version
     return $this->sourceDigest;
   }
 
-  protected function init() {
+  /**
+   * @return static
+   */
+  public function init() {
     if (!$this->database || !$this->tables) {
       $specification = new CRM_Core_CodeGen_Specification();
       $specification->parse($this->schemaPath, $this->buildVersion);
       $this->database = $specification->database;
       $this->tables = $specification->tables;
     }
+    return $this;
   }
 
 }
index f1c787f9f1fc0c6bad0c96f8732677c897a2816d..7eb83cade19ad792b41ae8ab4c1ccca1e23a012f 100644 (file)
@@ -119,7 +119,7 @@ class Test {
         echo "Installing {$dbName} schema\n";
         \Civi\Test::schema()->dropAll();
       }, 'headless-drop')
-      ->sqlFile($civiRoot . "/sql/civicrm.mysql")
+      ->coreSchema()
       ->sql("DELETE FROM civicrm_extension")
       ->callback(function ($ctx) {
         \Civi\Test::data()->populate();
@@ -158,6 +158,19 @@ class Test {
     return self::$singletons['schema'];
   }
 
+  /**
+   * @return \CRM_Core_CodeGen_Main
+   */
+  public static function codeGen() {
+    if (!isset(self::$singletons['codeGen'])) {
+      $civiRoot = dirname(__DIR__);
+      $codeGen = new \CRM_Core_CodeGen_Main("$civiRoot/CRM/Core/DAO", "$civiRoot/sql", $civiRoot, "$civiRoot/templates", NULL, "UnitTests", NULL, "$civiRoot/xml/schema/Schema.xml", NULL);
+      $codeGen->init();
+      self::$singletons['codeGen'] = $codeGen;
+    }
+    return self::$singletons['codeGen'];
+  }
+
   /**
    * @return \Civi\Test\Data
    */
index 3a6ab883935abf630bee0a8c1f9db714185c086d..8bce9d1fbf5e6a57d03e389ee92330d33b6555b8 100644 (file)
@@ -2,6 +2,7 @@
 namespace Civi\Test;
 
 use Civi\Test\CiviEnvBuilder\CallbackStep;
+use Civi\Test\CiviEnvBuilder\CoreSchemaStep;
 use Civi\Test\CiviEnvBuilder\ExtensionsStep;
 use Civi\Test\CiviEnvBuilder\SqlFileStep;
 use Civi\Test\CiviEnvBuilder\SqlStep;
@@ -41,6 +42,15 @@ class CiviEnvBuilder {
     return $this->addStep(new CallbackStep($callback, $signature));
   }
 
+  /**
+   * Generate the core SQL tables.
+   *
+   * @return \Civi\Test\CiviEnvBuilder
+   */
+  public function coreSchema() {
+    return $this->addStep(new CoreSchemaStep());
+  }
+
   public function sql($sql) {
     return $this->addStep(new SqlStep($sql));
   }
diff --git a/Civi/Test/CiviEnvBuilder/CoreSchemaStep.php b/Civi/Test/CiviEnvBuilder/CoreSchemaStep.php
new file mode 100644 (file)
index 0000000..5f8e56a
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+namespace Civi\Test\CiviEnvBuilder;
+
+/**
+ * Class CoreSchemaStep
+ * @package Civi\Test\CiviEnvBuilder
+ *
+ * An initialization step which loads the core SQL schema.
+ *
+ * Note that the computation of the schema is cached for the duration of
+ * the PHP process (\Civi\Test::$statics).
+ */
+class CoreSchemaStep implements StepInterface {
+
+  /**
+   * @return array
+   *   - digest: string
+   *   - content: string
+   */
+  public function getSql() {
+    if (!isset(\Civi\Test::$statics['core_schema_sql'])) {
+      $schema = new \CRM_Core_CodeGen_Schema(\Civi\Test::codeGen());
+      $files = $schema->generateCreateSql();
+      \Civi\Test::$statics['core_schema_sql'] = [
+        'digest' => md5($files['civicrm.mysql']),
+        'content' => $files['civicrm.mysql'],
+      ];
+    }
+    return \Civi\Test::$statics['core_schema_sql'];
+  }
+
+  public function getSig() {
+    return $this->getSql()['digest'];
+  }
+
+  public function isValid() {
+    return TRUE;
+  }
+
+  /**
+   * @param \Civi\Test\CiviEnvBuilder $ctx
+   */
+  public function run($ctx) {
+    $sql = $this->getSql();
+    if (\Civi\Test::execute($sql['content']) === FALSE) {
+      throw new \RuntimeException("Cannot execute SQL");
+    }
+  }
+
+}
index afa377febd84dbcc29ef910acb4c0a5d23c0abae..8cada62629b6cb198f3ad8cc6b5c6056bc29c390 100644 (file)
@@ -21,7 +21,12 @@ class Data {
       \Civi\Test::execute('SET NAMES utf8');
       $sqlDir = dirname(dirname(__DIR__)) . "/sql";
 
-      $query2 = file_get_contents("$sqlDir/civicrm_data.mysql");
+      if (!isset(\Civi\Test::$statics['locale_data'])) {
+        $schema = new \CRM_Core_CodeGen_Schema(\Civi\Test::codeGen());
+        \Civi\Test::$statics['locale_data'] = $schema->generateLocaleDataSql('en_US');
+      }
+
+      $query2 = \Civi\Test::$statics['locale_data']["civicrm_data.mysql"];
       $query3 = file_get_contents("$sqlDir/test_data.mysql");
       $query4 = file_get_contents("$sqlDir/test_data_second_domain.mysql");
       if (\Civi\Test::execute($query2) === FALSE) {