@@ -155,3 +155,191 @@ type MockIllRepositoryNoSelectedSupplier struct {
155155func (r * MockIllRepositoryNoSelectedSupplier ) GetSelectedSupplierForIllTransaction (ctx common.ExtendedContext , illTransId string ) (ill_db.LocatedSupplier , error ) {
156156 return ill_db.LocatedSupplier {}, pgx .ErrNoRows
157157}
158+
159+ // mockDuplicateCheckRepo overrides FindDuplicateIllTransaction to return
160+ // configurable results for duplicate-check testing.
161+ type mockDuplicateCheckRepo struct {
162+ mocks.MockIllRepositorySuccess
163+ duplicateId string
164+ err error
165+ called bool
166+ params ill_db.FindDuplicateIllTransactionParams
167+ }
168+
169+ func (r * mockDuplicateCheckRepo ) FindDuplicateIllTransaction (ctx common.ExtendedContext , params ill_db.FindDuplicateIllTransactionParams ) (string , error ) {
170+ r .called = true
171+ r .params = params
172+ return r .duplicateId , r .err
173+ }
174+
175+ func TestCheckDuplicateRequest (t * testing.T ) {
176+ window1 := 1
177+ window0 := 0
178+ windowNeg := - 1
179+
180+ baseRequest := & iso18626.Request {
181+ BibliographicInfo : iso18626.BibliographicInfo {
182+ SupplierUniqueRecordId : "rec-1" ,
183+ Title : "Test Title" ,
184+ },
185+ ServiceInfo : & iso18626.ServiceInfo {
186+ ServiceType : iso18626 .TypeServiceTypeLoan ,
187+ },
188+ PatronInfo : & iso18626.PatronInfo {
189+ PatronId : "patron-1" ,
190+ },
191+ }
192+
193+ isbnRequest := & iso18626.Request {
194+ BibliographicInfo : iso18626.BibliographicInfo {
195+ BibliographicItemId : []iso18626.BibliographicItemId {
196+ {
197+ BibliographicItemIdentifier : "978-1234" ,
198+ BibliographicItemIdentifierCode : iso18626.TypeSchemeValuePair {Text : "ISBN" },
199+ },
200+ },
201+ },
202+ ServiceInfo : & iso18626.ServiceInfo {ServiceType : iso18626 .TypeServiceTypeCopy },
203+ PatronInfo : & iso18626.PatronInfo {PatronId : "patron-2" },
204+ }
205+
206+ tests := []struct {
207+ name string
208+ request * iso18626.Request
209+ peer ill_db.Peer
210+ duplicateId string
211+ repoErr error
212+ wantErr error
213+ wantRepoCalled bool
214+ wantPatronId string
215+ wantWindowHrs int32
216+ wantIdentifier string
217+ wantIsbn string
218+ wantIssn string
219+ wantTitle string
220+ wantSvcType string
221+ }{
222+ {
223+ name : "no DuplicateCheckWindowHours configured - skips check" ,
224+ request : baseRequest ,
225+ peer : ill_db.Peer {},
226+ wantErr : nil ,
227+ wantRepoCalled : false ,
228+ },
229+ {
230+ name : "window is zero - skips check" ,
231+ request : baseRequest ,
232+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window0 }},
233+ wantErr : nil ,
234+ wantRepoCalled : false ,
235+ },
236+ {
237+ name : "window is negative - skips check" ,
238+ request : baseRequest ,
239+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & windowNeg }},
240+ wantErr : nil ,
241+ wantRepoCalled : false ,
242+ },
243+ {
244+ name : "db error - fails open, allows request through" ,
245+ request : baseRequest ,
246+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
247+ repoErr : errors .New ("db connection error" ),
248+ wantErr : nil ,
249+ wantRepoCalled : true ,
250+ wantPatronId : "patron-1" ,
251+ wantWindowHrs : 1 ,
252+ wantIdentifier : "rec-1" ,
253+ wantTitle : "Test Title" ,
254+ wantSvcType : "Loan" ,
255+ },
256+ {
257+ name : "no duplicate found (ErrNoRows) - not a duplicate" ,
258+ request : baseRequest ,
259+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
260+ repoErr : pgx .ErrNoRows ,
261+ wantErr : nil ,
262+ wantRepoCalled : true ,
263+ wantPatronId : "patron-1" ,
264+ wantWindowHrs : 1 ,
265+ wantIdentifier : "rec-1" ,
266+ wantTitle : "Test Title" ,
267+ wantSvcType : "Loan" ,
268+ },
269+ {
270+ name : "duplicate found - returns ErrDuplicateRequest" ,
271+ request : baseRequest ,
272+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
273+ duplicateId : "existing-tx-id" ,
274+ wantErr : ErrDuplicateRequest ,
275+ wantRepoCalled : true ,
276+ wantPatronId : "patron-1" ,
277+ wantWindowHrs : 1 ,
278+ wantIdentifier : "rec-1" ,
279+ wantTitle : "Test Title" ,
280+ wantSvcType : "Loan" ,
281+ },
282+ {
283+ name : "nil PatronInfo - uses empty patron ID in query" ,
284+ request : & iso18626.Request {
285+ BibliographicInfo : iso18626.BibliographicInfo {SupplierUniqueRecordId : "rec-1" },
286+ ServiceInfo : & iso18626.ServiceInfo {ServiceType : iso18626 .TypeServiceTypeLoan },
287+ },
288+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
289+ repoErr : pgx .ErrNoRows ,
290+ wantErr : nil ,
291+ wantRepoCalled : true ,
292+ wantPatronId : "" ,
293+ wantWindowHrs : 1 ,
294+ wantIdentifier : "rec-1" ,
295+ wantSvcType : "Loan" ,
296+ },
297+ {
298+ name : "isbn passed as parameter to DB query" ,
299+ request : isbnRequest ,
300+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
301+ repoErr : pgx .ErrNoRows ,
302+ wantErr : nil ,
303+ wantRepoCalled : true ,
304+ wantPatronId : "patron-2" ,
305+ wantWindowHrs : 1 ,
306+ wantIsbn : "978-1234" ,
307+ wantSvcType : "Copy" ,
308+ },
309+ {
310+ name : "duplicate found via isbn - returns ErrDuplicateRequest" ,
311+ request : isbnRequest ,
312+ peer : ill_db.Peer {CustomData : directory.Entry {DuplicateCheckWindowHours : & window1 }},
313+ duplicateId : "existing-tx-isbn" ,
314+ wantErr : ErrDuplicateRequest ,
315+ wantRepoCalled : true ,
316+ wantPatronId : "patron-2" ,
317+ wantWindowHrs : 1 ,
318+ wantIsbn : "978-1234" ,
319+ wantSvcType : "Copy" ,
320+ },
321+ }
322+
323+ for _ , tt := range tests {
324+ t .Run (tt .name , func (t * testing.T ) {
325+ appCtx := common .CreateExtCtxWithArgs (context .Background (), nil )
326+ mockRepo := & mockDuplicateCheckRepo {
327+ duplicateId : tt .duplicateId ,
328+ err : tt .repoErr ,
329+ }
330+ err := checkDuplicateRequest (appCtx , tt .request , mockRepo , "ISIL:REQ1" , tt .peer )
331+ assert .Equal (t , tt .wantErr , err )
332+ assert .Equal (t , tt .wantRepoCalled , mockRepo .called )
333+ if tt .wantRepoCalled {
334+ assert .Equal (t , "ISIL:REQ1" , mockRepo .params .RequesterSymbol .String )
335+ assert .Equal (t , tt .wantPatronId , mockRepo .params .PatronID )
336+ assert .Equal (t , tt .wantWindowHrs , mockRepo .params .Hours )
337+ assert .Equal (t , tt .wantIdentifier , mockRepo .params .Identifier )
338+ assert .Equal (t , tt .wantIsbn , mockRepo .params .Isbn )
339+ assert .Equal (t , tt .wantIssn , mockRepo .params .Issn )
340+ assert .Equal (t , tt .wantTitle , mockRepo .params .Title )
341+ assert .Equal (t , tt .wantSvcType , mockRepo .params .ServiceType )
342+ }
343+ })
344+ }
345+ }
0 commit comments