@@ -340,60 +340,6 @@ func TestComponent_incrementalUpdates(t *testing.T) {
340340 require .Equal (t , lastUpdate , sinceParams [2 ], "_since parameter should match the stored lastUpdate timestamp" )
341341}
342342
343- func TestComponent_noDuplicateResourcesInTransactionBundle (t * testing.T ) {
344- // This test verifies that when _history returns multiple versions of the same resource,
345- // the transaction bundle sent to the query directory contains no duplicates.
346- // This addresses the HAPI error: "Transaction bundle contains multiple resources with ID: urn:uuid:..."
347- emptyResponse , err := os .ReadFile ("test/regression_lrza_empty_history_response.json" )
348- require .NoError (t , err )
349- historyWithDuplicatesBytes , err := os .ReadFile ("test/history_with_duplicates.json" )
350- require .NoError (t , err )
351-
352- mockMux := http .NewServeMux ()
353- // Convert []byte responses to strings for pointer approach
354- historyWithDuplicatesStr := string (historyWithDuplicatesBytes )
355- emptyResponseStr3 := string (emptyResponse )
356-
357- mockHistoryEndpoints (mockMux , map [string ]* string {
358- "/Organization/_history" : & historyWithDuplicatesStr ,
359- "/Location/_history" : & emptyResponseStr3 ,
360- "/Endpoint/_history" : & emptyResponseStr3 ,
361- "/HealthcareService/_history" : & emptyResponseStr3 ,
362- })
363- mockServer := httptest .NewServer (mockMux )
364- defer mockServer .Close ()
365-
366- capturingClient := & test.StubFHIRClient {}
367- component , err := New (Config {
368- QueryDirectory : DirectoryConfig {FHIRBaseURL : "http://example.com/local/fhir" },
369- })
370- require .NoError (t , err )
371-
372- // Register as discovered directory to avoid Organization filtering
373- err = component .registerAdministrationDirectory (context .Background (), mockServer .URL , []string {"Organization" , "Endpoint" }, false )
374- require .NoError (t , err )
375-
376- component .fhirClientFn = func (baseURL * url.URL ) fhirclient.Client {
377- if baseURL .String () == mockServer .URL {
378- return fhirclient .New (baseURL , http .DefaultClient , & fhirclient.Config {UsePostSearch : false })
379- }
380- if baseURL .String () == "http://example.com/local/fhir" {
381- return capturingClient
382- }
383- return & test.StubFHIRClient {Error : errors .New ("unknown URL" )}
384- }
385-
386- ctx := context .Background ()
387- report , err := component .update (ctx )
388-
389- require .NoError (t , err )
390- require .Empty (t , report [mockServer .URL ].Errors , "Should not have errors after deduplication" )
391-
392- // Should have 0 Organizations because the DELETE operation is the most recent
393- orgs := capturingClient .CreatedResources ["Organization" ]
394- require .Len (t , orgs , 0 , "Should have 0 Organizations after deduplication (DELETE is most recent operation)" )
395- }
396-
397343func TestExtractResourceIDFromURL (t * testing.T ) {
398344 tests := []struct {
399345 name string
@@ -604,3 +550,82 @@ func TestGetLastUpdated(t *testing.T) {
604550 })
605551 }
606552}
553+
554+ func TestComponent_updateFromDirectory (t * testing.T ) {
555+ ctx := context .Background ()
556+
557+ t .Run ("#233: no entry.Request in _history results" , func (t * testing.T ) {
558+ t .Log ("See https://github.com/nuts-foundation/nuts-knooppunt/issues/233" )
559+ server := startMockServer (t , map [string ]string {
560+ "/fhir/Organization/_history" : "test/bugs/233-no-bundle-request/organization_response.json" ,
561+ })
562+ component , err := New (Config {})
563+ require .NoError (t , err )
564+ report , err := component .updateFromDirectory (ctx , server .URL + "/fhir" , []string {"Organization" }, false )
565+ require .NoError (t , err )
566+ require .NotNil (t , report )
567+ require .Len (t , report .Warnings , 1 )
568+ assert .Equal (t , report .Warnings [0 ], "Skipping entry with no request: #0" )
569+ assert .Empty (t , report .Errors )
570+ assert .Equal (t , 0 , report .CountCreated )
571+ assert .Equal (t , 0 , report .CountUpdated )
572+ assert .Equal (t , 0 , report .CountDeleted )
573+ })
574+
575+ t .Run ("no duplicate resources in transaction bundle" , func (t * testing.T ) {
576+ // This test verifies that when _history returns multiple versions of the same resource,
577+ // the transaction bundle sent to the query directory contains no duplicates.
578+ // This addresses the HAPI error: "Transaction bundle contains multiple resources with ID: urn:uuid:..."
579+ server := startMockServer (t , map [string ]string {
580+ "/fhir/Organization/_history" : "test/history_with_duplicates.json" ,
581+ })
582+ defer server .Close ()
583+
584+ capturingClient := & test.StubFHIRClient {}
585+ component , err := New (Config {})
586+ require .NoError (t , err )
587+
588+ component .fhirClientFn = func (baseURL * url.URL ) fhirclient.Client {
589+ if baseURL .String () == server .URL + "/fhir" {
590+ return fhirclient .New (baseURL , http .DefaultClient , & fhirclient.Config {UsePostSearch : false })
591+ }
592+ if baseURL .String () == "http://example.com/local/fhir" {
593+ return capturingClient
594+ }
595+ return & test.StubFHIRClient {Error : errors .New ("unknown URL" )}
596+ }
597+
598+ report , err := component .updateFromDirectory (ctx , server .URL + "/fhir" , []string {"Organization" , "Endpoint" }, false )
599+
600+ require .NoError (t , err )
601+ require .Empty (t , report .Errors , "Should not have errors after deduplication" )
602+
603+ // Should have 0 Organizations because the DELETE operation is the most recent
604+ orgs := capturingClient .CreatedResources ["Organization" ]
605+ require .Len (t , orgs , 0 , "Should have 0 Organizations after deduplication (DELETE is most recent operation)" )
606+ })
607+ }
608+
609+ func startMockServer (t * testing.T , filesToServe map [string ]string ) * httptest.Server {
610+ mux := http .NewServeMux ()
611+ server := httptest .NewServer (mux )
612+
613+ emptyBundleData , err := os .ReadFile ("test/empty_bundle_response.json" )
614+ require .NoError (t , err )
615+ emptyResponseStr := string (emptyBundleData )
616+ pathsToServe := map [string ]* string {
617+ "/fhir/Endpoint/_history" : & emptyResponseStr ,
618+ "/fhir/Organization/_history" : & emptyResponseStr ,
619+ "/fhir/Location/_history" : & emptyResponseStr ,
620+ "/fhir/HealthcareService/_history" : & emptyResponseStr ,
621+ }
622+ for path , filename := range filesToServe {
623+ data , err := os .ReadFile (filename )
624+ require .NoError (t , err )
625+ dataStr := string (data )
626+ pathsToServe [path ] = & dataStr
627+ }
628+
629+ mockHistoryEndpoints (mux , pathsToServe )
630+ return server
631+ }
0 commit comments