@@ -9,52 +9,65 @@ import (
9
9
"testing"
10
10
)
11
11
12
- type pipePair struct {
13
- * io.PipeReader
14
- * io.PipeWriter
12
+ type mockMaster struct {
13
+ gottyToMasterReader io.Reader
14
+ gottyToMasterWriter io.Writer
15
+ masterToGottyReader io.Reader
16
+ masterToGottyWriter io.Writer
17
+ }
18
+
19
+ type mockSlave struct {
20
+ gottyToSlaveReader io.Reader
21
+ gottyToSlaveWriter io.Writer
22
+ slaveToGottyReader io.Reader
23
+ slaveToGottyWriter io.Writer
24
+ columns , rows int
15
25
}
16
26
17
27
func TestWriteFromPTY (t * testing.T ) {
18
- connInPipeReader , connInPipeWriter := io . Pipe () // in to conn
19
- connOutPipeReader , _ := io . Pipe () // out from conn
28
+ mMaster := newMockMaster ()
29
+ mSlave := newMockSlave ()
20
30
21
- conn := pipePair {
22
- connOutPipeReader ,
23
- connInPipeWriter ,
24
- }
25
- dt , err := New (conn )
31
+ dt , err := New (mMaster , mSlave )
26
32
if err != nil {
27
33
t .Fatalf ("Unexpected error from New(): %s" , err )
28
34
}
29
35
36
+ // Launch GoTTY
30
37
ctx , cancel := context .WithCancel (context .Background ())
31
38
var wg sync.WaitGroup
32
39
wg .Add (1 )
33
40
go func () {
34
41
wg .Done ()
35
- err := dt .Run (ctx )
36
- if err != nil {
37
- t .Fatalf ("Unexpected error from Run(): %s" , err )
38
- }
42
+ dt .Run (ctx )
39
43
}()
40
44
41
- message := []byte ("foobar" )
42
- n , err := dt .TTY ().Write (message )
43
- if err != nil {
44
- t .Fatalf ("Unexpected error from Write(): %s" , err )
45
- }
46
- if n != len (message ) {
47
- t .Fatalf ("Write() accepted `%d` for message `%s`" , n , message )
48
- }
45
+ // Check that the initialization happens as expected
46
+ checkNextMsgType (t , mMaster .gottyToMasterReader , SetWindowTitle )
47
+ checkNextMsgType (t , mMaster .gottyToMasterReader , SetBufferSize )
49
48
49
+ // Simulate the slave (the process being run by GoTTY)
50
+ // echoing "foobar"
50
51
buf := make ([]byte , 1024 )
51
- n , err = connInPipeReader .Read (buf )
52
+ message := []byte ("foobar" )
53
+
54
+ wg .Add (1 )
55
+ go func () {
56
+ dt .handleSlaveReadEvent (message )
57
+ wg .Done ()
58
+ }()
59
+
60
+ // And then make sure it makes it way to the client
61
+ // through the websocket as an output message
62
+ n , err := mMaster .gottyToMasterReader .Read (buf )
52
63
if err != nil {
53
64
t .Fatalf ("Unexpected error from Read(): %s" , err )
54
65
}
55
66
if buf [0 ] != Output {
56
67
t .Fatalf ("Unexpected message type `%c`" , buf [0 ])
57
68
}
69
+
70
+ // Decode it and make sure it's intact
58
71
decoded := make ([]byte , 1024 )
59
72
n , err = base64 .StdEncoding .Decode (decoded , buf [1 :n ])
60
73
if err != nil {
@@ -68,29 +81,38 @@ func TestWriteFromPTY(t *testing.T) {
68
81
wg .Wait ()
69
82
}
70
83
71
- func TestWriteFromConn (t * testing.T ) {
72
- connInPipeReader , connInPipeWriter := io .Pipe () // in to conn
73
- connOutPipeReader , connOutPipeWriter := io .Pipe () // out from conn
84
+ func checkNextMsgType (t * testing.T , connInPipeReader io.Reader , expected byte ) {
85
+ msgType , _ := nextMsg (t , connInPipeReader )
86
+ if msgType != expected {
87
+ t .Fatalf ("Unexpected message type `%c`" , msgType )
88
+ }
89
+ }
74
90
75
- conn := pipePair {
76
- connOutPipeReader ,
77
- connInPipeWriter ,
91
+ func nextMsg (t * testing.T , reader io.Reader ) (byte , []byte ) {
92
+ buf := make ([]byte , 1024 )
93
+ _ , err := reader .Read (buf )
94
+ if err != nil {
95
+ t .Fatalf ("unexpected error %v" , err )
78
96
}
97
+ return buf [0 ], buf [1 :]
98
+ }
79
99
80
- dt , err := New (conn )
100
+ func TestWriteFromConn (t * testing.T ) {
101
+ mMaster := newMockMaster ()
102
+ mSlave := newMockSlave ()
103
+
104
+ dt , err := New (mMaster , mSlave , WithPermitWrite ())
81
105
if err != nil {
82
106
t .Fatalf ("Unexpected error from New(): %s" , err )
83
107
}
84
108
109
+ // Launch GoTTY
85
110
ctx , cancel := context .WithCancel (context .Background ())
86
111
var wg sync.WaitGroup
87
112
wg .Add (1 )
88
113
go func () {
89
114
wg .Done ()
90
- err := dt .Run (ctx )
91
- if err != nil {
92
- t .Fatalf ("Unexpected error from Run(): %s" , err )
93
- }
115
+ dt .Run (ctx )
94
116
}()
95
117
96
118
var (
@@ -99,17 +121,20 @@ func TestWriteFromConn(t *testing.T) {
99
121
)
100
122
readBuf := make ([]byte , 1024 )
101
123
102
- // input
103
- message = []byte ("0hello\n " ) // line buffered canonical mode
104
- n , err = connOutPipeWriter .Write (message )
105
- if err != nil {
106
- t .Fatalf ("Unexpected error from Write(): %s" , err )
107
- }
108
- if n != len (message ) {
109
- t .Fatalf ("Write() accepted `%d` for message `%s`" , n , message )
110
- }
124
+ // Absorb initialization messages
125
+ mMaster .gottyToMasterReader .Read (readBuf )
126
+ mMaster .gottyToMasterReader .Read (readBuf )
127
+
128
+ // simulate input from frontend...
129
+ message = []byte ("1hello\n " ) // line buffered canonical mode
130
+ wg .Add (1 )
131
+ go func () {
132
+ dt .handleMasterReadEvent (message )
133
+ wg .Done ()
134
+ }()
111
135
112
- n , err = dt .TTY ().Read (readBuf )
136
+ // ...and make sure it makes it through to the slave intact
137
+ n , err = mSlave .gottyToSlaveReader .Read (readBuf )
113
138
if err != nil {
114
139
t .Fatalf ("Unexpected error from Write(): %s" , err )
115
140
}
@@ -118,17 +143,20 @@ func TestWriteFromConn(t *testing.T) {
118
143
}
119
144
120
145
// ping
121
- message = []byte ("1\n " ) // line buffered canonical mode
122
- n , err = connOutPipeWriter .Write (message )
146
+ message = []byte ("2\n " ) // line buffered canonical mode
147
+ n , err = mMaster .masterToGottyWriter .Write (message )
148
+ if err != nil {
149
+ t .Fatalf ("Unexpected error from Write(): %s" , err )
150
+ }
123
151
if n != len (message ) {
124
152
t .Fatalf ("Write() accepted `%d` for message `%s`" , n , message )
125
153
}
126
154
127
- n , err = connInPipeReader .Read (readBuf )
155
+ n , err = mMaster . gottyToMasterReader .Read (readBuf )
128
156
if err != nil {
129
157
t .Fatalf ("Unexpected error from Read(): %s" , err )
130
158
}
131
- if ! bytes .Equal (readBuf [:n ], []byte {'1 ' }) {
159
+ if ! bytes .Equal (readBuf [:n ], []byte {'2 ' }) {
132
160
t .Fatalf ("Unexpected message received: `%s`" , readBuf [:n ])
133
161
}
134
162
@@ -137,3 +165,43 @@ func TestWriteFromConn(t *testing.T) {
137
165
cancel ()
138
166
wg .Wait ()
139
167
}
168
+
169
+ func newMockMaster () * mockMaster {
170
+ rv := & mockMaster {}
171
+ rv .gottyToMasterReader , rv .gottyToMasterWriter = io .Pipe ()
172
+ rv .masterToGottyReader , rv .masterToGottyWriter = io .Pipe ()
173
+ return rv
174
+ }
175
+
176
+ func (mm * mockMaster ) Read (buf []byte ) (int , error ) {
177
+ return mm .masterToGottyReader .Read (buf )
178
+ }
179
+
180
+ func (mm * mockMaster ) Write (buf []byte ) (int , error ) {
181
+ return mm .gottyToMasterWriter .Write (buf )
182
+ }
183
+
184
+ func newMockSlave () * mockSlave {
185
+ rv := & mockSlave {}
186
+ rv .gottyToSlaveReader , rv .gottyToSlaveWriter = io .Pipe ()
187
+ rv .slaveToGottyReader , rv .slaveToGottyWriter = io .Pipe ()
188
+ return rv
189
+ }
190
+
191
+ func (ms * mockSlave ) Read (buf []byte ) (int , error ) {
192
+ return ms .slaveToGottyReader .Read (buf )
193
+ }
194
+
195
+ func (ms * mockSlave ) Write (buf []byte ) (int , error ) {
196
+ return ms .gottyToSlaveWriter .Write (buf )
197
+ }
198
+
199
+ func (ms * mockSlave ) WindowTitleVariables () map [string ]interface {} {
200
+ return nil
201
+ }
202
+
203
+ func (ms * mockSlave ) ResizeTerminal (columns int , rows int ) error {
204
+ ms .columns = columns
205
+ ms .rows = rows
206
+ return nil
207
+ }
0 commit comments