@@ -181,6 +181,64 @@ def test_singleton_instances_are_reused():
181181 print (f"❌ Singleton test failed: { e } " )
182182 raise
183183
184+ def test_recognizers_not_reloaded ():
185+ """
186+ Test that recognizers are not fetched/reloaded on each analyze() call.
187+ This prevents the performance regression where "Fetching all recognizers for language en"
188+ appears in logs on every request.
189+ """
190+ print ("\n Testing that recognizers are not reloaded on each call..." )
191+
192+ # Reset module state
193+ if 'optillm.plugins.privacy_plugin' in sys .modules :
194+ del sys .modules ['optillm.plugins.privacy_plugin' ]
195+
196+ try :
197+ # Mock at the presidio level to track registry calls
198+ with patch ('presidio_analyzer.AnalyzerEngine' ) as MockAnalyzerEngine , \
199+ patch ('spacy.util.is_package' , return_value = True ):
200+
201+ # Create a mock analyzer instance
202+ mock_analyzer_instance = MagicMock ()
203+ mock_registry = MagicMock ()
204+
205+ # Track calls to get_recognizers
206+ mock_registry .get_recognizers = MagicMock (return_value = [])
207+ mock_analyzer_instance .registry = mock_registry
208+ mock_analyzer_instance .analyze = MagicMock (return_value = [])
209+
210+ MockAnalyzerEngine .return_value = mock_analyzer_instance
211+
212+ # Import module with mocks
213+ import optillm .plugins .privacy_plugin as privacy_plugin
214+
215+ # First call to get_analyzer_engine - should create and warm up
216+ analyzer1 = privacy_plugin .get_analyzer_engine ()
217+ initial_analyze_calls = mock_analyzer_instance .analyze .call_count
218+
219+ print (f"Warm-up analyze calls: { initial_analyze_calls } " )
220+ assert initial_analyze_calls == 1 , f"Expected 1 warm-up analyze call, got { initial_analyze_calls } "
221+
222+ # Second call - should return cached instance without additional analyze
223+ analyzer2 = privacy_plugin .get_analyzer_engine ()
224+ second_analyze_calls = mock_analyzer_instance .analyze .call_count
225+
226+ print (f"Total analyze calls after second get_analyzer_engine: { second_analyze_calls } " )
227+ assert second_analyze_calls == 1 , f"Analyzer should not call analyze() again on cached retrieval, got { second_analyze_calls } calls"
228+
229+ # Verify it's the same instance
230+ assert analyzer1 is analyzer2 , "Should return the same cached analyzer instance"
231+
232+ print ("✅ Recognizer reload test PASSED - Recognizers are pre-warmed and not reloaded!" )
233+ return True
234+
235+ except ImportError as e :
236+ print (f"⚠️ Skipping recognizer reload test - dependencies not installed: { e } " )
237+ return True
238+ except Exception as e :
239+ print (f"❌ Recognizer reload test failed: { e } " )
240+ raise
241+
184242if __name__ == "__main__" :
185243 print ("=" * 60 )
186244 print ("Privacy Plugin Performance & Caching Tests" )
@@ -200,6 +258,12 @@ def test_singleton_instances_are_reused():
200258 all_passed = False
201259 print (f"❌ Singleton instance test failed: { e } " )
202260
261+ try :
262+ test_recognizers_not_reloaded ()
263+ except Exception as e :
264+ all_passed = False
265+ print (f"❌ Recognizer reload test failed: { e } " )
266+
203267 try :
204268 test_privacy_plugin_performance ()
205269 except Exception as e :
0 commit comments