@@ -6,16 +6,10 @@ import ConnectionManager from '@/config/connectionmanager';
66// Mock ConnectionManager
77vi . mock ( '@/config/connectionmanager' , ( ) => {
88 const executeQuery = vi . fn ( ) ;
9- const beginTransaction = vi . fn ( ) ;
10- const commitTransaction = vi . fn ( ) ;
11- const rollbackTransaction = vi . fn ( ) ;
129 const closeConnection = vi . fn ( ) ;
1310 const cleanupStaleTransactions = vi . fn ( ) ;
1411 const instance = {
1512 executeQuery,
16- beginTransaction,
17- commitTransaction,
18- rollbackTransaction,
1913 closeConnection,
2014 cleanupStaleTransactions
2115 } ;
@@ -61,6 +55,11 @@ function makeParams() {
6155 } as any ;
6256}
6357
58+ /** Helper: generate mock FailedMeasurementID rows */
59+ function mockFailedIds ( count : number ) {
60+ return Array . from ( { length : count } , ( _ , i ) => ( { FailedMeasurementID : i + 1 } ) ) ;
61+ }
62+
6463describe ( 'reingest API routes' , ( ) => {
6564 let mockConnectionManager : any ;
6665 let mockValidateContextualValues : any ;
@@ -69,9 +68,6 @@ describe('reingest API routes', () => {
6968 vi . clearAllMocks ( ) ;
7069 mockConnectionManager = ConnectionManager . getInstance ( ) ;
7170 mockConnectionManager . cleanupStaleTransactions . mockResolvedValue ( undefined ) ;
72- mockConnectionManager . beginTransaction . mockResolvedValue ( 'test-transaction-id' ) ;
73- mockConnectionManager . commitTransaction . mockResolvedValue ( undefined ) ;
74- mockConnectionManager . rollbackTransaction . mockResolvedValue ( undefined ) ;
7571 mockConnectionManager . closeConnection . mockResolvedValue ( undefined ) ;
7672
7773 // Get the mocked function
@@ -91,12 +87,12 @@ describe('reingest API routes', () => {
9187
9288 describe ( 'POST route (move rows only)' , ( ) => {
9389 it ( 'moves rows from failedmeasurements to temporarymeasurements' , async ( ) => {
94- // Mock count query
9590 mockConnectionManager . executeQuery
96- . mockResolvedValueOnce ( [ { total : 5 } ] ) // Count query
97- . mockResolvedValueOnce ( undefined ) // DELETE temporarymeasurements
98- . mockResolvedValueOnce ( undefined ) // INSERT INTO temporarymeasurements
99- . mockResolvedValueOnce ( undefined ) ; // DELETE failedmeasurements
91+ . mockResolvedValueOnce ( [ { total : 5 } ] ) // 1. COUNT(*)
92+ . mockResolvedValueOnce ( mockFailedIds ( 5 ) ) // 2. SELECT FailedMeasurementID
93+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
94+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
95+ . mockResolvedValueOnce ( undefined ) ; // 5. DELETE failedmeasurements by IDs
10096
10197 const req = makeRequest ( 'POST' ) ;
10298 const res = await POST ( req , makeParams ( ) ) ;
@@ -107,13 +103,8 @@ describe('reingest API routes', () => {
107103 expect ( body . fileID ) . toBe ( 'reingestion.csv' ) ;
108104 expect ( body . batchID ) . toBe ( 'test-batch-id-12345' ) ;
109105
110- // Verify transaction management
111- expect ( mockConnectionManager . beginTransaction ) . toHaveBeenCalledTimes ( 1 ) ;
112- expect ( mockConnectionManager . commitTransaction ) . toHaveBeenCalledTimes ( 1 ) ;
113106 expect ( mockConnectionManager . closeConnection ) . toHaveBeenCalledTimes ( 1 ) ;
114-
115- // Verify queries were called
116- expect ( mockConnectionManager . executeQuery ) . toHaveBeenCalledTimes ( 4 ) ;
107+ expect ( mockConnectionManager . executeQuery ) . toHaveBeenCalledTimes ( 5 ) ;
117108 } ) ;
118109
119110 it ( 'returns 200 with rowsMoved=0 when no failed measurements exist' , async ( ) => {
@@ -128,7 +119,7 @@ describe('reingest API routes', () => {
128119 expect ( body . responseMessage ) . toMatch ( / N o f a i l e d m e a s u r e m e n t s f o u n d / i) ;
129120 } ) ;
130121
131- it ( 'rolls back transaction on error' , async ( ) => {
122+ it ( 'returns 500 on error' , async ( ) => {
132123 mockConnectionManager . executeQuery . mockRejectedValueOnce ( new Error ( 'Database error' ) ) ;
133124
134125 const req = makeRequest ( 'POST' ) ;
@@ -137,21 +128,22 @@ describe('reingest API routes', () => {
137128 expect ( res . status ) . toBe ( 500 ) ;
138129 const body = await res . json ( ) ;
139130 expect ( body . error ) . toBe ( 'Database error' ) ;
140- expect ( mockConnectionManager . rollbackTransaction ) . toHaveBeenCalledTimes ( 1 ) ;
131+ expect ( mockConnectionManager . closeConnection ) . toHaveBeenCalledTimes ( 1 ) ;
141132 } ) ;
142133 } ) ;
143134
144135 describe ( 'GET route (full reingestion)' , ( ) => {
145136 it ( 'moves rows and runs batch ingestion process' , async ( ) => {
146- // Mock all queries for full reingestion
147137 mockConnectionManager . executeQuery
148- . mockResolvedValueOnce ( [ { total : 10 } ] ) // Count query
149- . mockResolvedValueOnce ( undefined ) // DELETE temporarymeasurements
150- . mockResolvedValueOnce ( undefined ) // INSERT INTO temporarymeasurements
151- . mockResolvedValueOnce ( undefined ) // DELETE failedmeasurements
152- . mockResolvedValueOnce ( undefined ) // CALL bulkingestionprocess
153- . mockResolvedValueOnce ( [ { remaining : 2 } ] ) // Count remaining failures
154- . mockResolvedValueOnce ( undefined ) ; // CALL reviewfailed
138+ . mockResolvedValueOnce ( [ { total : 10 } ] ) // 1. COUNT(*)
139+ . mockResolvedValueOnce ( mockFailedIds ( 10 ) ) // 2. SELECT FailedMeasurementID
140+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
141+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
142+ . mockResolvedValueOnce ( undefined ) // 5. CALL bulkingestionprocess
143+ . mockResolvedValueOnce ( undefined ) // 6. DELETE failedmeasurements by IDs
144+ . mockResolvedValueOnce ( undefined ) // 7. CALL refresh_failedmeasurements_current
145+ . mockResolvedValueOnce ( [ { cnt : 0 } ] ) // 8. SELECT COUNT(*) ready for reingestion
146+ . mockResolvedValueOnce ( [ { remaining : 2 } ] ) ; // 9. COUNT(*) remaining failures
155147
156148 const req = makeRequest ( 'GET' ) ;
157149 const res = await GET ( req , makeParams ( ) ) ;
@@ -167,9 +159,9 @@ describe('reingest API routes', () => {
167159 const bulkIngestionCall = calls . find ( ( call : any ) => call [ 0 ] ?. includes ( 'bulkingestionprocess' ) ) ;
168160 expect ( bulkIngestionCall ) . toBeDefined ( ) ;
169161
170- // Verify reviewfailed was called
171- const reviewFailedCall = calls . find ( ( call : any ) => call [ 0 ] ?. includes ( 'reviewfailed ' ) ) ;
172- expect ( reviewFailedCall ) . toBeDefined ( ) ;
162+ // Verify refresh was called
163+ const refreshCall = calls . find ( ( call : any ) => call [ 0 ] ?. includes ( 'refresh_failedmeasurements_current ' ) ) ;
164+ expect ( refreshCall ) . toBeDefined ( ) ;
173165 } ) ;
174166
175167 it ( 'returns 200 with 0 processed when no failed measurements exist' , async ( ) => {
@@ -187,13 +179,15 @@ describe('reingest API routes', () => {
187179
188180 it ( 'handles all rows successfully reingested' , async ( ) => {
189181 mockConnectionManager . executeQuery
190- . mockResolvedValueOnce ( [ { total : 5 } ] )
191- . mockResolvedValueOnce ( undefined ) // DELETE temporarymeasurements
192- . mockResolvedValueOnce ( undefined ) // INSERT INTO temporarymeasurements
193- . mockResolvedValueOnce ( undefined ) // DELETE failedmeasurements
194- . mockResolvedValueOnce ( undefined ) // CALL bulkingestionprocess
195- . mockResolvedValueOnce ( [ { remaining : 0 } ] ) // All successful
196- . mockResolvedValueOnce ( undefined ) ; // CALL reviewfailed
182+ . mockResolvedValueOnce ( [ { total : 5 } ] ) // 1. COUNT(*)
183+ . mockResolvedValueOnce ( mockFailedIds ( 5 ) ) // 2. SELECT FailedMeasurementID
184+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
185+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
186+ . mockResolvedValueOnce ( undefined ) // 5. CALL bulkingestionprocess
187+ . mockResolvedValueOnce ( undefined ) // 6. DELETE failedmeasurements by IDs
188+ . mockResolvedValueOnce ( undefined ) // 7. CALL refresh_failedmeasurements_current
189+ . mockResolvedValueOnce ( [ { cnt : 0 } ] ) // 8. SELECT COUNT(*) ready
190+ . mockResolvedValueOnce ( [ { remaining : 0 } ] ) ; // 9. All successful
197191
198192 const req = makeRequest ( 'GET' ) ;
199193 const res = await GET ( req , makeParams ( ) ) ;
@@ -205,23 +199,47 @@ describe('reingest API routes', () => {
205199 expect ( body . remainingFailures ) . toBe ( 0 ) ;
206200 } ) ;
207201
208- it ( 'rolls back and tries to run reviewfailed on error' , async ( ) => {
202+ it ( 'returns 500 on error' , async ( ) => {
209203 mockConnectionManager . executeQuery
210- . mockResolvedValueOnce ( [ { total : 5 } ] )
211- . mockResolvedValueOnce ( undefined )
212- . mockRejectedValueOnce ( new Error ( 'Bulk ingestion failed' ) ) ;
204+ . mockResolvedValueOnce ( [ { total : 5 } ] ) // 1. COUNT(*)
205+ . mockResolvedValueOnce ( mockFailedIds ( 5 ) ) // 2. SELECT FailedMeasurementID
206+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
207+ . mockRejectedValueOnce ( new Error ( 'Bulk ingestion failed' ) ) ; // 4. INSERT fails
213208
214209 const req = makeRequest ( 'GET' ) ;
215210 const res = await GET ( req , makeParams ( ) ) ;
216211
217212 expect ( res . status ) . toBe ( 500 ) ;
218213 const body = await res . json ( ) ;
219214 expect ( body . error ) . toBe ( 'Bulk ingestion failed' ) ;
220- expect ( mockConnectionManager . rollbackTransaction ) . toHaveBeenCalledTimes ( 1 ) ;
215+ expect ( mockConnectionManager . closeConnection ) . toHaveBeenCalledTimes ( 1 ) ;
216+ } ) ;
217+
218+ it ( 'auto-reingests rows marked Ready for reingestion' , async ( ) => {
219+ mockConnectionManager . executeQuery
220+ . mockResolvedValueOnce ( [ { total : 5 } ] ) // 1. COUNT(*)
221+ . mockResolvedValueOnce ( mockFailedIds ( 5 ) ) // 2. SELECT FailedMeasurementID
222+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
223+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
224+ . mockResolvedValueOnce ( undefined ) // 5. CALL bulkingestionprocess
225+ . mockResolvedValueOnce ( undefined ) // 6. DELETE failedmeasurements by IDs
226+ . mockResolvedValueOnce ( undefined ) // 7. CALL refresh_failedmeasurements_current
227+ . mockResolvedValueOnce ( [ { cnt : 2 } ] ) // 8. 2 rows ready for reingestion
228+ . mockResolvedValueOnce ( undefined ) // 9. INSERT ready rows into temporarymeasurements
229+ . mockResolvedValueOnce ( undefined ) // 10. CALL bulkingestionprocess (auto-reingest)
230+ . mockResolvedValueOnce ( undefined ) // 11. DELETE ready rows from failedmeasurements
231+ . mockResolvedValueOnce ( [ { remaining : 1 } ] ) ; // 12. COUNT(*) remaining
221232
222- // Should attempt to run reviewfailed even after error
223- const reviewFailedCall = mockConnectionManager . executeQuery . mock . calls . find ( ( call : any ) => call [ 0 ] ?. includes ( 'reviewfailed' ) ) ;
224- expect ( reviewFailedCall ) . toBeDefined ( ) ;
233+ const req = makeRequest ( 'GET' ) ;
234+ const res = await GET ( req , makeParams ( ) ) ;
235+
236+ expect ( res . status ) . toBe ( 200 ) ;
237+ const body = await res . json ( ) ;
238+ expect ( body . totalProcessed ) . toBe ( 5 ) ;
239+ expect ( body . successfulReingestions ) . toBe ( 4 ) ;
240+ expect ( body . remainingFailures ) . toBe ( 1 ) ;
241+
242+ expect ( mockConnectionManager . executeQuery ) . toHaveBeenCalledTimes ( 12 ) ;
225243 } ) ;
226244 } ) ;
227245
@@ -250,12 +268,12 @@ describe('reingest API routes', () => {
250268
251269 describe ( 'Attribute persistence regression tests' , ( ) => {
252270 it ( 'should preserve Codes field when moving to temporarymeasurements' , async ( ) => {
253- // Mock count query
254271 mockConnectionManager . executeQuery
255- . mockResolvedValueOnce ( [ { total : 1 } ] ) // Count query
256- . mockResolvedValueOnce ( undefined ) // DELETE temporarymeasurements
257- . mockResolvedValueOnce ( { insertId : 1 , affectedRows : 1 } ) // INSERT INTO temporarymeasurements
258- . mockResolvedValueOnce ( undefined ) ; // DELETE failedmeasurements
272+ . mockResolvedValueOnce ( [ { total : 1 } ] ) // 1. COUNT(*)
273+ . mockResolvedValueOnce ( mockFailedIds ( 1 ) ) // 2. SELECT FailedMeasurementID
274+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
275+ . mockResolvedValueOnce ( { insertId : 1 , affectedRows : 1 } ) // 4. INSERT INTO temporarymeasurements
276+ . mockResolvedValueOnce ( undefined ) ; // 5. DELETE failedmeasurements by IDs
259277
260278 const req = makeRequest ( 'POST' ) ;
261279 const res = await POST ( req , makeParams ( ) ) ;
@@ -272,39 +290,38 @@ describe('reingest API routes', () => {
272290 expect ( insertCall [ 0 ] ) . toContain ( 'fm.Codes' ) ; // Maps from failedmeasurements
273291 } ) ;
274292
275- it ( 'should call reviewfailed after successful GET reingestion ' , async ( ) => {
293+ it ( 'should complete GET reingestion without extra validation calls ' , async ( ) => {
276294 mockConnectionManager . executeQuery
277- . mockResolvedValueOnce ( [ { total : 5 } ] )
278- . mockResolvedValueOnce ( undefined ) // DELETE temporarymeasurements
279- . mockResolvedValueOnce ( undefined ) // INSERT INTO temporarymeasurements
280- . mockResolvedValueOnce ( undefined ) // DELETE failedmeasurements
281- . mockResolvedValueOnce ( undefined ) // CALL bulkingestionprocess
282- . mockResolvedValueOnce ( [ { remaining : 0 } ] ) // Count remaining
283- . mockResolvedValueOnce ( undefined ) ; // CALL reviewfailed
295+ . mockResolvedValueOnce ( [ { total : 5 } ] ) // 1. COUNT(*)
296+ . mockResolvedValueOnce ( mockFailedIds ( 5 ) ) // 2. SELECT FailedMeasurementID
297+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
298+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
299+ . mockResolvedValueOnce ( undefined ) // 5. CALL bulkingestionprocess
300+ . mockResolvedValueOnce ( undefined ) // 6. DELETE failedmeasurements by IDs
301+ . mockResolvedValueOnce ( undefined ) // 7. CALL refresh_failedmeasurements_current
302+ . mockResolvedValueOnce ( [ { cnt : 0 } ] ) // 8. SELECT COUNT(*) ready
303+ . mockResolvedValueOnce ( [ { remaining : 0 } ] ) ; // 9. Count remaining
284304
285305 const req = makeRequest ( 'GET' ) ;
286306 const res = await GET ( req , makeParams ( ) ) ;
287307
288308 expect ( res . status ) . toBe ( 200 ) ;
289-
290- // Verify reviewfailed was called to update failure reasons
291- const reviewFailedCall = mockConnectionManager . executeQuery . mock . calls . find ( ( call : any ) => call [ 0 ] ?. includes ( 'reviewfailed' ) ) ;
292-
293- expect ( reviewFailedCall ) . toBeDefined ( ) ;
294309 } ) ;
295310
296311 it ( 'should handle rows with codes correctly in bulk ingestion' , async ( ) => {
297312 // This test verifies the complete flow:
298313 // failedmeasurements (with Codes) → temporarymeasurements → bulkingestionprocess → cmattributes
299314
300315 mockConnectionManager . executeQuery
301- . mockResolvedValueOnce ( [ { total : 1 } ] ) // Count
302- . mockResolvedValueOnce ( undefined ) // DELETE temp
303- . mockResolvedValueOnce ( undefined ) // INSERT temp
304- . mockResolvedValueOnce ( undefined ) // DELETE failed
305- . mockResolvedValueOnce ( undefined ) // bulkingestionprocess
306- . mockResolvedValueOnce ( [ { remaining : 0 } ] ) // Count remaining - all succeeded
307- . mockResolvedValueOnce ( undefined ) ; // reviewfailed
316+ . mockResolvedValueOnce ( [ { total : 1 } ] ) // 1. COUNT(*)
317+ . mockResolvedValueOnce ( mockFailedIds ( 1 ) ) // 2. SELECT FailedMeasurementID
318+ . mockResolvedValueOnce ( undefined ) // 3. DELETE temporarymeasurements
319+ . mockResolvedValueOnce ( undefined ) // 4. INSERT INTO temporarymeasurements
320+ . mockResolvedValueOnce ( undefined ) // 5. CALL bulkingestionprocess
321+ . mockResolvedValueOnce ( undefined ) // 6. DELETE failedmeasurements by IDs
322+ . mockResolvedValueOnce ( undefined ) // 7. CALL refresh_failedmeasurements_current
323+ . mockResolvedValueOnce ( [ { cnt : 0 } ] ) // 8. SELECT COUNT(*) ready
324+ . mockResolvedValueOnce ( [ { remaining : 0 } ] ) ; // 9. All succeeded
308325
309326 const req = makeRequest ( 'GET' ) ;
310327 const res = await GET ( req , makeParams ( ) ) ;
0 commit comments