Skip to content

Commit 4d1cd82

Browse files
committed
CDRIVER-3316 retryable reads test follow-up
1 parent 1afad73 commit 4d1cd82

9 files changed

+1510
-118
lines changed

src/libmongoc/doc/distinct-mapreduce.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ First define the ``map`` and ``reduce`` functions:
3434
:language: c
3535
:caption: constants.c
3636

37-
Run the ``mapReduce`` command:
37+
Run the ``mapReduce`` command. Use the generic command helpers (e.g. :symbol:`mongoc_database_command_simple()`).
38+
Do not the read command helpers (e.g. :symbol:`mongoc_database_read_command_with_opts()`) because they are considered
39+
retryable read operations. If retryable reads are enabled, those operations will retry once on a retryable error,
40+
giving undesirable behavior for ``mapReduce``.
3841

3942
.. literalinclude:: ../examples/basic_aggregation/map-reduce-basic.c
4043
:language: c

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

Lines changed: 90 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,7 +1326,7 @@ find (mongoc_collection_t *collection,
13261326
return true;
13271327
}
13281328

1329-
/* TODO: merge into single_write */
1329+
13301330
static bool
13311331
find_one (mongoc_collection_t *collection,
13321332
const bson_t *test,
@@ -1607,23 +1607,17 @@ list_databases (mongoc_client_t *client,
16071607
const bson_t *test,
16081608
const bson_t *operation,
16091609
mongoc_client_session_t *session,
1610-
const mongoc_read_prefs_t *read_prefs,
1611-
bson_t *reply,
1612-
bool name_only)
1610+
bson_t *reply)
16131611
{
16141612
mongoc_cursor_t *cursor;
1615-
bson_t cmd = BSON_INITIALIZER;
1613+
bson_t opts;
16161614

16171615
BSON_ASSERT (client);
1618-
BSON_APPEND_INT32 (&cmd, "listDatabases", 1);
1619-
1620-
if (name_only) {
1621-
BSON_APPEND_BOOL (&cmd, "nameOnly", true);
1622-
}
1616+
bson_init (&opts);
1617+
append_session (session, &opts);
16231618

1624-
/* ignore client read prefs */
1625-
cursor = _mongoc_cursor_array_new (client, "admin", &cmd, NULL, "databases");
1626-
bson_destroy (&cmd);
1619+
cursor = mongoc_client_find_databases_with_opts (client, &opts);
1620+
bson_destroy (&opts);
16271621

16281622
check_cursor (cursor, test, operation);
16291623
mongoc_cursor_destroy (cursor);
@@ -1632,80 +1626,73 @@ list_databases (mongoc_client_t *client,
16321626
}
16331627

16341628

1635-
/* TODO: use find_indexes/collection/databases helpers */
16361629
static bool
1637-
list_indexes (mongoc_collection_t *collection,
1638-
const bson_t *test,
1639-
const bson_t *operation,
1640-
mongoc_client_session_t *session,
1641-
const mongoc_read_prefs_t *read_prefs,
1642-
bson_t *reply,
1643-
bool name_only)
1630+
list_database_names (mongoc_client_t *client,
1631+
const bson_t *test,
1632+
const bson_t *operation,
1633+
mongoc_client_session_t *session,
1634+
bson_t *reply)
16441635
{
1645-
mongoc_cursor_t *cursor;
1646-
bson_t cmd = BSON_INITIALIZER;
1647-
bson_t child;
1636+
char **database_names;
1637+
bson_t opts;
16481638
bson_error_t error;
16491639

1650-
BSON_ASSERT (collection);
1640+
BSON_ASSERT (client);
1641+
bson_init (&opts);
1642+
append_session (session, &opts);
16511643

1652-
bson_append_utf8 (&cmd,
1653-
"listIndexes",
1654-
-1,
1655-
collection->collection,
1656-
collection->collectionlen);
1644+
database_names =
1645+
mongoc_client_get_database_names_with_opts (client, &opts, &error);
1646+
bson_destroy (&opts);
16571647

1658-
if (name_only) {
1659-
BSON_APPEND_BOOL (&cmd, "nameOnly", true);
1660-
}
1648+
check_result (
1649+
test, operation, database_names != NULL, NULL /* result */, &error);
1650+
bson_init (reply);
1651+
bson_strfreev (database_names);
1652+
return true;
1653+
}
16611654

1662-
BSON_APPEND_DOCUMENT_BEGIN (&cmd, "cursor", &child);
1663-
bson_append_document_end (&cmd, &child);
16641655

1665-
/* No read preference. Index Enumeration Spec: "run listIndexes on the
1666-
* primary node in replicaSet mode". */
1667-
cursor = _mongoc_cursor_cmd_new (
1668-
collection->client, collection->ns, &cmd, NULL, NULL, NULL, NULL);
1656+
static bool
1657+
list_indexes (mongoc_collection_t *collection,
1658+
const bson_t *test,
1659+
const bson_t *operation,
1660+
mongoc_client_session_t *session,
1661+
bson_t *reply)
1662+
{
1663+
bson_t opts;
1664+
mongoc_cursor_t *cursor;
16691665

1670-
if (!mongoc_cursor_error (cursor, &error)) {
1671-
_mongoc_cursor_prime (cursor);
1672-
}
1666+
BSON_ASSERT (collection);
16731667

1674-
bson_destroy (&cmd);
1668+
bson_init (&opts);
1669+
append_session (session, &opts);
16751670

1671+
cursor = mongoc_collection_find_indexes_with_opts (collection, &opts);
16761672
check_cursor (cursor, test, operation);
16771673
mongoc_cursor_destroy (cursor);
16781674
bson_init (reply);
1675+
bson_destroy (&opts);
16791676
return true;
16801677
}
16811678

16821679

16831680
static bool
1684-
list_collections (mongoc_client_t *client,
1681+
list_collections (mongoc_database_t *db,
16851682
const bson_t *test,
16861683
const bson_t *operation,
16871684
mongoc_client_session_t *session,
1688-
const mongoc_read_prefs_t *read_prefs,
1689-
bson_t *reply,
1690-
bool name_only)
1685+
bson_t *reply)
16911686
{
16921687
mongoc_cursor_t *cursor;
1693-
bson_t cmd = BSON_INITIALIZER;
1688+
bson_t opts;
16941689

1695-
BSON_APPEND_INT32 (&cmd, "listCollections", 1);
1690+
bson_init (&opts);
1691+
append_session (session, &opts);
16961692

1697-
if (name_only) {
1698-
BSON_APPEND_BOOL (&cmd, "nameOnly", true);
1699-
}
1693+
cursor = mongoc_database_find_collections_with_opts (db, &opts);
17001694

1701-
/* Enumerate Collections Spec: "run listCollections on the primary node in
1702-
* replicaset mode" */
1703-
cursor =
1704-
_mongoc_cursor_cmd_new (client, "admin", &cmd, NULL, NULL, NULL, NULL);
1705-
if (cursor->error.domain == 0) {
1706-
_mongoc_cursor_prime (cursor);
1707-
}
1708-
bson_destroy (&cmd);
1695+
bson_destroy (&opts);
17091696

17101697
check_cursor (cursor, test, operation);
17111698
mongoc_cursor_destroy (cursor);
@@ -1714,6 +1701,33 @@ list_collections (mongoc_client_t *client,
17141701
return true;
17151702
}
17161703

1704+
static bool
1705+
list_collection_names (mongoc_database_t *db,
1706+
const bson_t *test,
1707+
const bson_t *operation,
1708+
mongoc_client_session_t *session,
1709+
bson_t *reply)
1710+
{
1711+
char **collection_names;
1712+
bson_t opts;
1713+
bson_error_t error;
1714+
1715+
bson_init (&opts);
1716+
append_session (session, &opts);
1717+
1718+
collection_names =
1719+
mongoc_database_get_collection_names_with_opts (db, &opts, &error);
1720+
1721+
bson_destroy (&opts);
1722+
1723+
check_result (
1724+
test, operation, collection_names != NULL, NULL /* result */, &error);
1725+
bson_init (reply);
1726+
bson_strfreev (collection_names);
1727+
1728+
return true;
1729+
}
1730+
17171731

17181732
static bool
17191733
gridfs_download (mongoc_database_t *db,
@@ -1745,19 +1759,6 @@ gridfs_download (mongoc_database_t *db,
17451759
return true;
17461760
}
17471761

1748-
/* The download_by_name functionality is part of the Advanced API for GridFS
1749-
* and the C Driver hasn't implemented the Advanced API yet. This is a
1750-
* placeholder to be used when the download_by_name is implemented. */
1751-
static bool
1752-
gridfs_download_by_name ()
1753-
{
1754-
test_error ("The download_by_name functionality is part of the Advanced API "
1755-
"for GridFS and the C Driver hasn't implemented the Advanced "
1756-
"API yet.");
1757-
return false;
1758-
}
1759-
1760-
17611762
bool
17621763
json_test_operation (json_test_ctx_t *ctx,
17631764
const bson_t *test,
@@ -1837,18 +1838,17 @@ json_test_operation (json_test_ctx_t *ctx,
18371838
res = find_one (c, test, operation, session, read_prefs, reply);
18381839
} else if (!strcmp (op_name, "aggregate")) {
18391840
res = aggregate (c, test, operation, session, read_prefs, reply);
1840-
} else if (!strcmp (op_name, "listIndexNames")) {
1841-
res =
1842-
list_indexes (c, test, operation, session, read_prefs, reply, true);
18431841
} else if (!strcmp (op_name, "listIndexes")) {
1844-
res = list_indexes (
1845-
c, test, operation, session, read_prefs, reply, false);
1842+
res = list_indexes (c, test, operation, session, reply);
18461843
} else if (!strcmp (op_name, "watch")) {
18471844
bson_t pipeline = BSON_INITIALIZER;
18481845
mongoc_change_stream_destroy (ctx->change_stream);
18491846
ctx->change_stream = mongoc_collection_watch (c, &pipeline, NULL);
18501847
bson_init (reply);
18511848
bson_destroy (&pipeline);
1849+
} else if (!strcmp (op_name, "mapReduce") ||
1850+
!strcmp (op_name, "listIndexNames")) {
1851+
test_error ("operation not implemented in libmongoc");
18521852
} else {
18531853
test_error ("unrecognized collection operation name %s", op_name);
18541854
}
@@ -1857,19 +1857,18 @@ json_test_operation (json_test_ctx_t *ctx,
18571857
res = db_aggregate (db, test, operation, session, read_prefs, reply);
18581858
} else if (!strcmp (op_name, "runCommand")) {
18591859
res = command (db, test, operation, session, read_prefs, reply);
1860-
} else if (!strcmp (op_name, "listCollections") ||
1861-
!strcmp (op_name, "listCollectionObjects")) {
1862-
res = list_collections (
1863-
c->client, test, operation, session, read_prefs, reply, false);
1860+
} else if (!strcmp (op_name, "listCollections")) {
1861+
res = list_collections (db, test, operation, session, reply);
18641862
} else if (!strcmp (op_name, "listCollectionNames")) {
1865-
res = list_collections (
1866-
c->client, test, operation, session, read_prefs, reply, true);
1863+
res = list_collection_names (db, test, operation, session, reply);
18671864
} else if (!strcmp (op_name, "watch")) {
18681865
bson_t pipeline = BSON_INITIALIZER;
18691866
mongoc_change_stream_destroy (ctx->change_stream);
18701867
ctx->change_stream = mongoc_database_watch (db, &pipeline, NULL);
18711868
bson_init (reply);
18721869
bson_destroy (&pipeline);
1870+
} else if (!strcmp (op_name, "listCollectionObjects")) {
1871+
test_error ("listCollectionObjects is not implemented in libmongoc");
18731872
} else {
18741873
test_error ("unrecognized database operation name %s", op_name);
18751874
}
@@ -1905,19 +1904,18 @@ json_test_operation (json_test_ctx_t *ctx,
19051904
test_error ("unrecognized session operation name %s", op_name);
19061905
}
19071906
} else if (!strcmp (obj_name, "client")) {
1908-
if (!strcmp (op_name, "listDatabases") ||
1909-
!strcmp (op_name, "listDatabaseObjects")) {
1910-
res = list_databases (
1911-
c->client, test, operation, session, read_prefs, reply, false);
1907+
if (!strcmp (op_name, "listDatabases")) {
1908+
res = list_databases (c->client, test, operation, session, reply);
19121909
} else if (!strcmp (op_name, "listDatabaseNames")) {
1913-
res = list_databases (
1914-
c->client, test, operation, session, read_prefs, reply, true);
1910+
res = list_database_names (c->client, test, operation, session, reply);
19151911
} else if (!strcmp (op_name, "watch")) {
19161912
bson_t pipeline = BSON_INITIALIZER;
19171913
mongoc_change_stream_destroy (ctx->change_stream);
19181914
ctx->change_stream = mongoc_client_watch (c->client, &pipeline, NULL);
19191915
bson_init (reply);
19201916
bson_destroy (&pipeline);
1917+
} else if (!strcmp (op_name, "listDatabaseObjects")) {
1918+
test_error ("listDatabaseObjects is not implemented in libmongoc");
19211919
} else {
19221920
test_error ("unrecognized client operation name %s", op_name);
19231921
}
@@ -1926,8 +1924,8 @@ json_test_operation (json_test_ctx_t *ctx,
19261924
res =
19271925
gridfs_download (db, test, operation, session, read_prefs, reply);
19281926
} else if (!strcmp (op_name, "download_by_name")) {
1929-
res = gridfs_download_by_name ();
1930-
bson_init (reply);
1927+
test_error ("download_by_name is part of the optional advanced API "
1928+
"and not implemented in libmongoc");
19311929
} else {
19321930
test_error ("unrecognized gridfs operation name %s", op_name);
19331931
}

src/libmongoc/tests/json-test.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,6 @@ _should_skip_due_to_server_39704 (const bson_t *test)
12251225
}
12261226
}
12271227

1228-
12291228
return false;
12301229
}
12311230

@@ -1391,6 +1390,61 @@ json_test_config_cleanup (json_test_config_t *config)
13911390
}
13921391

13931392

1393+
/* Tests on unsupported operations are automatically skipped with a message
1394+
* indicating why. */
1395+
static bson_t *
1396+
_skip_if_unsupported (const char *test_name, bson_t *original)
1397+
{
1398+
int i;
1399+
bool skip = false;
1400+
const char *unsupported_tests[] = {
1401+
"/retryable_reads/gridfs-downloadByName",
1402+
"/retryable_reads/gridfs-downloadByName-serverErrors",
1403+
"/retryable_reads/listCollectionObjects",
1404+
"/retryable_reads/listCollectionObjects-serverErrors",
1405+
"/retryable_reads/listDatabaseObjects",
1406+
"/retryable_reads/listDatabaseObjects-serverErrors",
1407+
"/retryable_reads/listIndexNames",
1408+
"/retryable_reads/listIndexNames-serverErrors",
1409+
"/retryable_reads/mapReduce"};
1410+
1411+
for (i = 0; i < sizeof (unsupported_tests) / sizeof (unsupported_tests[0]);
1412+
i++) {
1413+
if (0 == strcmp (test_name, unsupported_tests[i])) {
1414+
skip = true;
1415+
break;
1416+
}
1417+
}
1418+
1419+
if (skip) {
1420+
/* Modify the test file to give all entries in "tests" a skipReason */
1421+
bson_t *modified = bson_new ();
1422+
bson_t modified_tests;
1423+
bson_iter_t iter;
1424+
1425+
bson_copy_to_excluding_noinit (original, modified, "tests", NULL);
1426+
BSON_APPEND_ARRAY_BEGIN (modified, "tests", &modified_tests);
1427+
BSON_ASSERT (bson_iter_init_find (&iter, original, "tests"));
1428+
for (bson_iter_recurse (&iter, &iter); bson_iter_next (&iter);) {
1429+
bson_t original_test;
1430+
bson_t modified_test;
1431+
1432+
bson_iter_bson (&iter, &original_test);
1433+
BSON_APPEND_DOCUMENT_BEGIN (
1434+
&modified_tests, bson_iter_key (&iter), &modified_test);
1435+
bson_concat (&modified_test, &original_test);
1436+
BSON_APPEND_UTF8 (&modified_test,
1437+
"skipReason",
1438+
"libmongoc does not support required operation.");
1439+
bson_append_document_end (&modified_tests, &modified_test);
1440+
}
1441+
bson_append_array_end (modified, &modified_tests);
1442+
bson_destroy (original);
1443+
return modified;
1444+
}
1445+
return original;
1446+
}
1447+
13941448
/*
13951449
*-----------------------------------------------------------------------
13961450
*
@@ -1432,6 +1486,7 @@ _install_json_test_suite_with_check (TestSuite *suite,
14321486
BSON_ASSERT (ext);
14331487
ext[0] = '\0';
14341488

1489+
test = _skip_if_unsupported (skip_json, test);
14351490
/* list of "check" functions that decide whether to skip the test */
14361491
va_start (ap, callback);
14371492
_V_TestSuite_AddFull (suite,

0 commit comments

Comments
 (0)