@@ -11,7 +11,27 @@ const pinoTest = require('pino-test')
11
11
const pino = require ( 'pino' )
12
12
const proxyPlugin = require ( '../' )
13
13
14
- async function createServices ( { t, wsReconnectOptions, wsTargetOptions, wsServerOptions } ) {
14
+ function waitForLogMessage ( loggerSpy , message , max = 100 ) {
15
+ return new Promise ( ( resolve , reject ) => {
16
+ let count = 0
17
+ const fn = ( received ) => {
18
+ console . log ( received )
19
+
20
+ if ( received . msg === message ) {
21
+ loggerSpy . off ( 'data' , fn )
22
+ resolve ( )
23
+ }
24
+ count ++
25
+ if ( count > max ) {
26
+ loggerSpy . off ( 'data' , fn )
27
+ reject ( new Error ( `Max message count reached on waitForLogMessage: ${ message } ` ) )
28
+ }
29
+ }
30
+ loggerSpy . on ( 'data' , fn )
31
+ } )
32
+ }
33
+
34
+ async function createServices ( { t, upstream, wsReconnectOptions, wsTargetOptions, wsServerOptions } ) {
15
35
const targetServer = createServer ( )
16
36
const targetWs = new WebSocket . Server ( { server : targetServer , ...wsTargetOptions } )
17
37
@@ -21,7 +41,7 @@ async function createServices ({ t, wsReconnectOptions, wsTargetOptions, wsServe
21
41
const logger = pino ( loggerSpy )
22
42
const proxy = Fastify ( { loggerInstance : logger } )
23
43
proxy . register ( proxyPlugin , {
24
- upstream : `ws://127.0.0.1:${ targetServer . address ( ) . port } ` ,
44
+ upstream : upstream || `ws://127.0.0.1:${ targetServer . address ( ) . port } ` ,
25
45
websocket : true ,
26
46
wsReconnect : wsReconnectOptions ,
27
47
wsServerOptions
@@ -46,12 +66,11 @@ async function createServices ({ t, wsReconnectOptions, wsTargetOptions, wsServe
46
66
} ,
47
67
proxy,
48
68
client,
49
- loggerSpy
69
+ loggerSpy,
70
+ upstream
50
71
}
51
72
}
52
-
53
- // TODO use fake timers ?
54
-
73
+ /*
55
74
test('should use ping/pong to verify connection is alive - from source (server on proxy) to target', async (t) => {
56
75
const wsReconnectOptions = { pingInterval: 100, reconnectInterval: 100, maxReconnectionRetries: 1 }
57
76
@@ -70,64 +89,131 @@ test('should use ping/pong to verify connection is alive - from source (server o
70
89
})
71
90
72
91
test('should reconnect on broken connection', async (t) => {
73
- const wsReconnectOptions = { pingInterval : 250 , reconnectInterval : 100 , maxReconnectionRetries : 1 , reconnectDecay : 2 }
92
+ const wsReconnectOptions = { pingInterval: 500 , reconnectInterval: 100, maxReconnectionRetries: 1, reconnectDecay: 2 }
74
93
75
94
const { target, loggerSpy } = await createServices({ t, wsReconnectOptions, wsTargetOptions: { autoPong: false } })
76
95
96
+ let breakConnection = true
77
97
target.ws.on('connection', async (socket) => {
78
98
socket.on('ping', async () => {
79
- // add latency to break the connection
80
- await wait ( 500 )
99
+ // add latency to break the connection once
100
+ if (breakConnection) {
101
+ await wait(wsReconnectOptions.pingInterval * 2)
102
+ breakConnection = false
103
+ }
81
104
socket.pong()
82
105
})
83
106
})
84
107
85
- await pinoTest . once ( loggerSpy , 'warn' , 'proxy ws connection is broken' )
86
- await pinoTest . once ( loggerSpy , 'info' , 'proxy ws reconnecting in 100 ms' )
87
- await pinoTest . once ( loggerSpy , 'info' , 'proxy ws reconnected' )
88
- } )
108
+ await waitForLogMessage(loggerSpy, 'proxy ws connection is broken')
109
+ await waitForLogMessage(loggerSpy, 'proxy ws target close event')
110
+ await waitForLogMessage(loggerSpy, 'proxy ws reconnected')
89
111
112
+ // TODO fix with source.removeAllListeners
90
113
91
- test ( 'should reconnect after failingwith retries' , async ( t ) => {
92
- const wsReconnectOptions = { pingInterval : 150 , reconnectInterval : 100 , reconnectOnClose : true }
114
+ t.end()
115
+ })
93
116
94
- const { target, logger } = await createServices ( { t, wsReconnectOptions, wsTargetOptions : { autoPong : false } } )
117
+ test('should not reconnect after max retries', async (t) => {
118
+ const wsReconnectOptions = { pingInterval: 150, reconnectInterval: 100, maxReconnectionRetries: 1 }
95
119
96
- const refuseNewConnections = false
120
+ const { target, loggerSpy } = await createServices({ t, wsReconnectOptions, wsTargetOptions: { autoPong: false } })
121
+
122
+ let breakConnection = true
97
123
98
124
target.ws.on('connection', async (socket) => {
99
125
socket.on('ping', async () => {
100
- // add latency to break the connection
101
- await wait ( 500 )
126
+ // add latency to break the connection once
127
+ if (breakConnection) {
128
+ await wait(wsReconnectOptions.pingInterval * 2)
129
+ breakConnection = false
130
+ }
102
131
socket.pong()
103
132
})
104
133
})
105
134
135
+ await waitForLogMessage(loggerSpy, 'proxy ws connection is broken')
136
+
137
+ target.ws.close()
138
+ target.server.close()
139
+
140
+ await waitForLogMessage(loggerSpy, 'proxy ws target close event')
141
+ await waitForLogMessage(loggerSpy, 'proxy ws reconnect error')
142
+ await waitForLogMessage(loggerSpy, 'proxy ws failed to reconnect! No more retries')
143
+
144
+ t.end()
145
+ })
146
+ */
147
+
148
+ test ( 'should not reconnect because of connection timeout' , async ( t ) => {
149
+ const wsReconnectOptions = { pingInterval : 150 , reconnectInterval : 100 , maxReconnectionRetries : 1 , connectionTimeout : 100 }
150
+
151
+ const { target, loggerSpy } = await createServices ( { t, wsReconnectOptions, wsTargetOptions : { autoPong : false } } )
152
+
153
+ let breakConnection = true
154
+
106
155
target . ws . on ( 'upgrade' , ( request , socket , head ) => {
107
- if ( refuseNewConnections ) {
108
- socket . destroy ( )
109
- }
156
+ console . log ( 'upgrade' )
110
157
} )
111
158
112
- // TODO use pino-test
113
- // await pinoTest.once(logger, 'warn', 'proxy ws connection is broken')
114
-
115
- // close the target server to fail new connections
116
- // setTimeout(() => {
117
- // refuseNewConnections = true
118
- // setTimeout(() => {
119
- // refuseNewConnections = false
120
- // }, 500)
121
- // }, 1000)
122
-
123
- // t.ok(logger._warn.find(l => l[1] === 'proxy ws connection is broken'))
124
- // t.ok(logger._info.find(l => l[1] === 'proxy ws reconnecting in 100 ms'))
125
- // t.ok(logger._error.find(l => l[1] === 'proxy ws reconnect error' && l[0].attempts === 1))
126
- // t.ok(logger._info.find(l => l[1] === 'proxy ws reconnected' && l[0].attempts === 2))
159
+ target . ws . on ( 'connection' , async ( socket ) => {
160
+ socket . on ( 'ping' , async ( ) => {
161
+ // add latency to break the connection once
162
+ if ( breakConnection ) {
163
+ await wait ( wsReconnectOptions . pingInterval * 2 )
164
+ breakConnection = false
165
+ }
166
+ socket . pong ( )
167
+ } )
168
+ } )
169
+
170
+ await waitForLogMessage ( loggerSpy , 'proxy ws connection is broken' )
171
+
172
+ target . ws . close ( )
173
+ target . server . close ( )
174
+
175
+ await waitForLogMessage ( loggerSpy , 'proxy ws target close event' )
176
+ await waitForLogMessage ( loggerSpy , 'proxy ws reconnect error' )
177
+ await waitForLogMessage ( loggerSpy , 'proxy ws failed to reconnect! No more retries' )
178
+
179
+ t . end ( )
180
+ } )
181
+
182
+ // TODO reconnect regular close
183
+
184
+ /*
185
+ test('should reconnect with retry', async (t) => {
186
+ const wsReconnectOptions = { pingInterval: 150, reconnectInterval: 100, reconnectOnClose: true }
187
+
188
+ const { target, loggerSpy, upstream } = await createServices({ t, wsReconnectOptions, wsTargetOptions: { autoPong: false } })
189
+
190
+ let breakConnection = true
191
+
192
+ target.ws.on('connection', async (socket) => {
193
+ socket.on('ping', async () => {
194
+ // add latency to break the connection once
195
+ if (breakConnection) {
196
+ await wait(wsReconnectOptions.pingInterval * 2)
197
+ breakConnection = false
198
+ }
199
+ socket.pong()
200
+ })
201
+ })
202
+
203
+ await waitForLogMessage(loggerSpy, 'proxy ws connection is broken')
204
+
205
+ // recreate a new target with the same upstream
206
+
207
+ target.ws.close()
208
+ target.server.close()
209
+ await createServices({ t, upstream, wsReconnectOptions, wsTargetOptions: { autoPong: false } })
210
+
211
+ await waitForLogMessage(loggerSpy, 'proxy ws target close event')
212
+ await waitForLogMessage(loggerSpy, 'proxy ws reconnect error')
213
+ await waitForLogMessage(loggerSpy, 'proxy ws reconnected')
214
+
215
+ t.end()
127
216
})
217
+ */
128
218
129
- // TODO reconnect fails becase of timeout
130
- // cant reconnect
131
- // TODO reconnect on close/error/unexpected-response
132
- // TODO reconnectOnClose ... on shutdown
133
- // TODO check only socket to target
219
+ // TODO reconnectOnClose but close all on shutdown
0 commit comments