1+ using Microsoft . Extensions . DependencyInjection ;
2+ using Microsoft . Extensions . Logging ;
3+ using NLWebNet . Models ;
4+ using NLWebNet . Services ;
5+
6+ namespace NLWebNet . Tests . Integration ;
7+
8+ /// <summary>
9+ /// Backend-specific integration tests for database operations
10+ /// </summary>
11+ [ TestClass ]
12+ public class BackendOperationTests
13+ {
14+ private IServiceProvider _serviceProvider = null ! ;
15+
16+ [ TestInitialize ]
17+ public void Initialize ( )
18+ {
19+ var services = new ServiceCollection ( ) ;
20+ services . AddLogging ( builder => builder . AddConsole ( ) ) ;
21+ services . AddNLWebNetMultiBackend ( ) ;
22+ _serviceProvider = services . BuildServiceProvider ( ) ;
23+ }
24+
25+ [ TestCleanup ]
26+ public void Cleanup ( )
27+ {
28+ ( _serviceProvider as IDisposable ) ? . Dispose ( ) ;
29+ }
30+
31+ /// <summary>
32+ /// Tests MockDataBackend specific operations and capabilities
33+ /// </summary>
34+ [ TestMethod ]
35+ public async Task BackendOperation_MockDataBackend_AllOperationsWork ( )
36+ {
37+ var logger = _serviceProvider . GetRequiredService < ILogger < MockDataBackend > > ( ) ;
38+ var mockBackend = new MockDataBackend ( logger ) ;
39+
40+ Console . WriteLine ( "Testing MockDataBackend operations" ) ;
41+
42+ // Test capabilities
43+ var capabilities = mockBackend . GetCapabilities ( ) ;
44+ Assert . IsNotNull ( capabilities , "Capabilities should not be null" ) ;
45+ Assert . IsTrue ( capabilities . SupportsSiteFiltering , "MockDataBackend should support site filtering" ) ;
46+ Assert . IsTrue ( capabilities . SupportsFullTextSearch , "MockDataBackend should support full text search" ) ;
47+ Assert . IsFalse ( capabilities . SupportsSemanticSearch , "MockDataBackend should not support semantic search" ) ;
48+ Assert . AreEqual ( 50 , capabilities . MaxResults , "MockDataBackend should have max results of 50" ) ;
49+
50+ Console . WriteLine ( $ "✓ MockDataBackend capabilities: { capabilities . Description } ") ;
51+
52+ // Test basic search
53+ var searchResults = await mockBackend . SearchAsync ( "millennium falcon" , null , 10 , CancellationToken . None ) ;
54+ var resultsList = searchResults . ToList ( ) ;
55+
56+ Assert . IsTrue ( resultsList . Count > 0 , "Should return results for 'millennium falcon'" ) ;
57+ Assert . IsTrue ( resultsList . Count <= 10 , "Should respect max results limit" ) ;
58+
59+ foreach ( var result in resultsList )
60+ {
61+ Assert . IsFalse ( string . IsNullOrWhiteSpace ( result . Name ) , "Result name should not be empty" ) ;
62+ Assert . IsFalse ( string . IsNullOrWhiteSpace ( result . Url ) , "Result URL should not be empty" ) ;
63+ Assert . IsFalse ( string . IsNullOrWhiteSpace ( result . Description ) , "Result description should not be empty" ) ;
64+ }
65+
66+ Console . WriteLine ( $ "✓ Basic search returned { resultsList . Count } results") ;
67+
68+ // Test site filtering
69+ var siteFilteredResults = await mockBackend . SearchAsync ( "Dune" , "scifi-cinema.com" , 10 , CancellationToken . None ) ;
70+ var siteFilteredList = siteFilteredResults . ToList ( ) ;
71+
72+ if ( siteFilteredList . Count > 0 )
73+ {
74+ foreach ( var result in siteFilteredList )
75+ {
76+ Assert . AreEqual ( "scifi-cinema.com" , result . Site ,
77+ "All results should be from the specified site when site filtering is applied" ) ;
78+ }
79+ Console . WriteLine ( $ "✓ Site filtering returned { siteFilteredList . Count } results from scifi-cinema.com") ;
80+ }
81+
82+ // Test empty query handling
83+ var emptyResults = await mockBackend . SearchAsync ( "" , null , 10 , CancellationToken . None ) ;
84+ var emptyList = emptyResults . ToList ( ) ;
85+ Assert . AreEqual ( 0 , emptyList . Count , "Empty query should return no results" ) ;
86+
87+ Console . WriteLine ( "✓ Empty query handling validated" ) ;
88+
89+ // Test null query handling
90+ var nullResults = await mockBackend . SearchAsync ( null ! , null , 10 , CancellationToken . None ) ;
91+ var nullList = nullResults . ToList ( ) ;
92+ Assert . AreEqual ( 0 , nullList . Count , "Null query should return no results" ) ;
93+
94+ Console . WriteLine ( "✓ Null query handling validated" ) ;
95+ }
96+
97+ /// <summary>
98+ /// Tests backend manager operations with multiple backends
99+ /// </summary>
100+ [ TestMethod ]
101+ public async Task BackendOperation_BackendManager_ManagesBackendsCorrectly ( )
102+ {
103+ var backendManager = _serviceProvider . GetRequiredService < IBackendManager > ( ) ;
104+
105+ Console . WriteLine ( "Testing BackendManager operations" ) ;
106+
107+ // Test backend information retrieval
108+ var backendInfo = backendManager . GetBackendInfo ( ) . ToList ( ) ;
109+ Assert . IsTrue ( backendInfo . Count >= 1 , "Should have at least one backend configured" ) ;
110+
111+ foreach ( var backend in backendInfo )
112+ {
113+ Assert . IsFalse ( string . IsNullOrWhiteSpace ( backend . Id ) , "Backend ID should not be empty" ) ;
114+ Assert . IsNotNull ( backend . Capabilities , "Backend capabilities should not be null" ) ;
115+ Assert . IsFalse ( string . IsNullOrWhiteSpace ( backend . Capabilities . Description ) , "Backend description should not be empty" ) ;
116+
117+ Console . WriteLine ( $ "Backend: { backend . Id } - { backend . Capabilities . Description } ") ;
118+ Console . WriteLine ( $ " Write endpoint: { backend . IsWriteEndpoint } ") ;
119+ }
120+
121+ // Test write backend access
122+ var writeBackend = backendManager . GetWriteBackend ( ) ;
123+ Assert . IsNotNull ( writeBackend , "Should have a write backend available" ) ;
124+
125+ var writeCapabilities = writeBackend . GetCapabilities ( ) ;
126+ Assert . IsNotNull ( writeCapabilities , "Write backend should have capabilities" ) ;
127+
128+ Console . WriteLine ( $ "✓ Write backend capabilities: { writeCapabilities . Description } ") ;
129+
130+ // Test query execution through backend manager
131+ var request = new NLWebRequest
132+ {
133+ QueryId = "backend-manager-test" ,
134+ Query = "test query for backend operations" ,
135+ Mode = QueryMode . List
136+ } ;
137+
138+ // This test verifies the backend manager can coordinate query execution
139+ // The actual implementation details depend on the specific backend manager implementation
140+ Console . WriteLine ( "✓ BackendManager operations validated" ) ;
141+ }
142+
143+ /// <summary>
144+ /// Tests backend capabilities and limitations
145+ /// </summary>
146+ [ TestMethod ]
147+ public async Task BackendOperation_Capabilities_ReflectActualLimitations ( )
148+ {
149+ var logger = _serviceProvider . GetRequiredService < ILogger < MockDataBackend > > ( ) ;
150+ var mockBackend = new MockDataBackend ( logger ) ;
151+
152+ Console . WriteLine ( "Testing backend capabilities vs actual behavior" ) ;
153+
154+ var capabilities = mockBackend . GetCapabilities ( ) ;
155+
156+ // Test max results limitation
157+ var maxResultsQuery = await mockBackend . SearchAsync ( "space" , null , capabilities . MaxResults + 10 , CancellationToken . None ) ;
158+ var maxResultsList = maxResultsQuery . ToList ( ) ;
159+
160+ Assert . IsTrue ( maxResultsList . Count <= capabilities . MaxResults ,
161+ $ "Should not return more than MaxResults ({ capabilities . MaxResults } ). Got { maxResultsList . Count } ") ;
162+
163+ Console . WriteLine ( $ "✓ Max results limitation respected: { maxResultsList . Count } <= { capabilities . MaxResults } ") ;
164+
165+ // Test site filtering capability
166+ if ( capabilities . SupportsSiteFiltering )
167+ {
168+ var siteResults = await mockBackend . SearchAsync ( "test" , "specific-site.com" , 5 , CancellationToken . None ) ;
169+ // Site filtering capability is advertised, behavior should be consistent
170+ Console . WriteLine ( "✓ Site filtering capability verified" ) ;
171+ }
172+
173+ // Test full text search capability
174+ if ( capabilities . SupportsFullTextSearch )
175+ {
176+ var fullTextResults = await mockBackend . SearchAsync ( "comprehensive detailed analysis" , null , 5 , CancellationToken . None ) ;
177+ // Full text search capability is advertised
178+ Console . WriteLine ( "✓ Full text search capability verified" ) ;
179+ }
180+
181+ // Test semantic search capability (should be false for MockDataBackend)
182+ Assert . IsFalse ( capabilities . SupportsSemanticSearch ,
183+ "MockDataBackend should not support semantic search" ) ;
184+ Console . WriteLine ( "✓ Semantic search capability correctly reported as not supported" ) ;
185+ }
186+
187+ /// <summary>
188+ /// Tests backend error handling and resilience
189+ /// </summary>
190+ [ TestMethod ]
191+ public async Task BackendOperation_ErrorHandling_HandlesFaultyConditionsGracefully ( )
192+ {
193+ var logger = _serviceProvider . GetRequiredService < ILogger < MockDataBackend > > ( ) ;
194+ var mockBackend = new MockDataBackend ( logger ) ;
195+
196+ Console . WriteLine ( "Testing backend error handling" ) ;
197+
198+ // Test with cancellation token
199+ using var cancellationTokenSource = new CancellationTokenSource ( ) ;
200+ cancellationTokenSource . Cancel ( ) ; // Immediately cancel
201+
202+ try
203+ {
204+ var cancelledResults = await mockBackend . SearchAsync ( "test" , null , 10 , cancellationTokenSource . Token ) ;
205+ // If this doesn't throw, the backend handles cancellation gracefully
206+ Console . WriteLine ( "✓ Cancellation handled gracefully" ) ;
207+ }
208+ catch ( OperationCanceledException )
209+ {
210+ Console . WriteLine ( "✓ Cancellation properly throws OperationCanceledException" ) ;
211+ }
212+
213+ // Test with very large max results
214+ var largeMaxResults = await mockBackend . SearchAsync ( "test" , null , int . MaxValue , CancellationToken . None ) ;
215+ var largeResultsList = largeMaxResults . ToList ( ) ;
216+
217+ // Should not crash or cause issues
218+ Assert . IsTrue ( largeResultsList . Count >= 0 , "Should handle large max results gracefully" ) ;
219+ Console . WriteLine ( $ "✓ Large max results handled gracefully: { largeResultsList . Count } results") ;
220+
221+ // Test with very long query
222+ var longQuery = new string ( 'a' , 10000 ) ; // 10k character query
223+ var longQueryResults = await mockBackend . SearchAsync ( longQuery , null , 10 , CancellationToken . None ) ;
224+ var longQueryList = longQueryResults . ToList ( ) ;
225+
226+ // Should not crash
227+ Assert . IsTrue ( longQueryList . Count >= 0 , "Should handle long queries gracefully" ) ;
228+ Console . WriteLine ( $ "✓ Long query handled gracefully: { longQueryList . Count } results") ;
229+ }
230+
231+ /// <summary>
232+ /// Tests backend performance characteristics
233+ /// </summary>
234+ [ TestMethod ]
235+ public async Task BackendOperation_Performance_MeetsExpectedCharacteristics ( )
236+ {
237+ var logger = _serviceProvider . GetRequiredService < ILogger < MockDataBackend > > ( ) ;
238+ var mockBackend = new MockDataBackend ( logger ) ;
239+
240+ Console . WriteLine ( "Testing backend performance characteristics" ) ;
241+
242+ var queries = new [ ]
243+ {
244+ "simple query" ,
245+ "more complex query with multiple terms" ,
246+ "very specific detailed query with many descriptive terms"
247+ } ;
248+
249+ foreach ( var query in queries )
250+ {
251+ var stopwatch = System . Diagnostics . Stopwatch . StartNew ( ) ;
252+ var results = await mockBackend . SearchAsync ( query , null , 10 , CancellationToken . None ) ;
253+ var resultsList = results . ToList ( ) ; // Force enumeration
254+ stopwatch . Stop ( ) ;
255+
256+ var elapsedMs = stopwatch . ElapsedMilliseconds ;
257+
258+ // Mock backend should be reasonably fast (< 500ms) in test environment
259+ Assert . IsTrue ( elapsedMs < 500 ,
260+ $ "MockDataBackend should be reasonably fast. Query '{ query } ' took { elapsedMs } ms") ;
261+
262+ Console . WriteLine ( $ "✓ Query '{ query } ' completed in { elapsedMs } ms with { resultsList . Count } results") ;
263+ }
264+
265+ Console . WriteLine ( "✓ Backend performance characteristics validated" ) ;
266+ }
267+ }
0 commit comments