diff options
| author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
|---|---|---|
| committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2025-02-14 14:26:38 -0300 |
| commit | 294bc6ecabf14c09c9bc8644704921dcf97cb44e (patch) | |
| tree | 279b1e0bab53901a1647ac63c1c724f0f789a663 /src/mongo/db/exec/document_value/document_value_test.cpp | |
| parent | 70be7c27a251621187a1de533462ae2bb1e3bd39 (diff) | |
| parent | 1e917fd798aa25b7066d4b414b51184f13d5a092 (diff) | |
Update upstream source from tag 'upstream/6.0.10'debian/6.0.10-1
Update to upstream version '6.0.10'
with Debian dir 2d176fa254eee97b139f712fec5709641335a8c3
Diffstat (limited to 'src/mongo/db/exec/document_value/document_value_test.cpp')
| -rw-r--r-- | src/mongo/db/exec/document_value/document_value_test.cpp | 193 |
1 files changed, 190 insertions, 3 deletions
diff --git a/src/mongo/db/exec/document_value/document_value_test.cpp b/src/mongo/db/exec/document_value/document_value_test.cpp index 421da707001..ecc550f6ee0 100644 --- a/src/mongo/db/exec/document_value/document_value_test.cpp +++ b/src/mongo/db/exec/document_value/document_value_test.cpp @@ -46,6 +46,16 @@ #include "mongo/dbtests/dbtests.h" #include "mongo/logv2/log.h" +#define ASSERT_DOES_NOT_THROW(EXPRESSION) \ + try { \ + EXPRESSION; \ + } catch (const AssertionException& e) { \ + ::mongo::str::stream err; \ + err << "Threw an exception incorrectly: " << e.toString() \ + << " Exception occured in: " << #EXPRESSION; \ + ::mongo::unittest::TestAssertionFailure(__FILE__, __LINE__, err).stream(); \ + } + namespace DocumentTests { using std::numeric_limits; @@ -355,6 +365,46 @@ TEST(DocumentGetFieldNonCaching, TraverseArray) { checkArrayTagIsReturned(); } +TEST(DocumentSize, ApproximateSizeIsSnapshotted) { + const auto rawBson = BSON("field" + << "value"); + const Document document{rawBson}; + const auto noCacheSize = document.getApproximateSize(); + + // Force the cache construction, making the total size of the 'Document' bigger. + // 'getApproximateSize()' must still return the same value. + document.fillCache(); + const auto fullCacheSizeSnapshot = document.getApproximateSize(); + const auto fullCacheSizeCurrent = document.getCurrentApproximateSize(); + ASSERT_EQ(noCacheSize, fullCacheSizeSnapshot); + ASSERT_LT(noCacheSize, fullCacheSizeCurrent); +} + +TEST(DocumentSize, ApproximateSizeDuringBuildIsUpdated) { + MutableDocument builder; + builder.addField("a1", Value(1)); + builder.addField("a2", mongo::Value(2)); + builder.addField("a3", mongo::Value(3)); + auto middleBuildSize = builder.getApproximateSize(); + + builder.addField("a4", Value(4)); + builder.addField("a5", mongo::Value(5)); + builder.addField("a6", mongo::Value(6)); + auto peekSize = builder.peek().getApproximateSize(); + + builder.addField("a7", Value(7)); + builder.addField("a8", mongo::Value(8)); + builder.addField("a9", mongo::Value(9)); + auto beforeFreezeSize = builder.getApproximateSize(); + + Document result = builder.freeze(); + auto frozenSize = result.getApproximateSize(); + + ASSERT_LT(middleBuildSize, peekSize); + ASSERT_LT(peekSize, beforeFreezeSize); + ASSERT_EQ(beforeFreezeSize, frozenSize); +} + /** Add Document fields. */ class AddField { public: @@ -705,6 +755,22 @@ public: BSONObjBuilder objBuilder; BSONArrayBuilder arrBuilder; }; + +TEST(DocumentTest, ToBsonSizeTraits) { + constexpr size_t longStringLength = 9 * 1024 * 1024; + static_assert(longStringLength <= BSONObjMaxInternalSize && + 2 * longStringLength > BSONObjMaxInternalSize && + 2 * longStringLength <= BufferMaxSize); + std::string longString(longStringLength, 'A'); + MutableDocument md; + md.addField("a", Value(longString)); + ASSERT_DOES_NOT_THROW(md.peek().toBson()); + md.addField("b", Value(longString)); + ASSERT_THROWS_CODE(md.peek().toBson(), DBException, ErrorCodes::BSONObjectTooLarge); + ASSERT_THROWS_CODE( + md.peek().toBson<BSONObj::DefaultSizeTrait>(), DBException, ErrorCodes::BSONObjectTooLarge); + ASSERT_DOES_NOT_THROW(md.peek().toBson<BSONObj::LargeSizeTrait>()); +} } // namespace Document namespace MetaFields { @@ -840,7 +906,8 @@ TEST(MetaFields, CopyMetadataFromCopiesAllMetadata) { << "foo" << "h" << 1 << "$indexKey" << BSON("y" << 1) << "$searchScoreDetails" << BSON("scoreDetails" - << "foo"))); + << "foo") + << "$searchSortValues" << BSON("a" << 1) << "$vectorSearchScore" << 6.7)); MutableDocument destination{}; destination.copyMetaDataFrom(source); @@ -857,6 +924,8 @@ TEST(MetaFields, CopyMetadataFromCopiesAllMetadata) { ASSERT_BSONOBJ_EQ(result.metadata().getSearchScoreDetails(), BSON("scoreDetails" << "foo")); + ASSERT_BSONOBJ_EQ(result.metadata().getSearchSortValues(), BSON("a" << 1)); + ASSERT_EQ(result.metadata().getVectorSearchScore(), 6.7); } class SerializationTest : public unittest::Test { @@ -877,6 +946,8 @@ protected: ASSERT_EQ(output.metadata().hasSearchScore(), input.metadata().hasSearchScore()); ASSERT_EQ(output.metadata().hasSearchHighlights(), input.metadata().hasSearchHighlights()); ASSERT_EQ(output.metadata().hasIndexKey(), input.metadata().hasIndexKey()); + ASSERT_EQ(output.metadata().hasVectorSearchScore(), + input.metadata().hasVectorSearchScore()); if (input.metadata().hasTextScore()) { ASSERT_EQ(output.metadata().getTextScore(), input.metadata().getTextScore()); } @@ -897,6 +968,10 @@ protected: ASSERT_BSONOBJ_EQ(output.metadata().getSearchScoreDetails(), input.metadata().getSearchScoreDetails()); } + if (input.metadata().hasVectorSearchScore()) { + ASSERT_EQ(output.metadata().getVectorSearchScore(), + input.metadata().getVectorSearchScore()); + } ASSERT(output.toBson().binaryEqual(input.toBson())); } @@ -911,6 +986,7 @@ TEST_F(SerializationTest, MetaSerializationNoVals) { << "def"_sd)); docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails" << "foo")); + docBuilder.metadata().setVectorSearchScore(40.0); assertRoundTrips(docBuilder.freeze()); } @@ -925,6 +1001,7 @@ TEST_F(SerializationTest, MetaSerializationWithVals) { docBuilder.metadata().setIndexKey(BSON("key" << 42)); docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails" << "foo")); + docBuilder.metadata().setVectorSearchScore(40.0); assertRoundTrips(docBuilder.freeze()); } @@ -947,6 +1024,8 @@ TEST(MetaFields, ToAndFromBson) { << "def"_sd)); docBuilder.metadata().setSearchScoreDetails(BSON("scoreDetails" << "foo")); + docBuilder.metadata().setSearchSortValues(BSON("a" << 42)); + docBuilder.metadata().setVectorSearchScore(40.0); Document doc = docBuilder.freeze(); BSONObj obj = doc.toBsonWithMetaData(); ASSERT_EQ(10.0, obj[Document::metaFieldTextScore].Double()); @@ -958,6 +1037,8 @@ TEST(MetaFields, ToAndFromBson) { ASSERT_BSONOBJ_EQ(obj[Document::metaFieldSearchScoreDetails].Obj(), BSON("scoreDetails" << "foo")); + ASSERT_BSONOBJ_EQ(BSON("a" << 42), obj[Document::metaFieldSearchSortValues].Obj()); + ASSERT_EQ(40.0, obj[Document::metaFieldVectorSearchScore].Double()); Document fromBson = Document::fromBsonWithMetaData(obj); ASSERT_TRUE(fromBson.metadata().hasTextScore()); ASSERT_TRUE(fromBson.metadata().hasRandVal()); @@ -966,6 +1047,110 @@ TEST(MetaFields, ToAndFromBson) { ASSERT_BSONOBJ_EQ(BSON("scoreDetails" << "foo"), fromBson.metadata().getSearchScoreDetails()); + ASSERT_BSONOBJ_EQ(BSON("a" << 42), fromBson.metadata().getSearchSortValues()); + ASSERT_EQ(40.0, fromBson.metadata().getVectorSearchScore()); +} + +TEST(MetaFields, ToAndFromBsonTrivialConvertibility) { + Value sortKey{Document{{"token"_sd, "SOMENCODEDATA"_sd}}}; + // Create a document with a backing BSONObj and separate metadata. + auto origObjNoMetadata = BSON("a" << 42); + ASSERT_FALSE(origObjNoMetadata.hasField(Document::metaFieldSortKey)); + + MutableDocument docBuilder; + docBuilder.reset(origObjNoMetadata, false); + docBuilder.metadata().setSortKey(sortKey, true); + Document docWithSeparateBsonAndMetadata = docBuilder.freeze(); + + BSONObj origObjWithMetadata = docWithSeparateBsonAndMetadata.toBsonWithMetaData(); + ASSERT_TRUE(origObjWithMetadata.hasField(Document::metaFieldSortKey)); + Document restoredDocWithMetadata = Document::fromBsonWithMetaData(origObjWithMetadata); + ASSERT_DOCUMENT_EQ(docWithSeparateBsonAndMetadata, restoredDocWithMetadata); + + // Test the 'isTriviallyConvertible()' function. + // The original document is trivially convertible without metadata because the metadata was + // added to the document separately from the backing BSON object. + ASSERT_TRUE(docWithSeparateBsonAndMetadata.isTriviallyConvertible()); + // The original document is NOT trivially convertible with metadata because the metadata was + // added to the document and does not exist in the BSONObj. + ASSERT_FALSE(docWithSeparateBsonAndMetadata.isTriviallyConvertibleWithMetadata()); + // The restored document is trivially convertible with metadata because the underlying BSONObj + // contains the metadata serialized from the original document. + ASSERT_TRUE(restoredDocWithMetadata.isTriviallyConvertibleWithMetadata()); + // The restored document is NOT trivially convertible without metadata because the metadata + // fields need to be stripped from the underlying BSONObj. + ASSERT_FALSE(restoredDocWithMetadata.isTriviallyConvertible()); + + // Test that the conversion with metadata 'origObjWithMetadata' -> 'restoredDocWithMetadata' -> + // 'restoredObjWithMetadata' is trivial because the backing BSON already contains metadata and + // neither the metadata nor the non-metadata fields have been modified. + BSONObj restoredObjWithMetadata = restoredDocWithMetadata.toBsonWithMetaData(); + ASSERT_TRUE(restoredObjWithMetadata.hasField(Document::metaFieldSortKey)); + // Test that 'restoredObjWithMetadata' is referring to the exact same memory location as + // 'origObjWithMetadata', i.e. both objdata() and objsize() match. + ASSERT_EQ(origObjWithMetadata.objdata(), restoredObjWithMetadata.objdata()); + ASSERT_EQ(origObjWithMetadata.objsize(), restoredObjWithMetadata.objsize()); + + // Test that the conversion without metadata 'origObjWithMetadata' -> 'restoredDocWithMetadata' + // -> 'strippedRestoredObj' is NOT trivial because the backing BSON has metadata that must be + // omitted during serialization. + BSONObj strippedRestoredObj = restoredDocWithMetadata.toBson(); + ASSERT_FALSE(strippedRestoredObj.hasField(Document::metaFieldSortKey)); + // 'restoredDocWithMetadata' is trivially convertible with metadata and converting it to BSON + // without metadata will return a new BSON object. + ASSERT_TRUE(origObjNoMetadata.binaryEqual(strippedRestoredObj)); + ASSERT_NE(origObjNoMetadata.objdata(), strippedRestoredObj.objdata()); + + // Test that the conversion without metadata 'origObjNoMetadata' -> + // 'docWithSeparateBsonAndMetadata' -> 'restoredObjNoMetadata' is trivial because + // 'origObjNoMetadata' does not contain any metadata. + BSONObj restoredObjNoMetadata = docWithSeparateBsonAndMetadata.toBson(); + ASSERT_FALSE(restoredObjNoMetadata.hasField(Document::metaFieldSortKey)); + // Test that 'restoredObjNoMetadata' is referring to the exact same memory location as + // 'origObjNoMetadata', i.e. both objdata() and objsize() match. + ASSERT_EQ(origObjNoMetadata.objdata(), restoredObjNoMetadata.objdata()); + ASSERT_EQ(origObjNoMetadata.objsize(), restoredObjNoMetadata.objsize()); +} + +TEST(MetaFields, TrivialConvertibilityBsonWithoutMetadata) { + // Test that an unmodified document without metadata is trivially convertible to BSON with and + // without metadata. + auto bsonWithoutMetadata = BSON("a" << 42); + Document doc(bsonWithoutMetadata); + ASSERT_TRUE(doc.isTriviallyConvertible()); + ASSERT_TRUE(doc.isTriviallyConvertibleWithMetadata()); +} + +TEST(MetaFields, TrivialConvertibilityNoBson) { + // A Document created with no backing BSON is not trivially convertible. + auto docNoBson = Document{{"a", 42}}; + ASSERT_FALSE(docNoBson.isTriviallyConvertible()); + ASSERT_FALSE(docNoBson.isTriviallyConvertibleWithMetadata()); + + // An empty Document is trivially convertible, since the default BSONObj is also empty. + auto emptyDoc = Document{}; + ASSERT_TRUE(emptyDoc.isTriviallyConvertible()); + ASSERT_TRUE(emptyDoc.isTriviallyConvertibleWithMetadata()); +} + +TEST(MetaFields, TrivialConvertibilityModified) { + // Modifying a document with a backing BSON renders it not trivially convertible. + MutableDocument mutDocModified(Document(BSON("a" << 42))); + mutDocModified.addField("b", Value(43)); + auto modifiedDoc = mutDocModified.freeze(); + ASSERT_FALSE(modifiedDoc.isTriviallyConvertible()); + ASSERT_FALSE(modifiedDoc.isTriviallyConvertibleWithMetadata()); +} + +TEST(MetaFields, TrivialConvertibilityMetadataModified) { + // Modifying the metadata of a document with a backing BSON renders it not trivially convertible + // with metadata. + MutableDocument mutDocModifiedMd( + Document::fromBsonWithMetaData(BSON(Document::metaFieldTextScore << 10.0))); + mutDocModifiedMd.metadata().setRandVal(20.0); + auto modifiedMdDoc = mutDocModifiedMd.freeze(); + ASSERT_FALSE(modifiedMdDoc.isTriviallyConvertible()); + ASSERT_FALSE(modifiedMdDoc.isTriviallyConvertibleWithMetadata()); } TEST(MetaFields, MetaFieldsIncludedInDocumentApproximateSize) { @@ -983,8 +1168,10 @@ TEST(MetaFields, MetaFieldsIncludedInDocumentApproximateSize) { const size_t bigMetadataDocSize = doc2.getApproximateSize(); ASSERT_GT(bigMetadataDocSize, smallMetadataDocSize); - // Do a sanity check on the amount of space taken by metadata in document 2. - ASSERT_LT(doc2.getMetadataApproximateSize(), 300U); + // Do a sanity check on the amount of space taken by metadata in document 2. Note that the size + // of certain data types may vary on different build variants, so we cannot assert on the exact + // size. + ASSERT_LT(doc2.getMetadataApproximateSize(), 400U); Document emptyDoc; ASSERT_LT(emptyDoc.getMetadataApproximateSize(), 100U); |
