| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- """简短业务入口:身份解析、环境隔离、网关默认策略与未决身份阻断。"""
- import json
- from pathlib import Path
- from types import SimpleNamespace
- import pytest
- from extensions.main_fan.schemas import MainFanInput, MainFanResult
- from extensions.main_fan.targets import load_catalog, TargetResolutionError
- from extensions.main_fan.tools import analyze_main_fan
- @pytest.fixture
- def target_catalog(monkeypatch):
- root=Path(__file__).resolve().parents[1]
- monkeypatch.setenv('MAIN_FAN_TARGETS_FILE',str(root/'examples/main_fan/mock_targets.json'))
- monkeypatch.setenv('SHANXI_GATEWAY_URL','http://127.0.0.1:8766')
- monkeypatch.setenv('SHANXI_GATEWAY_TOKEN','synthetic-test-token')
- monkeypatch.setenv('SHANXI_GATEWAY_ENABLED','1')
- monkeypatch.setenv('MAIN_FAN_DEFAULT_DOCUMENT_CACHE_POLICY','refresh')
- @pytest.mark.parametrize('value',[
- {'target':'众源煤业1号主通风机'},
- {'target':'mock-report-fan-1'},
- '{"target":"众源煤业1号主通风机"}',
- '审核众源煤业1号主通风机',
- '请对陕西众源煤业集团有限公司的一号主通风机进行研判',
- {'mine_name':'众源煤业','fan_name':'1#通风机'},
- {'fan_id':'mock-report-fan-1'},
- {'fanId':'mock-report-fan-1'},
- ])
- def test_single_target_resolves_configured_identity_and_internal_defaults(target_catalog,value):
- result=MainFanInput.model_validate(value)
- assert result.mine_code=='mock-zy'
- assert result.mine_name=='陕西众源煤业集团有限公司'
- assert result.fan_id=='mock-report-fan-1'
- assert result.fan_name=='1号通风机'
- assert result.use_gateway is True and result.document_cache_policy=='refresh'
- assert result.reports==[] and result.points==[] and result.confirmed_bindings==[]
- def test_second_fan_is_not_replaced_with_first_fan(target_catalog):
- result=MainFanInput.model_validate({'target':'审核众源煤业二号主通风机'})
- assert result.fan_id=='mock-report-fan-2' and result.fan_name=='2号通风机'
- @pytest.mark.parametrize('value',[
- {'target':'众源煤业3号主通风机'},
- {'target':'其他煤矿1号主通风机'},
- {'target':'众源煤业1号主通风机','mine_code':'other-mine'},
- {'target':'众源煤业1号主通风机','mine_name':'其他矿井'},
- {'target':'众源煤业1号主通风机','fan_id':'mock-report-fan-2'},
- {'target':'众源煤业1号主通风机','fan_name':'2号通风机'},
- {'target':'众源煤业1号主通风机','mine_code':123},
- {'target':'众源煤业1号主通风机','mine_code':'mock-zy','mineCode':'other'},
- '{"target":',
- ])
- def test_ambiguous_unknown_or_conflicting_identity_is_rejected(target_catalog,value):
- with pytest.raises(ValueError):MainFanInput.model_validate(value)
- def test_mock_identity_catalog_cannot_be_used_with_real_gateway(target_catalog,monkeypatch):
- monkeypatch.setenv('SHANXI_GATEWAY_URL','https://real-gateway.invalid')
- with pytest.raises(ValueError,match='绑定的网关'):load_catalog()
- with pytest.raises(ValueError,match='绑定的网关'):
- MainFanInput.model_validate({'target':'众源煤业1号主通风机'})
- def test_target_resolution_without_catalog_never_fabricates_codes(monkeypatch):
- monkeypatch.delenv('MAIN_FAN_TARGETS_FILE',raising=False)
- with pytest.raises(ValueError):MainFanInput.model_validate({'target':'众源煤业1号主通风机'})
- def test_explicit_local_material_and_cache_choices_are_preserved(target_catalog):
- result=MainFanInput.model_validate({'target':'众源煤业1号主通风机',
- 'materials':[{'path':'/workspace/uploads/raw.pdf'}],'document_cache_policy':'off'})
- assert result.use_gateway is False and result.document_cache_policy=='off'
- explicit=MainFanInput.model_validate({'target':'众源煤业1号主通风机',
- 'use_gateway':False,'document_cache_policy':'auto'})
- assert explicit.use_gateway is False and explicit.document_cache_policy=='auto'
- def test_disabling_gateway_does_not_activate_mock_implicitly(target_catalog,monkeypatch):
- monkeypatch.setenv('SHANXI_GATEWAY_ENABLED','0')
- assert MainFanInput.model_validate({'target':'众源煤业1号主通风机'}).use_gateway is False
- def test_complete_input_and_camel_case_remain_compatible(monkeypatch):
- monkeypatch.delenv('MAIN_FAN_TARGETS_FILE',raising=False)
- value=MainFanInput.model_validate({'mineCode':'formal-code','mineName':'正式矿井',
- 'fanId':'formal-fan','fan_name':'1号通风机','use_gateway':False})
- assert value.mine_code=='formal-code' and value.fan_id=='formal-fan'
- assert value.document_cache_policy=='auto'
- @pytest.mark.asyncio
- async def test_short_tool_call_passes_server_resolved_parameters(target_catalog,monkeypatch):
- seen=[]
- async def fake_analyze(data,user,session,**kwargs):
- seen.append((data,user,session))
- return MainFanResult(status='needs_materials',mine_code=data['mine_code'],mine_name=data['mine_name'],
- check_object=data['fan_name'],result_title='测试',result='仅验证输入路由').model_dump(mode='json')
- monkeypatch.setattr('extensions.main_fan.service.analyze',fake_analyze)
- runtime=SimpleNamespace(config={'configurable':{'workspace_user':'test','workspace_session':'test-session'}})
- await analyze_main_fan('审核众源煤业1号主通风机',runtime)
- data,user,session=seen[0]
- assert data['fan_id']=='mock-report-fan-1' and data['use_gateway'] is True
- assert data['document_cache_policy']=='refresh' and not data.get('reports')
- assert (user,session)==('test','test-session')
- @pytest.mark.asyncio
- async def test_ambiguous_tool_target_never_calls_gateway_or_analyzer(target_catalog,monkeypatch):
- from extensions.main_fan.targets import TargetCatalog
- content=load_catalog().model_dump()
- for record in content['targets']:record.pop('fan_pair')
- monkeypatch.setattr('extensions.main_fan.targets.load_catalog',lambda:TargetCatalog.model_validate(content))
- async def forbidden(*args,**kwargs):raise AssertionError('身份未定不得分析')
- monkeypatch.setattr('extensions.main_fan.service.analyze',forbidden)
- runtime=SimpleNamespace(config={'configurable':{'workspace_user':'test','workspace_session':'test-session'}})
- result=await analyze_main_fan('审核众源煤业主通风机',runtime)
- assert result['status']=='needs_materials' and not result['analysis_id']
- assert '1号通风机' in result['result'] and '2号通风机' in result['result']
- @pytest.mark.parametrize('value',[{'target':'众源煤业'},{'mine_code':'mock-zy'},'审核众源煤业主通风机','审核众源煤业主通风机及备用是否一致'])
- def test_mine_request_resolves_one_configured_fan_pair(target_catalog,value):
- result=MainFanInput.model_validate(value)
- assert result.fan_pair==['mock-report-fan-1','mock-report-fan-2']
- assert result.paired_assessment is True
- def test_job_api_accepts_one_target_parameter(target_catalog,monkeypatch):
- from runtime.business_tasks import submit
- from db import business_store
- monkeypatch.setenv('SHANXI_GATEWAY_ENABLED','0')
- job=submit('main_fan',{'target':'众源煤业1号主通风机'},user_name='one-parameter',publish=False)
- stored=json.loads(business_store.get(job['id'])['payload'])['input']
- assert stored['mine_code']=='mock-zy' and stored['fan_id']=='mock-report-fan-1'
- assert stored['document_cache_policy']=='refresh'
|