Files
odoo_source/addons/test_website/tests/test_fuzzy.py
T
Benoit Socias 6179adb555 [FIX] website, test_website: fallback on exact search if max reached
For performance reasons, when fuzzy search was introduces it was
decided to limit the number of records used for finding fuzzy terms to
1000.  Because of this, when a database contains more than 1000
products matching words that start with the same letter, further
products are not examined. This can lead to searches not finding an
existing exact match.

This commit introduces a fallback mechanism so that, if we are in a
situation where the maximum number of examined records was fetched, we
also explicitly check for a possible exact match across all records.

Steps to reproduce:
- Do not install the pg_trgm extension.
- Have more than 1000 products containing searchable words (name,
description...) starting with the same letter.
- Add one more such product (so that it is not in the 1000 first ones).
- Search for that last product by correctly typing the word.
=> Exact match was not returned.

task-2870947

closes odoo/odoo#97657

X-original-commit: 6d24ea28b236155d542e3d2be3da379b9f4e9ce6
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
2022-08-08 23:45:53 +02:00

75 lines
3.2 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.addons.website.controllers.main import Website
from odoo.addons.website.tools import MockRequest
import odoo.tests
from odoo.tests.common import TransactionCase
_logger = logging.getLogger(__name__)
@odoo.tests.tagged('-at_install', 'post_install')
class TestAutoComplete(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.website = cls.env['website'].browse(1)
cls.WebsiteController = Website()
def _autocomplete(self, term, expected_count, expected_fuzzy_term):
""" Calls the autocomplete for a given term and performs general checks """
with MockRequest(self.env, website=self.website):
suggestions = self.WebsiteController.autocomplete(
search_type="test", term=term, max_nb_chars=50, options={},
)
self.assertEqual(expected_count, suggestions['results_count'], "Wrong number of suggestions")
self.assertEqual(expected_fuzzy_term, suggestions.get('fuzzy_search', 'Not found'), "Wrong fuzzy match")
def test_01_many_records(self):
# REF1000~REF3999
data = [{
'name': 'REF%s' % count,
'is_published': True,
} for count in range(1000, 4000)]
self.env['test.model'].create(data)
# NUM1000~NUM1998
data = [{
'name': 'NUM%s' % count,
'is_published': True,
} for count in range(1000, 1999)]
self.env['test.model'].create(data)
# There are more than 1000 "R*" records
# => Find exact match through the fallback
self._autocomplete('REF3000', 1, False)
# => No exact match => Find fuzzy within first 1000 (distance=3: replace D by F, move 3, add 1)
self._autocomplete('RED3000', 1, 'ref1003')
# => Find exact match through the fallback
self._autocomplete('REF300', 10, False)
# => Find exact match through the fallback
self._autocomplete('REF1', 1000, False)
# => No exact match => Nothing close enough (min distance=5)
self._autocomplete('REFX', 0, "Not found")
# => Find exact match through the fallback - unfortunate because already in the first 1000 records
self._autocomplete('REF1230', 1, False)
# => Find exact match through the fallback
self._autocomplete('REF2230', 1, False)
# There are less than 1000 "N*" records
# => Fuzzy within N* (distance=1: add 1)
self._autocomplete('NUM000', 1, "num1000")
# => Exact match (distance=0 shortcut logic)
self._autocomplete('NUM100', 10, False)
# => Exact match (distance=0 shortcut logic)
self._autocomplete('NUM199', 9, False)
# => Exact match (distance=0 shortcut logic)
self._autocomplete('NUM1998', 1, False)
# => Fuzzy within N* (distance=1: replace 1 by 9)
self._autocomplete('NUM1999', 1, 'num1199')
# => Fuzzy within N* (distance=1: add 1)
self._autocomplete('NUM200', 1, 'num1200')
# There are no "X*" records
self._autocomplete('XEF1000', 0, "Not found")