@@ -744,59 +744,34 @@ func RegisterRoutes(rg *gin.RouterGroup) {
744744}
745745
746746func TestAsyncDispatchKeywords (t * testing.T ) {
747- // Test the full linker flow to verify edge types.
748- // Uses a Go caller with CreateTask (async) and a Python route handler.
749747 dir , err := os .MkdirTemp ("" , "httplink-async-*" )
750748 if err != nil {
751749 t .Fatal (err )
752750 }
753751 defer os .RemoveAll (dir )
754752
755- // Write a Go file with CreateTask + URL (async dispatch)
756- asyncDir := filepath .Join (dir , "taskworker" )
757- if err := os .MkdirAll (asyncDir , 0o755 ); err != nil {
758- t .Fatal (err )
759- }
760- if err := os .WriteFile (filepath .Join (asyncDir , "dispatch.go" ), []byte (`package taskworker
753+ writeTestFile (t , dir , "taskworker" , "dispatch.go" , `package taskworker
761754
762755func DispatchOrder(orderID string) {
763756 url := "https://api.internal.com/api/orders"
764757 client.CreateTask(ctx, url, payload)
765758}
766- ` ), 0o600 ); err != nil {
767- t .Fatal (err )
768- }
769-
770- // Write a Go file with requests.post + URL (sync HTTP call)
771- syncDir := filepath .Join (dir , "synccaller" )
772- if err := os .MkdirAll (syncDir , 0o755 ); err != nil {
773- t .Fatal (err )
774- }
775- if err := os .WriteFile (filepath .Join (syncDir , "caller.go" ), []byte (`package synccaller
759+ ` )
760+ writeTestFile (t , dir , "synccaller" , "caller.go" , `package synccaller
776761
777762func CallOrder() {
778763 url := "https://api.internal.com/api/orders"
779764 requests.post(url, data)
780765}
781- ` ), 0o600 ); err != nil {
782- t .Fatal (err )
783- }
784-
785- // Write a Go file with both sync + async keywords (sync takes precedence)
786- bothDir := filepath .Join (dir , "bothcaller" )
787- if err := os .MkdirAll (bothDir , 0o755 ); err != nil {
788- t .Fatal (err )
789- }
790- if err := os .WriteFile (filepath .Join (bothDir , "both.go" ), []byte (`package bothcaller
766+ ` )
767+ writeTestFile (t , dir , "bothcaller" , "both.go" , `package bothcaller
791768
792769func CallAndDispatch() {
793770 url := "https://api.internal.com/api/orders"
794771 requests.post(url, data)
795772 client.CreateTask(ctx, url, payload)
796773}
797- ` ), 0o600 ); err != nil {
798- t .Fatal (err )
799- }
774+ ` )
800775
801776 s , err := store .OpenMemory ()
802777 if err != nil {
@@ -809,35 +784,15 @@ func CallAndDispatch() {
809784 t .Fatal (err )
810785 }
811786
812- // Async caller function
813- _ , _ = s .UpsertNode (& store.Node {
814- Project : project , Label : "Function" , Name : "DispatchOrder" ,
815- QualifiedName : "testproj.taskworker.dispatch.DispatchOrder" ,
816- FilePath : "taskworker/dispatch.go" , StartLine : 3 , EndLine : 6 ,
817- })
818-
819- // Sync caller function
820- _ , _ = s .UpsertNode (& store.Node {
821- Project : project , Label : "Function" , Name : "CallOrder" ,
822- QualifiedName : "testproj.synccaller.caller.CallOrder" ,
823- FilePath : "synccaller/caller.go" , StartLine : 3 , EndLine : 6 ,
824- })
787+ createTestNode (t , s , project , "DispatchOrder" , "testproj.taskworker.dispatch.DispatchOrder" , "taskworker/dispatch.go" , 3 , 6 )
788+ createTestNode (t , s , project , "CallOrder" , "testproj.synccaller.caller.CallOrder" , "synccaller/caller.go" , 3 , 6 )
789+ createTestNode (t , s , project , "CallAndDispatch" , "testproj.bothcaller.both.CallAndDispatch" , "bothcaller/both.go" , 3 , 7 )
825790
826- // Both keywords caller function
827- _ , _ = s .UpsertNode (& store.Node {
828- Project : project , Label : "Function" , Name : "CallAndDispatch" ,
829- QualifiedName : "testproj.bothcaller.both.CallAndDispatch" ,
830- FilePath : "bothcaller/both.go" , StartLine : 3 , EndLine : 7 ,
831- })
832-
833- // Route handler (different service)
834791 _ , _ = s .UpsertNode (& store.Node {
835792 Project : project , Label : "Function" , Name : "create_order" ,
836793 QualifiedName : "testproj.handler.routes.create_order" ,
837794 FilePath : "handler/routes.py" ,
838- Properties : map [string ]any {
839- "decorators" : []any {`@app.post("/api/orders")` },
840- },
795+ Properties : map [string ]any {"decorators" : []any {`@app.post("/api/orders")` }},
841796 })
842797
843798 linker := New (s , project )
@@ -846,56 +801,68 @@ func CallAndDispatch() {
846801 t .Fatalf ("Run: %v" , err )
847802 }
848803
849- // Build a map of callerQN -> edgeType for verification
850804 edgeTypes := map [string ]string {}
851805 for _ , link := range links {
852806 edgeTypes [link .CallerQN ] = link .EdgeType
853807 }
854808
855- // Async caller (CreateTask only) -> ASYNC_CALLS
856- if et , ok := edgeTypes ["testproj.taskworker.dispatch.DispatchOrder" ]; ! ok {
857- t .Error ("expected link from async caller DispatchOrder" )
858- } else if et != "ASYNC_CALLS" {
859- t .Errorf ("DispatchOrder edge type = %q, want ASYNC_CALLS" , et )
860- }
809+ assertEdgeType (t , edgeTypes , "testproj.taskworker.dispatch.DispatchOrder" , "ASYNC_CALLS" )
810+ assertEdgeType (t , edgeTypes , "testproj.synccaller.caller.CallOrder" , "HTTP_CALLS" )
811+ assertEdgeType (t , edgeTypes , "testproj.bothcaller.both.CallAndDispatch" , "HTTP_CALLS" )
812+
813+ assertStoredEdgeCounts (t , s , project , "testproj.taskworker.dispatch.DispatchOrder" , 1 , 0 )
814+ assertStoredEdgeCounts (t , s , project , "testproj.synccaller.caller.CallOrder" , 0 , 1 )
815+ }
861816
862- // Sync caller (requests.post only) -> HTTP_CALLS
863- if et , ok := edgeTypes ["testproj.synccaller.caller.CallOrder" ]; ! ok {
864- t .Error ("expected link from sync caller CallOrder" )
865- } else if et != "HTTP_CALLS" {
866- t .Errorf ("CallOrder edge type = %q, want HTTP_CALLS" , et )
817+ func writeTestFile (t * testing.T , dir , subdir , filename , content string ) {
818+ t .Helper ()
819+ d := filepath .Join (dir , subdir )
820+ if err := os .MkdirAll (d , 0o755 ); err != nil {
821+ t .Fatal (err )
822+ }
823+ if err := os .WriteFile (filepath .Join (d , filename ), []byte (content ), 0o600 ); err != nil {
824+ t .Fatal (err )
867825 }
826+ }
868827
869- // Both keywords (sync takes precedence) -> HTTP_CALLS
870- if et , ok := edgeTypes ["testproj.bothcaller.both.CallAndDispatch" ]; ! ok {
871- t .Error ("expected link from both-keyword caller CallAndDispatch" )
872- } else if et != "HTTP_CALLS" {
873- t .Errorf ("CallAndDispatch edge type = %q, want HTTP_CALLS" , et )
828+ func createTestNode (t * testing.T , s * store.Store , project , name , qn , filePath string , startLine , endLine int ) {
829+ t .Helper ()
830+ _ , err := s .UpsertNode (& store.Node {
831+ Project : project , Label : "Function" , Name : name ,
832+ QualifiedName : qn , FilePath : filePath ,
833+ StartLine : startLine , EndLine : endLine ,
834+ })
835+ if err != nil {
836+ t .Fatal (err )
874837 }
838+ }
875839
876- // Verify edges in store match
877- asyncNode , _ := s .FindNodeByQN (project , "testproj.taskworker.dispatch.DispatchOrder" )
878- if asyncNode != nil {
879- asyncEdges , _ := s .FindEdgesBySourceAndType (asyncNode .ID , "ASYNC_CALLS" )
880- if len (asyncEdges ) != 1 {
881- t .Errorf ("expected 1 ASYNC_CALLS edge from async caller, got %d" , len (asyncEdges ))
882- }
883- httpEdges , _ := s .FindEdgesBySourceAndType (asyncNode .ID , "HTTP_CALLS" )
884- if len (httpEdges ) != 0 {
885- t .Errorf ("expected 0 HTTP_CALLS edges from async caller, got %d" , len (httpEdges ))
886- }
840+ func assertEdgeType (t * testing.T , edgeTypes map [string ]string , qn , wantType string ) {
841+ t .Helper ()
842+ et , ok := edgeTypes [qn ]
843+ if ! ok {
844+ t .Errorf ("expected link from %s" , qn )
845+ return
846+ }
847+ if et != wantType {
848+ t .Errorf ("%s edge type = %q, want %q" , qn , et , wantType )
887849 }
850+ }
888851
889- syncNode , _ := s .FindNodeByQN (project , "testproj.synccaller.caller.CallOrder" )
890- if syncNode != nil {
891- httpEdges , _ := s .FindEdgesBySourceAndType (syncNode .ID , "HTTP_CALLS" )
892- if len (httpEdges ) != 1 {
893- t .Errorf ("expected 1 HTTP_CALLS edge from sync caller, got %d" , len (httpEdges ))
894- }
895- asyncEdges , _ := s .FindEdgesBySourceAndType (syncNode .ID , "ASYNC_CALLS" )
896- if len (asyncEdges ) != 0 {
897- t .Errorf ("expected 0 ASYNC_CALLS edges from sync caller, got %d" , len (asyncEdges ))
898- }
852+ func assertStoredEdgeCounts (t * testing.T , s * store.Store , project , qn string , wantAsync , wantHTTP int ) {
853+ t .Helper ()
854+ node , _ := s .FindNodeByQN (project , qn )
855+ if node == nil {
856+ t .Errorf ("node not found: %s" , qn )
857+ return
858+ }
859+ asyncEdges , _ := s .FindEdgesBySourceAndType (node .ID , "ASYNC_CALLS" )
860+ if len (asyncEdges ) != wantAsync {
861+ t .Errorf ("%s: ASYNC_CALLS edges = %d, want %d" , qn , len (asyncEdges ), wantAsync )
862+ }
863+ httpEdges , _ := s .FindEdgesBySourceAndType (node .ID , "HTTP_CALLS" )
864+ if len (httpEdges ) != wantHTTP {
865+ t .Errorf ("%s: HTTP_CALLS edges = %d, want %d" , qn , len (httpEdges ), wantHTTP )
899866 }
900867}
901868
0 commit comments