Skip to content

Commit 4ea9914

Browse files
committed
CDRIVER-3121 loosen error code numeric checks
Permit double and int64, since they may appear when error codes are returned via failpoints.
1 parent e7126c8 commit 4ea9914

File tree

7 files changed

+105
-20
lines changed

7 files changed

+105
-20
lines changed

src/libmongoc/src/mongoc/mongoc-collection.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3220,8 +3220,9 @@ mongoc_collection_find_and_modify_with_opts (
32203220
retry_server_stream = mongoc_cluster_stream_for_writes (
32213221
cluster, parts.assembled.session, NULL /* reply */, &ignored_error);
32223222

3223-
if (retry_server_stream && retry_server_stream->sd->max_wire_version >=
3224-
WIRE_VERSION_RETRY_WRITES) {
3223+
if (retry_server_stream &&
3224+
retry_server_stream->sd->max_wire_version >=
3225+
WIRE_VERSION_RETRY_WRITES) {
32253226
parts.assembled.server_stream = retry_server_stream;
32263227
GOTO (retry);
32273228
}
@@ -3235,7 +3236,7 @@ mongoc_collection_find_and_modify_with_opts (
32353236
BSON_ASSERT (bson_iter_recurse (&iter, &inner));
32363237
while (bson_iter_next (&inner)) {
32373238
if (BSON_ITER_IS_KEY (&inner, "code")) {
3238-
code = bson_iter_int32 (&inner);
3239+
code = (uint32_t) bson_iter_as_int64 (&inner);
32393240
} else if (BSON_ITER_IS_KEY (&inner, "errmsg")) {
32403241
errmsg = bson_iter_utf8 (&inner, NULL);
32413242
}

src/libmongoc/src/mongoc/mongoc-rpc.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ _mongoc_rpc_decompress (mongoc_rpc_t *rpc_le, uint8_t *buf, size_t buflen)
800800
rpc_le->compressed.compressed_message_len,
801801
buf + 16,
802802
&uncompressed_size);
803-
803+
804804
BSON_ASSERT (original_uncompressed_size == uncompressed_size);
805805

806806
if (ok) {
@@ -1067,9 +1067,13 @@ _parse_error_reply (const bson_t *doc,
10671067
BSON_ASSERT (code);
10681068
*code = 0;
10691069

1070+
/* The server only returns real error codes as int32.
1071+
* But it may return as a double or int64 if a failpoint
1072+
* based on how it is configured to error. */
10701073
if (bson_iter_init_find (&iter, doc, "code") &&
1071-
BSON_ITER_HOLDS_INT32 (&iter)) {
1072-
*code = (uint32_t) bson_iter_int32 (&iter);
1074+
BSON_ITER_HOLDS_NUMBER (&iter)) {
1075+
*code = (uint32_t) bson_iter_as_int64 (&iter);
1076+
BSON_ASSERT (*code);
10731077
found_error = true;
10741078
}
10751079

@@ -1095,8 +1099,9 @@ _parse_error_reply (const bson_t *doc,
10951099
bson_iter_t child;
10961100
BSON_ASSERT (bson_iter_recurse (&iter, &child));
10971101
if (bson_iter_find (&child, "code") &&
1098-
BSON_ITER_HOLDS_INT32 (&child)) {
1099-
*code = (uint32_t) bson_iter_int32 (&child);
1102+
BSON_ITER_HOLDS_NUMBER (&child)) {
1103+
*code = (uint32_t) bson_iter_as_int64 (&child);
1104+
BSON_ASSERT (*code);
11001105
found_error = true;
11011106
}
11021107
BSON_ASSERT (bson_iter_recurse (&iter, &child));
@@ -1236,8 +1241,9 @@ _mongoc_populate_query_error (const bson_t *doc,
12361241
BSON_ASSERT (doc);
12371242

12381243
if (bson_iter_init_find (&iter, doc, "code") &&
1239-
BSON_ITER_HOLDS_INT32 (&iter)) {
1240-
code = (uint32_t) bson_iter_int32 (&iter);
1244+
BSON_ITER_HOLDS_NUMBER (&iter)) {
1245+
code = (uint32_t) bson_iter_as_int64 (&iter);
1246+
BSON_ASSERT (code);
12411247
}
12421248

12431249
if (bson_iter_init_find (&iter, doc, "$err") &&

src/libmongoc/src/mongoc/mongoc-write-command.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1345,7 +1345,7 @@ _set_error_from_response (bson_t *bson_array,
13451345
while (bson_iter_next (&doc_iter)) {
13461346
/* use the first error code we find */
13471347
if (BSON_ITER_IS_KEY (&doc_iter, "code") && code == 0) {
1348-
code = bson_iter_int32 (&doc_iter);
1348+
code = (uint32_t) bson_iter_as_int64 (&doc_iter);
13491349
} else if (BSON_ITER_IS_KEY (&doc_iter, "errmsg")) {
13501350
errmsg = bson_iter_utf8 (&doc_iter, NULL);
13511351

src/libmongoc/src/mongoc/mongoc-write-concern.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ _mongoc_parse_wc_err (const bson_t *doc, bson_error_t *error)
462462
BSON_ASSERT (bson_iter_recurse (&iter, &inner));
463463
while (bson_iter_next (&inner)) {
464464
if (BSON_ITER_IS_KEY (&inner, "code")) {
465-
code = bson_iter_int32 (&inner);
465+
code = (uint32_t) bson_iter_as_int64 (&inner);
466466
} else if (BSON_ITER_IS_KEY (&inner, "errmsg")) {
467467
errmsg = bson_iter_utf8 (&inner, NULL);
468468
}

src/libmongoc/tests/json-test-monitoring.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,22 @@ apm_match_visitor (match_ctx_t *ctx,
364364
}
365365

366366

367+
static void
368+
_apm_match_error_context (const bson_t *actual, const bson_t *expectations)
369+
{
370+
char *actual_str;
371+
char *expectations_str;
372+
373+
actual_str = bson_as_canonical_extended_json (actual, NULL);
374+
expectations_str = bson_as_canonical_extended_json (expectations, NULL);
375+
fprintf (stderr,
376+
"Error in APM matching\nFull list of captured events: %s\nFull "
377+
"list of expectations: %s",
378+
actual_str,
379+
expectations_str);
380+
bson_free (actual_str);
381+
bson_free (expectations_str);
382+
}
367383
/*
368384
*-----------------------------------------------------------------------
369385
*
@@ -443,6 +459,7 @@ check_json_apm_events (json_test_ctx_t *ctx, const bson_t *expectations)
443459
* non-matching ones */
444460
continue;
445461
} else {
462+
_apm_match_error_context (&ctx->events, expectations);
446463
test_error ("could not match APM event\n"
447464
"\texpected: %s\n\n"
448465
"\tactual : %s\n\n"
@@ -454,6 +471,7 @@ check_json_apm_events (json_test_ctx_t *ctx, const bson_t *expectations)
454471
}
455472

456473
if (!matched) {
474+
_apm_match_error_context (&ctx->events, expectations);
457475
test_error ("expectation unmatched\n"
458476
"\texpected: %s\n\n",
459477
bson_as_canonical_extended_json (&expectation, NULL));
@@ -468,6 +486,7 @@ check_json_apm_events (json_test_ctx_t *ctx, const bson_t *expectations)
468486
bson_t extra;
469487

470488
bson_iter_bson (&actual_iter, &extra);
489+
_apm_match_error_context (&ctx->events, expectations);
471490
test_error ("extra actual event was not found in expectations: %s\n",
472491
bson_as_canonical_extended_json (&extra, NULL));
473492
}

src/libmongoc/tests/test-libmongoc.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,6 +2271,10 @@ test_framework_skip_if_no_failpoint (void)
22712271
bool ret;
22722272
bson_error_t error;
22732273

2274+
if (!TestSuite_CheckLive ()) {
2275+
return 0;
2276+
}
2277+
22742278
client = test_framework_client_new ();
22752279
mongoc_client_set_error_api (client, MONGOC_ERROR_API_VERSION_2);
22762280
ret = mongoc_client_command_simple (

src/libmongoc/tests/test-mongoc-write-commands.c

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,8 @@ test_split_insert (void)
4747

4848
_mongoc_write_result_init (&result);
4949

50-
_mongoc_write_command_init_insert (&command,
51-
docs[0],
52-
NULL,
53-
write_flags,
54-
++client->cluster.operation_id);
50+
_mongoc_write_command_init_insert (
51+
&command, docs[0], NULL, write_flags, ++client->cluster.operation_id);
5552

5653
for (i = 1; i < 3000; i++) {
5754
_mongoc_write_command_insert_append (&command, docs[i]);
@@ -576,6 +573,59 @@ test_w0_legacy_insert_many (void)
576573
mock_server_destroy (server);
577574
}
578575

576+
static void
577+
_configure_failpoint (mongoc_client_t *client,
578+
const char *mode,
579+
const char *data)
580+
{
581+
bool ret;
582+
bson_error_t error;
583+
584+
ret = mongoc_client_command_simple (
585+
client,
586+
"admin",
587+
tmp_bson ("{'configureFailPoint': 'failCommand', 'mode': %s, 'data': %s}",
588+
mode,
589+
data),
590+
NULL,
591+
NULL,
592+
&error);
593+
ASSERT_OR_PRINT (ret, error);
594+
}
595+
596+
static void
597+
_test_invalid_wc_server_error (void *unused)
598+
{
599+
mongoc_client_t *client;
600+
mongoc_collection_t *coll;
601+
bool ret;
602+
bson_t reply;
603+
bson_error_t error;
604+
605+
client = test_framework_client_new ();
606+
mongoc_client_set_error_api (client, MONGOC_ERROR_API_VERSION_2);
607+
coll = get_test_collection (client, "server_wc_error");
608+
609+
_configure_failpoint (client,
610+
"{'times': 2}",
611+
"{ 'failCommands': ['insert'], "
612+
"'writeConcernError': {'code' : "
613+
"91.0, 'errmsg': 'Replication is "
614+
"being shut down' }}");
615+
ret = mongoc_collection_insert_one (
616+
coll, tmp_bson ("{'x':1}"), NULL /* opts */, &reply, &error);
617+
BSON_ASSERT (!ret);
618+
ASSERT_MATCH (&reply,
619+
"{'writeConcernErrors': [{'code': 91, 'errmsg': "
620+
"'Replication is being shut down'}]}");
621+
622+
_configure_failpoint (client, "'off'", "{}");
623+
624+
bson_destroy (&reply);
625+
mongoc_collection_destroy (coll);
626+
mongoc_client_destroy (client);
627+
}
628+
579629
void
580630
test_write_command_install (TestSuite *suite)
581631
{
@@ -596,7 +646,12 @@ test_write_command_install (TestSuite *suite)
596646
TestSuite_AddMockServerTest (suite,
597647
"/WriteCommand/insert_disconnect_mid_batch",
598648
test_opmsg_disconnect_mid_batch);
599-
TestSuite_AddMockServerTest (suite,
600-
"/WriteCommand/w0_legacy_insert_many",
601-
test_w0_legacy_insert_many);
649+
TestSuite_AddMockServerTest (
650+
suite, "/WriteCommand/w0_legacy_insert_many", test_w0_legacy_insert_many);
651+
TestSuite_AddFull (suite,
652+
"/WriteCommand/invalid_wc_server_error",
653+
_test_invalid_wc_server_error,
654+
NULL,
655+
NULL,
656+
test_framework_skip_if_no_failpoint);
602657
}

0 commit comments

Comments
 (0)