package infra import ( "context" "strings" "testing" "time" ) func TestPTYCaptureStream(t *testing.T) { t.Run("snapshots crecientes con pausas", func(t *testing.T) { if testing.Short() { t.Skip("skip en modo corto: timing sensible") } ctx := context.Background() // bash -lc imprime A, pausa 0.3s, B, pausa 0.3s, C, pausa 0.3s. // Con snapshotInterval 100ms e idle 400ms debería recibir varios snapshots // y el último debe contener A, B y C. ch, err := PTYCaptureStream( ctx, "bash", []string{"-lc", "printf A; sleep 0.3; printf B; sleep 0.3; printf C; sleep 0.3"}, 50*time.Millisecond, // warmup nil, // inputs 0, // stepDelay 100*time.Millisecond, // snapshotInterval 400*time.Millisecond, // idle 5*time.Second, // maxDur ) if err != nil { t.Fatalf("error inesperado al arrancar: %v", err) } var snapshots []string for s := range ch { snapshots = append(snapshots, s) } if len(snapshots) < 2 { t.Errorf("se esperaban >=2 snapshots, got %d", len(snapshots)) } // Snapshots deben ser acumulativos (monótonos en longitud). for i := 1; i < len(snapshots); i++ { if len(snapshots[i]) < len(snapshots[i-1]) { t.Errorf("snapshot[%d] len=%d < snapshot[%d] len=%d — no acumulativo", i, len(snapshots[i]), i-1, len(snapshots[i-1])) } } // El último snapshot debe contener A, B y C. last := snapshots[len(snapshots)-1] for _, want := range []string{"A", "B", "C"} { if !strings.Contains(last, want) { t.Errorf("último snapshot no contiene %q: %q", want, last) } } }) t.Run("snapshot final siempre presente", func(t *testing.T) { if testing.Short() { t.Skip("skip en modo corto") } ctx := context.Background() // Output instantáneo; con idle 300ms el canal cierra rápido. ch, err := PTYCaptureStream( ctx, "bash", []string{"-lc", "printf HOLA"}, 50*time.Millisecond, nil, 0, 150*time.Millisecond, // snapshotInterval 300*time.Millisecond, // idle 5*time.Second, ) if err != nil { t.Fatalf("error inesperado: %v", err) } var last string for s := range ch { last = s } if !strings.Contains(last, "HOLA") { t.Errorf("último snapshot no contiene 'HOLA': %q", last) } }) t.Run("timeout duro con sleep 10", func(t *testing.T) { if testing.Short() { t.Skip("skip en modo corto: espera ~1s de timeout") } ctx := context.Background() start := time.Now() ch, err := PTYCaptureStream( ctx, "sleep", []string{"10"}, 50*time.Millisecond, nil, 0, 200*time.Millisecond, // snapshotInterval 600*time.Millisecond, // idle 1*time.Second, // maxDur duro en 1s ) if err != nil { t.Fatalf("error inesperado al arrancar: %v", err) } // Drenar completamente el canal. for range ch { } elapsed := time.Since(start) // La función debe retornar en menos de 3s, no esperar los 10s del sleep. if elapsed >= 3*time.Second { t.Errorf("la función tardó %v, se esperaba < 3s", elapsed) } }) }