@@ -316,3 +316,139 @@ func TestGetIssuesByIDsInTx_SmallInputLargeWispTable(t *testing.T) {
316316 t .Fatalf ("read tx: %v" , err )
317317 }
318318}
319+
320+ // TestExportHydrationHelpers_SmallInputLargeWispTable covers the bulk
321+ // hydration helpers used by `bd export`. These helpers must partition input IDs
322+ // with a scoped WispIDSetInTx query; falling back to per-ID IsActiveWispInTx
323+ // checks is correct but becomes painfully slow against remote Dolt servers.
324+ func TestExportHydrationHelpers_SmallInputLargeWispTable (t * testing.T ) {
325+ store , cleanup := setupTestStore (t )
326+ defer cleanup ()
327+
328+ ctx , cancel := testContext (t )
329+ defer cancel ()
330+
331+ blocker := & types.Issue {
332+ ID : "export-hydrate-blocker" ,
333+ Title : "blocker" ,
334+ Status : types .StatusOpen ,
335+ Priority : 2 ,
336+ IssueType : types .TypeTask ,
337+ }
338+ if err := store .CreateIssue (ctx , blocker , "tester" ); err != nil {
339+ t .Fatalf ("create blocker: %v" , err )
340+ }
341+
342+ perm := & types.Issue {
343+ ID : "export-hydrate-perm" ,
344+ Title : "perm" ,
345+ Status : types .StatusOpen ,
346+ Priority : 2 ,
347+ IssueType : types .TypeTask ,
348+ }
349+ if err := store .CreateIssue (ctx , perm , "tester" ); err != nil {
350+ t .Fatalf ("create perm: %v" , err )
351+ }
352+ if _ , err := store .AddIssueComment (ctx , perm .ID , "tester" , "perm comment" ); err != nil {
353+ t .Fatalf ("add perm comment: %v" , err )
354+ }
355+ if err := store .AddDependency (ctx , & types.Dependency {
356+ IssueID : perm .ID ,
357+ DependsOnID : blocker .ID ,
358+ Type : types .DepBlocks ,
359+ }, "tester" ); err != nil {
360+ t .Fatalf ("add perm dependency: %v" , err )
361+ }
362+
363+ target := & types.Issue {
364+ Title : "target wisp" ,
365+ Status : types .StatusOpen ,
366+ Priority : 2 ,
367+ IssueType : types .TypeTask ,
368+ Ephemeral : true ,
369+ }
370+ if err := store .CreateIssue (ctx , target , "tester" ); err != nil {
371+ t .Fatalf ("create target wisp: %v" , err )
372+ }
373+ if _ , err := store .AddIssueComment (ctx , target .ID , "tester" , "target comment" ); err != nil {
374+ t .Fatalf ("add target comment: %v" , err )
375+ }
376+ if err := store .AddDependency (ctx , & types.Dependency {
377+ IssueID : target .ID ,
378+ DependsOnID : blocker .ID ,
379+ Type : types .DepBlocks ,
380+ }, "tester" ); err != nil {
381+ t .Fatalf ("add target dependency: %v" , err )
382+ }
383+
384+ const noiseCount = 20
385+ noiseIDs := make ([]string , 0 , noiseCount )
386+ for i := 0 ; i < noiseCount ; i ++ {
387+ iss := & types.Issue {
388+ Title : fmt .Sprintf ("noise wisp %d" , i ),
389+ Status : types .StatusOpen ,
390+ Priority : 2 ,
391+ IssueType : types .TypeTask ,
392+ Ephemeral : true ,
393+ }
394+ if err := store .CreateIssue (ctx , iss , "tester" ); err != nil {
395+ t .Fatalf ("create noise %d: %v" , i , err )
396+ }
397+ if _ , err := store .AddIssueComment (ctx , iss .ID , "tester" , fmt .Sprintf ("noise comment %d" , i )); err != nil {
398+ t .Fatalf ("add noise comment %d: %v" , i , err )
399+ }
400+ noiseIDs = append (noiseIDs , iss .ID )
401+ }
402+
403+ input := []string {perm .ID , target .ID }
404+
405+ if err := store .withReadTx (ctx , func (tx * sql.Tx ) error {
406+ commentMap , err := issueops .GetCommentsForIssuesInTx (ctx , tx , input )
407+ if err != nil {
408+ return fmt .Errorf ("GetCommentsForIssuesInTx: %w" , err )
409+ }
410+ if got := len (commentMap [perm .ID ]); got != 1 {
411+ t .Errorf ("perm comments: got %d, want 1" , got )
412+ }
413+ if got := len (commentMap [target .ID ]); got != 1 {
414+ t .Errorf ("target comments: got %d, want 1" , got )
415+ }
416+
417+ commentCounts , err := issueops .GetCommentCountsInTx (ctx , tx , input )
418+ if err != nil {
419+ return fmt .Errorf ("GetCommentCountsInTx: %w" , err )
420+ }
421+ if got := commentCounts [perm .ID ]; got != 1 {
422+ t .Errorf ("perm comment count: got %d, want 1" , got )
423+ }
424+ if got := commentCounts [target .ID ]; got != 1 {
425+ t .Errorf ("target comment count: got %d, want 1" , got )
426+ }
427+
428+ depMap , err := issueops .GetDependencyRecordsForIssuesInTx (ctx , tx , input )
429+ if err != nil {
430+ return fmt .Errorf ("GetDependencyRecordsForIssuesInTx: %w" , err )
431+ }
432+ if got := len (depMap [perm .ID ]); got != 1 {
433+ t .Errorf ("perm dependencies: got %d, want 1" , got )
434+ }
435+ if got := len (depMap [target .ID ]); got != 1 {
436+ t .Errorf ("target dependencies: got %d, want 1" , got )
437+ }
438+
439+ for _ , n := range noiseIDs {
440+ if _ , leaked := commentMap [n ]; leaked {
441+ t .Errorf ("comments leaked noise wisp %q" , n )
442+ }
443+ if _ , leaked := commentCounts [n ]; leaked {
444+ t .Errorf ("comment counts leaked noise wisp %q" , n )
445+ }
446+ if _ , leaked := depMap [n ]; leaked {
447+ t .Errorf ("dependencies leaked noise wisp %q" , n )
448+ }
449+ }
450+ return nil
451+ }); err != nil {
452+ t .Fatalf ("read tx: %v" , err )
453+ }
454+ }
0 commit comments