Skip to content

Commit 2e0b56e

Browse files
committed
test(cmd): cover --jq fail-fast wiring
Add a hermetic test proving the root command's PersistentPreRunE runs GlobalOpts.PreRun and rejects an invalid --jq expression before any subcommand's RunE builds a client or reaches the network. A test-only probe subcommand records whether its RunE ran; the fail-fast path leaves it untouched, and a control case confirms a valid expression lets it run. Also note at the assignment that this is the sole PersistentPreRunE in the tree, so a subcommand defining its own would silently disable --jq fail-fast validation.
1 parent 2fea014 commit 2e0b56e

2 files changed

Lines changed: 73 additions & 1 deletion

File tree

internal/cmd/root.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func NewRootCmd() *cobra.Command {
3939
pf.BoolVarP(&g.Quiet, "quiet", "q", false, "Suppress non-essential output")
4040
pf.StringVar(&g.JQ, "jq", "", "Filter JSON output with a jq expression")
4141

42+
// Sole PersistentPreRunE in the tree — cobra runs only the closest such hook,
43+
// so a subcommand defining its own would silently suppress this and disable
44+
// --jq fail-fast validation.
4245
root.PersistentPreRunE = func(cmd *cobra.Command, args []string) error {
4346
return g.PreRun()
4447
}

internal/cmd/root_test.go

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
package cmd
22

3-
import "testing"
3+
import (
4+
"io"
5+
"strings"
6+
"testing"
7+
8+
"github.com/spf13/cobra"
9+
)
410

511
func TestNewRootCmdRegistersJQFlag(t *testing.T) {
612
root := NewRootCmd()
@@ -9,3 +15,66 @@ func TestNewRootCmdRegistersJQFlag(t *testing.T) {
915
t.Fatal("expected root command to register a persistent --jq flag")
1016
}
1117
}
18+
19+
// newProbeRoot returns the real root command (with its PersistentPreRunE
20+
// wiring) plus a test-only "probe" subcommand that records whether its RunE
21+
// ran. The probe stands in for a real API-calling command (ping, task list, …)
22+
// but touches neither config nor the network, so the tests below stay
23+
// hermetic and deterministic in CI.
24+
func newProbeRoot(ran *bool) *cobra.Command {
25+
root := NewRootCmd()
26+
root.AddCommand(&cobra.Command{
27+
Use: "probe",
28+
Args: cobra.NoArgs,
29+
RunE: func(*cobra.Command, []string) error {
30+
*ran = true
31+
return nil
32+
},
33+
})
34+
root.SetOut(io.Discard)
35+
root.SetErr(io.Discard)
36+
return root
37+
}
38+
39+
// TestPersistentPreRunEFailsFastOnInvalidJQ proves the root command's
40+
// PersistentPreRunE wiring runs GlobalOpts.PreRun and rejects an invalid --jq
41+
// expression before any subcommand's RunE executes — i.e. before a client is
42+
// built or the network is reached. The probe subcommand inherits root's
43+
// PersistentPreRunE (cobra runs the closest hook), so its RunE must stay
44+
// untouched on the fail-fast path.
45+
func TestPersistentPreRunEFailsFastOnInvalidJQ(t *testing.T) {
46+
var ranRunE bool
47+
root := newProbeRoot(&ranRunE)
48+
root.SetArgs([]string{"probe", "--jq", "("})
49+
50+
err := root.Execute()
51+
if err == nil {
52+
t.Fatal("expected an error from the invalid --jq expression")
53+
}
54+
// Assert the specific compile error, not merely that some error occurred, so
55+
// this distinguishes a PreRun short-circuit from a RunE/config/network
56+
// failure — only the former proves the wiring runs and fails fast.
57+
if !strings.Contains(err.Error(), "invalid --jq expression") {
58+
t.Fatalf("error = %q, want it to contain %q", err.Error(), "invalid --jq expression")
59+
}
60+
if ranRunE {
61+
t.Fatal("subcommand RunE ran; PreRun did not short-circuit before the command executed")
62+
}
63+
}
64+
65+
// TestPersistentPreRunERunsRunEForValidJQ is the control for the fail-fast
66+
// test: with a valid --jq the same probe subcommand's RunE does run. Without
67+
// this, the fail-fast assertion could pass vacuously (e.g. if the probe never
68+
// ran for an unrelated reason).
69+
func TestPersistentPreRunERunsRunEForValidJQ(t *testing.T) {
70+
var ranRunE bool
71+
root := newProbeRoot(&ranRunE)
72+
root.SetArgs([]string{"probe", "--jq", ".task.id"})
73+
74+
if err := root.Execute(); err != nil {
75+
t.Fatalf("unexpected error with a valid --jq: %v", err)
76+
}
77+
if !ranRunE {
78+
t.Fatal("probe RunE did not run with a valid --jq; the fail-fast assertion would be vacuous")
79+
}
80+
}

0 commit comments

Comments
 (0)