Skip to content

Commit

Permalink
Merge 317f35f into a44de27
Browse files Browse the repository at this point in the history
  • Loading branch information
tuutti authored Aug 15, 2023
2 parents a44de27 + 317f35f commit 7fb01f9
Show file tree
Hide file tree
Showing 4 changed files with 306 additions and 0 deletions.
16 changes: 16 additions & 0 deletions modules/helfi_react_search/helfi_react_search.module
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,19 @@ function helfi_react_search_preprocess_paragraph(array &$variables) : void {
$variables['#attached']['drupalSettings']['helfi_react_search']['elastic_proxy_url'] = $proxyUrl;
}
}

/**
* Implements hook_theme().
*/
function helfi_react_search_theme() : array {
return [
'debug_item__search_api' => [
'variables' => [
'id' => NULL,
'label' => NULL,
'data' => [],
],
'template' => 'debug-item--search-api',
],
];
}
106 changes: 106 additions & 0 deletions modules/helfi_react_search/src/Plugin/DebugDataItem/SearchApiIndex.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

declare(strict_types=1);

namespace Drupal\helfi_react_search\Plugin\DebugDataItem;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\helfi_api_base\DebugDataItemPluginBase;
use Drupal\search_api\SearchApiException;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Plugin implementation of the debug_data_item.
*
* @DebugDataItem(
* id = "search_api",
* label = @Translation("SearchApi index"),
* description = @Translation("SearchApi index")
* )
*/
final class SearchApiIndex extends DebugDataItemPluginBase implements ContainerFactoryPluginInterface {

/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
private EntityTypeManagerInterface $entityTypeManager;

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) : self {
$instance = new self($configuration, $plugin_id, $plugin_definition);
$instance->entityTypeManager = $container->get('entity_type.manager');

return $instance;
}

/**
* {@inheritdoc}
*/
public function collect(): array {
$data = [];

if (!$this->entityTypeManager->hasDefinition('search_api_index')) {
return [];
}
$indexes = $this->entityTypeManager
->getStorage('search_api_index')
->loadMultiple();

if (!$indexes) {
return [];
}
/** @var \Drupal\search_api\IndexInterface $index */
foreach ($indexes as $index) {
$result = $status = NULL;

try {
$status = $index->getServerInstance()?->isAvailable();
$tracker = $index->getTrackerInstance();

$result = $this->resolveResult(
$tracker->getIndexedItemsCount(),
$tracker->getTotalItemsCount()
);

}
catch (SearchApiException) {
}
$data[] = [
'id' => $index->getOriginalId(),
'result' => $result,
'status' => $status,
];
}

return $data;
}

/**
* Resolve return value based on index status.
*
* @param int $indexed
* Amount of up-to-date items in index.
* @param int $total
* Maximum number of items in index.
*
* @return string
* Status.
*/
private function resolveResult(int $indexed, int $total): string {
if ($indexed == 0 || $total == 0) {
return 'indexing or index rebuild required';
}

if ($indexed === $total) {
return 'Index up to date';
}

return "$indexed/$total";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{#
/**
* To actually show any data from a custom plugin, you *MUST* override this template
* with a template called 'debug-item--{{ id }}.html.twig'.
*
* For example: debug-item--composer.html.twig, where 'composer' is your plugin's ID.
*
* You can then loop your data with something like this:
* {% for item in data.packages %}
* {{ item.name }}
* {{ item.version }}
* {% endfor %}
*
* Available variables:
* - id: The ID of your plugin
* - label The label of your plugin
* - data: An array of data returned by your plugin's collect() method.
*/
#}

<h2>{{ 'Search API indexes'|t }}</h2>
<table style="width:auto;" aria-label="{{ 'Search API indexes'|t }}">
<thead>
<tr>
<th>Index</th>
<th>Status</th>
<th>Result</th>
</tr>
</thead>
<tbody>
{% for value in data %}
<tr>
<td>
{{ value.id }}
</td>
<td>
{{ value.status ? 'Online'|t : 'Offline'|t }}
</td>
<td>
{{ value.result }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
139 changes: 139 additions & 0 deletions modules/helfi_react_search/tests/src/Unit/SearchApiIndexItemTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

declare(strict_types = 1);

namespace Drupal\Tests\helfi_react_search\Unit;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\helfi_react_search\Plugin\DebugDataItem\SearchApiIndex;
use Drupal\search_api\Entity\SearchApiConfigEntityStorage;
use Drupal\search_api\IndexInterface;
use Drupal\search_api\SearchApiException;
use Drupal\search_api\ServerInterface;
use Drupal\search_api\Tracker\TrackerInterface;
use Drupal\Tests\UnitTestCase;
use Prophecy\PhpUnit\ProphecyTrait;

/**
* Tests Search api index plugin.
*
* @coversDefaultClass \Drupal\helfi_react_search\Plugin\DebugDataItem\SearchApiIndex
* @group helfi_api_base
*/
class SearchApiIndexItemTest extends UnitTestCase {

use ProphecyTrait;

/**
* @covers ::create
* @covers ::collect
*/
public function testNoSearchApiStorage() : void {
$entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$entityTypeManager->hasDefinition('search_api_index')->willReturn(FALSE);
$container = new ContainerBuilder();
$container->set('entity_type.manager', $entityTypeManager->reveal());
$sut = SearchApiIndex::create($container, [], '', []);
$this->assertEmpty($sut->collect());
}

/**
* @covers ::create
* @covers ::collect
*/
public function testNoIndex() : void {
$indexStorage = $this->prophesize(SearchApiConfigEntityStorage::class);
$indexStorage->loadMultiple()->willReturn([]);
$entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$entityTypeManager->hasDefinition('search_api_index')
->willReturn(TRUE);
$entityTypeManager->getStorage('search_api_index')
->willReturn($indexStorage->reveal());
$container = new ContainerBuilder();
$container->set('entity_type.manager', $entityTypeManager->reveal());

$sut = SearchApiIndex::create($container, [], '', []);
$this->assertEmpty($sut->collect());
}

/**
* @covers ::create
* @covers ::collect
* @covers ::resolveResult
*/
public function testCollect() : void {
$index1 = $this->prophesize(IndexInterface::class);
$index1->getOriginalId()->willReturn('index1');
$index1->getServerInstance()->willThrow(new SearchApiException());

$server = $this->prophesize(ServerInterface::class);
$server->isAvailable()->willReturn(TRUE);

$tracker2 = $this->prophesize(TrackerInterface::class);
$tracker2->getIndexedItemsCount()->willReturn(0);
$tracker2->getTotalItemsCount()->willReturn(0);

$index2 = $this->prophesize(IndexInterface::class);
$index2->getOriginalId()->willReturn('index2');
$index2->getServerInstance()->willReturn($server->reveal());
$index2->getTrackerInstance()->willReturn($tracker2->reveal());

$tracker3 = $this->prophesize(TrackerInterface::class);
$tracker3->getIndexedItemsCount()->willReturn(20);
$tracker3->getTotalItemsCount()->willReturn(20);

$index3 = $this->prophesize(IndexInterface::class);
$index3->getOriginalId()->willReturn('index3');
$index3->getServerInstance()->willReturn($server->reveal());
$index3->getTrackerInstance()->willReturn($tracker3->reveal());

$tracker4 = $this->prophesize(TrackerInterface::class);
$tracker4->getIndexedItemsCount()->willReturn(10);
$tracker4->getTotalItemsCount()->willReturn(20);
$index4 = $this->prophesize(IndexInterface::class);
$index4->getOriginalId()->willReturn('index4');
$index4->getServerInstance()->willReturn($server->reveal());
$index4->getTrackerInstance()->willReturn($tracker4->reveal());

$indexStorage = $this->prophesize(SearchApiConfigEntityStorage::class);
$indexStorage->loadMultiple()->willReturn([
$index1->reveal(),
$index2->reveal(),
$index3->reveal(),
$index4->reveal(),
]);
$entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
$entityTypeManager->getStorage('search_api_index')
->willReturn($indexStorage->reveal());
$entityTypeManager->hasDefinition('search_api_index')
->willReturn(TRUE);
$container = new ContainerBuilder();
$container->set('entity_type.manager', $entityTypeManager->reveal());

$sut = SearchApiIndex::create($container, [], '', []);
$this->assertEquals([
[
'id' => 'index1',
'result' => NULL,
'status' => NULL,
],
[
'id' => 'index2',
'result' => 'indexing or index rebuild required',
'status' => TRUE,
],
[
'id' => 'index3',
'result' => 'Index up to date',
'status' => TRUE,
],
[
'id' => 'index4',
'result' => '10/20',
'status' => TRUE,
],
], $sut->collect());
}

}

0 comments on commit 7fb01f9

Please sign in to comment.