//go:build !windows package sshd import ( "errors" "strings" "testing" "golang.org/x/crypto/ssh" ) func session(t *testing.T) (*ssh.Session, func()) { t.Helper() good := newSigner(t) addr, _, _ := start(t, good) c, err := dial(addr, ssh.PublicKeys(good)) if err != nil { t.Fatal(err) } s, err := c.NewSession() if err != nil { t.Fatal(err) } return s, func() { s.Close(); c.Close() } } func TestExec(t *testing.T) { s, done := session(t) defer done() out, err := s.Output("echo hello; echo oops >&2") if err != nil || string(out) != "hello\n" { t.Fatalf("got %q, %v", out, err) } } func TestExecExitStatus(t *testing.T) { s, done := session(t) defer done() err := s.Run("exit 3") var ee *ssh.ExitError if !errors.As(err, &ee) || ee.ExitStatus() != 3 { t.Fatalf("want exit status 3, got %v", err) } } func TestExecReadsStdin(t *testing.T) { s, done := session(t) defer done() s.Stdin = strings.NewReader("from the client\n") out, err := s.Output("cat") if err != nil || string(out) != "from the client\n" { t.Fatalf("got %q, %v", out, err) } } func TestPtyExec(t *testing.T) { s, done := session(t) defer done() if err := s.RequestPty("xterm", 24, 80, ssh.TerminalModes{ssh.ECHO: 0}); err != nil { t.Fatal(err) } out, err := s.CombinedOutput(`echo term=$TERM; test -t 0 && echo tty`) if err != nil || !strings.Contains(string(out), "term=xterm") || !strings.Contains(string(out), "tty") { t.Fatalf("got %q, %v", out, err) } } func TestShell(t *testing.T) { s, done := session(t) defer done() s.Stdin = strings.NewReader("echo from-shell\nexit 4\n") var out strings.Builder s.Stdout = &out err := s.Shell() if err != nil { t.Fatal(err) } err = s.Wait() var ee *ssh.ExitError if !errors.As(err, &ee) || ee.ExitStatus() != 4 || !strings.Contains(out.String(), "from-shell") { t.Fatalf("got %q, %v", out.String(), err) } }