1
- /* Copyright 2013 -present MongoDB Inc.
1
+ /* Copyright 2010 -present MongoDB Inc.
2
2
*
3
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
4
* you may not use this file except in compliance with the License.
14
14
*/
15
15
16
16
using System ;
17
+ using System . Collections . Generic ;
17
18
using System . IO ;
18
19
using System . Net ;
19
20
using System . Net . Sockets ;
23
24
using MongoDB . Bson ;
24
25
using MongoDB . Bson . Serialization . Serializers ;
25
26
using MongoDB . TestHelpers . XunitExtensions ;
27
+ using MongoDB . Driver . Core . Authentication ;
26
28
using MongoDB . Driver . Core . Clusters ;
27
29
using MongoDB . Driver . Core . Configuration ;
28
30
using MongoDB . Driver . Core . Events ;
32
34
using MongoDB . Driver . Core . TestHelpers . Logging ;
33
35
using MongoDB . Driver . Core . WireProtocol . Messages ;
34
36
using MongoDB . Driver . Core . WireProtocol . Messages . Encoders ;
37
+ using MongoDB . Driver . Core . WireProtocol . Messages . Encoders . BinaryEncoders ;
35
38
using Moq ;
36
39
using Xunit ;
37
40
38
41
namespace MongoDB . Driver . Core . Connections
39
42
{
40
43
public class BinaryConnectionTests : LoggableTestClass
41
44
{
45
+ private ConnectionInitializerContext _connectionInitializerContext ;
42
46
private Mock < IConnectionInitializer > _mockConnectionInitializer ;
43
47
private ConnectionDescription _connectionDescription ;
48
+ private readonly IReadOnlyList < IAuthenticator > __emptyAuthenticators = new IAuthenticator [ 0 ] ;
44
49
private DnsEndPoint _endPoint ;
45
50
private EventCapturer _capturedEvents ;
46
51
private MessageEncoderSettings _messageEncoderSettings = new MessageEncoderSettings ( ) ;
47
52
private Mock < IStreamFactory > _mockStreamFactory ;
53
+ private readonly ServerId _serverId ;
54
+
48
55
private BinaryConnection _subject ;
49
56
50
57
public BinaryConnectionTests ( Xunit . Abstractions . ITestOutputHelper output ) : base ( output )
@@ -53,27 +60,28 @@ public BinaryConnectionTests(Xunit.Abstractions.ITestOutputHelper output) : base
53
60
_mockStreamFactory = new Mock < IStreamFactory > ( ) ;
54
61
55
62
_endPoint = new DnsEndPoint ( "localhost" , 27017 ) ;
56
- var serverId = new ServerId ( new ClusterId ( ) , _endPoint ) ;
57
- var connectionId = new ConnectionId ( serverId ) ;
63
+ _serverId = new ServerId ( new ClusterId ( ) , _endPoint ) ;
64
+ var connectionId = new ConnectionId ( _serverId ) ;
58
65
var helloResult = new HelloResult ( new BsonDocument { { "ok" , 1 } , { "maxMessageSizeBytes" , 48000000 } , { "maxWireVersion" , WireVersion . Server36 } } ) ;
59
66
_connectionDescription = new ConnectionDescription ( connectionId , helloResult ) ;
67
+ _connectionInitializerContext = new ConnectionInitializerContext ( _connectionDescription , __emptyAuthenticators ) ;
60
68
61
69
_mockConnectionInitializer = new Mock < IConnectionInitializer > ( ) ;
62
70
_mockConnectionInitializer
63
71
. Setup ( i => i . SendHello ( It . IsAny < IConnection > ( ) , CancellationToken . None ) )
64
- . Returns ( _connectionDescription ) ;
72
+ . Returns ( _connectionInitializerContext ) ;
65
73
_mockConnectionInitializer
66
- . Setup ( i => i . Authenticate ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionDescription > ( ) , CancellationToken . None ) )
74
+ . Setup ( i => i . Authenticate ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionInitializerContext > ( ) , CancellationToken . None ) )
67
75
. Returns ( _connectionDescription ) ;
68
76
_mockConnectionInitializer
69
77
. Setup ( i => i . SendHelloAsync ( It . IsAny < IConnection > ( ) , CancellationToken . None ) )
70
- . ReturnsAsync ( _connectionDescription ) ;
78
+ . ReturnsAsync ( _connectionInitializerContext ) ;
71
79
_mockConnectionInitializer
72
- . Setup ( i => i . AuthenticateAsync ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionDescription > ( ) , CancellationToken . None ) )
80
+ . Setup ( i => i . AuthenticateAsync ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionInitializerContext > ( ) , CancellationToken . None ) )
73
81
. ReturnsAsync ( _connectionDescription ) ;
74
82
75
83
_subject = new BinaryConnection (
76
- serverId : serverId ,
84
+ serverId : _serverId ,
77
85
endPoint : _endPoint ,
78
86
settings : new ConnectionSettings ( ) ,
79
87
streamFactory : _mockStreamFactory . Object ,
@@ -94,8 +102,7 @@ public void Dispose_should_raise_the_correct_events()
94
102
95
103
[ Theory ]
96
104
[ ParameterAttributeData ]
97
- public void Open_should_always_create_description_if_handshake_was_successful (
98
- [ Values ( false , true ) ] bool async )
105
+ public void Open_should_always_create_description_if_handshake_was_successful ( [ Values ( false , true ) ] bool async )
99
106
{
100
107
var serviceId = ObjectId . GenerateNewId ( ) ;
101
108
var connectionDescription = new ConnectionDescription (
@@ -105,15 +112,15 @@ public void Open_should_always_create_description_if_handshake_was_successful(
105
112
var socketException = new SocketException ( ) ;
106
113
_mockConnectionInitializer
107
114
. Setup ( i => i . SendHello ( It . IsAny < IConnection > ( ) , CancellationToken . None ) )
108
- . Returns ( connectionDescription ) ;
115
+ . Returns ( new ConnectionInitializerContext ( connectionDescription , __emptyAuthenticators ) ) ;
109
116
_mockConnectionInitializer
110
117
. Setup ( i => i . SendHelloAsync ( It . IsAny < IConnection > ( ) , CancellationToken . None ) )
111
- . ReturnsAsync ( connectionDescription ) ;
118
+ . ReturnsAsync ( new ConnectionInitializerContext ( connectionDescription , __emptyAuthenticators ) ) ;
112
119
_mockConnectionInitializer
113
- . Setup ( i => i . Authenticate ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionDescription > ( ) , CancellationToken . None ) )
120
+ . Setup ( i => i . Authenticate ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionInitializerContext > ( ) , CancellationToken . None ) )
114
121
. Throws ( socketException ) ;
115
122
_mockConnectionInitializer
116
- . Setup ( i => i . AuthenticateAsync ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionDescription > ( ) , CancellationToken . None ) )
123
+ . Setup ( i => i . AuthenticateAsync ( It . IsAny < IConnection > ( ) , It . IsAny < ConnectionInitializerContext > ( ) , CancellationToken . None ) )
117
124
. ThrowsAsync ( socketException ) ;
118
125
119
126
Exception exception ;
@@ -131,6 +138,68 @@ public void Open_should_always_create_description_if_handshake_was_successful(
131
138
ex . InnerException . Should ( ) . BeOfType < SocketException > ( ) ;
132
139
}
133
140
141
+ [ Theory ]
142
+ [ ParameterAttributeData ]
143
+ public async Task Open_should_create_authenticators_only_once(
144
+ [ Values ( false , true ) ] bool async )
145
+ {
146
+ var connectionDescription = new ConnectionDescription (
147
+ new ConnectionId ( new ServerId ( new ClusterId ( ) , _endPoint ) ) ,
148
+ new HelloResult ( new BsonDocument ( ) ) ) ;
149
+
150
+ using var memoryStream = new MemoryStream ( ) ;
151
+ var clonedMessageEncoderSettings = _messageEncoderSettings. Clone( ) ;
152
+ var encoderFactory = new BinaryMessageEncoderFactory ( memoryStream , clonedMessageEncoderSettings , compressorSource : null ) ;
153
+ var encoder = encoderFactory. GetCommandResponseMessageEncoder( ) ;
154
+ encoder . WriteMessage ( CreateResponseMessage ( ) ) ;
155
+ var mockStreamFactory = new Mock < IStreamFactory > ( ) ;
156
+ using var stream = new IgnoreWritesMemoryStream ( memoryStream . ToArray ( ) ) ;
157
+ mockStreamFactory
158
+ . Setup ( s => s . CreateStream ( It . IsAny < EndPoint > ( ) , CancellationToken . None ) )
159
+ . Returns ( stream ) ;
160
+ mockStreamFactory
161
+ . Setup ( s => s . CreateStreamAsync ( It . IsAny < EndPoint > ( ) , CancellationToken . None ) )
162
+ . ReturnsAsync ( stream ) ;
163
+
164
+ var connectionInitializer = new ConnectionInitializer (
165
+ null ,
166
+ new CompressorConfiguration [ 0 ] ,
167
+ new ServerApi ( ServerApiVersion . V1 ) ) ; // use serverApi to choose command message protocol
168
+ var authenticatorFactoryMock = new Mock < IAuthenticatorFactory > ( ) ;
169
+ authenticatorFactoryMock
170
+ . Setup ( a => a . Create ( ) )
171
+ . Returns ( Mock . Of < IAuthenticator > ( a => a . CustomizeInitialHelloCommand ( It . IsAny < BsonDocument > ( ) ) == new BsonDocument ( OppressiveLanguageConstants . LegacyHelloCommandName , 1 ) ) ) ;
172
+
173
+ using var subject = new BinaryConnection (
174
+ serverId : _serverId ,
175
+ endPoint : _endPoint ,
176
+ settings : new ConnectionSettings ( new [ ] { authenticatorFactoryMock . Object } ) ,
177
+ streamFactory : mockStreamFactory . Object ,
178
+ connectionInitializer : connectionInitializer ,
179
+ eventSubscriber : _capturedEvents ,
180
+ LoggerFactory ) ;
181
+
182
+ if ( async)
183
+ {
184
+ await subject . OpenAsync ( CancellationToken . None ) ;
185
+ }
186
+ else
187
+ {
188
+ subject . Open ( CancellationToken . None ) ;
189
+ }
190
+
191
+ authenticatorFactoryMock . Verify ( f => f . Create ( ) , Times . Once ( ) ) ;
192
+
193
+ ResponseMessage CreateResponseMessage ( )
194
+ {
195
+ var section0Document = $"{{ {OppressiveLanguageConstants.LegacyHelloResponseIsWritablePrimaryFieldName} : true, ok : 1, connectionId : 1 }}" ;
196
+ var section0 = new Type0CommandMessageSection < RawBsonDocument > (
197
+ new RawBsonDocument ( BsonDocument . Parse ( section0Document ) . ToBson ( ) ) ,
198
+ RawBsonDocumentSerializer . Instance ) ;
199
+ return new CommandResponseMessage ( new CommandMessage ( 1 , RequestMessage . CurrentGlobalRequestId + 1 , new [ ] { section0 } , false ) ) ;
200
+ }
201
+ }
202
+
134
203
[ Theory ]
135
204
[ ParameterAttributeData ]
136
205
public void Open_should_throw_an_ObjectDisposedException_if_the_connection_is_disposed(
@@ -161,7 +230,7 @@ public void Open_should_raise_the_correct_events_upon_failure(
161
230
Action act ;
162
231
if ( async )
163
232
{
164
- var result = new TaskCompletionSource < ConnectionDescription > ( ) ;
233
+ var result = new TaskCompletionSource < ConnectionInitializerContext > ( ) ;
165
234
result . SetException ( new SocketException ( ) ) ;
166
235
_mockConnectionInitializer . Setup ( i => i . SendHelloAsync ( It . IsAny < IConnection > ( ) , It . IsAny < CancellationToken > ( ) ) )
167
236
. Returns ( result . Task ) ;
@@ -803,5 +872,15 @@ public void SendMessages_should_put_the_messages_on_the_stream_and_raise_the_cor
803
872
_capturedEvents. Any ( ) . Should ( ) . BeFalse ( ) ;
804
873
}
805
874
}
875
+
876
+ // nested type
877
+ private sealed class IgnoreWritesMemoryStream : MemoryStream
878
+ {
879
+ public IgnoreWritesMemoryStream( byte [ ] bytes ) : base ( bytes ) { }
880
+ public override void Write( byte [ ] buffer , int offset , int count )
881
+ {
882
+ // Do nothing
883
+ }
884
+ }
806
885
}
807
886
}
0 commit comments