refactor: Rename 'expect' package to 'console' (#297)

Fixes #291 - renames the `expect` go package to `console`, and changes the api from `expect.NewTestConsole` to `console.New`, and a few other small changes to support the linter (ie, `ConsoleOpts` -> `Opts`)
This commit is contained in:
Bryan
2022-02-15 16:47:33 -08:00
committed by GitHub
parent 35291d358a
commit 6009c90d1d
16 changed files with 71 additions and 70 deletions

View File

@ -3,11 +3,12 @@ package clitest_test
import (
"testing"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/expect"
"github.com/stretchr/testify/require"
"go.uber.org/goleak"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/console"
)
func TestMain(m *testing.M) {
@ -20,11 +21,11 @@ func TestCli(t *testing.T) {
client := coderdtest.New(t)
cmd, config := clitest.New(t)
clitest.SetupConfig(t, client, config)
console := expect.NewTestConsole(t, cmd)
cons := console.New(t, cmd)
go func() {
err := cmd.Execute()
require.NoError(t, err)
}()
_, err := console.ExpectString("coder")
_, err := cons.ExpectString("coder")
require.NoError(t, err)
}

View File

@ -4,8 +4,8 @@ import (
"testing"
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/expect"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/console"
"github.com/stretchr/testify/require"
)
@ -26,7 +26,7 @@ func TestLogin(t *testing.T) {
// accurately detect Windows ptys when they are not attached to a process:
// https://github.com/mattn/go-isatty/issues/59
root, _ := clitest.New(t, "login", client.URL.String(), "--force-tty")
console := expect.NewTestConsole(t, root)
cons := console.New(t, root)
go func() {
err := root.Execute()
require.NoError(t, err)
@ -42,12 +42,12 @@ func TestLogin(t *testing.T) {
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
_, err := console.ExpectString(match)
_, err := cons.ExpectString(match)
require.NoError(t, err)
_, err = console.SendLine(value)
_, err = cons.SendLine(value)
require.NoError(t, err)
}
_, err := console.ExpectString("Welcome to Coder")
_, err := cons.ExpectString("Welcome to Coder")
require.NoError(t, err)
})
}

View File

@ -7,8 +7,8 @@ import (
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/console"
"github.com/coder/coder/database"
"github.com/coder/coder/expect"
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
)
@ -26,7 +26,7 @@ func TestProjectCreate(t *testing.T) {
cmd, root := clitest.New(t, "projects", "create", "--directory", source, "--provisioner", string(database.ProvisionerTypeEcho))
clitest.SetupConfig(t, client, root)
_ = coderdtest.NewProvisionerDaemon(t, client)
console := expect.NewTestConsole(t, cmd)
console := console.New(t, cmd)
closeChan := make(chan struct{})
go func() {
err := cmd.Execute()
@ -73,7 +73,7 @@ func TestProjectCreate(t *testing.T) {
cmd, root := clitest.New(t, "projects", "create", "--directory", source, "--provisioner", string(database.ProvisionerTypeEcho))
clitest.SetupConfig(t, client, root)
coderdtest.NewProvisionerDaemon(t, client)
console := expect.NewTestConsole(t, cmd)
cons := console.New(t, cmd)
closeChan := make(chan struct{})
go func() {
err := cmd.Execute()
@ -91,9 +91,9 @@ func TestProjectCreate(t *testing.T) {
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
_, err := console.ExpectString(match)
_, err := cons.ExpectString(match)
require.NoError(t, err)
_, err = console.SendLine(value)
_, err = cons.SendLine(value)
require.NoError(t, err)
}
<-closeChan

View File

@ -5,7 +5,7 @@ import (
"github.com/coder/coder/cli/clitest"
"github.com/coder/coder/coderd/coderdtest"
"github.com/coder/coder/expect"
"github.com/coder/coder/console"
"github.com/coder/coder/provisioner/echo"
"github.com/coder/coder/provisionersdk/proto"
"github.com/stretchr/testify/require"
@ -36,7 +36,7 @@ func TestWorkspaceCreate(t *testing.T) {
cmd, root := clitest.New(t, "workspaces", "create", project.Name)
clitest.SetupConfig(t, client, root)
console := expect.NewTestConsole(t, cmd)
cons := console.New(t, cmd)
closeChan := make(chan struct{})
go func() {
err := cmd.Execute()
@ -51,12 +51,12 @@ func TestWorkspaceCreate(t *testing.T) {
for i := 0; i < len(matches); i += 2 {
match := matches[i]
value := matches[i+1]
_, err := console.ExpectString(match)
_, err := cons.ExpectString(match)
require.NoError(t, err)
_, err = console.SendLine(value)
_, err = cons.SendLine(value)
require.NoError(t, err)
}
_, err := console.ExpectString("Create")
_, err := cons.ExpectString("Create")
require.NoError(t, err)
<-closeChan
})

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package expect
package console
import (
"bufio"
@ -23,7 +23,7 @@ import (
"os"
"unicode/utf8"
"github.com/coder/coder/expect/pty"
"github.com/coder/coder/console/pty"
)
// Console is an interface to automate input and output for interactive
@ -31,17 +31,17 @@ import (
// input back on it's tty. Console can also multiplex other sources of input
// and multiplex its output to other writers.
type Console struct {
opts ConsoleOpts
opts Opts
pty pty.Pty
runeReader *bufio.Reader
closers []io.Closer
}
// ConsoleOpt allows setting Console options.
type ConsoleOpt func(*ConsoleOpts) error
// Opt allows setting Console options.
type Opt func(*Opts) error
// ConsoleOpts provides additional options on creating a Console.
type ConsoleOpts struct {
// Opts provides additional options on creating a Console.
type Opts struct {
Logger *log.Logger
Stdouts []io.Writer
ExpectObservers []Observer
@ -62,8 +62,8 @@ type Observer func(matchers []Matcher, buf string, err error)
// last writer, writing to it's internal buffer for matching expects.
// If a listed writer returns an error, that overall write operation stops and
// returns the error; it does not continue down the list.
func WithStdout(writers ...io.Writer) ConsoleOpt {
return func(opts *ConsoleOpts) error {
func WithStdout(writers ...io.Writer) Opt {
return func(opts *Opts) error {
opts.Stdouts = append(opts.Stdouts, writers...)
return nil
}
@ -71,24 +71,24 @@ func WithStdout(writers ...io.Writer) ConsoleOpt {
// WithLogger adds a logger for Console to log debugging information to. By
// default Console will discard logs.
func WithLogger(logger *log.Logger) ConsoleOpt {
return func(opts *ConsoleOpts) error {
func WithLogger(logger *log.Logger) Opt {
return func(opts *Opts) error {
opts.Logger = logger
return nil
}
}
// WithExpectObserver adds an ExpectObserver to allow monitoring Expect operations.
func WithExpectObserver(observers ...Observer) ConsoleOpt {
return func(opts *ConsoleOpts) error {
func WithExpectObserver(observers ...Observer) Opt {
return func(opts *Opts) error {
opts.ExpectObservers = append(opts.ExpectObservers, observers...)
return nil
}
}
// NewConsole returns a new Console with the given options.
func NewConsole(opts ...ConsoleOpt) (*Console, error) {
options := ConsoleOpts{
func NewConsole(opts ...Opt) (*Console, error) {
options := Opts{
Logger: log.New(ioutil.Discard, "", 0),
}
@ -105,14 +105,14 @@ func NewConsole(opts ...ConsoleOpt) (*Console, error) {
closers := []io.Closer{consolePty}
reader := consolePty.Reader()
console := &Console{
cons := &Console{
opts: options,
pty: consolePty,
runeReader: bufio.NewReaderSize(reader, utf8.UTFMax),
closers: closers,
}
return console, nil
return cons, nil
}
// Tty returns an input Tty for accepting input

View File

@ -16,4 +16,4 @@
// applications. It is unlike expect in that it does not spawn or manage
// process lifecycle. This package only focuses on expecting output and sending
// input through it's psuedoterminal.
package expect
package console

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package expect
package console
import (
"bufio"
@ -40,8 +40,8 @@ func (c *Console) ExpectString(s string) (string, error) {
// expecting input yet, it will be blocked. Sends are queued up in tty's
// internal buffer so that the next Expect will read the remaining bytes (i.e.
// rest of prompt) as well as its conditions.
func (c *Console) Expect(opts ...Opt) (string, error) {
var options Opts
func (c *Console) Expect(opts ...ExpectOpt) (string, error) {
var options ExpectOpts
for _, opt := range opts {
if err := opt(&options); err != nil {
return "", err

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package expect
package console
import (
"bytes"
@ -20,22 +20,22 @@ import (
"time"
)
// Opt allows settings Expect options.
type Opt func(*Opts) error
// ExpectOpt allows settings Expect options.
type ExpectOpt func(*ExpectOpts) error
// ConsoleCallback is a callback function to execute if a match is found for
// Callback is a callback function to execute if a match is found for
// the chained matcher.
type ConsoleCallback func(buf *bytes.Buffer) error
type Callback func(buf *bytes.Buffer) error
// Opts provides additional options on Expect.
type Opts struct {
// ExpectOpts provides additional options on Expect.
type ExpectOpts struct {
Matchers []Matcher
ReadTimeout *time.Duration
}
// Match sequentially calls Match on all matchers in ExpectOpts and returns the
// first matcher if a match exists, otherwise nil.
func (eo Opts) Match(v interface{}) Matcher {
func (eo ExpectOpts) Match(v interface{}) Matcher {
for _, matcher := range eo.Matchers {
if matcher.Match(v) {
return matcher
@ -83,7 +83,7 @@ func (sm *stringMatcher) Criteria() interface{} {
// allMatcher fulfills the Matcher interface to match a group of ExpectOpt
// against any value.
type allMatcher struct {
options Opts
options ExpectOpts
}
func (am *allMatcher) Match(v interface{}) bool {
@ -109,9 +109,9 @@ func (am *allMatcher) Criteria() interface{} {
// All adds an Expect condition to exit if the content read from Console's tty
// matches all of the provided ExpectOpt, in any order.
func All(expectOpts ...Opt) Opt {
return func(opts *Opts) error {
var options Opts
func All(expectOpts ...ExpectOpt) ExpectOpt {
return func(opts *ExpectOpts) error {
var options ExpectOpts
for _, opt := range expectOpts {
if err := opt(&options); err != nil {
return err
@ -127,8 +127,8 @@ func All(expectOpts ...Opt) Opt {
// String adds an Expect condition to exit if the content read from Console's
// tty contains any of the given strings.
func String(strs ...string) Opt {
return func(opts *Opts) error {
func String(strs ...string) ExpectOpt {
return func(opts *ExpectOpts) error {
for _, str := range strs {
opts.Matchers = append(opts.Matchers, &stringMatcher{
str: str,

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package expect_test
package console_test
import (
"bytes"
@ -20,7 +20,7 @@ import (
"github.com/stretchr/testify/require"
. "github.com/coder/coder/expect"
. "github.com/coder/coder/console"
)
func TestExpectOptString(t *testing.T) {
@ -28,7 +28,7 @@ func TestExpectOptString(t *testing.T) {
tests := []struct {
title string
opt Opt
opt ExpectOpt
data string
expected bool
}{
@ -63,7 +63,7 @@ func TestExpectOptString(t *testing.T) {
t.Run(test.title, func(t *testing.T) {
t.Parallel()
var options Opts
var options ExpectOpts
err := test.opt(&options)
require.Nil(t, err)
@ -86,7 +86,7 @@ func TestExpectOptAll(t *testing.T) {
tests := []struct {
title string
opt Opt
opt ExpectOpt
data string
expected bool
}{
@ -144,7 +144,7 @@ func TestExpectOptAll(t *testing.T) {
test := test
t.Run(test.title, func(t *testing.T) {
t.Parallel()
var options Opts
var options ExpectOpts
err := test.opt(&options)
require.Nil(t, err)

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package expect_test
package console_test
import (
"bufio"
@ -26,7 +26,7 @@ import (
"golang.org/x/xerrors"
. "github.com/coder/coder/expect"
. "github.com/coder/coder/console"
)
var (
@ -71,14 +71,14 @@ func Prompt(in io.Reader, out io.Writer) error {
return nil
}
func newTestConsole(t *testing.T, opts ...ConsoleOpt) (*Console, error) {
opts = append([]ConsoleOpt{
func newTestConsole(t *testing.T, opts ...Opt) (*Console, error) {
opts = append([]Opt{
expectNoError(t),
}, opts...)
return NewConsole(opts...)
}
func expectNoError(t *testing.T) ConsoleOpt {
func expectNoError(t *testing.T) Opt {
return WithExpectObserver(
func(matchers []Matcher, buf string, err error) {
if err == nil {

View File

@ -9,7 +9,7 @@ import (
"golang.org/x/sys/windows"
"github.com/coder/coder/expect/conpty"
"github.com/coder/coder/console/conpty"
)
func newPty() (Pty, error) {

View File

@ -1,4 +1,4 @@
package expect
package console
import (
"bufio"
@ -16,9 +16,9 @@ var (
stripAnsi = regexp.MustCompile("[\u001B\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\u0007)|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))")
)
// NewTestConsole creates a new TTY bound to the command provided.
// New creates a new TTY bound to the command provided.
// All ANSI escape codes are stripped to provide clean output.
func NewTestConsole(t *testing.T, cmd *cobra.Command) *Console {
func New(t *testing.T, cmd *cobra.Command) *Console {
reader, writer := io.Pipe()
scanner := bufio.NewScanner(reader)
t.Cleanup(func() {