forked from mongodb/mongo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbson_compare_bug.js
39 lines (33 loc) · 2.21 KB
/
bson_compare_bug.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
db.bson_compare_bug.drop();
// We want some BSON objects for this test. One convenient way to get that is to insert them
// into the database and then get them back through a query.
const coll = db.bson_compare_bug;
assert.commandWorked(coll.insert(
[{_id: 1, obj: {val: [], _id: 1}}, {_id: 2, obj: {val: []}}, {_id: 3, obj: {_id: 1, val: []}}],
{writeConcern: {w: "majority"}}));
// The $replaceRoot is so we can get back two results that have an "_id" field and one that
// doesn't. The first two results from this query are the same, except for that.
// res[0]: {val: [], _id: 1}
// res[1]: {val: []}
const res = coll.aggregate([{$sort: {_id: 1}}, {$replaceRoot: {newRoot: "$obj"}}]).toArray();
assert.eq(3, res.length);
// bsonBinaryEqual() should see that the BSON results from the query are not equal.
assert(!bsonBinaryEqual(res[0], res[1]));
// A magic trick: the shell represents the objects in res[0] and res[1] as JavaScript objects
// that internally store raw BSON data but also maintain JavaScript properties for each of their
// BSON fields. The BSON and JavaScript properties are kept in sync both ways. Reading the "val"
// property for the first time results in a call to BSONInfo::resolve(), which materializes the
// "val" BSON field as a JavaScript property. In this case, the resolve function also
// conservatively marks the object as "altered," because "val" is an array, and there's no way
// to observe modifications to it.
assert.eq(res[0].val, res[1].val);
// We repeat the BSON comparison, but this time, the objects are "altered," and bsonBinaryEqual
// needs to sync the JavaScript properties back into BSON. Before SERVER-39521, a bug in the
// conversion would ignore the "_id" field unless it was previously resolved, which would cause
// res[0] and res[1] to appear equal.
assert(!bsonBinaryEqual(res[0], res[1]));
// The bug that caused the "_id" field to get dropped in conversion involves code that is
// supposed to move the "_id" field to the front when converting a JavaScript object to BSON.
// This check ensures that "_id" is still getting moved to the front. The value of res[0] should
// now have changed so that both it and res[2] have their _id field first.
assert(bsonBinaryEqual(res[0], res[2]));