@@ -1301,7 +1301,7 @@ test_oversize (void)
13011301 ASSERT_ERROR_CONTAINS (error ,
13021302 MONGOC_ERROR_GRIDFS ,
13031303 MONGOC_ERROR_GRIDFS_CORRUPT ,
1304- "corrupt chunk number 0: bad size" );
1304+ "corrupt chunk number 0: greater than chunk size" );
13051305
13061306 mongoc_gridfs_file_destroy (file );
13071307 ASSERT_OR_PRINT (mongoc_gridfs_drop (gridfs , & error ), error );
@@ -1584,6 +1584,156 @@ test_write_failure (void)
15841584 mock_server_destroy (server );
15851585}
15861586
1587+ static void
1588+ test_reading_multiple_chunks (void )
1589+ {
1590+ mongoc_client_t * client = test_framework_new_default_client ();
1591+ bson_error_t error ;
1592+
1593+ // Test reading a file spanning two chunks.
1594+ {
1595+ mongoc_gridfs_t * gridfs = mongoc_client_get_gridfs (
1596+ client , "test_reading_multiple_chunks" , NULL , & error );
1597+
1598+ ASSERT_OR_PRINT (gridfs , error );
1599+ // Drop prior test data.
1600+ ASSERT_OR_PRINT (mongoc_gridfs_drop (gridfs , & error ), error );
1601+
1602+ // Write a file spanning two chunks.
1603+ {
1604+ mongoc_gridfs_file_opt_t opts = {.chunk_size = 4 ,
1605+ .filename = "test_file" };
1606+ mongoc_iovec_t iov = {.iov_base = (void * ) "foobar" , .iov_len = 7 };
1607+ mongoc_gridfs_file_t * file = mongoc_gridfs_create_file (gridfs , & opts );
1608+ // First chunk is 4 bytes: "foob", second chunk is 3 bytes: "ar\0"
1609+ ASSERT_CMPSSIZE_T (
1610+ mongoc_gridfs_file_writev (file , & iov , 1 , 0 ), = = , 7 );
1611+ BSON_ASSERT (mongoc_gridfs_file_save (file ));
1612+ mongoc_gridfs_file_destroy (file );
1613+ }
1614+
1615+ // Read the entire file.
1616+ {
1617+ bson_string_t * str = bson_string_new ("" );
1618+ uint8_t buf [7 ] = {0 };
1619+ mongoc_iovec_t iov = {.iov_base = (void * ) buf ,
1620+ .iov_len = sizeof (buf )};
1621+ mongoc_gridfs_file_t * file =
1622+ mongoc_gridfs_find_one_by_filename (gridfs , "test_file" , & error );
1623+ ASSERT_OR_PRINT (file , error );
1624+
1625+ // First read gets first chunk.
1626+ {
1627+ ssize_t got = mongoc_gridfs_file_readv (file ,
1628+ & iov ,
1629+ 1 /* iovcnt */ ,
1630+ 1 /* min_bytes */ ,
1631+ 0 /* timeout_msec */ );
1632+ ASSERT_CMPSSIZE_T (got , >=, 0 );
1633+ ASSERT (bson_in_range_int_signed (got ));
1634+ bson_string_append_printf (str , "%.*s" , (int ) got , (char * ) buf );
1635+ ASSERT_CMPSSIZE_T (got , = = , 4 );
1636+ }
1637+
1638+ // Second read gets second chunk.
1639+ {
1640+ ssize_t got = mongoc_gridfs_file_readv (file ,
1641+ & iov ,
1642+ 1 /* iovcnt */ ,
1643+ 1 /* min_bytes */ ,
1644+ 0 /* timeout_msec */ );
1645+ ASSERT_CMPSSIZE_T (got , >=, 0 );
1646+ ASSERT (bson_in_range_int_signed (got ));
1647+ bson_string_append_printf (str , "%.*s" , (int ) got , (char * ) buf );
1648+ ASSERT_CMPSSIZE_T (got , = = , 3 );
1649+ }
1650+
1651+ ASSERT_CMPSTR (str -> str , "foobar" );
1652+ bson_string_free (str , true);
1653+ mongoc_gridfs_file_destroy (file );
1654+ }
1655+
1656+ mongoc_gridfs_destroy (gridfs );
1657+ }
1658+
1659+ // Test an error occurs if reading an incomplete chunk. This is a regression
1660+ // test for CDRIVER-5506.
1661+ {
1662+ mongoc_gridfs_t * gridfs = mongoc_client_get_gridfs (
1663+ client , "test_reading_multiple_chunks" , NULL , & error );
1664+
1665+ ASSERT_OR_PRINT (gridfs , error );
1666+ // Drop prior test data.
1667+ ASSERT_OR_PRINT (mongoc_gridfs_drop (gridfs , & error ), error );
1668+
1669+ // Write a file spanning two chunks.
1670+ {
1671+ mongoc_gridfs_file_opt_t opts = {.chunk_size = 4 ,
1672+ .filename = "test_file" };
1673+ mongoc_iovec_t iov = {.iov_base = (void * ) "foobar" , .iov_len = 7 };
1674+ mongoc_gridfs_file_t * file = mongoc_gridfs_create_file (gridfs , & opts );
1675+ // First chunk is 4 bytes: "foob", second chunk is 3 bytes: "ar\0"
1676+ ASSERT_CMPSSIZE_T (
1677+ mongoc_gridfs_file_writev (file , & iov , 1 , 0 ), = = , 7 );
1678+ BSON_ASSERT (mongoc_gridfs_file_save (file ));
1679+ mongoc_gridfs_file_destroy (file );
1680+ }
1681+
1682+ // Manually remove data from the first chunk.
1683+ {
1684+ mongoc_collection_t * coll = mongoc_client_get_collection (
1685+ client , "test_reading_multiple_chunks" , "fs.chunks" );
1686+ bson_t reply ;
1687+ // Change the data of the first chunk from "foob" to "foo".
1688+ bool ok = mongoc_collection_update_one (
1689+ coll ,
1690+ tmp_bson (BSON_STR ({"n" : 0 })),
1691+ tmp_bson (BSON_STR ({
1692+ "$set" :
1693+ {"data" : {"$binary" : {"base64" : "Zm9v ", " subType " : " 0 "}}}
1694+ })),
1695+ NULL /* opts */ ,
1696+ & reply ,
1697+ & error );
1698+ ASSERT_OR_PRINT (ok , error );
1699+ ASSERT_MATCH (& reply , BSON_STR ({"modifiedCount" : 1 }));
1700+ mongoc_collection_destroy (coll );
1701+ }
1702+
1703+ // Attempt to read the entire file.
1704+ {
1705+ uint8_t buf [7 ] = {0 };
1706+ mongoc_iovec_t iov = {.iov_base = (void * ) buf ,
1707+ .iov_len = sizeof (buf )};
1708+ mongoc_gridfs_file_t * file =
1709+ mongoc_gridfs_find_one_by_filename (gridfs , "test_file" , & error );
1710+ ASSERT_OR_PRINT (file , error );
1711+
1712+ // First read gets an error.
1713+ {
1714+ ssize_t got = mongoc_gridfs_file_readv (file ,
1715+ & iov ,
1716+ 1 /* iovcnt */ ,
1717+ 1 /* min_bytes */ ,
1718+ 0 /* timeout_msec */ );
1719+ ASSERT_CMPSSIZE_T (got , = = , -1 );
1720+ ASSERT (mongoc_gridfs_file_error (file , & error ));
1721+ ASSERT_ERROR_CONTAINS (
1722+ error ,
1723+ MONGOC_ERROR_GRIDFS ,
1724+ MONGOC_ERROR_GRIDFS_CORRUPT ,
1725+ "corrupt chunk number 0: not equal to chunk size: 4" );
1726+ }
1727+
1728+ mongoc_gridfs_file_destroy (file );
1729+ }
1730+
1731+ mongoc_gridfs_destroy (gridfs );
1732+ }
1733+
1734+ mongoc_client_destroy (client );
1735+ }
1736+
15871737
15881738void
15891739test_gridfs_install (TestSuite * suite )
@@ -1628,4 +1778,7 @@ test_gridfs_install (TestSuite *suite)
16281778 suite , "/gridfs_old/inherit_client_config" , test_inherit_client_config );
16291779 TestSuite_AddMockServerTest (
16301780 suite , "/gridfs_old/write_failure" , test_write_failure );
1781+ TestSuite_AddLive (suite ,
1782+ "/gridfs_old/reading_multiple_chunks" ,
1783+ test_reading_multiple_chunks );
16311784}
0 commit comments