1
1
'use strict' ;
2
- const Readable = require ( 'stream' ) . Readable ;
3
- const Writable = require ( 'stream' ) . Writable ;
2
+ const { on, once } = require ( 'events' ) ;
3
+ const { Readable, Writable } = require ( 'stream' ) ;
4
+
4
5
const { MessageStream } = require ( '../../../src/cmap/message_stream' ) ;
5
6
const { Msg } = require ( '../../../src/cmap/commands' ) ;
6
7
const expect = require ( 'chai' ) . expect ;
7
8
const { LEGACY_HELLO_COMMAND } = require ( '../../../src/constants' ) ;
9
+ const { generateOpMsgBuffer } = require ( '../../tools/utils' ) ;
8
10
9
11
function bufferToStream ( buffer ) {
10
12
const stream = new Readable ( ) ;
@@ -18,117 +20,117 @@ function bufferToStream(buffer) {
18
20
return stream ;
19
21
}
20
22
21
- describe ( 'Message Stream' , function ( ) {
22
- describe ( 'reading' , function ( ) {
23
- [
24
- {
25
- description : 'valid OP_REPLY' ,
26
- data : Buffer . from (
27
- '370000000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' ,
28
- 'hex'
29
- ) ,
30
- documents : [ { [ LEGACY_HELLO_COMMAND ] : 1 } ]
31
- } ,
32
- {
33
- description : 'valid multiple OP_REPLY' ,
34
- expectedMessageCount : 4 ,
35
- data : Buffer . from (
36
- '370000000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' +
37
- '370000000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' +
38
- '370000000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' +
39
- '370000000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' ,
40
- 'hex'
41
- ) ,
42
- documents : [ { [ LEGACY_HELLO_COMMAND ] : 1 } ]
43
- } ,
44
- {
45
- description : 'valid OP_REPLY (partial)' ,
46
- data : [
47
- Buffer . from ( '37' , 'hex' ) ,
48
- Buffer . from ( '0000' , 'hex' ) ,
49
- Buffer . from (
50
- '000100000001000000010000000000000000000000000000000000000001000000130000001069736d6173746572000100000000' ,
51
- 'hex'
52
- )
53
- ] ,
54
- documents : [ { [ LEGACY_HELLO_COMMAND ] : 1 } ]
55
- } ,
56
-
57
- {
58
- description : 'valid OP_MSG' ,
59
- data : Buffer . from (
60
- '370000000100000000000000dd0700000000000000220000001069736d6173746572000100000002246462000600000061646d696e0000' ,
61
- 'hex'
62
- ) ,
63
- documents : [ { $db : 'admin' , [ LEGACY_HELLO_COMMAND ] : 1 } ]
64
- } ,
65
- {
66
- description : 'valid multiple OP_MSG' ,
67
- expectedMessageCount : 4 ,
68
- data : Buffer . from (
69
- '370000000100000000000000dd0700000000000000220000001069736d6173746572000100000002246462000600000061646d696e0000' +
70
- '370000000100000000000000dd0700000000000000220000001069736d6173746572000100000002246462000600000061646d696e0000' +
71
- '370000000100000000000000dd0700000000000000220000001069736d6173746572000100000002246462000600000061646d696e0000' +
72
- '370000000100000000000000dd0700000000000000220000001069736d6173746572000100000002246462000600000061646d696e0000' ,
73
- 'hex'
74
- ) ,
75
- documents : [ { $db : 'admin' , [ LEGACY_HELLO_COMMAND ] : 1 } ]
76
- } ,
77
-
78
- {
79
- description : 'Invalid message size (negative)' ,
80
- data : Buffer . from ( 'ffffffff' , 'hex' ) ,
81
- error : 'Invalid message size: -1'
82
- } ,
83
- {
84
- description : 'Invalid message size (exceeds maximum)' ,
85
- data : Buffer . from ( '01000004' , 'hex' ) ,
86
- error : 'Invalid message size: 67108865, max allowed: 67108864'
87
- }
88
- ] . forEach ( test => {
89
- it ( test . description , function ( done ) {
90
- const error = test . error ;
91
- const expectedMessageCount = test . expectedMessageCount || 1 ;
92
- const inputStream = bufferToStream ( test . data ) ;
93
- const messageStream = new MessageStream ( ) ;
23
+ describe ( 'MessageStream' , function ( ) {
24
+ context ( 'when the stream is for a monitoring connection' , function ( ) {
25
+ const response = { isWritablePrimary : true } ;
26
+ const lastResponse = { ok : 1 } ;
27
+ let firstHello ;
28
+ let secondHello ;
29
+ let thirdHello ;
30
+ let partial ;
31
+
32
+ beforeEach ( function ( ) {
33
+ firstHello = generateOpMsgBuffer ( response ) ;
34
+ secondHello = generateOpMsgBuffer ( response ) ;
35
+ thirdHello = generateOpMsgBuffer ( lastResponse ) ;
36
+ partial = Buffer . alloc ( 5 ) ;
37
+ partial . writeInt32LE ( 100 , 0 ) ;
38
+ } ) ;
94
39
95
- let messageCount = 0 ;
96
- messageStream . on ( 'message' , msg => {
97
- messageCount ++ ;
98
- if ( error ) {
99
- done ( new Error ( `expected error: ${ error } ` ) ) ;
100
- return ;
101
- }
40
+ it ( 'only reads the last message in the buffer' , async function ( ) {
41
+ const inputStream = bufferToStream ( Buffer . concat ( [ firstHello , secondHello , thirdHello ] ) ) ;
42
+ const messageStream = new MessageStream ( ) ;
43
+ messageStream . isMonitoringConnection = true ;
44
+
45
+ inputStream . pipe ( messageStream ) ;
46
+ const messages = await once ( messageStream , 'message' ) ;
47
+ const msg = messages [ 0 ] ;
48
+ msg . parse ( ) ;
49
+ expect ( msg ) . to . have . property ( 'documents' ) . that . deep . equals ( [ lastResponse ] ) ;
50
+ // Make sure there is nothing left in the buffer.
51
+ expect ( messageStream . buffer . length ) . to . equal ( 0 ) ;
52
+ } ) ;
102
53
103
- msg . parse ( ) ;
54
+ it ( 'does not read partial messages' , async function ( ) {
55
+ const inputStream = bufferToStream (
56
+ Buffer . concat ( [ firstHello , secondHello , thirdHello , partial ] )
57
+ ) ;
58
+ const messageStream = new MessageStream ( ) ;
59
+ messageStream . isMonitoringConnection = true ;
60
+
61
+ inputStream . pipe ( messageStream ) ;
62
+ const messages = await once ( messageStream , 'message' ) ;
63
+ const msg = messages [ 0 ] ;
64
+ msg . parse ( ) ;
65
+ expect ( msg ) . to . have . property ( 'documents' ) . that . deep . equals ( [ lastResponse ] ) ;
66
+ // Make sure the buffer wasn't read to the end.
67
+ expect ( messageStream . buffer . length ) . to . equal ( 5 ) ;
68
+ } ) ;
69
+ } ) ;
104
70
105
- if ( test . documents ) {
106
- expect ( msg ) . to . have . property ( 'documents' ) . that . deep . equals ( test . documents ) ;
107
- }
71
+ context ( 'when the stream is not for a monitoring connection' , function ( ) {
72
+ context ( 'when the messages are valid' , function ( ) {
73
+ const response = { isWritablePrimary : true } ;
74
+ let firstHello ;
75
+ let secondHello ;
76
+ let thirdHello ;
77
+ let messageCount = 0 ;
78
+
79
+ beforeEach ( function ( ) {
80
+ firstHello = generateOpMsgBuffer ( response ) ;
81
+ secondHello = generateOpMsgBuffer ( response ) ;
82
+ thirdHello = generateOpMsgBuffer ( response ) ;
83
+ } ) ;
108
84
109
- if ( messageCount === expectedMessageCount ) {
110
- done ( ) ;
111
- }
112
- } ) ;
85
+ it ( 'reads all messages in the buffer' , async function ( ) {
86
+ const inputStream = bufferToStream ( Buffer . concat ( [ firstHello , secondHello , thirdHello ] ) ) ;
87
+ const messageStream = new MessageStream ( ) ;
113
88
114
- messageStream . on ( 'error' , err => {
115
- if ( error == null ) {
116
- done ( err ) ;
89
+ inputStream . pipe ( messageStream ) ;
90
+ for await ( const messages of on ( messageStream , 'message' ) ) {
91
+ messageCount ++ ;
92
+ const msg = messages [ 0 ] ;
93
+ msg . parse ( ) ;
94
+ expect ( msg ) . to . have . property ( 'documents' ) . that . deep . equals ( [ response ] ) ;
95
+ // Test will not complete until 3 messages processed.
96
+ if ( messageCount === 3 ) {
117
97
return ;
118
98
}
99
+ }
100
+ } ) ;
101
+ } ) ;
119
102
120
- expect ( err ) . to . have . property ( 'message' ) . that . equals ( error ) ;
103
+ context ( 'when the messages are invalid' , function ( ) {
104
+ context ( 'when the message size is negative' , function ( ) {
105
+ it ( 'emits an error' , async function ( ) {
106
+ const inputStream = bufferToStream ( Buffer . from ( 'ffffffff' , 'hex' ) ) ;
107
+ const messageStream = new MessageStream ( ) ;
121
108
122
- done ( ) ;
109
+ inputStream . pipe ( messageStream ) ;
110
+ const errors = await once ( messageStream , 'error' ) ;
111
+ const err = errors [ 0 ] ;
112
+ expect ( err ) . to . have . property ( 'message' ) . that . equals ( 'Invalid message size: -1' ) ;
123
113
} ) ;
114
+ } ) ;
124
115
125
- inputStream . pipe ( messageStream ) ;
116
+ context ( 'when the message size exceeds the bson maximum' , function ( ) {
117
+ it ( 'emits an error' , async function ( ) {
118
+ const inputStream = bufferToStream ( Buffer . from ( '01000004' , 'hex' ) ) ;
119
+ const messageStream = new MessageStream ( ) ;
120
+
121
+ inputStream . pipe ( messageStream ) ;
122
+ const errors = await once ( messageStream , 'error' ) ;
123
+ const err = errors [ 0 ] ;
124
+ expect ( err )
125
+ . to . have . property ( 'message' )
126
+ . that . equals ( 'Invalid message size: 67108865, max allowed: 67108864' ) ;
127
+ } ) ;
126
128
} ) ;
127
129
} ) ;
128
130
} ) ;
129
131
130
- describe ( ' writing', function ( ) {
131
- it ( 'should write a message to the stream ' , function ( done ) {
132
+ context ( 'when writing to the message stream ', function ( ) {
133
+ it ( 'pushes the message ' , function ( done ) {
132
134
const readableStream = new Readable ( { read ( ) { } } ) ;
133
135
const writeableStream = new Writable ( {
134
136
write : ( chunk , _ , callback ) => {
0 commit comments