Use pty for term tests
Test no longer needs to be linux only since the pty package can handle
different platforms, and also does not require root.
This fixes an issue where the term tests are skipped in CI since there
is no TTY available.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
Brian Goff
4 years ago
3 | 3 | |
4 | 4 | require ( |
5 | 5 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 |
6 | github.com/creack/pty v1.1.9 | |
6 | 7 | github.com/google/go-cmp v0.3.1 |
7 | 8 | github.com/pkg/errors v0.9.1 // indirect |
8 | 9 | golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 |
0 | 0 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= |
1 | 1 | github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= |
2 | github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= | |
3 | github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | |
2 | 4 | github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= |
3 | 5 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= |
4 | 6 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= |
0 | //+build linux | |
1 | ||
2 | package term | |
3 | ||
4 | import ( | |
5 | "io/ioutil" | |
6 | "os" | |
7 | "strings" | |
8 | "testing" | |
9 | ||
10 | "github.com/google/go-cmp/cmp" | |
11 | "gotest.tools/assert" | |
12 | ) | |
13 | ||
14 | // RequiresRoot skips tests that require root, unless the test.root flag has | |
15 | // been set | |
16 | func RequiresRoot(t *testing.T) { | |
17 | if os.Getuid() != 0 { | |
18 | t.Skip("skipping test that requires root") | |
19 | return | |
20 | } | |
21 | } | |
22 | ||
23 | func newTtyForTest(t *testing.T) (*os.File, error) { | |
24 | RequiresRoot(t) | |
25 | file, err := os.OpenFile("/dev/tty", os.O_RDWR, os.ModeDevice) | |
26 | if err != nil && strings.Contains(err.Error(), "no such device or address") { | |
27 | t.Skip("terminal missing, skipping test") | |
28 | } | |
29 | return file, err | |
30 | } | |
31 | ||
32 | func newTempFile() (*os.File, error) { | |
33 | return ioutil.TempFile(os.TempDir(), "temp") | |
34 | } | |
35 | ||
36 | func TestGetWinsize(t *testing.T) { | |
37 | tty, err := newTtyForTest(t) | |
38 | assert.NilError(t, err) | |
39 | defer tty.Close() | |
40 | winSize, err := GetWinsize(tty.Fd()) | |
41 | assert.NilError(t, err) | |
42 | assert.Assert(t, winSize != nil) | |
43 | ||
44 | newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} | |
45 | err = SetWinsize(tty.Fd(), &newSize) | |
46 | assert.NilError(t, err) | |
47 | winSize, err = GetWinsize(tty.Fd()) | |
48 | assert.NilError(t, err) | |
49 | assert.DeepEqual(t, *winSize, newSize, cmpWinsize) | |
50 | } | |
51 | ||
52 | var cmpWinsize = cmp.AllowUnexported(Winsize{}) | |
53 | ||
54 | func TestSetWinsize(t *testing.T) { | |
55 | tty, err := newTtyForTest(t) | |
56 | assert.NilError(t, err) | |
57 | defer tty.Close() | |
58 | winSize, err := GetWinsize(tty.Fd()) | |
59 | assert.NilError(t, err) | |
60 | assert.Assert(t, winSize != nil) | |
61 | newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} | |
62 | err = SetWinsize(tty.Fd(), &newSize) | |
63 | assert.NilError(t, err) | |
64 | winSize, err = GetWinsize(tty.Fd()) | |
65 | assert.NilError(t, err) | |
66 | assert.DeepEqual(t, *winSize, newSize, cmpWinsize) | |
67 | } | |
68 | ||
69 | func TestGetFdInfo(t *testing.T) { | |
70 | tty, err := newTtyForTest(t) | |
71 | assert.NilError(t, err) | |
72 | defer tty.Close() | |
73 | inFd, isTerminal := GetFdInfo(tty) | |
74 | assert.Equal(t, inFd, tty.Fd()) | |
75 | assert.Equal(t, isTerminal, true) | |
76 | tmpFile, err := newTempFile() | |
77 | assert.NilError(t, err) | |
78 | defer tmpFile.Close() | |
79 | inFd, isTerminal = GetFdInfo(tmpFile) | |
80 | assert.Equal(t, inFd, tmpFile.Fd()) | |
81 | assert.Equal(t, isTerminal, false) | |
82 | } | |
83 | ||
84 | func TestIsTerminal(t *testing.T) { | |
85 | tty, err := newTtyForTest(t) | |
86 | assert.NilError(t, err) | |
87 | defer tty.Close() | |
88 | isTerminal := IsTerminal(tty.Fd()) | |
89 | assert.Equal(t, isTerminal, true) | |
90 | tmpFile, err := newTempFile() | |
91 | assert.NilError(t, err) | |
92 | defer tmpFile.Close() | |
93 | isTerminal = IsTerminal(tmpFile.Fd()) | |
94 | assert.Equal(t, isTerminal, false) | |
95 | } | |
96 | ||
97 | func TestSaveState(t *testing.T) { | |
98 | tty, err := newTtyForTest(t) | |
99 | assert.NilError(t, err) | |
100 | defer tty.Close() | |
101 | state, err := SaveState(tty.Fd()) | |
102 | assert.NilError(t, err) | |
103 | assert.Assert(t, state != nil) | |
104 | tty, err = newTtyForTest(t) | |
105 | assert.NilError(t, err) | |
106 | defer tty.Close() | |
107 | err = RestoreTerminal(tty.Fd(), state) | |
108 | assert.NilError(t, err) | |
109 | } | |
110 | ||
111 | func TestDisableEcho(t *testing.T) { | |
112 | tty, err := newTtyForTest(t) | |
113 | assert.NilError(t, err) | |
114 | defer tty.Close() | |
115 | state, err := SetRawTerminal(tty.Fd()) | |
116 | defer RestoreTerminal(tty.Fd(), state) | |
117 | assert.NilError(t, err) | |
118 | assert.Assert(t, state != nil) | |
119 | err = DisableEcho(tty.Fd(), state) | |
120 | assert.NilError(t, err) | |
121 | } |
0 | // +build !windows | |
1 | ||
2 | package term | |
3 | ||
4 | import ( | |
5 | "io/ioutil" | |
6 | "os" | |
7 | "testing" | |
8 | ||
9 | "github.com/creack/pty" | |
10 | "github.com/google/go-cmp/cmp" | |
11 | "gotest.tools/assert" | |
12 | ) | |
13 | ||
14 | func newTtyForTest(t *testing.T) (*os.File, *os.File) { | |
15 | t.Helper() | |
16 | pty, tty, err := pty.Open() | |
17 | if err != nil { | |
18 | t.Fatalf("error creating pty: %v", err) | |
19 | } | |
20 | ||
21 | return pty, tty | |
22 | } | |
23 | ||
24 | func newTempFile() (*os.File, error) { | |
25 | return ioutil.TempFile(os.TempDir(), "temp") | |
26 | } | |
27 | ||
28 | func TestGetWinsize(t *testing.T) { | |
29 | pty, tty := newTtyForTest(t) | |
30 | defer pty.Close() | |
31 | defer tty.Close() | |
32 | winSize, err := GetWinsize(tty.Fd()) | |
33 | assert.NilError(t, err) | |
34 | assert.Assert(t, winSize != nil) | |
35 | ||
36 | newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} | |
37 | err = SetWinsize(tty.Fd(), &newSize) | |
38 | assert.NilError(t, err) | |
39 | winSize, err = GetWinsize(tty.Fd()) | |
40 | assert.NilError(t, err) | |
41 | assert.DeepEqual(t, *winSize, newSize, cmpWinsize) | |
42 | } | |
43 | ||
44 | var cmpWinsize = cmp.AllowUnexported(Winsize{}) | |
45 | ||
46 | func TestSetWinsize(t *testing.T) { | |
47 | pty, tty := newTtyForTest(t) | |
48 | defer pty.Close() | |
49 | defer tty.Close() | |
50 | winSize, err := GetWinsize(tty.Fd()) | |
51 | assert.NilError(t, err) | |
52 | assert.Assert(t, winSize != nil) | |
53 | newSize := Winsize{Width: 200, Height: 200, x: winSize.x, y: winSize.y} | |
54 | err = SetWinsize(tty.Fd(), &newSize) | |
55 | assert.NilError(t, err) | |
56 | winSize, err = GetWinsize(tty.Fd()) | |
57 | assert.NilError(t, err) | |
58 | assert.DeepEqual(t, *winSize, newSize, cmpWinsize) | |
59 | } | |
60 | ||
61 | func TestGetFdInfo(t *testing.T) { | |
62 | pty, tty := newTtyForTest(t) | |
63 | defer pty.Close() | |
64 | defer tty.Close() | |
65 | inFd, isTerminal := GetFdInfo(tty) | |
66 | assert.Equal(t, inFd, tty.Fd()) | |
67 | assert.Equal(t, isTerminal, true) | |
68 | tmpFile, err := newTempFile() | |
69 | assert.NilError(t, err) | |
70 | defer tmpFile.Close() | |
71 | inFd, isTerminal = GetFdInfo(tmpFile) | |
72 | assert.Equal(t, inFd, tmpFile.Fd()) | |
73 | assert.Equal(t, isTerminal, false) | |
74 | } | |
75 | ||
76 | func TestIsTerminal(t *testing.T) { | |
77 | pty, tty := newTtyForTest(t) | |
78 | defer pty.Close() | |
79 | defer tty.Close() | |
80 | isTerminal := IsTerminal(tty.Fd()) | |
81 | assert.Equal(t, isTerminal, true) | |
82 | tmpFile, err := newTempFile() | |
83 | assert.NilError(t, err) | |
84 | defer tmpFile.Close() | |
85 | isTerminal = IsTerminal(tmpFile.Fd()) | |
86 | assert.Equal(t, isTerminal, false) | |
87 | } | |
88 | ||
89 | func TestSaveState(t *testing.T) { | |
90 | pty, tty := newTtyForTest(t) | |
91 | defer pty.Close() | |
92 | defer tty.Close() | |
93 | state, err := SaveState(tty.Fd()) | |
94 | assert.NilError(t, err) | |
95 | assert.Assert(t, state != nil) | |
96 | pty, tty = newTtyForTest(t) | |
97 | defer pty.Close() | |
98 | defer tty.Close() | |
99 | err = RestoreTerminal(tty.Fd(), state) | |
100 | assert.NilError(t, err) | |
101 | } | |
102 | ||
103 | func TestDisableEcho(t *testing.T) { | |
104 | pty, tty := newTtyForTest(t) | |
105 | defer pty.Close() | |
106 | defer tty.Close() | |
107 | state, err := SetRawTerminal(tty.Fd()) | |
108 | defer RestoreTerminal(tty.Fd(), state) | |
109 | assert.NilError(t, err) | |
110 | assert.Assert(t, state != nil) | |
111 | err = DisableEcho(tty.Fd(), state) | |
112 | assert.NilError(t, err) | |
113 | } |