Skip to content

Commit 7f83475

Browse files
committed
CDRIVER-879 test cluster node reconnect
1 parent b145f9f commit 7f83475

File tree

5 files changed

+188
-0
lines changed

5 files changed

+188
-0
lines changed

tests/mock_server/mock-server.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,47 @@ mock_server_hangs_up (request_t *request)
11141114
}
11151115

11161116

1117+
/*--------------------------------------------------------------------------
1118+
*
1119+
* mock_server_resets --
1120+
*
1121+
* Forcefully reset a connection from the client.
1122+
*
1123+
* Returns:
1124+
* None.
1125+
*
1126+
* Side effects:
1127+
* Causes ECONNRESET on the client side.
1128+
*
1129+
*--------------------------------------------------------------------------
1130+
*/
1131+
1132+
void
1133+
mock_server_resets (request_t *request)
1134+
{
1135+
struct linger no_linger;
1136+
no_linger.l_onoff = 1;
1137+
no_linger.l_linger = 0;
1138+
1139+
if (mock_server_get_verbose (request->server)) {
1140+
printf ("%5.2f %hu <- %hu \treset!\n",
1141+
mock_server_get_uptime_sec (request->server),
1142+
request->client_port,
1143+
request_get_server_port (request));
1144+
fflush (stdout);
1145+
}
1146+
1147+
/* send RST packet to client */
1148+
mongoc_stream_setsockopt (request->client,
1149+
SOL_SOCKET,
1150+
SO_LINGER,
1151+
&no_linger,
1152+
sizeof no_linger);
1153+
1154+
mongoc_stream_close (request->client);
1155+
}
1156+
1157+
11171158
/*--------------------------------------------------------------------------
11181159
*
11191160
* mock_server_replies --

tests/mock_server/mock-server.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ request_t *mock_server_receives_kill_cursors (mock_server_t *server,
131131

132132
void mock_server_hangs_up (request_t *request);
133133

134+
void mock_server_resets (request_t *request);
135+
134136
void mock_server_replies (request_t *request,
135137
uint32_t flags,
136138
int64_t cursor_id,

tests/mock_server/request.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,28 @@ request_get_server_port (request_t *request)
461461
}
462462

463463

464+
/*--------------------------------------------------------------------------
465+
*
466+
* request_get_client_port --
467+
*
468+
* Get the client port this request was sent from.
469+
*
470+
* Returns:
471+
* A port number.
472+
*
473+
* Side effects:
474+
* None.
475+
*
476+
*--------------------------------------------------------------------------
477+
*/
478+
479+
uint16_t
480+
request_get_client_port (request_t *request)
481+
{
482+
return request->client_port;
483+
}
484+
485+
464486
/*--------------------------------------------------------------------------
465487
*
466488
* request_destroy --

tests/mock_server/request.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ bool request_matches_kill_cursors (const request_t *request,
9191

9292
uint16_t request_get_server_port (request_t *request);
9393

94+
uint16_t request_get_client_port (request_t *request);
95+
9496
void request_destroy (request_t *request);
9597

9698
#endif //REQUEST_H

tests/test-mongoc-cluster.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
#include <mongoc.h>
22

33
#include "mongoc-client-private.h"
4+
#include "mongoc-uri-private.h"
45

6+
#include "mock_server/mock-server.h"
7+
#include "mock_server/future.h"
8+
#include "mock_server/future-functions.h"
59
#include "mongoc-tests.h"
610
#include "TestSuite.h"
711
#include "test-libmongoc.h"
12+
#include "test-conveniences.h"
813

914

1015
#undef MONGOC_LOG_DOMAIN
@@ -91,9 +96,125 @@ test_get_max_msg_size (void)
9196
mongoc_client_pool_destroy (pool);
9297
}
9398

99+
100+
#define ASSERT_CURSOR_ERR() do { \
101+
char *error_message = bson_strdup_printf ( \
102+
"Failed to read 4 bytes from socket within %d milliseconds.", \
103+
socket_timeout_ms); \
104+
BSON_ASSERT (!future_get_bool (future)); \
105+
BSON_ASSERT (mongoc_cursor_error (cursor, &error)); \
106+
ASSERT_CMPINT (error.domain, ==, MONGOC_ERROR_STREAM); \
107+
ASSERT_CMPINT (error.code, ==, MONGOC_ERROR_STREAM_SOCKET); \
108+
ASSERT_CMPSTR (error.message, error_message); \
109+
bson_free (error_message); \
110+
} while (0)
111+
112+
113+
#define START_QUERY(client_port_variable) do { \
114+
cursor = mongoc_collection_find (collection, \
115+
MONGOC_QUERY_NONE, \
116+
0, 0, 0, tmp_bson ("{}"), \
117+
NULL, NULL); \
118+
future = future_cursor_next (cursor, &doc); \
119+
request = mock_server_receives_query (server, "test.test", \
120+
MONGOC_QUERY_SLAVE_OK, 0, 0, \
121+
"{}", NULL); \
122+
BSON_ASSERT (request); \
123+
client_port_variable = request_get_client_port (request); \
124+
} while (0)
125+
126+
127+
#define CLEANUP_QUERY() do { \
128+
request_destroy (request); \
129+
future_destroy (future); \
130+
mongoc_cursor_destroy (cursor); \
131+
} while (0)
132+
133+
134+
/* test that we reconnect a cluster node after disconnect */
135+
static void
136+
_test_cluster_node_disconnect (bool pooled)
137+
{
138+
mock_server_t *server;
139+
const int32_t socket_timeout_ms = 100;
140+
mongoc_uri_t *uri;
141+
mongoc_client_pool_t *pool = NULL;
142+
mongoc_client_t *client;
143+
mongoc_collection_t *collection;
144+
const bson_t *doc;
145+
mongoc_cursor_t *cursor;
146+
future_t *future;
147+
request_t *request;
148+
uint16_t client_port_0, client_port_1;
149+
bson_error_t error;
150+
151+
server = mock_server_with_autoismaster (0);
152+
mock_server_run (server);
153+
154+
uri = mongoc_uri_copy (mock_server_get_uri (server));
155+
mongoc_uri_set_option_as_int32 (uri, "socketTimeoutMS", socket_timeout_ms);
156+
157+
if (pooled) {
158+
pool = mongoc_client_pool_new (uri);
159+
client = mongoc_client_pool_pop (pool);
160+
} else {
161+
client = mongoc_client_new_from_uri (uri);
162+
}
163+
164+
collection = mongoc_client_get_collection (client, "test", "test");
165+
166+
/* query 0 fails. set client_port_0 to the port used by the query. */
167+
START_QUERY (client_port_0);
168+
if (pooled) {
169+
suppress_one_message ();
170+
}
171+
172+
mock_server_resets (request);
173+
ASSERT_CURSOR_ERR ();
174+
CLEANUP_QUERY ();
175+
176+
/* query 1 opens a new socket. set client_port_1 to the new port. */
177+
START_QUERY (client_port_1);
178+
ASSERT_CMPINT (client_port_1, !=, client_port_0);
179+
mock_server_replies_simple (request, "{'a': 1}");
180+
181+
/* success! */
182+
BSON_ASSERT (future_get_bool (future));
183+
184+
CLEANUP_QUERY ();
185+
mongoc_collection_destroy (collection);
186+
187+
if (pooled) {
188+
mongoc_client_pool_push (pool, client);
189+
mongoc_client_pool_destroy (pool);
190+
} else {
191+
mongoc_client_destroy (client);
192+
}
193+
194+
mongoc_uri_destroy (uri);
195+
mock_server_destroy (server);
196+
}
197+
198+
199+
static void
200+
test_cluster_node_disconnect_single (void)
201+
{
202+
_test_cluster_node_disconnect (false);
203+
}
204+
205+
206+
static void
207+
test_cluster_node_disconnect_pooled (void)
208+
{
209+
_test_cluster_node_disconnect (true);
210+
}
211+
212+
94213
void
95214
test_cluster_install (TestSuite *suite)
96215
{
97216
TestSuite_Add (suite, "/Cluster/test_get_max_bson_obj_size", test_get_max_bson_obj_size);
98217
TestSuite_Add (suite, "/Cluster/test_get_max_msg_size", test_get_max_msg_size);
218+
TestSuite_Add (suite, "/Cluster/disconnect/single", test_cluster_node_disconnect_single);
219+
TestSuite_Add (suite, "/Cluster/disconnect/pooled", test_cluster_node_disconnect_pooled);
99220
}

0 commit comments

Comments
 (0)