|
@@ -0,0 +1,95 @@
|
|
|
|
|
+# -*- coding: utf-8 -*-
|
|
|
|
|
+import pytest
|
|
|
|
|
+from unittest.mock import patch, MagicMock
|
|
|
|
|
+from app.visa_free_config_fetchers.vfs_fetcher import _select_candidate_with_llm
|
|
|
|
|
+
|
|
|
|
|
+def test_select_candidate_with_llm():
|
|
|
|
|
+ candidates = [
|
|
|
|
|
+ {"code": "A", "name": "Option A"},
|
|
|
|
|
+ {"code": "B", "name": "Option B"}
|
|
|
|
|
+ ]
|
|
|
|
|
+ prompt_context = "选择 Option B"
|
|
|
|
|
+
|
|
|
|
|
+ mock_resp = MagicMock()
|
|
|
|
|
+ mock_resp.status_code = 200
|
|
|
|
|
+ mock_resp.json.return_value = {
|
|
|
|
|
+ "choices": [
|
|
|
|
|
+ {"message": {"content": "1"}}
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ with patch("curl_cffi.requests.post", return_value=mock_resp):
|
|
|
|
|
+ selected = _select_candidate_with_llm(candidates, prompt_context)
|
|
|
|
|
+ assert selected == {"code": "B", "name": "Option B"}
|
|
|
|
|
+
|
|
|
|
|
+from app.visa_free_config_fetchers.vfs_fetcher import VFSFetcher
|
|
|
|
|
+
|
|
|
|
|
+def test_fetch_external_vac_info_success():
|
|
|
|
|
+ fetcher = VFSFetcher()
|
|
|
|
|
+
|
|
|
|
|
+ mock_centers = [
|
|
|
|
|
+ {
|
|
|
|
|
+ "isoCode": "NTDB",
|
|
|
|
|
+ "centerName": "Netherlands Visa Application Center - Dublin",
|
|
|
|
|
+ "address": "130 Francis Street, Dublin"
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ mock_cats = [
|
|
|
|
|
+ {
|
|
|
|
|
+ "visaCategoryCode": "TA",
|
|
|
|
|
+ "name": "Short Stay Visa"
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ mock_subcats = [
|
|
|
|
|
+ {
|
|
|
|
|
+ "subCategoryCode": "To",
|
|
|
|
|
+ "subCategoryName": "Tourist"
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ def mock_get(url, **kwargs):
|
|
|
|
|
+ resp = MagicMock()
|
|
|
|
|
+ resp.status_code = 200
|
|
|
|
|
+ if "master/center" in url:
|
|
|
|
|
+ resp.json.return_value = mock_centers
|
|
|
|
|
+ elif "master/visacategory" in url:
|
|
|
|
|
+ resp.json.return_value = mock_cats
|
|
|
|
|
+ elif "master/subvisacategory" in url:
|
|
|
|
|
+ resp.json.return_value = mock_subcats
|
|
|
|
|
+ else:
|
|
|
|
|
+ resp.status_code = 404
|
|
|
|
|
+ return resp
|
|
|
|
|
+
|
|
|
|
|
+ with patch("curl_cffi.requests.get", side_effect=mock_get):
|
|
|
|
|
+ res = fetcher.fetch_external_vac_info("ie", "nl", "tourist", "dub")
|
|
|
|
|
+ assert res["vac_code"] == "NTDB"
|
|
|
|
|
+ assert res["center_name"] == "Netherlands Visa Application Center - Dublin"
|
|
|
|
|
+ assert res["category_code"] == "TA"
|
|
|
|
|
+ assert res["subcategory_code"] == "To"
|
|
|
|
|
+
|
|
|
|
|
+def test_fetch_external_vac_info_hard_failure():
|
|
|
|
|
+ fetcher = VFSFetcher()
|
|
|
|
|
+ mock_resp = MagicMock()
|
|
|
|
|
+ mock_resp.status_code = 500
|
|
|
|
|
+
|
|
|
|
|
+ with patch("curl_cffi.requests.get", return_value=mock_resp):
|
|
|
|
|
+ with pytest.raises(RuntimeError):
|
|
|
|
|
+ fetcher.fetch_external_vac_info("ie", "nl", "tourist", "nonexistent")
|
|
|
|
|
+
|
|
|
|
|
+def test_fetch_free_config_fallback_to_external():
|
|
|
|
|
+ fetcher = VFSFetcher()
|
|
|
|
|
+ mock_ext = {
|
|
|
|
|
+ "routing_key": "slot.test.nl.tourist",
|
|
|
|
|
+ "vac_code": "TEST",
|
|
|
|
|
+ "center_name": "Test Center",
|
|
|
|
|
+ "address": "Test Address",
|
|
|
|
|
+ "category_code": "CAT",
|
|
|
|
|
+ "category_name": "Cat Name",
|
|
|
|
|
+ "subcategory_code": "SUB",
|
|
|
|
|
+ "subcategory_name": "Sub Name"
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ with patch.object(fetcher, "fetch_external_vac_info", return_value=mock_ext):
|
|
|
|
|
+ config = fetcher.fetch_free_config("ie", "nl", "tourist", "unknown_vac_code")
|
|
|
|
|
+ assert "slot.test.nl.tourist" in config["apt_configs"]
|
|
|
|
|
+ assert config["apt_configs"]["slot.test.nl.tourist"]["vac_code"] == "TEST"
|