1
1
using System . Net . WebSockets ;
2
+ using System . Reactive . Subjects ;
3
+ using System . Text ;
2
4
using AutoFixture ;
3
5
using Epsilon . Controllers ;
6
+ using Epsilon . Handler . WebsocketMessageHandler ;
7
+ using Epsilon . Models ;
8
+ using Epsilon . Services . WebsocketStateService ;
4
9
using Microsoft . AspNetCore . Http ;
5
10
using Microsoft . AspNetCore . Mvc ;
6
11
using Moq ;
12
+ using Newtonsoft . Json ;
7
13
using Xunit ;
8
14
9
15
namespace Epsilon . Tests . Controllers ;
10
16
11
17
public class WebSocketControllerTest
12
18
{
19
+ private readonly Mock < IMessageHandler < string > > _mockWebsocketMessageHandler = new ( ) ;
20
+ private readonly Mock < IWebsocketStateService > _websocketStateService = new ( ) ;
13
21
private readonly Mock < HttpContext > _mockHttpContext = new ( ) ;
14
22
private readonly Mock < WebSocketManager > _mockWebSocketManager = new ( ) ;
15
23
private readonly Mock < WebSocket > _mockWebSocket = new ( ) ;
@@ -26,7 +34,11 @@ public WebSocketControllerTest()
26
34
. Setup ( context => context . WebSockets )
27
35
. Returns ( _mockWebSocketManager . Object ) ;
28
36
29
- _webSocketController = new WebSocketController
37
+ _websocketStateService
38
+ . Setup ( service => service . GetWebsocketState ( It . IsAny < string > ( ) ) )
39
+ . Returns ( _fixture . Create < WebsocketState > ( ) ) ;
40
+
41
+ _webSocketController = new WebSocketController ( _websocketStateService . Object , _mockWebsocketMessageHandler . Object )
30
42
{
31
43
ControllerContext = new ControllerContext
32
44
{
@@ -50,21 +62,24 @@ public async Task WebSocket_ShouldCloseConnection_WhenCloseMessageSent()
50
62
51
63
await _webSocketController . WebSocket ( ) ;
52
64
65
+ _websocketStateService . Verify ( service => service . CreateWebsocket ( It . IsAny < string > ( ) ) ) ;
66
+ _websocketStateService . Verify ( service => service . DeleteWebsocket ( It . IsAny < string > ( ) ) ) ;
67
+
53
68
_mockWebSocket . Verify ( socket =>
54
69
socket . CloseAsync ( WebSocketCloseStatus . NormalClosure , "Closed" , It . IsAny < CancellationToken > ( ) )
55
70
) ;
56
71
}
57
72
58
73
[ Fact ]
59
- public async Task WebSocket_ShouldEchoMessage_WhenWeSendAMessage ( )
74
+ public async Task WebSocket_ShouldHandleMessage_WhenWeSendAMessage ( )
60
75
{
61
- var isFirst = true ;
76
+ var runs = 0 ;
62
77
var message = _fixture . CreateMany < byte > ( 1024 ) . ToArray ( ) ;
63
78
_mockWebSocket
64
79
. Setup ( socket => socket . ReceiveAsync ( It . IsAny < ArraySegment < byte > > ( ) , It . IsAny < CancellationToken > ( ) ) )
65
80
. ReturnsAsync ( ( ArraySegment < byte > buffer , CancellationToken _ ) =>
66
81
{
67
- if ( ! isFirst )
82
+ if ( runs > 5 )
68
83
{
69
84
return new WebSocketReceiveResult (
70
85
0 ,
@@ -75,7 +90,8 @@ public async Task WebSocket_ShouldEchoMessage_WhenWeSendAMessage()
75
90
) ;
76
91
}
77
92
78
- isFirst = false ;
93
+ runs ++ ;
94
+
79
95
var count = Math . Min ( buffer . Count , message . Length ) ;
80
96
Array . Copy ( message , buffer . Array ! , count ) ;
81
97
return new WebSocketReceiveResult (
@@ -87,13 +103,81 @@ public async Task WebSocket_ShouldEchoMessage_WhenWeSendAMessage()
87
103
88
104
await _webSocketController . WebSocket ( ) ;
89
105
106
+ _mockWebsocketMessageHandler . Verify ( handler =>
107
+ handler . HandleMessage ( Encoding . UTF8 . GetString ( message ) , It . IsAny < string > ( ) ) , Times . Exactly ( 6 )
108
+ ) ;
109
+
110
+ _websocketStateService . Verify ( service => service . CreateWebsocket ( It . IsAny < string > ( ) ) ) ;
111
+ _websocketStateService . Verify ( service => service . DeleteWebsocket ( It . IsAny < string > ( ) ) ) ;
90
112
91
113
_mockWebSocket . Verify ( socket =>
92
- socket . SendAsync ( new ArraySegment < byte > ( message , 0 , message . Length ) , WebSocketMessageType . Text , false , It . IsAny < CancellationToken > ( ) )
114
+ socket . CloseAsync ( WebSocketCloseStatus . NormalClosure , "Closed" , It . IsAny < CancellationToken > ( ) )
115
+ ) ;
116
+ }
117
+
118
+ [ Fact ]
119
+ public async Task WebSocket_ShouldSendMessage_WhenWePushOneToObservable ( )
120
+ {
121
+ var replay = new ReplaySubject < object > ( ) ;
122
+ _websocketStateService
123
+ . Setup ( service => service . GetWebsocketState ( It . IsAny < string > ( ) ) )
124
+ . Returns ( new WebsocketState ( "" , false , replay ) ) ;
125
+
126
+ var message = _fixture . Create < WebsocketMessage < LoginRequest > > ( ) ;
127
+ replay . OnNext ( message ) ;
128
+
129
+ _mockWebSocket
130
+ . Setup ( socket => socket . ReceiveAsync ( It . IsAny < ArraySegment < byte > > ( ) , It . IsAny < CancellationToken > ( ) ) )
131
+ . ReturnsAsync ( new WebSocketReceiveResult (
132
+ 0 ,
133
+ WebSocketMessageType . Close ,
134
+ true ,
135
+ WebSocketCloseStatus . NormalClosure ,
136
+ "Closed"
137
+ ) ) ;
138
+
139
+ await _webSocketController . WebSocket ( ) ;
140
+
141
+ var messageBytes = Encoding . UTF8 . GetBytes ( JsonConvert . SerializeObject ( message ) ) ;
142
+
143
+ _mockWebSocket . Verify ( socket =>
144
+ socket . SendAsync ( new ArraySegment < byte > ( messageBytes , 0 , messageBytes . Length ) , WebSocketMessageType . Text , true , It . IsAny < CancellationToken > ( ) )
93
145
) ;
94
146
95
147
_mockWebSocket . Verify ( socket =>
96
148
socket . CloseAsync ( WebSocketCloseStatus . NormalClosure , "Closed" , It . IsAny < CancellationToken > ( ) )
97
149
) ;
98
150
}
151
+
152
+ [ Fact ]
153
+ public async Task WebSocket_ShouldNotSendMessage_WhenWeCloseTheWebsocket ( )
154
+ {
155
+ var replay = new ReplaySubject < object > ( ) ;
156
+ _websocketStateService
157
+ . Setup ( service => service . GetWebsocketState ( It . IsAny < string > ( ) ) )
158
+ . Returns ( new WebsocketState ( "" , false , replay ) ) ;
159
+
160
+ _mockWebSocket
161
+ . Setup ( socket => socket . ReceiveAsync ( It . IsAny < ArraySegment < byte > > ( ) , It . IsAny < CancellationToken > ( ) ) )
162
+ . ReturnsAsync ( new WebSocketReceiveResult (
163
+ 0 ,
164
+ WebSocketMessageType . Close ,
165
+ true ,
166
+ WebSocketCloseStatus . NormalClosure ,
167
+ "Closed"
168
+ ) ) ;
169
+
170
+ await _webSocketController . WebSocket ( ) ;
171
+
172
+ var message = _fixture . Create < WebsocketMessage < LoginRequest > > ( ) ;
173
+ replay . OnNext ( message ) ;
174
+
175
+ _mockWebSocket . Verify ( socket =>
176
+ socket . CloseAsync ( WebSocketCloseStatus . NormalClosure , "Closed" , It . IsAny < CancellationToken > ( ) )
177
+ ) ;
178
+
179
+ _mockWebSocket . Verify ( socket =>
180
+ socket . SendAsync ( It . IsAny < ArraySegment < byte > > ( ) , WebSocketMessageType . Text , true , It . IsAny < CancellationToken > ( ) ) , Times . Never
181
+ ) ;
182
+ }
99
183
}
0 commit comments