@@ -3,6 +3,7 @@ package uniws
33import (
44 "context"
55 "encoding/json"
6+ "errors"
67 "net/http"
78 "net/http/httptest"
89 "net/url"
@@ -192,3 +193,79 @@ func TestUnidirectionalWebSocket(t *testing.T) {
192193 require .True (t , pingReceived , "Expected to receive ping message" )
193194 })
194195}
196+
197+ func TestUnidirectionalWebSocket_CloseFrameSent (t * testing.T ) {
198+ t .Parallel ()
199+
200+ // Create a custom node to trigger server-side disconnect.
201+ testNode , err := centrifuge .New (centrifuge.Config {})
202+ require .NoError (t , err )
203+ t .Cleanup (func () { _ = testNode .Shutdown (context .Background ()) })
204+
205+ testNode .OnConnecting (func (ctx context.Context , event centrifuge.ConnectEvent ) (centrifuge.ConnectReply , error ) {
206+ return centrifuge.ConnectReply {
207+ Credentials : & centrifuge.Credentials {},
208+ }, nil
209+ })
210+
211+ testNode .OnConnect (func (client * centrifuge.Client ) {
212+ client .Disconnect (centrifuge .DisconnectConnectionLimit )
213+ })
214+
215+ testHandler := NewHandler (testNode , Config {}, func (r * http.Request ) bool {
216+ return true
217+ }, centrifuge.PingPongConfig {})
218+
219+ testServer := httptest .NewServer (middleware .LogRequest (testHandler ))
220+ t .Cleanup (func () { testServer .Close () })
221+
222+ testWsURL := "ws" + strings .TrimPrefix (testServer .URL , "http" )
223+
224+ // Wait for test server to start.
225+ for {
226+ resp , err := http .Get (testServer .URL )
227+ if err != nil {
228+ time .Sleep (100 * time .Millisecond )
229+ continue
230+ }
231+ _ = resp .Body .Close ()
232+ break
233+ }
234+
235+ dialer := websocket.Dialer {}
236+ conn , _ , _ , err := dialer .Dial (testWsURL , nil )
237+ require .NoError (t , err )
238+ defer func () { _ = conn .Close () }()
239+
240+ // Send connect request.
241+ err = conn .WriteMessage (websocket .TextMessage , []byte (`{}` ))
242+ require .NoError (t , err )
243+
244+ // Read connect reply.
245+ _ , data , err := conn .ReadMessage ()
246+ require .NoError (t , err )
247+ ensureMessageHasClient (t , data )
248+
249+ require .NoError (t , conn .SetReadDeadline (time .Now ().Add (10 * time .Second )))
250+
251+ // Read until connection is closed - server should send close frame.
252+ var closeErr * websocket.CloseError
253+ for {
254+ _ , _ , err := conn .ReadMessage ()
255+ if err != nil {
256+ t .Logf ("ReadMessage error: %v" , err )
257+ closeErr = & websocket.CloseError {}
258+ if ok := errors .As (err , & closeErr ); ok {
259+ t .Logf ("Close frame received: code=%d, text=%s" , closeErr .Code , closeErr .Text )
260+ break
261+ }
262+ // Some other error occurred.
263+ break
264+ }
265+ }
266+
267+ // Verify close frame was received with correct code and reason.
268+ require .NotNil (t , closeErr , "Expected to receive close frame" )
269+ require .Equal (t , centrifuge .DisconnectConnectionLimit .Code , uint32 (closeErr .Code ))
270+ require .Equal (t , centrifuge .DisconnectConnectionLimit .Reason , closeErr .Text )
271+ }
0 commit comments