e2e/term_test.go
87 lines · 2990 bytes
1package e2e
2
3import (
4 "os"
5 "os/exec"
6 "path/filepath"
7 "strings"
8 "testing"
9)
10
11// GITBAY_TERM selects terminal output per session. Stock ssh without it
12// gets the plain rows scripts read.
13func TestTermEnvSelectsTerminalOutput(t *testing.T) {
14 t.Parallel()
15 inst := startInstance(t)
16 key := inst.newKey(t, "alice")
17 inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub",
18 "--email", "alice@example.test", "--verified")
19 if _, errOut, code := inst.ssh(t, key, "", "repo", "create", "alice/app"); code != 0 {
20 t.Fatalf("repo create: %d %s", code, errOut)
21 }
22
23 plain, _, _ := inst.sshTerm(t, key, "", "repo", "list")
24 if strings.Contains(plain, "alice/app ") || !strings.Contains(plain, "alice/app\t") {
25 t.Errorf("plain repo list: %q", plain)
26 }
27 term, _, _ := inst.sshTerm(t, key, "80,color", "repo", "list")
28 if !strings.HasPrefix(term, "\x1b[1m\x1b[34mRepositories (1)") {
29 t.Errorf("terminal repo list: %q", term)
30 }
31}
32
33// The CLI shares one connection per instance. Each session's terminal
34// selection must reach the server on its own, not the one the master
35// session was opened with — which is why it travels as a leading
36// --term=<v> argument rather than SetEnv: OpenSSH's mux client does not
37// forward a new session's SetEnv onto an existing ControlMaster.
38func TestTermEnvOverMultiplexedSession(t *testing.T) {
39 t.Parallel()
40 inst := startInstance(t)
41 key := inst.newKey(t, "alice")
42 inst.admin(t, "admin", "user", "create", "alice", "--key", key+".pub",
43 "--email", "alice@example.test", "--verified")
44 inst.ssh(t, key, "", "repo", "create", "alice/app")
45
46 dir, err := os.MkdirTemp("", "gbmux")
47 if err != nil {
48 t.Fatal(err)
49 }
50 t.Cleanup(func() { os.RemoveAll(dir) })
51 sock := filepath.Join(dir, "cm")
52 mux := func(term string) string {
53 t.Helper()
54 cmdArgs := []string{"repo", "list"}
55 if term != "" {
56 // "--" stops the local ssh client from parsing --term=... as one
57 // of its own options; it is not part of the remote command line.
58 cmdArgs = append([]string{"--", "--term=" + term}, cmdArgs...)
59 }
60 cmd := inst.sshCmd(key, cmdArgs...)
61 opts := []string{"-o", "ControlMaster=auto", "-o", "ControlPath=" + sock, "-o", "ControlPersist=30"}
62 for j, a := range cmd.Args {
63 if a == "git@127.0.0.1" {
64 cmd.Args = append(cmd.Args[:j:j], append(opts, cmd.Args[j:]...)...)
65 break
66 }
67 }
68 out, err := cmd.Output()
69 if err != nil {
70 t.Fatalf("ssh %s: %v", term, err)
71 }
72 return string(out)
73 }
74 t.Cleanup(func() {
75 exec.Command("ssh", "-o", "ControlPath="+sock, "-O", "exit", "git@127.0.0.1").Run()
76 })
77
78 if out := mux("80"); !strings.HasPrefix(out, "Repositories (1)\nalice/app public") {
79 t.Fatalf("master session: %q", out)
80 }
81 if out := mux("80,color"); !strings.HasPrefix(out, "\x1b[1m\x1b[34mRepositories") {
82 t.Errorf("second session kept the master's GITBAY_TERM: %q", out)
83 }
84 if out := mux(""); !strings.HasPrefix(out, "alice/app\t") {
85 t.Errorf("session without GITBAY_TERM got terminal output: %q", out)
86 }
87}