@@ -4,49 +4,74 @@ import (
4
4
"bytes"
5
5
"context"
6
6
"errors"
7
- "math/rand"
7
+ "fmt"
8
+ "math/rand/v2"
8
9
"net"
9
10
"strconv"
10
11
"sync"
11
12
"testing"
12
13
"time"
13
14
)
14
15
16
+ // TestEchoClientAndServer validates the EPP server is able to read the data
17
+ // provided in the client request and to respond back correctly.
18
+ //
19
+ // It does this by passing an instance of a `Server` to `echoServer()`, which
20
+ // runs in a goroutine. The echo server runs forever or until the passed in
21
+ // context is canceled. Inside the echo server it checks for any context
22
+ // cancellations and returns early if so (it will optionally record the error if
23
+ // the error is not an expected type). Otherwise, it handles 10 requests at a
24
+ // time, spinning up each request in a new goroutine. Each goroutine handles a
25
+ // response to the client request. Each request is sending a unique 'data unit'
26
+ // to be processed and the response is sent back to the `serverConn`.
27
+ //
28
+ // We use a `net.Pipe()` to simulate the client/server request/response flows.
29
+ // i.e. a write to `clientConn` is readable via `serverConn` (and vice-versa).
30
+ //
31
+ // So c.ExchangeDataUnit() writes data to the `clientConn` which causes a copy
32
+ // of the data to be written into `serverConn` for it to read. Then writing to
33
+ // `serverConn` causes a copy of that data to be written into `clientConn` for
34
+ // it to read. Simulating a bidirectional network connection.
15
35
func TestEchoClientAndServer (t * testing.T ) {
16
36
ctx , cancel := context .WithCancelCause (context .Background ())
17
37
defer cancel (errTestDone )
18
38
19
39
clientConn , serverConn := net .Pipe ()
20
40
c := & Client {Conn : clientConn }
21
41
s := & Server {Conn : serverConn }
22
- go echoServer (t , ctx , s )
42
+ n := 100
43
+ echoServerErr := make (chan error , n )
44
+
45
+ go echoServer (ctx , s , echoServerErr )
23
46
24
47
sem := make (chan struct {}, 2 )
25
48
var wg sync.WaitGroup
26
49
27
- for i := 0 ; i < 100 ; i ++ {
28
- if t .Failed () {
29
- break
30
- }
31
- req := []byte (strconv .FormatInt (int64 (i ), 10 ))
50
+ for i := 0 ; i < n ; i ++ {
51
+ data := []byte (strconv .FormatInt (int64 (i ), 10 ))
32
52
sem <- struct {}{}
33
53
wg .Add (1 )
34
54
go func () {
35
55
defer wg .Done ()
36
56
ctx , cancel := context .WithCancel (ctx )
37
57
defer cancel ()
38
58
time .Sleep (randDuration (10 * time .Millisecond ))
39
- res , err := c .ExchangeDataUnit (ctx , req )
59
+ res , err := c .ExchangeDataUnit (ctx , data )
60
+ // t.Logf("data received from server connection: %s\n", res)
40
61
if err != nil {
41
- t .Errorf ("ExchangeDataUnit(): err == %v " , err )
62
+ echoServerErr <- fmt .Errorf ("ExchangeDataUnit(): err == %w " , err )
42
63
}
43
- if ! bytes .Equal (req , res ) {
44
- t .Errorf ("ExchangeDataUnit(): got %s, expected %s" , string (res ), string (req ))
64
+ if ! bytes .Equal (data , res ) {
65
+ echoServerErr <- fmt .Errorf ("ExchangeDataUnit(): got %s, expected %s" , string (res ), string (data ))
45
66
}
46
67
<- sem
47
68
}()
48
69
}
49
70
wg .Wait ()
71
+ close (echoServerErr )
72
+ for err := range echoServerErr {
73
+ t .Error (err )
74
+ }
50
75
}
51
76
52
77
func TestClientContextDeadline (t * testing.T ) {
@@ -56,53 +81,70 @@ func TestClientContextDeadline(t *testing.T) {
56
81
clientConn , serverConn := net .Pipe ()
57
82
c := & Client {Conn : clientConn }
58
83
s := & Server {Conn : serverConn }
59
- go echoServer (t , ctx , s )
84
+ echoServerErr := make (chan error )
85
+
86
+ go echoServer (ctx , s , echoServerErr )
60
87
61
88
wantErr := errors .New ("test deadline exceeded" )
62
89
ctx , cancel2 := context .WithDeadlineCause (ctx , time .Now (), wantErr )
63
90
defer cancel2 ()
64
91
65
92
_ , err := c .ExchangeDataUnit (ctx , []byte ("hello" ))
66
93
if err != wantErr {
67
- t .Errorf ("ExchangeDataUnit(): err == %v, expected %v" , err , wantErr )
68
- t .Fail ()
94
+ echoServerErr <- fmt .Errorf ("ExchangeDataUnit(): err == %w, expected %w" , err , wantErr )
95
+ }
96
+ close (echoServerErr )
97
+ for err := range echoServerErr {
98
+ t .Error (err )
69
99
}
70
100
}
71
101
72
- func TestClientContextCancelled (t * testing.T ) {
73
- wantErr := errors . New ( "client context canceled" )
102
+ func TestClientContextCanceled (t * testing.T ) {
103
+ wantErr := errCtxCanceled
74
104
ctx , cancel := context .WithCancelCause (context .Background ())
75
105
cancel (wantErr )
76
106
77
107
clientConn , serverConn := net .Pipe ()
78
108
c := & Client {Conn : clientConn }
79
109
s := & Server {Conn : serverConn }
80
- go echoServer (t , ctx , s )
110
+ echoServerErr := make (chan error )
111
+
112
+ go echoServer (ctx , s , echoServerErr )
81
113
82
114
_ , err := c .ExchangeDataUnit (ctx , []byte ("hello" ))
83
115
if err != wantErr {
84
- t .Errorf ("ExchangeDataUnit(): err == %v, expected %v" , err , wantErr )
85
- t .Fail ()
116
+ echoServerErr <- fmt .Errorf ("ExchangeDataUnit(): err == %w, expected %w" , err , wantErr )
117
+ }
118
+ close (echoServerErr )
119
+ for err := range echoServerErr {
120
+ t .Error (err )
86
121
}
87
122
}
88
123
89
- func TestServerContextCancelled (t * testing.T ) {
124
+ func TestServerContextCanceled (t * testing.T ) {
90
125
ctx , cancel := context .WithCancelCause (context .Background ())
91
126
defer cancel (errTestDone )
92
127
93
128
clientConn , serverConn := net .Pipe ()
94
129
c := & Client {Conn : clientConn }
95
130
s := & Server {Conn : serverConn }
96
131
97
- go c .ExchangeDataUnit (ctx , []byte ("hello" ))
132
+ go func () {
133
+ _ , _ = c .ExchangeDataUnit (ctx , []byte ("hello" ))
134
+ }()
98
135
99
136
wantErr := errors .New ("server context canceled" )
100
137
serverCtx , cancel := context .WithCancelCause (context .Background ())
101
138
cancel (wantErr )
102
139
103
- err := echoServer (t , serverCtx , s )
104
- if err != wantErr {
105
- t .Errorf ("echoServer(): err == %v, expected %v" , err , wantErr )
140
+ echoServerErr := make (chan error )
141
+
142
+ go echoServer (serverCtx , s , echoServerErr )
143
+
144
+ for err := range echoServerErr {
145
+ if err != wantErr {
146
+ t .Errorf ("unexpected error: %s" , err )
147
+ }
106
148
}
107
149
}
108
150
@@ -114,7 +156,9 @@ func TestMultipleResponseError(t *testing.T) {
114
156
c := & Client {Conn : clientConn }
115
157
s := & Server {Conn : serverConn }
116
158
117
- go c .ExchangeDataUnit (ctx , []byte ("hello" ))
159
+ go func () {
160
+ _ , _ = c .ExchangeDataUnit (ctx , []byte ("hello" ))
161
+ }()
118
162
119
163
req , r , err := s .ServeDataUnit (ctx )
120
164
if err != nil {
@@ -133,18 +177,20 @@ func TestMultipleResponseError(t *testing.T) {
133
177
134
178
// echoServer implements a rudimentary EPP data unit server that echoes
135
179
// back each received request.
136
- func echoServer (t * testing. T , ctx context.Context , s * Server ) error {
180
+ func echoServer (ctx context.Context , s * Server , echoServerErr chan <- error ) {
137
181
ctx , cancel := context .WithCancelCause (ctx )
138
182
defer cancel (errTestDone )
139
183
140
184
sem := make (chan struct {}, 10 )
141
185
for {
142
- if t .Failed () {
143
- return errTestFailed
144
- }
145
186
err := context .Cause (ctx )
146
187
if err != nil {
147
- return err
188
+ if err == errTestDone || err == errCtxCanceled {
189
+ return
190
+ }
191
+ echoServerErr <- err
192
+ close (echoServerErr )
193
+ return
148
194
}
149
195
sem <- struct {}{}
150
196
go func () {
@@ -153,28 +199,31 @@ func echoServer(t *testing.T, ctx context.Context, s *Server) error {
153
199
reqCtx , cancel := context .WithCancel (ctx )
154
200
defer cancel ()
155
201
156
- req , r , err := s .ServeDataUnit (reqCtx )
202
+ data , r , err := s .ServeDataUnit (reqCtx )
157
203
if err != nil {
158
204
if err == errTestDone {
159
205
return
160
206
}
161
- t .Errorf ("echoServer: ServeDataUnit(): err == %v" , err )
207
+ echoServerErr <- fmt .Errorf ("echoServer: ServeDataUnit(): err == %w" , err )
208
+ return
162
209
}
163
210
time .Sleep (randDuration (10 * time .Millisecond ))
164
- err = r .RespondDataUnit (reqCtx , req )
211
+ err = r .RespondDataUnit (reqCtx , data )
165
212
if err != nil {
166
213
if err == errTestDone {
167
214
return
168
215
}
169
- t .Errorf ("echoServer: WriteDataUnit (): err == %v " , err )
216
+ echoServerErr <- fmt .Errorf ("echoServer: RespondDataUnit (): err == %w " , err )
170
217
}
171
218
}()
172
219
}
173
220
}
174
221
175
222
func randDuration (max time.Duration ) time.Duration {
176
- return time .Duration (rand .Int63n ( int64 ( max ) ))
223
+ return time .Duration (rand .N ( max ))
177
224
}
178
225
179
- var errTestDone = errors .New ("test done" )
180
- var errTestFailed = errors .New ("test failed" )
226
+ var (
227
+ errCtxCanceled = errors .New ("context canceled" )
228
+ errTestDone = errors .New ("test done" )
229
+ )
0 commit comments