|
5 | 5 |
|
6 | 6 | import random
|
7 | 7 | import smtplib
|
| 8 | +import time |
8 | 9 | from logging import Logger
|
9 | 10 | from unittest import mock
|
10 | 11 |
|
|
13 | 14 | from django.core.cache import cache
|
14 | 15 | from django.core.exceptions import ValidationError
|
15 | 16 | from django.core.files.storage import default_storage
|
| 17 | +from django.db import transaction |
16 | 18 | from django.test.utils import override_settings
|
17 | 19 | from django.utils import timezone
|
18 | 20 |
|
19 | 21 | import pytest
|
20 | 22 |
|
21 | 23 | from core import factories, models
|
| 24 | +from core.services.search_indexers import FindDocumentIndexer |
| 25 | +from core.tasks.find import document_indexer_debounce_key |
22 | 26 |
|
23 | 27 | pytestmark = pytest.mark.django_db
|
24 | 28 |
|
@@ -1323,3 +1327,99 @@ def test_models_documents_compute_ancestors_links_paths_mapping_structure(
|
1323 | 1327 | {"link_reach": sibling.link_reach, "link_role": sibling.link_role},
|
1324 | 1328 | ],
|
1325 | 1329 | }
|
| 1330 | + |
| 1331 | + |
| 1332 | +@mock.patch.object(FindDocumentIndexer, "push") |
| 1333 | +@pytest.mark.django_db(transaction=True) |
| 1334 | +def test_models_documents_post_save_indexer(mock_push, settings): |
| 1335 | + settings.SEARCH_INDEXER_COUNTDOWN = 0 |
| 1336 | + |
| 1337 | + user = factories.UserFactory() |
| 1338 | + |
| 1339 | + with transaction.atomic(): |
| 1340 | + doc1, doc2, doc3 = factories.DocumentFactory.create_batch(3) |
| 1341 | + |
| 1342 | + factories.UserDocumentAccessFactory(document=doc1, user=user) |
| 1343 | + factories.UserDocumentAccessFactory(document=doc2, user=user) |
| 1344 | + factories.UserDocumentAccessFactory(document=doc3, user=user) |
| 1345 | + |
| 1346 | + time.sleep(0.1) # waits for the end of the tasks |
| 1347 | + |
| 1348 | + accesses = { |
| 1349 | + str(doc1.path): {"users": [user.sub]}, |
| 1350 | + str(doc2.path): {"users": [user.sub]}, |
| 1351 | + str(doc3.path): {"users": [user.sub]}, |
| 1352 | + } |
| 1353 | + |
| 1354 | + data = [call.args[0] for call in mock_push.call_args_list] |
| 1355 | + |
| 1356 | + indexer = FindDocumentIndexer() |
| 1357 | + |
| 1358 | + def sortkey(d): |
| 1359 | + return d["id"] |
| 1360 | + |
| 1361 | + assert sorted(data, key=sortkey) == sorted( |
| 1362 | + [ |
| 1363 | + indexer.serialize_document(doc1, accesses), |
| 1364 | + indexer.serialize_document(doc2, accesses), |
| 1365 | + indexer.serialize_document(doc3, accesses), |
| 1366 | + ], |
| 1367 | + key=sortkey, |
| 1368 | + ) |
| 1369 | + |
| 1370 | + |
| 1371 | +@mock.patch.object(FindDocumentIndexer, "push") |
| 1372 | +@pytest.mark.django_db(transaction=True) |
| 1373 | +def test_models_documents_post_save_indexer_debounce(mock_push, settings): |
| 1374 | + settings.SEARCH_INDEXER_COUNTDOWN = 0 |
| 1375 | + |
| 1376 | + indexer = FindDocumentIndexer() |
| 1377 | + user = factories.UserFactory() |
| 1378 | + |
| 1379 | + with transaction.atomic(): |
| 1380 | + doc = factories.DocumentFactory() |
| 1381 | + factories.UserDocumentAccessFactory(document=doc, user=user) |
| 1382 | + |
| 1383 | + accesses = { |
| 1384 | + str(doc.path): {"users": [user.sub]}, |
| 1385 | + } |
| 1386 | + |
| 1387 | + time.sleep(0.1) # waits for the end of the tasks |
| 1388 | + |
| 1389 | + # One save from the factory |
| 1390 | + assert [call.args[0] for call in mock_push.call_args_list] == [ |
| 1391 | + indexer.serialize_document(doc, accesses), |
| 1392 | + ] |
| 1393 | + |
| 1394 | + # The debounce counter should be reset |
| 1395 | + assert cache.get(document_indexer_debounce_key(doc.pk)) == 0 |
| 1396 | + |
| 1397 | + # Now simulate 1 waiting task |
| 1398 | + cache.set(document_indexer_debounce_key(doc.pk), 1) |
| 1399 | + |
| 1400 | + # save it again to trigger the indexer, but nothing should be done since |
| 1401 | + # the counter is over 0 |
| 1402 | + with transaction.atomic(): |
| 1403 | + updated_doc = models.Document.objects.get(pk=doc.pk) |
| 1404 | + updated_doc.save() |
| 1405 | + |
| 1406 | + time.sleep(0.1) # waits for the end of the tasks |
| 1407 | + |
| 1408 | + # Still on the first indexation. |
| 1409 | + assert [call.args[0] for call in mock_push.call_args_list] == [ |
| 1410 | + indexer.serialize_document(doc, accesses), |
| 1411 | + ] |
| 1412 | + |
| 1413 | + # Reset the counter |
| 1414 | + cache.set(document_indexer_debounce_key(doc.pk), 0) |
| 1415 | + |
| 1416 | + with transaction.atomic(): |
| 1417 | + updated_doc = models.Document.objects.get(pk=doc.pk) |
| 1418 | + updated_doc.save() |
| 1419 | + |
| 1420 | + time.sleep(0.1) # waits for the end of the tasks |
| 1421 | + |
| 1422 | + assert [call.args[0] for call in mock_push.call_args_list] == [ |
| 1423 | + indexer.serialize_document(doc, accesses), |
| 1424 | + indexer.serialize_document(updated_doc, accesses), |
| 1425 | + ] |
0 commit comments