You are here

public function BasicTrackerTest::testTracking in Search API 8

Tests tracking.

@dataProvider trackingDataProvider

Parameters

string $indexing_order: The indexing order setting to use – "fifo" or "lifo".

File

tests/src/Kernel/BasicTrackerTest.php, line 86

Class

BasicTrackerTest
Tests the "default" tracker plugin.

Namespace

Drupal\Tests\search_api\Kernel

Code

public function testTracking($indexing_order) {

  // Add a logger that throws an exception when used, so a caught exception
  // within any of the tracker methods will still cause a test fail.

  /** @var \PHPUnit\Framework\MockObject\MockObject|\Psr\Log\LoggerInterface $logger */
  $logger = $this
    ->createMock(LoggerInterface::class);
  $logger
    ->method('log')
    ->willReturnCallback(function ($level, $message, array $variables) {
    $error = 'Tracking operation threw ';
    $error .= strtr($message, $variables);
    throw new \Exception($error);
  });
  $this->tracker
    ->setLogger($logger);
  $this->tracker
    ->setConfiguration([
    'indexing_order' => $indexing_order,
  ]);
  $datasource_1 = 'test1';
  $datasource_2 = 'test2';
  $ids = [];
  foreach ([
    $datasource_1,
    $datasource_2,
  ] as $num => $datasource_id) {
    foreach ([
      1,
      2,
      3,
    ] as $raw_id) {
      $ids[$num][] = Utility::createCombinedId($datasource_id, $raw_id);
    }
  }

  // Make sure we start from a "clean slate".
  $this
    ->assertIndexingStatus(0, 0);
  $this
    ->assertIndexingStatus(0, 0, $datasource_1);
  $this
    ->assertIndexingStatus(0, 0, $datasource_2);

  // Make sure tracking items as deleted, updated or indexed has no effect if
  // none were inserted before.
  $this->tracker
    ->trackItemsDeleted([
    $ids[0][0],
  ]);
  $this
    ->assertIndexingStatus(0, 0);
  $this->tracker
    ->trackItemsUpdated([
    $ids[0][0],
  ]);
  $this
    ->assertIndexingStatus(0, 0);
  $this->tracker
    ->trackItemsIndexed([
    $ids[0][0],
  ]);
  $this
    ->assertIndexingStatus(0, 0);

  // Now, finally, actually do something sensible and insert some items.
  $this->tracker
    ->trackItemsInserted([
    $ids[0][0],
  ]);
  $this->tracker
    ->trackItemsInserted([
    $ids[1][1],
  ]);
  $this->timeService
    ->advanceTime();
  $this->tracker
    ->trackItemsInserted([
    $ids[0][2],
    $ids[1][0],
  ]);
  $this->timeService
    ->advanceTime();

  // Make sure re-inserting an item doesn't cause problems.
  $this->tracker
    ->trackItemsInserted([
    $ids[0][1],
    $ids[1][2],
    $ids[0][0],
  ]);
  $this->timeService
    ->advanceTime();
  $this
    ->assertIndexingStatus(0, 6);
  $this
    ->assertIndexingStatus(0, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 3, $datasource_2);

  // Make sure the remaining items are returned as expected.
  $fifo = $indexing_order === 'fifo';
  $to_index = $this->tracker
    ->getRemainingItems(4);
  sort($to_index);
  if ($fifo) {
    $expected = [
      $ids[0][0],
      $ids[0][2],
      $ids[1][0],
      $ids[1][1],
    ];
  }
  else {
    $expected = [
      $ids[0][1],
      $ids[0][2],
      $ids[1][0],
      $ids[1][2],
    ];
  }
  $this
    ->assertEquals($expected, $to_index);
  $to_index = $this->tracker
    ->getRemainingItems(1, $datasource_1);
  if ($fifo) {
    $expected = [
      $ids[0][0],
    ];
  }
  else {
    $expected = [
      $ids[0][1],
    ];
  }
  $this
    ->assertEquals($expected, $to_index);
  $to_index = $this->tracker
    ->getRemainingItems(-1);
  sort($to_index);
  $expected = array_merge($ids[0], $ids[1]);
  $this
    ->assertEquals($expected, $to_index);
  $to_index = $this->tracker
    ->getRemainingItems(-1, $datasource_2);
  sort($to_index);
  $this
    ->assertEquals($ids[1], $to_index);

  // Make sure that tracking an unindexed item as updated will not affect its
  // position for FIFO, but will get it to the front for LIFO. (If we do this
  // with the item that's in front for FIFO anyways, we can use the same code
  // in both cases.)
  $this->tracker
    ->trackItemsUpdated([
    $ids[0][0],
  ]);
  $this->timeService
    ->advanceTime();
  $to_index = $this->tracker
    ->getRemainingItems(1, $datasource_1);
  $this
    ->assertEquals([
    $ids[0][0],
  ], $to_index);

  // Make sure calling methods with an empty $ids array doesn't blow anything
  // up.
  $this->tracker
    ->trackItemsInserted([]);
  $this->tracker
    ->trackItemsUpdated([]);
  $this->tracker
    ->trackItemsIndexed([]);
  $this->tracker
    ->trackItemsDeleted([]);

  // None of this should have changed the indexing status of any items.
  $this
    ->assertIndexingStatus(0, 6);
  $this
    ->assertIndexingStatus(0, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 3, $datasource_2);

  // Now, change the status of some of the items.
  $this->tracker
    ->trackItemsIndexed([
    $ids[0][0],
    $ids[0][1],
    $ids[1][0],
  ]);
  $this
    ->assertIndexingStatus(3, 6);
  $this
    ->assertIndexingStatus(2, 3, $datasource_1);
  $this
    ->assertIndexingStatus(1, 3, $datasource_2);
  $to_index = $this->tracker
    ->getRemainingItems(-1);
  sort($to_index);
  $expected = [
    $ids[0][2],
    $ids[1][1],
    $ids[1][2],
  ];
  $this
    ->assertEquals($expected, $to_index);
  $this->tracker
    ->trackItemsUpdated([
    $ids[0][0],
    $ids[0][2],
  ]);
  $this->timeService
    ->advanceTime();
  $this
    ->assertIndexingStatus(2, 6);
  $this
    ->assertIndexingStatus(1, 3, $datasource_1);
  $this
    ->assertIndexingStatus(1, 3, $datasource_2);
  $to_index = $this->tracker
    ->getRemainingItems(-1);
  sort($to_index);
  array_unshift($expected, $ids[0][0]);
  $this
    ->assertEquals($expected, $to_index);
  $this->tracker
    ->trackItemsDeleted([
    $ids[1][0],
    $ids[1][2],
  ]);
  $this
    ->assertIndexingStatus(1, 4);
  $this
    ->assertIndexingStatus(1, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 1, $datasource_2);
  $to_index = $this->tracker
    ->getRemainingItems(-1);
  sort($to_index);

  // The last element of $expected is $ids[1][2], which we just deleted.
  unset($expected[3]);
  $this
    ->assertEquals($expected, $to_index);

  // Make sure the right items are "at the front" of the queue in each case.
  if ($fifo) {

    // These are the only two (remaining) items that were never indexed, so
    // they still have their original insert time stamp and thus go first.
    $expected = [
      $ids[0][2],
      $ids[1][1],
    ];
  }
  else {

    // We just tracked an update for both of these, so they go first.
    $expected = [
      $ids[0][0],
      $ids[0][2],
    ];
  }
  $to_index = $this->tracker
    ->getRemainingItems(2);
  sort($to_index);
  $this
    ->assertEquals($expected, $to_index);

  // Some more status changes.
  $this->tracker
    ->trackItemsInserted([
    $ids[1][2],
  ]);
  $this->timeService
    ->advanceTime();
  $this
    ->assertIndexingStatus(1, 5);
  $this
    ->assertIndexingStatus(1, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 2, $datasource_2);
  $this->tracker
    ->trackItemsIndexed(array_merge($ids[0], $ids[1]));
  $this
    ->assertIndexingStatus(5, 5);
  $this
    ->assertIndexingStatus(3, 3, $datasource_1);
  $this
    ->assertIndexingStatus(2, 2, $datasource_2);
  $this->tracker
    ->trackAllItemsUpdated($datasource_1);
  $this->timeService
    ->advanceTime();
  $this
    ->assertIndexingStatus(2, 5);
  $this
    ->assertIndexingStatus(0, 3, $datasource_1);
  $this
    ->assertIndexingStatus(2, 2, $datasource_2);
  $this->tracker
    ->trackItemsIndexed([
    $ids[0][0],
  ]);
  $this
    ->assertIndexingStatus(3, 5);
  $this
    ->assertIndexingStatus(1, 3, $datasource_1);
  $this
    ->assertIndexingStatus(2, 2, $datasource_2);
  $this->tracker
    ->trackAllItemsUpdated();
  $this->timeService
    ->advanceTime();
  $this
    ->assertIndexingStatus(0, 5);
  $this
    ->assertIndexingStatus(0, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 2, $datasource_2);
  $this->tracker
    ->trackAllItemsDeleted($datasource_2);
  $this
    ->assertIndexingStatus(0, 3);
  $this
    ->assertIndexingStatus(0, 3, $datasource_1);
  $this
    ->assertIndexingStatus(0, 0, $datasource_2);
  $this->tracker
    ->trackAllItemsDeleted();
  $this
    ->assertIndexingStatus(0, 0);
  $this
    ->assertIndexingStatus(0, 0, $datasource_1);
  $this
    ->assertIndexingStatus(0, 0, $datasource_2);
}