Skip to content

Commit 091ba52

Browse files
committed
🧪 Add tests for feature
1 parent 40541c5 commit 091ba52

File tree

4 files changed

+193
-2
lines changed

4 files changed

+193
-2
lines changed

‎test/backend/app/test_vectordatabase_app.py‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,53 @@ async def test_get_index_files_permission_exception(vdb_core_mock):
673673
mock_list_files.assert_called_once()
674674

675675

676+
@pytest.mark.asyncio
677+
async def test_get_index_chunks_success(vdb_core_mock):
678+
"""
679+
Test retrieving index chunks successfully.
680+
Verifies that the endpoint forwards query params and returns the service payload.
681+
"""
682+
with patch("backend.apps.vectordatabase_app.get_vector_db_core", return_value=vdb_core_mock), \
683+
patch("backend.apps.vectordatabase_app.ElasticSearchService.get_index_chunks") as mock_get_chunks:
684+
685+
index_name = "test_index"
686+
expected_response = {
687+
"status": "success",
688+
"message": "ok",
689+
"chunks": [{"id": "1"}],
690+
"total": 1
691+
}
692+
mock_get_chunks.return_value = expected_response
693+
694+
response = client.post(
695+
f"/indices/{index_name}/chunks",
696+
params={"batch_size": 500}
697+
)
698+
699+
assert response.status_code == 200
700+
assert response.json() == expected_response
701+
mock_get_chunks.assert_called_once_with(index_name, 500, ANY)
702+
703+
704+
@pytest.mark.asyncio
705+
async def test_get_index_chunks_error(vdb_core_mock):
706+
"""
707+
Test retrieving index chunks with service error.
708+
Ensures the endpoint maps the exception to HTTP 500.
709+
"""
710+
with patch("backend.apps.vectordatabase_app.get_vector_db_core", return_value=vdb_core_mock), \
711+
patch("backend.apps.vectordatabase_app.ElasticSearchService.get_index_chunks") as mock_get_chunks:
712+
713+
index_name = "test_index"
714+
mock_get_chunks.side_effect = Exception("Chunk failure")
715+
716+
response = client.post(f"/indices/{index_name}/chunks")
717+
718+
assert response.status_code == 500
719+
assert response.json() == {"detail": "Error getting chunks: Chunk failure"}
720+
mock_get_chunks.assert_called_once_with(index_name, 1000, ANY)
721+
722+
676723
@pytest.mark.asyncio
677724
async def test_health_check_success(vdb_core_mock):
678725
"""

‎test/backend/services/test_vectordatabase_service.py‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,57 @@ def test_get_summary_not_found(self, mock_get_record):
12841284

12851285
self.assertIn("Unable to get summary", str(context.exception))
12861286

1287+
def test_get_index_chunks_filters_fields(self):
1288+
"""
1289+
Test chunk retrieval filters unsupported fields and reports totals.
1290+
"""
1291+
self.mock_vdb_core.get_index_chunks.return_value = [
1292+
{"id": "1", "content": "A", "path_or_url": "/a", "extra": "ignore"},
1293+
{"content": "B", "create_time": "2024-01-01T00:00:00"}
1294+
]
1295+
1296+
result = ElasticSearchService.get_index_chunks(
1297+
index_name="kb-index",
1298+
batch_size=500,
1299+
vdb_core=self.mock_vdb_core
1300+
)
1301+
1302+
self.assertEqual(result["status"], "success")
1303+
self.assertEqual(result["total"], 2)
1304+
self.assertEqual(result["chunks"][0], {"id": "1", "content": "A", "path_or_url": "/a"})
1305+
self.assertEqual(result["chunks"][1], {"content": "B", "create_time": "2024-01-01T00:00:00"})
1306+
self.mock_vdb_core.get_index_chunks.assert_called_once_with("kb-index", 500)
1307+
1308+
def test_get_index_chunks_keeps_non_dict_entries(self):
1309+
"""
1310+
Test chunk retrieval keeps non-dict entries unchanged.
1311+
"""
1312+
self.mock_vdb_core.get_index_chunks.return_value = ["raw_chunk"]
1313+
1314+
result = ElasticSearchService.get_index_chunks(
1315+
index_name="kb-index",
1316+
batch_size=10,
1317+
vdb_core=self.mock_vdb_core
1318+
)
1319+
1320+
self.assertEqual(result["chunks"], ["raw_chunk"])
1321+
self.assertEqual(result["total"], 1)
1322+
1323+
def test_get_index_chunks_error(self):
1324+
"""
1325+
Test chunk retrieval error handling.
1326+
"""
1327+
self.mock_vdb_core.get_index_chunks.side_effect = Exception("boom")
1328+
1329+
with self.assertRaises(Exception) as exc:
1330+
ElasticSearchService.get_index_chunks(
1331+
index_name="kb-index",
1332+
batch_size=10,
1333+
vdb_core=self.mock_vdb_core
1334+
)
1335+
1336+
self.assertIn("Error retrieving chunks from index kb-index: boom", str(exc.exception))
1337+
12871338
@patch('backend.services.vectordatabase_service.get_knowledge_info_by_tenant_id')
12881339
@patch('fastapi.Response')
12891340
def test_list_indices_success_status_200(self, mock_response, mock_get_knowledge):

‎test/sdk/vector_database/test_elasticsearch_core.py‎

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from unittest.mock import MagicMock, patch
33
import time
44
from typing import List, Dict, Any
5+
from elasticsearch import exceptions
56

67
# Import the class under test
78
from sdk.nexent.vector_database.elasticsearch_core import ElasticSearchCore
@@ -445,8 +446,6 @@ def test_delete_index_success(elasticsearch_core_instance):
445446

446447
def test_delete_index_not_found(elasticsearch_core_instance):
447448
"""Test deleting an index that doesn't exist."""
448-
from elasticsearch import exceptions
449-
450449
with patch.object(elasticsearch_core_instance.client.indices, 'delete') as mock_delete:
451450
mock_delete.side_effect = exceptions.NotFoundError(
452451
"Index not found", {}, {})
@@ -574,6 +573,69 @@ def test_delete_documents_success(elasticsearch_core_instance):
574573
mock_delete.assert_called_once()
575574

576575

576+
def test_get_index_chunks_success(elasticsearch_core_instance):
577+
"""Test fetching chunks via scroll API."""
578+
elasticsearch_core_instance.client = MagicMock()
579+
elasticsearch_core_instance.client.search.return_value = {
580+
"_scroll_id": "scroll123",
581+
"hits": {
582+
"hits": [
583+
{"_id": "doc-1", "_source": {"id": "chunk-1", "content": "A"}},
584+
{"_id": "doc-2", "_source": {"content": "B"}}
585+
]
586+
}
587+
}
588+
elasticsearch_core_instance.client.scroll.return_value = {
589+
"_scroll_id": "scroll123",
590+
"hits": {"hits": []}
591+
}
592+
593+
chunks = elasticsearch_core_instance.get_index_chunks("kb-index", batch_size=2)
594+
595+
assert chunks == [
596+
{"id": "chunk-1", "content": "A"},
597+
{"content": "B", "id": "doc-2"}
598+
]
599+
elasticsearch_core_instance.client.search.assert_called_once()
600+
elasticsearch_core_instance.client.scroll.assert_called_once_with(scroll_id="scroll123", scroll="2m")
601+
elasticsearch_core_instance.client.clear_scroll.assert_called_once_with(scroll_id="scroll123")
602+
603+
604+
def test_get_index_chunks_not_found(elasticsearch_core_instance):
605+
"""Test fetching chunks when index does not exist."""
606+
elasticsearch_core_instance.client = MagicMock()
607+
elasticsearch_core_instance.client.search.side_effect = exceptions.NotFoundError(404, "not found", {})
608+
609+
chunks = elasticsearch_core_instance.get_index_chunks("missing-index")
610+
611+
assert chunks == []
612+
elasticsearch_core_instance.client.clear_scroll.assert_not_called()
613+
614+
615+
def test_get_index_chunks_cleanup_failure(elasticsearch_core_instance):
616+
"""Test cleanup warning path when clear_scroll raises."""
617+
elasticsearch_core_instance.client = MagicMock()
618+
elasticsearch_core_instance.client.search.return_value = {
619+
"_scroll_id": "scroll123",
620+
"hits": {
621+
"hits": [
622+
{"_id": "doc-1", "_source": {"content": "A"}}
623+
]
624+
}
625+
}
626+
elasticsearch_core_instance.client.scroll.return_value = {
627+
"_scroll_id": "scroll123",
628+
"hits": {"hits": []}
629+
}
630+
elasticsearch_core_instance.client.clear_scroll.side_effect = Exception("cleanup error")
631+
632+
chunks = elasticsearch_core_instance.get_index_chunks("kb-index")
633+
634+
assert len(chunks) == 1
635+
assert chunks[0]["id"] == "doc-1"
636+
elasticsearch_core_instance.client.clear_scroll.assert_called_once_with(scroll_id="scroll123")
637+
638+
577639
# ----------------------------------------------------------------------------
578640
# Tests for search operations
579641
# ----------------------------------------------------------------------------

‎test/sdk/vector_database/test_elasticsearch_core_coverage.py‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,37 @@ def test_delete_documents_exception(self, vdb_core):
258258
assert result == 0
259259
vdb_core.client.delete_by_query.assert_called_once()
260260

261+
def test_get_index_chunks_not_found(self, vdb_core):
262+
"""Ensure get_index_chunks handles missing index gracefully."""
263+
vdb_core.client = MagicMock()
264+
vdb_core.client.search.side_effect = exceptions.NotFoundError(
265+
404, "missing", {})
266+
267+
result = vdb_core.get_index_chunks("missing-index")
268+
269+
assert result == []
270+
vdb_core.client.clear_scroll.assert_not_called()
271+
272+
def test_get_index_chunks_cleanup_warning(self, vdb_core):
273+
"""Ensure clear_scroll errors are swallowed."""
274+
vdb_core.client = MagicMock()
275+
vdb_core.client.search.return_value = {
276+
"_scroll_id": "scroll123",
277+
"hits": {"hits": [{"_id": "doc-1", "_source": {"content": "A"}}]}
278+
}
279+
vdb_core.client.scroll.return_value = {
280+
"_scroll_id": "scroll123",
281+
"hits": {"hits": []}
282+
}
283+
vdb_core.client.clear_scroll.side_effect = Exception("cleanup-failed")
284+
285+
result = vdb_core.get_index_chunks("kb-index", batch_size=1)
286+
287+
assert len(result) == 1
288+
assert result[0]["id"] == "doc-1"
289+
vdb_core.client.clear_scroll.assert_called_once_with(
290+
scroll_id="scroll123")
291+
261292
def test_create_index_request_error_existing(self, vdb_core):
262293
"""Ensure RequestError with resource already exists still succeeds."""
263294
vdb_core.client = MagicMock()

0 commit comments

Comments
 (0)