drupal_yext-8.x-1.0/src/SelfTest/SelfTest.php
src/SelfTest/SelfTest.php
<?php
namespace Drupal\drupal_yext\SelfTest;
use Drupal\drupal_yext\traits\Singleton;
use Drupal\drupal_yext\traits\CommonUtilities;
use Drupal\drupal_yext\YextContent\NodeMigrationAtCreation;
use Drupal\drupal_yext\YextContent\YextEntityFactory;
use Drupal\drupal_yext\YextContent\YextSourceRecord;
use Drupal\drupal_yext\YextContent\YextTargetNode;
// drupal_yext_find_by_title is not a dependency of drupal_yext, however
// in this context this is self-test code and it's being run by the
// the CI script, so we can control whether drupal_yext_find_by_title is
// enabled, plus we're explicitly checking that it's enabled before using
// it.
use Drupal\drupal_yext_find_by_title\YextFindByTitle;
/**
* Run some self tests.
*
* Usage:
*
* ./scripts/self-test-running-environment.sh
*/
class SelfTest {
use Singleton;
use CommonUtilities;
/**
* Assert that two values are equal.
*
* @param mixed $val1
* The first value.
* @param mixed $val2
* The second value.
* @param string $desc
* Description of the test.
*/
public function assert($val1, $val2, string $desc) {
$this->print('Testing that ' . $desc);
$this->print('val1 (should be equal to val2):');
$this->print($val1);
$this->print(PHP_EOL);
$this->print('val2 (should be equal to val1):');
$this->print($val2);
$this->print(PHP_EOL);
if ($val1 === $val2) {
$this->print('TEST PASSED');
}
else {
$this->print('TEST FAILED :( KILLING THE PROCESS');
throw new \Exception('Test failed');
}
}
/**
* Generate a dummy node.
*
* @param string $title
* The node title.
*
* @return array
* An array with one item whose key is the node id, and the value is
* an object of class YextTargetNode.
*/
public function generateDummy(string $title) : array {
$node = YextEntityFactory::instance()->generate('node', 'article');
$node->drupalEntity()->setTitle($title);
$node->drupalEntity()->save();
return [
$node->id() => $node,
];
}
/**
* Print something to the screen.
*
* @param mixed $data
* A string or anything else which can be printed.
*/
public function print($data) {
if (is_string($data)) {
print_r($data . PHP_EOL);
}
else {
print_r($data);
}
}
/**
* Perform a mock migration of one record from Yext to Drupal.
*
* @param array $structure
* A mock data structure on Yext.
*
* @return \Drupal\drupal_yext\YextContent\YextTargetNode
* A resulting target node on Drupal.
*/
public function mockMigrate(array $structure) : YextTargetNode {
$source = new YextSourceRecord($structure);
$entity = $this->yext()->getOrCreateUniqueNode($source);
(new NodeMigrationAtCreation($source, $entity))->migrate();
$this->assert($entity->drupalEntity()->getTitle(), $structure['locationName'], 'Drupal entity title should be the location name when mock migrating a record.');
return $entity;
}
/**
* Run some self-tests. Exit with non-zero code if errors occur.
*
* Usage:
*
* ./scripts/self-test-running-environment.sh
*/
public function run() {
$live_key = $this->stateGet('drupal_yext_api', '');
$old_dryrun = $this->stateGet('drupal_yext_dryrun', FALSE);
$error = FALSE;
$entity = NULL;
$entity5 = NULL;
$entityImport = NULL;
$dummy_nodes = [];
try {
$this->print('Starting self-test.');
$this->assert($this->drupalModuleHandler()->moduleExists('drupal_yext_find_by_title'), TRUE, 'Please enable the drupal_yext_find_by_title module before running selftests.');
$this->print('Confirming we can create a new node based on Yext data.');
$this->stateSet('drupal_yext_api', 'dummy-key');
$this->stateSet('drupal_yext_dryrun', TRUE);
$entity = $this->mockMigrate([
'id' => '12345',
'locationName' => 'Hello World',
'timestamp' => 2,
]);
$this->print('Created entity with id ' . $entity->id() . '.');
$this->assert($entity->drupalEntity()->getTitle(), 'Hello World', 'node title is location name');
$entity2 = $this->mockMigrate([
'id' => '12345',
'locationName' => 'Hello World2',
'timestamp' => 1,
]);
$this->assert($entity->id(), $entity2->id(), 'the second time we try to get or creat the entity, the existing entity is returned because the yext id is the same.');
$this->assert($entity->drupalEntity()->getTitle(), 'Hello World', 'node title is NOT updated location name because timestamp of second migrated item is earlier than the first');
$entity3 = $this->mockMigrate([
'id' => '12345',
'locationName' => 'Hello World2',
'timestamp' => 3,
]);
$this->assert($entity3->id(), $entity2->id(), 'the third time we try to get or creat the entity, the existing entity is returned because the yext id is the same.');
$this->assert($entity3->drupalEntity()->getTitle(), 'Hello World2', 'node title is updated location name because timestamp of third migrated item is later than the first');
$this->print('Creating some dummy nodes.');
$random = rand();
$dummy_nodes += $this->generateDummy($random . 'ONE OF THESE');
$dummy_nodes += $this->generateDummy($random . 'TWO OF THESE');
$dummy_nodes += $this->generateDummy($random . 'TWO OF THESE');
$dummy_nodes += $this->generateDummy($random . 'ONE OF THESE IS EMPTY');
$has_yext_id = $this->generateDummy($random . 'ONE OF THESE IS EMPTY');
$has_yext_id = array_pop($has_yext_id);
$has_yext_id->setYextId('whatever');
$has_yext_id->drupalEntity()->save();
$dummy_nodes += [
$has_yext_id->id() => $has_yext_id,
];
$this->assert(FALSE, is_null(YextFindByTitle::instance()->candidate($random . 'ONE OF THESE')), 'If there is only one node with no yext ID and a specific title, use it.');
$this->assert(TRUE, is_null(YextFindByTitle::instance()->candidate($random . 'TWO OF THESE')), 'If there is more than one node with a specific title, do not use it as it is too ambiguous.');
$this->assert(FALSE, is_null(YextFindByTitle::instance()->candidate($random . 'ONE OF THESE IS EMPTY')), 'If there are two nodes with a specific title, but one already has a yext id, then use the other one.');
$entity4 = $this->mockMigrate([
'id' => 'not important ' . rand(),
'locationName' => $random . 'ONE OF THESE',
'timestamp' => 1,
]);
$entity5 = $this->mockMigrate([
'id' => 'not important ' . rand(),
'locationName' => $random . 'TWO OF THESE',
'timestamp' => 1,
]);
$entity6 = $this->mockMigrate([
'id' => 'not important ' . rand(),
'locationName' => $random . 'ONE OF THESE IS EMPTY',
'timestamp' => 1,
]);
$entityImport = $this->mockMigrate([
'id' => 'not important ' . rand(),
'locationName' => rand() . ' RANDOM',
'customFields' => [
'123' => 'hello',
'345' => [
'hello',
'world',
],
],
'single' => 'hello2',
'multi' => [
'hello2',
'world2',
],
'timestamp' => 1,
]);
$this->assert($entityImport->drupalEntity()->get('field_numeric_single')->getValue(), [
[
"value" => "hello",
],
], 'field_numeric_single import works');
$this->assert($entityImport->drupalEntity()->get('field_numeric_multi')->getValue(), [
[
"value" => "hello",
],
[
"value" => "world",
],
], 'field_numeric_multi import works');
$this->assert($entityImport->drupalEntity()->get('field_non_numeric_single')->getValue(), [
[
"value" => "hello2",
],
], 'field_non_numeric_single import works');
$this->assert($entityImport->drupalEntity()->get('field_non_numeric_multi')->getValue(), [
[
"value" => "hello2",
],
[
"value" => "world2",
],
], 'field_non_numeric_multi import works');
$this->assert(TRUE, in_array($entity4->id(), array_keys($dummy_nodes)), 'Uses existing node if possible (1).');
$this->assert(FALSE, in_array($entity5->id(), array_keys($dummy_nodes)), 'Uses new node if existing title is ambiguous.');
$this->assert(TRUE, in_array($entity6->id(), array_keys($dummy_nodes)), 'Uses existing node if possible (2).');
$this->print('Self-test completed successfully.');
}
catch (\Throwable $t) {
$error = TRUE;
$this->print($t->getMessage());
$this->print('An error occurred, aborting.');
}
$this->print('Deleting the entities we created.');
if ($entity) {
$entity->drupalEntity()->delete();
}
foreach ($dummy_nodes as $node) {
$node->drupalEntity()->delete();
}
if ($entity5) {
$entity5->drupalEntity()->delete();
}
if ($entityImport) {
$entityImport->drupalEntity()->delete();
}
$this->stateSet('drupal_yext_api', $live_key);
$this->stateSet('drupal_yext_dryrun', $old_dryrun);
if ($error) {
$this->print('');
$this->print('Exiting with error.');
$this->print('');
die(1);
}
$this->print('');
$this->print('SELF-TEST: SUCCESS!');
$this->print('');
}
}
