test: batch 00 of refactoring CLI tests not to use PTY (#25868)

Part of https://github.com/coder/internal/issues/1400

Batch of refactored CLI tests to avoid creating PTYs.
This commit is contained in:
Spike Curtis
2026-05-29 15:33:45 -04:00
committed by GitHub
parent 0401ed3af5
commit 8a47b7fa14
9 changed files with 192 additions and 180 deletions
+5 -6
View File
@@ -10,8 +10,8 @@ import (
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/pty/ptytest"
"github.com/coder/coder/v2/testutil"
"github.com/coder/coder/v2/testutil/expecter"
"github.com/coder/serpent"
)
@@ -21,7 +21,6 @@ func TestExternalAuth(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
ptty := ptytest.New(t)
cmd := &serpent.Command{
Handler: func(inv *serpent.Invocation) error {
var fetched atomic.Bool
@@ -42,16 +41,16 @@ func TestExternalAuth(t *testing.T) {
}
inv := cmd.Invoke().WithContext(ctx)
stdout := expecter.NewAttachedToInvocation(t, inv)
ptty.Attach(inv)
done := make(chan struct{})
go func() {
defer close(done)
err := inv.Run()
assert.NoError(t, err)
}()
ptty.ExpectMatchContext(ctx, "You must authenticate with")
ptty.ExpectMatchContext(ctx, "https://example.com/gitauth/github")
ptty.ExpectMatchContext(ctx, "Successfully authenticated with GitHub")
stdout.ExpectMatchContext(ctx, "You must authenticate with")
stdout.ExpectMatchContext(ctx, "https://example.com/gitauth/github")
stdout.ExpectMatchContext(ctx, "Successfully authenticated with GitHub")
<-done
}
+19 -20
View File
@@ -16,8 +16,8 @@ import (
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/pty/ptytest"
"github.com/coder/coder/v2/testutil"
"github.com/coder/coder/v2/testutil/expecter"
"github.com/coder/serpent"
)
@@ -48,12 +48,12 @@ func TestProvisionerJob(t *testing.T) {
test.JobMutex.Unlock()
})
testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.PTY.ExpectMatch(cliui.ProvisioningStateRunning)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateRunning)
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateRunning)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateRunning)
return true
}, testutil.IntervalFast)
})
@@ -85,12 +85,12 @@ func TestProvisionerJob(t *testing.T) {
test.JobMutex.Unlock()
})
testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.PTY.ExpectMatch("Something")
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, "Something")
test.Next <- struct{}{}
test.PTY.ExpectMatch("Something")
test.Stdout.ExpectMatchContext(ctx, "Something")
return true
}, testutil.IntervalFast)
})
@@ -151,12 +151,12 @@ func TestProvisionerJob(t *testing.T) {
test.JobMutex.Unlock()
})
testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
test.PTY.ExpectRegexMatch(tc.expected)
test.Stdout.ExpectRegexMatchContext(ctx, tc.expected)
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued) // step completed
test.PTY.ExpectMatch(cliui.ProvisioningStateRunning)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued) // step completed
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateRunning)
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateRunning)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateRunning)
return true
}, testutil.IntervalFast)
})
@@ -193,11 +193,11 @@ func TestProvisionerJob(t *testing.T) {
test.JobMutex.Unlock()
})
testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
test.Next <- struct{}{}
test.PTY.ExpectMatch("Gracefully canceling")
test.Stdout.ExpectMatchContext(ctx, "Gracefully canceling")
test.Next <- struct{}{}
test.PTY.ExpectMatch(cliui.ProvisioningStateQueued)
test.Stdout.ExpectMatchContext(ctx, cliui.ProvisioningStateQueued)
return true
}, testutil.IntervalFast)
})
@@ -208,7 +208,7 @@ type provisionerJobTest struct {
Job *codersdk.ProvisionerJob
JobMutex *sync.Mutex
Logs chan codersdk.ProvisionerJobLog
PTY *ptytest.PTY
Stdout *expecter.Expecter
}
func newProvisionerJob(t *testing.T) provisionerJobTest {
@@ -240,8 +240,7 @@ func newProvisionerJob(t *testing.T) provisionerJobTest {
}
inv := cmd.Invoke()
ptty := ptytest.New(t)
ptty.Attach(inv)
stdout := expecter.NewAttachedToInvocation(t, inv)
done := make(chan struct{})
go func() {
defer close(done)
@@ -258,7 +257,7 @@ func newProvisionerJob(t *testing.T) provisionerJobTest {
Job: job,
JobMutex: &jobLock,
Logs: logs,
PTY: ptty,
Stdout: stdout,
}
}
+7 -13
View File
@@ -8,7 +8,6 @@ import (
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk"
"github.com/coder/coder/v2/pty/ptytest"
"github.com/coder/serpent"
)
@@ -16,10 +15,9 @@ func TestSelect(t *testing.T) {
t.Parallel()
t.Run("Select", func(t *testing.T) {
t.Parallel()
ptty := ptytest.New(t)
msgChan := make(chan string)
go func() {
resp, err := newSelect(ptty, cliui.SelectOptions{
resp, err := newSelect(cliui.SelectOptions{
Options: []string{"First", "Second"},
})
assert.NoError(t, err)
@@ -29,7 +27,7 @@ func TestSelect(t *testing.T) {
})
}
func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) {
func newSelect(opts cliui.SelectOptions) (string, error) {
value := ""
cmd := &serpent.Command{
Handler: func(inv *serpent.Invocation) error {
@@ -39,7 +37,6 @@ func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) {
},
}
inv := cmd.Invoke()
ptty.Attach(inv)
return value, inv.Run()
}
@@ -47,10 +44,10 @@ func TestRichSelect(t *testing.T) {
t.Parallel()
t.Run("RichSelect", func(t *testing.T) {
t.Parallel()
ptty := ptytest.New(t)
msgChan := make(chan string)
go func() {
resp, err := newRichSelect(ptty, cliui.RichSelectOptions{
resp, err := newRichSelect(cliui.RichSelectOptions{
Options: []codersdk.TemplateVersionParameterOption{
{Name: "A-Name", Value: "A-Value", Description: "A-Description."},
{Name: "B-Name", Value: "B-Value", Description: "B-Description."},
@@ -63,7 +60,7 @@ func TestRichSelect(t *testing.T) {
})
}
func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, error) {
func newRichSelect(opts cliui.RichSelectOptions) (string, error) {
value := ""
cmd := &serpent.Command{
Handler: func(inv *serpent.Invocation) error {
@@ -75,7 +72,6 @@ func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, err
},
}
inv := cmd.Invoke()
ptty.Attach(inv)
return value, inv.Run()
}
@@ -181,11 +177,10 @@ func TestMultiSelect(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ptty := ptytest.New(t)
msgChan := make(chan []string)
go func() {
resp, err := newMultiSelect(ptty, tt.items, tt.allowCustom)
resp, err := newMultiSelect(tt.items, tt.allowCustom)
assert.NoError(t, err)
msgChan <- resp
}()
@@ -195,7 +190,7 @@ func TestMultiSelect(t *testing.T) {
}
}
func newMultiSelect(pty *ptytest.PTY, items []string, custom bool) ([]string, error) {
func newMultiSelect(items []string, custom bool) ([]string, error) {
var values []string
cmd := &serpent.Command{
Handler: func(inv *serpent.Invocation) error {
@@ -211,6 +206,5 @@ func newMultiSelect(pty *ptytest.PTY, items []string, custom bool) ([]string, er
},
}
inv := cmd.Invoke()
pty.Attach(inv)
return values, inv.Run()
}