Skip to content

Commit 56bcb6f

Browse files
authored
Make Cobra runner compatible with testing interactive flows (#957)
## Changes This PR enables testing commands with stdin ## Tests #914
1 parent 283f241 commit 56bcb6f

File tree

1 file changed

+49
-1
lines changed

1 file changed

+49
-1
lines changed

internal/helpers.go

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bufio"
55
"bytes"
66
"context"
7+
"encoding/json"
78
"fmt"
89
"io"
910
"math/rand"
@@ -17,6 +18,7 @@ import (
1718

1819
"github.com/databricks/cli/cmd"
1920
_ "github.com/databricks/cli/cmd/version"
21+
"github.com/databricks/cli/libs/cmdio"
2022
"github.com/databricks/databricks-sdk-go"
2123
"github.com/databricks/databricks-sdk-go/apierr"
2224
"github.com/databricks/databricks-sdk-go/service/compute"
@@ -63,6 +65,8 @@ type cobraTestRunner struct {
6365
args []string
6466
stdout bytes.Buffer
6567
stderr bytes.Buffer
68+
stdinR *io.PipeReader
69+
stdinW *io.PipeWriter
6670

6771
ctx context.Context
6872

@@ -119,15 +123,46 @@ func (t *cobraTestRunner) registerFlagCleanup(c *cobra.Command) {
119123
})
120124
}
121125

126+
// Like [cobraTestRunner.Eventually], but more specific
127+
func (t *cobraTestRunner) WaitForTextPrinted(text string, timeout time.Duration) {
128+
t.Eventually(func() bool {
129+
currentStdout := t.stdout.String()
130+
return strings.Contains(currentStdout, text)
131+
}, timeout, 50*time.Millisecond)
132+
}
133+
134+
func (t *cobraTestRunner) WithStdin() {
135+
reader, writer := io.Pipe()
136+
t.stdinR = reader
137+
t.stdinW = writer
138+
}
139+
140+
func (t *cobraTestRunner) CloseStdin() {
141+
if t.stdinW == nil {
142+
panic("no standard input configured")
143+
}
144+
t.stdinW.Close()
145+
}
146+
147+
func (t *cobraTestRunner) SendText(text string) {
148+
if t.stdinW == nil {
149+
panic("no standard input configured")
150+
}
151+
t.stdinW.Write([]byte(text + "\n"))
152+
}
153+
122154
func (t *cobraTestRunner) RunBackground() {
123155
var stdoutR, stderrR io.Reader
124156
var stdoutW, stderrW io.WriteCloser
125157
stdoutR, stdoutW = io.Pipe()
126158
stderrR, stderrW = io.Pipe()
127-
root := cmd.New(context.Background())
159+
root := cmd.New(t.ctx)
128160
root.SetOut(stdoutW)
129161
root.SetErr(stderrW)
130162
root.SetArgs(t.args)
163+
if t.stdinW != nil {
164+
root.SetIn(t.stdinR)
165+
}
131166

132167
// Register cleanup function to restore flags to their original values
133168
// once test has been executed. This is needed because flag values reside
@@ -239,6 +274,19 @@ func (c *cobraTestRunner) Eventually(condition func() bool, waitFor time.Duratio
239274
}
240275
}
241276

277+
func (t *cobraTestRunner) RunAndExpectOutput(heredoc string) {
278+
stdout, _, err := t.Run()
279+
require.NoError(t, err)
280+
require.Equal(t, cmdio.Heredoc(heredoc), strings.TrimSpace(stdout.String()))
281+
}
282+
283+
func (t *cobraTestRunner) RunAndParseJSON(v any) {
284+
stdout, _, err := t.Run()
285+
require.NoError(t, err)
286+
err = json.Unmarshal(stdout.Bytes(), &v)
287+
require.NoError(t, err)
288+
}
289+
242290
func NewCobraTestRunner(t *testing.T, args ...string) *cobraTestRunner {
243291
return &cobraTestRunner{
244292
T: t,

0 commit comments

Comments
 (0)