From 4bac667dfdf8713a61235770d71b83927e18261b Mon Sep 17 00:00:00 2001 From: Alexander Skvortsov Date: Thu, 7 Jan 2021 17:23:56 -0500 Subject: [PATCH] Fix fulltext search tests Under InnoDB, database entries created in transactions are not processed by fulltext indexes until the transaction is committed. To work around this, cases that test fulltext search have been split off into a separate class that adds and removes seed discussions/posts outside of transactions during setUp/tearDown. --- .../integration/api/discussions/ListTest.php | 92 ------------- .../ListTestWithFulltextSearch.php | 130 ++++++++++++++++++ 2 files changed, 130 insertions(+), 92 deletions(-) create mode 100644 tests/integration/api/discussions/ListTestWithFulltextSearch.php diff --git a/tests/integration/api/discussions/ListTest.php b/tests/integration/api/discussions/ListTest.php index d09ea5afa..48e1ee949 100644 --- a/tests/integration/api/discussions/ListTest.php +++ b/tests/integration/api/discussions/ListTest.php @@ -67,96 +67,4 @@ class ListTest extends TestCase $this->assertEquals(200, $response->getStatusCode()); } - - /** - * @test - */ - public function can_search_for_word_in_post() - { - $this->database()->table('discussions')->insert([ - ['id' => 2, 'title' => 'lightsail in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'comment_count' => 1], - ['id' => 3, 'title' => 'not in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'comment_count' => 1], - ]); - - $this->database()->table('posts')->insert([ - ['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '

not in text

'], - ['id' => 3, 'discussion_id' => 3, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '

lightsail in text

'], - ]); - - $response = $this->send( - $this->request('GET', '/api/discussions') - ->withQueryParams([ - 'filter' => ['q' => 'lightsail'], - 'include' => 'mostRelevantPost', - ]) - ); - - $data = json_decode($response->getBody()->getContents(), true); - $ids = array_map(function ($row) { - return $row['id']; - }, $data['data']); - - // Order-independent comparison - $this->assertEquals(['3'], $ids, 'IDs do not match', 0.0, 10, true); - } - - /** - * @test - */ - public function ignores_non_word_characters_when_searching() - { - $this->database()->table('discussions')->insert([ - ['id' => 2, 'title' => 'lightsail in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'comment_count' => 1], - ['id' => 3, 'title' => 'not in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'comment_count' => 1], - ]); - - $this->database()->table('posts')->insert([ - ['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '

not in text

'], - ['id' => 3, 'discussion_id' => 3, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 2, 'type' => 'comment', 'content' => '

lightsail in text

'], - ]); - - $response = $this->send( - $this->request('GET', '/api/discussions') - ->withQueryParams([ - 'filter' => ['q' => 'lightsail+'], - 'include' => 'mostRelevantPost', - ]) - ); - - $data = json_decode($response->getBody()->getContents(), true); - $ids = array_map(function ($row) { - return $row['id']; - }, $data['data']); - - // Order-independent comparison - $this->assertEquals(['3'], $ids, 'IDs do not match', 0.0, 10, true); - } - - /** - * @test - */ - public function search_for_special_characters_gives_empty_result() - { - $response = $this->send( - $this->request('GET', '/api/discussions') - ->withQueryParams([ - 'filter' => ['q' => '*'], - 'include' => 'mostRelevantPost', - ]) - ); - - $data = json_decode($response->getBody()->getContents(), true); - $this->assertEquals([], $data['data']); - - $response = $this->send( - $this->request('GET', '/api/discussions') - ->withQueryParams([ - 'filter' => ['q' => '@'], - 'include' => 'mostRelevantPost', - ]) - ); - - $data = json_decode($response->getBody()->getContents(), true); - $this->assertEquals([], $data['data']); - } } diff --git a/tests/integration/api/discussions/ListTestWithFulltextSearch.php b/tests/integration/api/discussions/ListTestWithFulltextSearch.php new file mode 100644 index 000000000..e2de57bb5 --- /dev/null +++ b/tests/integration/api/discussions/ListTestWithFulltextSearch.php @@ -0,0 +1,130 @@ +database()->rollBack(); + + // We need to insert these outside of a transaction, because FULLTEXT indexing, + // which is needed for search, doesn't happen in transactions. + // We clean it up explcitly at the end. + $this->database()->table('discussions')->insert([ + ['id' => 1, 'title' => 'lightsail in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1], + ['id' => 2, 'title' => 'not in title', 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'comment_count' => 1], + ]); + + $this->database()->table('posts')->insert([ + ['id' => 1, 'discussion_id' => 1, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '

not in text

'], + ['id' => 2, 'discussion_id' => 2, 'created_at' => Carbon::now()->toDateTimeString(), 'user_id' => 1, 'type' => 'comment', 'content' => '

lightsail in text

'], + ]); + + // We need to call these again, since we rolled back the transaction started by `::app()`. + $this->database()->beginTransaction(); + + $this->populateDatabase(); + } + + /** + * @inheritDoc + */ + protected function tearDown(): void + { + parent::tearDown(); + + $this->database()->table('discussions')->whereIn('id', [1,2])->delete(); + $this->database()->table('posts')->whereIn('id', [1, 2])->delete(); + } + + /** + * @test + */ + public function can_search_for_word_in_post() + { + $response = $this->send( + $this->request('GET', '/api/discussions') + ->withQueryParams([ + 'filter' => ['q' => 'lightsail'], + 'include' => 'mostRelevantPost', + ]) + ); + + $data = json_decode($response->getBody()->getContents(), true); + $ids = array_map(function ($row) { + return $row['id']; + }, $data['data']); + + // Order-independent comparison + $this->assertEquals(['3'], $ids, 'IDs do not match', 0.0, 10, true); + } + + /** + * @test + */ + public function ignores_non_word_characters_when_searching() + { + $response = $this->send( + $this->request('GET', '/api/discussions') + ->withQueryParams([ + 'filter' => ['q' => 'lightsail+'], + 'include' => 'mostRelevantPost', + ]) + ); + + $data = json_decode($response->getBody()->getContents(), true); + $ids = array_map(function ($row) { + return $row['id']; + }, $data['data']); + + // Order-independent comparison + $this->assertEquals(['3'], $ids, 'IDs do not match', 0.0, 10, true); + } + + /** + * @test + */ + public function search_for_special_characters_gives_empty_result() + { + $response = $this->send( + $this->request('GET', '/api/discussions') + ->withQueryParams([ + 'filter' => ['q' => '*'], + 'include' => 'mostRelevantPost', + ]) + ); + + $data = json_decode($response->getBody()->getContents(), true); + $this->assertEquals([], $data['data']); + + $response = $this->send( + $this->request('GET', '/api/discussions') + ->withQueryParams([ + 'filter' => ['q' => '@'], + 'include' => 'mostRelevantPost', + ]) + ); + + $data = json_decode($response->getBody()->getContents(), true); + $this->assertEquals([], $data['data']); + } +}