diff --git a/cli/clitest/clitest_test.go b/cli/clitest/clitest_test.go index f5be5a45db12c..fa11db7c04e9b 100644 --- a/cli/clitest/clitest_test.go +++ b/cli/clitest/clitest_test.go @@ -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) } diff --git a/cli/login_test.go b/cli/login_test.go index 43859ba56199c..b6c581cc41f12 100644 --- a/cli/login_test.go +++ b/cli/login_test.go @@ -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) }) } diff --git a/cli/projectcreate_test.go b/cli/projectcreate_test.go index 0cd654ec657d5..6311aaf141f30 100644 --- a/cli/projectcreate_test.go +++ b/cli/projectcreate_test.go @@ -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 diff --git a/cli/workspacecreate_test.go b/cli/workspacecreate_test.go index 4112223a61a4d..306caa65c4b0c 100644 --- a/cli/workspacecreate_test.go +++ b/cli/workspacecreate_test.go @@ -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 }) diff --git a/expect/conpty/conpty.go b/console/conpty/conpty.go similarity index 100% rename from expect/conpty/conpty.go rename to console/conpty/conpty.go diff --git a/expect/conpty/syscall.go b/console/conpty/syscall.go similarity index 100% rename from expect/conpty/syscall.go rename to console/conpty/syscall.go diff --git a/expect/console.go b/console/console.go similarity index 85% rename from expect/console.go rename to console/console.go index 3a9592cce7ba0..e5af7fa20977b 100644 --- a/expect/console.go +++ b/console/console.go @@ -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 diff --git a/expect/doc.go b/console/doc.go similarity index 98% rename from expect/doc.go rename to console/doc.go index a0163f0e508d5..7a5fc545cd982 100644 --- a/expect/doc.go +++ b/console/doc.go @@ -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 diff --git a/expect/expect.go b/console/expect.go similarity index 96% rename from expect/expect.go rename to console/expect.go index be266ca049434..c2e3f583b0a06 100644 --- a/expect/expect.go +++ b/console/expect.go @@ -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 diff --git a/expect/expect_opt.go b/console/expect_opt.go similarity index 84% rename from expect/expect_opt.go rename to console/expect_opt.go index 9262d6df12f57..fec0d9b8f3e0b 100644 --- a/expect/expect_opt.go +++ b/console/expect_opt.go @@ -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, diff --git a/expect/expect_opt_test.go b/console/expect_opt_test.go similarity index 94% rename from expect/expect_opt_test.go rename to console/expect_opt_test.go index e9f5aba95d603..91efc935fca4e 100644 --- a/expect/expect_opt_test.go +++ b/console/expect_opt_test.go @@ -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) diff --git a/expect/expect_test.go b/console/expect_test.go similarity index 94% rename from expect/expect_test.go rename to console/expect_test.go index f74fc781f2d94..c80f981717d44 100644 --- a/expect/expect_test.go +++ b/console/expect_test.go @@ -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 { diff --git a/expect/pty/pty.go b/console/pty/pty.go similarity index 100% rename from expect/pty/pty.go rename to console/pty/pty.go diff --git a/expect/pty/pty_other.go b/console/pty/pty_other.go similarity index 100% rename from expect/pty/pty_other.go rename to console/pty/pty_other.go diff --git a/expect/pty/pty_windows.go b/console/pty/pty_windows.go similarity index 97% rename from expect/pty/pty_windows.go rename to console/pty/pty_windows.go index 1d8645840516d..01fbe39169f04 100644 --- a/expect/pty/pty_windows.go +++ b/console/pty/pty_windows.go @@ -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) { diff --git a/expect/test_console.go b/console/test_console.go similarity index 86% rename from expect/test_console.go rename to console/test_console.go index e7d8c2a87a743..d1d845d6cb4db 100644 --- a/expect/test_console.go +++ b/console/test_console.go @@ -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() {