Skip to content

Commit e23e5a7

Browse files
authored
PHPORM-432 Wait for search indexes to be dropped before creating new one in tests (#3460)
* Use a distinct collection names for each test using atlas search indexes * Revert to only wait for the previous search indexes to be dropped * Factorize search indexes waiting helper
1 parent dee170a commit e23e5a7

File tree

4 files changed

+81
-32
lines changed

4 files changed

+81
-32
lines changed

docs/includes/fundamentals/as-avs/AtlasSearchTest.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@
88
use Illuminate\Support\Facades\DB;
99
use MongoDB\Builder\Query;
1010
use MongoDB\Builder\Search;
11+
use MongoDB\Collection;
1112
use MongoDB\Driver\Exception\ServerException;
1213
use MongoDB\Laravel\Schema\Builder;
14+
use MongoDB\Laravel\Tests\AtlasSearchIndexManagement;
1315
use MongoDB\Laravel\Tests\TestCase;
1416
use PHPUnit\Framework\Attributes\Group;
1517

@@ -18,11 +20,12 @@
1820
use function rand;
1921
use function range;
2022
use function srand;
21-
use function usleep;
2223

2324
#[Group('atlas-search')]
2425
class AtlasSearchTest extends TestCase
2526
{
27+
use AtlasSearchIndexManagement;
28+
2629
private array $vectors;
2730

2831
protected function setUp(): void
@@ -32,6 +35,7 @@ protected function setUp(): void
3235
parent::setUp();
3336

3437
$moviesCollection = DB::connection('mongodb')->getCollection('movies');
38+
self::assertInstanceOf(Collection::class, $moviesCollection);
3539
$moviesCollection->drop();
3640

3741
Movie::insert([
@@ -49,7 +53,7 @@ protected function setUp(): void
4953
['title' => 'D', 'plot' => 'Stranded on a distant planet, astronauts must repair their ship before supplies run out.'],
5054
]));
5155

52-
$moviesCollection = DB::connection('mongodb')->getCollection('movies');
56+
$this->waitForSearchIndexesDropped($moviesCollection);
5357

5458
try {
5559
$moviesCollection->createSearchIndex([
@@ -82,16 +86,7 @@ protected function setUp(): void
8286
throw $e;
8387
}
8488

85-
// Waits for the index to be ready
86-
do {
87-
$ready = true;
88-
usleep(10_000);
89-
foreach ($moviesCollection->listSearchIndexes() as $index) {
90-
if ($index['status'] !== 'READY') {
91-
$ready = false;
92-
}
93-
}
94-
} while (! $ready);
89+
$this->waitForSearchIndexesReady($moviesCollection);
9590
}
9691

9792
/**
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace MongoDB\Laravel\Tests;
4+
5+
use MongoDB\Collection;
6+
use RuntimeException;
7+
8+
use function hrtime;
9+
use function usleep;
10+
11+
/**
12+
* Helpers for managing Atlas Search indexes in tests with awaiting mechanism.
13+
*/
14+
trait AtlasSearchIndexManagement
15+
{
16+
/**
17+
* Waits for the search index created in the previous test to be deleted
18+
*/
19+
public function waitForSearchIndexesDropped(Collection $collection)
20+
{
21+
$timeout = hrtime()[0] + 30;
22+
// Waits for the search index created in the previous test to be deleted
23+
while ($collection->listSearchIndexes()->count()) {
24+
if (hrtime()[0] > $timeout) {
25+
throw new RuntimeException('Timed out waiting for search indexes to be dropped');
26+
}
27+
28+
usleep(1000);
29+
}
30+
}
31+
32+
/**
33+
* Waits for all search indexes to be ready
34+
*/
35+
public function waitForSearchIndexesReady(Collection $collection)
36+
{
37+
$timeout = hrtime()[0] + 30;
38+
do {
39+
if (hrtime()[0] > $timeout) {
40+
throw new RuntimeException('Timed out waiting for search indexes to be ready');
41+
}
42+
43+
usleep(1000);
44+
$ready = true;
45+
foreach ($collection->listSearchIndexes() as $index) {
46+
$ready = $ready && $index['queryable'];
47+
}
48+
} while (! $ready);
49+
}
50+
}

tests/AtlasSearchTest.php

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,23 @@
1919
use function rand;
2020
use function range;
2121
use function srand;
22-
use function usleep;
2322
use function usort;
2423

2524
#[Group('atlas-search')]
2625
class AtlasSearchTest extends TestCase
2726
{
27+
use AtlasSearchIndexManagement;
28+
2829
private array $vectors;
2930

3031
public function setUp(): void
3132
{
3233
parent::setUp();
3334

35+
$collection = $this->getConnection('mongodb')->getCollection('books');
36+
assert($collection instanceof MongoDBCollection);
37+
$collection->drop();
38+
3439
Book::insert($this->addVector([
3540
['title' => 'Introduction to Algorithms'],
3641
['title' => 'Clean Code: A Handbook of Agile Software Craftsmanship'],
@@ -54,10 +59,9 @@ public function setUp(): void
5459
['title' => 'Pattern Recognition and Machine Learning'],
5560
]));
5661

57-
$collection = $this->getConnection('mongodb')->getCollection('books');
58-
assert($collection instanceof MongoDBCollection);
59-
6062
try {
63+
$this->waitForSearchIndexesDropped($collection);
64+
6165
$collection->createSearchIndex([
6266
'mappings' => [
6367
'fields' => [
@@ -89,16 +93,7 @@ public function setUp(): void
8993
throw $e;
9094
}
9195

92-
// Wait for the index to be ready
93-
do {
94-
$ready = true;
95-
usleep(10_000);
96-
foreach ($collection->listSearchIndexes() as $index) {
97-
if ($index['status'] !== 'READY') {
98-
$ready = false;
99-
}
100-
}
101-
} while (! $ready);
96+
$this->waitForSearchIndexesReady($collection);
10297
}
10398

10499
public function tearDown(): void

tests/Scout/ScoutIntegrationTest.php

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Illuminate\Support\LazyCollection;
88
use Laravel\Scout\ScoutServiceProvider;
99
use LogicException;
10+
use MongoDB\Laravel\Tests\AtlasSearchIndexManagement;
1011
use MongoDB\Laravel\Tests\Scout\Models\ScoutUser;
1112
use MongoDB\Laravel\Tests\Scout\Models\SearchableInSameNamespace;
1213
use MongoDB\Laravel\Tests\TestCase;
@@ -17,6 +18,7 @@
1718
use function array_merge;
1819
use function count;
1920
use function env;
21+
use function hrtime;
2022
use function iterator_to_array;
2123
use function Orchestra\Testbench\artisan;
2224
use function range;
@@ -26,6 +28,8 @@
2628
#[Group('atlas-search')]
2729
class ScoutIntegrationTest extends TestCase
2830
{
31+
use AtlasSearchIndexManagement;
32+
2933
#[Override]
3034
protected function getPackageProviders($app): array
3135
{
@@ -96,23 +100,28 @@ public function setUp(): void
96100
/** This test create the search index for tests performing search */
97101
public function testItCanCreateTheCollection()
98102
{
103+
$this->skipIfSearchIndexManagementIsNotSupported();
104+
99105
$collection = DB::connection('mongodb')->getCollection('prefix_scout_users');
100106
$collection->drop();
107+
$this->waitForSearchIndexesDropped($collection);
101108

102109
// Recreate the indexes using the artisan commands
103110
// Ensure they return a success exit code (0)
104111
self::assertSame(0, artisan($this, 'scout:delete-index', ['name' => ScoutUser::class]));
105-
self::assertSame(0, artisan($this, 'scout:index', ['name' => ScoutUser::class]));
106112
self::assertSame(0, artisan($this, 'scout:import', ['model' => ScoutUser::class]));
113+
self::assertSame(0, artisan($this, 'scout:index', ['name' => ScoutUser::class]));
107114

108115
self::assertSame(44, $collection->countDocuments());
109116

110117
$searchIndexes = $collection->listSearchIndexes(['name' => 'scout', 'typeMap' => ['root' => 'array', 'document' => 'array', 'array' => 'array']]);
111118
self::assertCount(1, $searchIndexes);
112119
self::assertSame(['mappings' => ['dynamic' => true, 'fields' => ['bool_field' => ['type' => 'boolean']]]], iterator_to_array($searchIndexes)[0]['latestDefinition']);
113120

121+
$this->waitForSearchIndexesReady($collection);
122+
114123
// Wait for all documents to be indexed asynchronously
115-
$i = 100;
124+
$timeout = hrtime()[0] + 30;
116125
while (true) {
117126
$indexedDocuments = $collection->aggregate([
118127
['$search' => ['index' => 'scout', 'exists' => ['path' => 'name']]],
@@ -122,11 +131,11 @@ public function testItCanCreateTheCollection()
122131
break;
123132
}
124133

125-
if ($i-- === 0) {
126-
self::fail('Documents not indexed');
134+
if (hrtime()[0] > $timeout) {
135+
self::fail('Timed out waiting for documents to be indexed');
127136
}
128137

129-
usleep(100_000);
138+
usleep(1000);
130139
}
131140

132141
self::assertCount(44, $indexedDocuments);
@@ -135,7 +144,7 @@ public function testItCanCreateTheCollection()
135144
#[Depends('testItCanCreateTheCollection')]
136145
public function testItCanUseBasicSearch()
137146
{
138-
// All the search queries use "sort" option to ensure the results are deterministic
147+
// All the search queries use the "sort" option to ensure the results are deterministic
139148
$results = ScoutUser::search('lar')->take(10)->orderBy('id')->get();
140149

141150
self::assertSame([

0 commit comments

Comments
 (0)