httpClient = $this->createMock(HttpClientInterface::class); $this->bus = $this->createMock(MessageBusInterface::class); $this->cache = new ArrayAdapter(); $this->service = new MeilisearchService( $this->httpClient, $this->bus, 'http://meilisearch:7700', 'test-key', $this->cache, ); } public function testIndexExistsReturnsTrue(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $this->httpClient->method('request')->willReturn($response); self::assertTrue($this->service->indexExists('events')); } public function testIndexExistsReturnsFalseOnException(): void { $this->httpClient->method('request')->willThrowException(new \RuntimeException('fail')); self::assertFalse($this->service->indexExists('events')); } public function testCreateIndexIfNotExistsCreatesWhenMissing(): void { $this->httpClient->method('request')->willThrowException(new \RuntimeException('not found')); $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'createIndex' === $m->action)) ->willReturn(new Envelope(new \stdClass())); $this->service->createIndexIfNotExists('events'); } public function testCreateIndexIfNotExistsSkipsWhenExists(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $this->httpClient->method('request')->willReturn($response); $this->bus->expects(self::never())->method('dispatch'); $this->service->createIndexIfNotExists('events'); } public function testCreateIndexDispatchesMessage(): void { $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'createIndex' === $m->action && 'events' === $m->index)) ->willReturn(new Envelope(new \stdClass())); $this->service->createIndex('events'); } public function testDeleteIndexDispatchesMessage(): void { $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'deleteIndex' === $m->action)) ->willReturn(new Envelope(new \stdClass())); $this->service->deleteIndex('events'); } public function testAddDocumentsDispatchesMessage(): void { $docs = [['id' => 1, 'title' => 'Test']]; $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'addDocuments' === $m->action && $m->payload['documents'] === $docs)) ->willReturn(new Envelope(new \stdClass())); $this->service->addDocuments('events', $docs); } public function testUpdateDocumentsDispatchesMessage(): void { $docs = [['id' => 1, 'title' => 'Updated']]; $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'updateDocuments' === $m->action && $m->payload['documents'] === $docs)) ->willReturn(new Envelope(new \stdClass())); $this->service->updateDocuments('events', $docs); } public function testDeleteDocumentDispatchesMessage(): void { $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'deleteDocument' === $m->action && 42 === $m->payload['documentId'])) ->willReturn(new Envelope(new \stdClass())); $this->service->deleteDocument('events', 42); } public function testDeleteDocumentsDispatchesMessage(): void { $ids = [1, 2, 3]; $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'deleteDocuments' === $m->action && $m->payload['ids'] === $ids)) ->willReturn(new Envelope(new \stdClass())); $this->service->deleteDocuments('events', $ids); } public function testUpdateSettingsDispatchesMessage(): void { $settings = ['filterableAttributes' => ['status']]; $this->bus->expects(self::once()) ->method('dispatch') ->with(self::callback(fn (MeilisearchMessage $m) => 'updateSettings' === $m->action && $m->payload['settings'] === $settings)) ->willReturn(new Envelope(new \stdClass())); $this->service->updateSettings('events', $settings); } public function testSearchMakesPostRequest(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn(['hits' => []]); $this->httpClient->method('request')->willReturn($response); $result = $this->service->search('events', 'test'); self::assertArrayHasKey('hits', $result); } public function testGetDocumentReturnsArray(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn(['id' => 1, 'title' => 'Event']); $this->httpClient->method('request')->willReturn($response); $result = $this->service->getDocument('events', 1); self::assertSame(1, $result['id']); } public function testRequestReturnsEmptyArrayOn204(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(204); $this->httpClient->method('request')->willReturn($response); $result = $this->service->request('DELETE', '/indexes/events'); self::assertSame([], $result); } public function testGetAllDocumentIdsSinglePage(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn([ 'results' => [ ['id' => 1], ['id' => 2], ['id' => 3], ], ]); $this->httpClient->method('request')->willReturn($response); $ids = $this->service->getAllDocumentIds('events'); self::assertSame([1, 2, 3], $ids); } public function testGetAllDocumentIdsMultiplePages(): void { // First call returns exactly 1000 results (triggers next page) $firstPageDocs = array_map(fn (int $i) => ['id' => $i], range(1, 1000)); $secondPageDocs = [['id' => 1001], ['id' => 1002]]; $response1 = $this->createMock(ResponseInterface::class); $response1->method('getStatusCode')->willReturn(200); $response1->method('toArray')->willReturn(['results' => $firstPageDocs]); $response2 = $this->createMock(ResponseInterface::class); $response2->method('getStatusCode')->willReturn(200); $response2->method('toArray')->willReturn(['results' => $secondPageDocs]); $this->httpClient->method('request')->willReturnOnConsecutiveCalls($response1, $response2); $ids = $this->service->getAllDocumentIds('events'); self::assertCount(1002, $ids); self::assertSame(1, $ids[0]); self::assertSame(1002, $ids[1001]); } public function testGetAllDocumentIdsEmptyIndex(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn(['results' => []]); $this->httpClient->method('request')->willReturn($response); $ids = $this->service->getAllDocumentIds('events'); self::assertSame([], $ids); } public function testListIndexes(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn([ 'results' => [ ['uid' => 'events'], ['uid' => 'users'], ], ]); $this->httpClient->method('request')->willReturn($response); $indexes = $this->service->listIndexes(); self::assertSame(['events', 'users'], $indexes); } public function testListIndexesEmpty(): void { $response = $this->createMock(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); $response->method('toArray')->willReturn(['results' => []]); $this->httpClient->method('request')->willReturn($response); $indexes = $this->service->listIndexes(); self::assertSame([], $indexes); } }