@@ -4,13 +4,14 @@ import { Socket } from 'net';
4
4
import * as sinon from 'sinon' ;
5
5
import { setTimeout } from 'timers' ;
6
6
7
+ import { BinMsg } from '../../../src/cmap/commands' ;
7
8
import { connect } from '../../../src/cmap/connect' ;
8
9
import { Connection , hasSessionSupport } from '../../../src/cmap/connection' ;
9
10
import { MessageStream } from '../../../src/cmap/message_stream' ;
10
11
import { MongoNetworkTimeoutError } from '../../../src/error' ;
11
12
import { isHello , ns } from '../../../src/utils' ;
12
13
import * as mock from '../../tools/mongodb-mock/index' ;
13
- import { getSymbolFrom } from '../../tools/utils' ;
14
+ import { generateOpMsgBuffer , getSymbolFrom } from '../../tools/utils' ;
14
15
import { createTimerSandbox } from '../timer_sandbox' ;
15
16
16
17
const connectionOptionsDefaults = {
@@ -22,6 +23,25 @@ const connectionOptionsDefaults = {
22
23
loadBalanced : false
23
24
} ;
24
25
26
+ /** The absolute minimum socket API needed by Connection as of writing this test */
27
+ class FakeSocket extends EventEmitter {
28
+ address ( ) {
29
+ // is never called
30
+ }
31
+ pipe ( ) {
32
+ // does not need to do anything
33
+ }
34
+ destroy ( ) {
35
+ // is called, has no side effects
36
+ }
37
+ get remoteAddress ( ) {
38
+ return 'iLoveJavaScript' ;
39
+ }
40
+ get remotePort ( ) {
41
+ return 123 ;
42
+ }
43
+ }
44
+
25
45
describe ( 'new Connection()' , function ( ) {
26
46
let server ;
27
47
after ( ( ) => mock . cleanup ( ) ) ;
@@ -137,6 +157,89 @@ describe('new Connection()', function () {
137
157
} ) ;
138
158
} ) ;
139
159
160
+ describe ( '#onMessage' , function ( ) {
161
+ context ( 'when the connection is a monitoring connection' , function ( ) {
162
+ let queue : Map < number , OperationDescription > ;
163
+ let driverSocket : FakeSocket ;
164
+ let connection : Connection ;
165
+
166
+ beforeEach ( function ( ) {
167
+ driverSocket = sinon . spy ( new FakeSocket ( ) ) ;
168
+ // @ts -expect-error: driverSocket does not fully satisfy the stream type, but that's okay
169
+ connection = sinon . spy ( new Connection ( driverSocket , connectionOptionsDefaults ) ) ;
170
+ connection . isMonitoringConnection = true ;
171
+ const queueSymbol = getSymbolFrom ( connection , 'queue' ) ;
172
+ queue = connection [ queueSymbol ] ;
173
+ } ) ;
174
+
175
+ context ( 'when requestId/responseTo do not match' , function ( ) {
176
+ let callbackSpy ;
177
+ const document = { ok : 1 } ;
178
+
179
+ beforeEach ( function ( ) {
180
+ callbackSpy = sinon . spy ( ) ;
181
+ // Create the operation description.
182
+ const operationDescription : OperationDescription = {
183
+ requestId : 1 ,
184
+ cb : callbackSpy
185
+ } ;
186
+
187
+ // Stick an operation description in the queue.
188
+ queue . set ( 1 , operationDescription ) ;
189
+ // Emit a message that won't match the existing operation description.
190
+ const msg = generateOpMsgBuffer ( document ) ;
191
+ const msgHeader : MessageHeader = {
192
+ length : msg . readInt32LE ( 0 ) ,
193
+ requestId : msg . readInt32LE ( 4 ) ,
194
+ responseTo : msg . readInt32LE ( 8 ) ,
195
+ opCode : msg . readInt32LE ( 12 )
196
+ } ;
197
+ const msgBody = msg . subarray ( 16 ) ;
198
+
199
+ const message = new BinMsg ( msg , msgHeader , msgBody ) ;
200
+ driverSocket . emit ( 'message' , message ) ;
201
+ } ) ;
202
+
203
+ it ( 'calls the operation description callback with the document' , function ( ) {
204
+ expect ( callbackSpy ) . to . be . calledWith ( document ) ;
205
+ } ) ;
206
+ } ) ;
207
+
208
+ context ( 'when requestId/reponseTo match' , function ( ) {
209
+ let callbackSpy ;
210
+ const document = { ok : 1 } ;
211
+
212
+ beforeEach ( function ( ) {
213
+ callbackSpy = sinon . spy ( ) ;
214
+ // Create the operation description.
215
+ const operationDescription : OperationDescription = {
216
+ requestId : 1 ,
217
+ cb : callbackSpy
218
+ } ;
219
+
220
+ // Stick an operation description in the queue.
221
+ queue . set ( 1 , operationDescription ) ;
222
+ // Emit a message that matches the existing operation description.
223
+ const msg = generateOpMsgBuffer ( document ) ;
224
+ const msgHeader : MessageHeader = {
225
+ length : msg . readInt32LE ( 0 ) ,
226
+ requestId : 2 ,
227
+ responseTo : 1 ,
228
+ opCode : msg . readInt32LE ( 12 )
229
+ } ;
230
+ const msgBody = msg . subarray ( 16 ) ;
231
+
232
+ const message = new BinMsg ( msg , msgHeader , msgBody ) ;
233
+ driverSocket . emit ( 'message' , message ) ;
234
+ } ) ;
235
+
236
+ it ( 'calls the operation description callback with the document' , function ( ) {
237
+ expect ( callbackSpy ) . to . be . calledWith ( document ) ;
238
+ } ) ;
239
+ } ) ;
240
+ } ) ;
241
+ } ) ;
242
+
140
243
describe ( 'onTimeout()' , ( ) => {
141
244
let connection : sinon . SinonSpiedInstance < Connection > ;
142
245
let clock : sinon . SinonFakeTimers ;
@@ -146,25 +249,6 @@ describe('new Connection()', function () {
146
249
let kDelayedTimeoutId : symbol ;
147
250
let NodeJSTimeoutClass : any ;
148
251
149
- /** The absolute minimum socket API needed by Connection as of writing this test */
150
- class FakeSocket extends EventEmitter {
151
- address ( ) {
152
- // is never called
153
- }
154
- pipe ( ) {
155
- // does not need to do anything
156
- }
157
- destroy ( ) {
158
- // is called, has no side effects
159
- }
160
- get remoteAddress ( ) {
161
- return 'iLoveJavaScript' ;
162
- }
163
- get remotePort ( ) {
164
- return 123 ;
165
- }
166
- }
167
-
168
252
beforeEach ( ( ) => {
169
253
timerSandbox = createTimerSandbox ( ) ;
170
254
clock = sinon . useFakeTimers ( ) ;
0 commit comments