@@ -66,6 +66,18 @@ func writeLeiosNotifyTestSegment(
6666 require .NoError (t , err )
6767}
6868
69+ type leiosNotifyFailWriteConn struct {
70+ net.Conn
71+ }
72+
73+ var errLeiosNotifyTestWrite = errors .New (
74+ "test: forced transport write failure" ,
75+ )
76+
77+ func (leiosNotifyFailWriteConn ) Write ([]byte ) (int , error ) {
78+ return 0 , errLeiosNotifyTestWrite
79+ }
80+
6981func TestNewServer (t * testing.T ) {
7082 connId := connection.ConnectionId {
7183 LocalAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
@@ -112,6 +124,169 @@ func TestHandleRequestNext_CallbackIsCalled(t *testing.T) {
112124 assert .True (t , called , "expected RequestNextFunc to be called" )
113125}
114126
127+ func TestHandleRequestNextReportsSuccessfulSend (t * testing.T ) {
128+ connId := connection.ConnectionId {
129+ LocalAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
130+ RemoteAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
131+ }
132+ connA , connB := net .Pipe ()
133+ defer connA .Close ()
134+ defer connB .Close ()
135+ m := muxer .New (connA )
136+ defer m .Stop ()
137+
138+ response := NewMsgBlockAnnouncement (cbor.RawMessage {0x82 , 0x01 , 0x02 })
139+ type sendResult struct {
140+ msg protocol.Message
141+ err error
142+ }
143+ resultCh := make (chan sendResult , 1 )
144+ cfg := NewConfig (
145+ WithRequestNextFunc (func (CallbackContext ) (protocol.Message , error ) {
146+ return response , nil
147+ }),
148+ WithResponseSentFunc (func (
149+ _ CallbackContext ,
150+ msg protocol.Message ,
151+ err error ,
152+ ) {
153+ resultCh <- sendResult {msg : msg , err : err }
154+ }),
155+ )
156+ server := NewServer (protocol.ProtocolOptions {
157+ ConnectionId : connId ,
158+ Muxer : m ,
159+ }, & cfg )
160+ server .Start ()
161+ defer server .Protocol .Stop ()
162+ m .Start ()
163+
164+ requestData , err := cbor .Encode (NewMsgNotificationRequestNext ())
165+ require .NoError (t , err )
166+ writeLeiosNotifyTestSegment (
167+ t ,
168+ connB ,
169+ muxer .NewSegment (ProtocolId , requestData , false ),
170+ )
171+ require .NoError (t , connB .SetReadDeadline (time .Now ().Add (time .Second )))
172+ _ , err = readLeiosNotifyTestSegment (t , connB )
173+ require .NoError (t , err )
174+
175+ select {
176+ case result := <- resultCh :
177+ require .Same (t , response , result .msg )
178+ require .NoError (t , result .err )
179+ case <- time .After (time .Second ):
180+ t .Fatal ("timed out waiting for response send callback" )
181+ }
182+ }
183+
184+ func TestHandleRequestNextReportsFailedSend (t * testing.T ) {
185+ connId := connection.ConnectionId {
186+ LocalAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
187+ RemoteAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
188+ }
189+ resultCh := make (chan error , 1 )
190+ connA , connB := net .Pipe ()
191+ defer connA .Close ()
192+ defer connB .Close ()
193+ m := muxer .New (leiosNotifyFailWriteConn {Conn : connA })
194+ defer m .Stop ()
195+ cfg := NewConfig (
196+ WithRequestNextFunc (func (CallbackContext ) (protocol.Message , error ) {
197+ return NewMsgBlockAnnouncement (cbor.RawMessage {0x81 , 0x01 }), nil
198+ }),
199+ WithResponseSentFunc (func (
200+ _ CallbackContext ,
201+ _ protocol.Message ,
202+ err error ,
203+ ) {
204+ resultCh <- err
205+ }),
206+ )
207+ server := NewServer (protocol.ProtocolOptions {
208+ ConnectionId : connId ,
209+ Muxer : m ,
210+ }, & cfg )
211+ server .Start ()
212+ defer server .Protocol .Stop ()
213+ m .Start ()
214+
215+ requestData , err := cbor .Encode (NewMsgNotificationRequestNext ())
216+ require .NoError (t , err )
217+ writeLeiosNotifyTestSegment (
218+ t ,
219+ connB ,
220+ muxer .NewSegment (ProtocolId , requestData , false ),
221+ )
222+
223+ select {
224+ case sendErr := <- resultCh :
225+ require .ErrorIs (t , sendErr , errLeiosNotifyTestWrite )
226+ case <- time .After (time .Second ):
227+ t .Fatal ("timed out waiting for failed response send callback" )
228+ }
229+ }
230+
231+ func TestHandleRequestNextReportsShutdownBeforeDelivery (t * testing.T ) {
232+ connId := connection.ConnectionId {
233+ LocalAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
234+ RemoteAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
235+ }
236+ connA , connB := net .Pipe ()
237+ defer connA .Close ()
238+ defer connB .Close ()
239+ m := muxer .New (connA )
240+ defer m .Stop ()
241+
242+ requestCalled := make (chan struct {})
243+ releaseRequest := make (chan struct {})
244+ resultCh := make (chan error , 1 )
245+ cfg := NewConfig (
246+ WithRequestNextFunc (func (CallbackContext ) (protocol.Message , error ) {
247+ close (requestCalled )
248+ // Keep the response from being queued until shutdown is observable.
249+ <- releaseRequest
250+ return NewMsgBlockAnnouncement (cbor.RawMessage {0x81 , 0x01 }), nil
251+ }),
252+ WithResponseSentFunc (func (
253+ _ CallbackContext ,
254+ _ protocol.Message ,
255+ err error ,
256+ ) {
257+ resultCh <- err
258+ }),
259+ )
260+ server := NewServer (protocol.ProtocolOptions {
261+ ConnectionId : connId ,
262+ Muxer : m ,
263+ }, & cfg )
264+ server .Start ()
265+ m .Start ()
266+
267+ requestData , err := cbor .Encode (NewMsgNotificationRequestNext ())
268+ require .NoError (t , err )
269+ writeLeiosNotifyTestSegment (
270+ t ,
271+ connB ,
272+ muxer .NewSegment (ProtocolId , requestData , false ),
273+ )
274+ select {
275+ case <- requestCalled :
276+ case <- time .After (time .Second ):
277+ t .Fatal ("timed out waiting for request callback" )
278+ }
279+ server .Protocol .Stop ()
280+ close (releaseRequest )
281+
282+ select {
283+ case sendErr := <- resultCh :
284+ require .ErrorIs (t , sendErr , protocol .ErrProtocolShuttingDown )
285+ case <- time .After (time .Second ):
286+ t .Fatal ("timed out waiting for shutdown delivery callback" )
287+ }
288+ }
289+
115290func TestHandleRequestNext_NilCallback (t * testing.T ) {
116291 connId := connection.ConnectionId {
117292 LocalAddr : & net.TCPAddr {IP : net .IPv4 (127 , 0 , 0 , 1 ), Port : 0 },
0 commit comments