1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #include "mongo/platform/basic.h"
32
33 #include "mongo/db/index/sort_key_generator.h"
34
35 #include "mongo/db/query/collation/collator_interface_mock.h"
36 #include "mongo/stdx/memory.h"
37 #include "mongo/unittest/death_test.h"
38 #include "mongo/unittest/unittest.h"
39
40 namespace mongo {
41 namespace {
42
TEST(SortKeyGeneratorTest,ExtractNumberKeyForNonCompoundSortNonNested)43 TEST(SortKeyGeneratorTest, ExtractNumberKeyForNonCompoundSortNonNested) {
44 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), nullptr);
45 auto sortKey = sortKeyGen->getSortKey(fromjson("{_id: 0, a: 5}"), nullptr);
46 ASSERT_OK(sortKey.getStatus());
47 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 5));
48 }
49
TEST(SortKeyGeneratorTest,ExtractNumberKeyFromDocWithSeveralFields)50 TEST(SortKeyGeneratorTest, ExtractNumberKeyFromDocWithSeveralFields) {
51 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), nullptr);
52 auto sortKey = sortKeyGen->getSortKey(fromjson("{_id: 0, z: 10, a: 6, b: 16}"), nullptr);
53 ASSERT_OK(sortKey.getStatus());
54 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 6));
55 }
56
TEST(SortKeyGeneratorTest,ExtractStringKeyNonCompoundNonNested)57 TEST(SortKeyGeneratorTest, ExtractStringKeyNonCompoundNonNested) {
58 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), nullptr);
59 auto sortKey =
60 sortKeyGen->getSortKey(fromjson("{_id: 0, z: 'thing1', a: 'thing2', b: 16}"), nullptr);
61 ASSERT_OK(sortKey.getStatus());
62 ASSERT_BSONOBJ_EQ(sortKey.getValue(),
63 BSON(""
64 << "thing2"));
65 }
66
TEST(SortKeyGeneratorTest,CompoundSortPattern)67 TEST(SortKeyGeneratorTest, CompoundSortPattern) {
68 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1 << "b" << 1), nullptr);
69 auto sortKey =
70 sortKeyGen->getSortKey(fromjson("{_id: 0, z: 'thing1', a: 99, c: {a: 4}, b: 16}"), nullptr);
71 ASSERT_OK(sortKey.getStatus());
72 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 99 << "" << 16));
73 }
74
TEST(SortKeyGeneratorTest,CompoundSortPatternWithDottedPath)75 TEST(SortKeyGeneratorTest, CompoundSortPatternWithDottedPath) {
76 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("c.a" << 1 << "b" << 1), nullptr);
77 auto sortKey =
78 sortKeyGen->getSortKey(fromjson("{_id: 0, z: 'thing1', a: 99, c: {a: 4}, b: 16}"), nullptr);
79 ASSERT_OK(sortKey.getStatus());
80 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 4 << "" << 16));
81 }
82
TEST(SortKeyGeneratorTest,CompoundPatternLeadingFieldIsArray)83 TEST(SortKeyGeneratorTest, CompoundPatternLeadingFieldIsArray) {
84 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("c" << 1 << "b" << 1), nullptr);
85 auto sortKey = sortKeyGen->getSortKey(
86 fromjson("{_id: 0, z: 'thing1', a: 99, c: [2, 4, 1], b: 16}"), nullptr);
87 ASSERT_OK(sortKey.getStatus());
88 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 1 << "" << 16));
89 }
90
TEST(SortKeyGeneratorTest,ExtractStringSortKeyWithCollatorUsesComparisonKey)91 TEST(SortKeyGeneratorTest, ExtractStringSortKeyWithCollatorUsesComparisonKey) {
92 CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
93 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), &collator);
94 auto sortKey =
95 sortKeyGen->getSortKey(fromjson("{_id: 0, z: 'thing1', a: 'thing2', b: 16}"), nullptr);
96 ASSERT_OK(sortKey.getStatus());
97 ASSERT_BSONOBJ_EQ(sortKey.getValue(),
98 BSON(""
99 << "2gniht"));
100 }
101
TEST(SortKeyGeneratorTest,CollatorHasNoEffectWhenExtractingNonStringSortKey)102 TEST(SortKeyGeneratorTest, CollatorHasNoEffectWhenExtractingNonStringSortKey) {
103 CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
104 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), &collator);
105 auto sortKey = sortKeyGen->getSortKey(fromjson("{_id: 0, z: 10, a: 6, b: 16}"), nullptr);
106 ASSERT_OK(sortKey.getStatus());
107 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 6));
108 }
109
TEST(SortKeyGeneratorTest,SortKeyGenerationForArraysChoosesCorrectKey)110 TEST(SortKeyGeneratorTest, SortKeyGenerationForArraysChoosesCorrectKey) {
111 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << -1), nullptr);
112 auto sortKey = sortKeyGen->getSortKey(fromjson("{_id: 0, a: [1, 2, 3, 4]}"), nullptr);
113 ASSERT_OK(sortKey.getStatus());
114 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 4));
115 }
116
TEST(SortKeyGeneratorTest,EnsureSortKeyGenerationForArraysRespectsCollation)117 TEST(SortKeyGeneratorTest, EnsureSortKeyGenerationForArraysRespectsCollation) {
118 CollatorInterfaceMock collator(CollatorInterfaceMock::MockType::kReverseString);
119 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1), &collator);
120 auto sortKey =
121 sortKeyGen->getSortKey(fromjson("{_id: 0, a: ['aaz', 'zza', 'yya', 'zzb']}"), nullptr);
122 ASSERT_OK(sortKey.getStatus());
123 ASSERT_BSONOBJ_EQ(sortKey.getValue(),
124 BSON(""
125 << "ayy"));
126 }
127
TEST(SortKeyGeneratorTest,SortKeyGenerationForArraysRespectsCompoundOrdering)128 TEST(SortKeyGeneratorTest, SortKeyGenerationForArraysRespectsCompoundOrdering) {
129 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a.b" << 1 << "a.c" << -1), nullptr);
130 auto sortKey = sortKeyGen->getSortKey(
131 fromjson("{_id: 0, a: [{b: 1, c: 0}, {b: 0, c: 3}, {b: 0, c: 1}]}"), nullptr);
132 ASSERT_OK(sortKey.getStatus());
133 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 0 << "" << 3));
134 }
135
TEST(SortKeyGeneratorTest,SortKeyGenerationForMissingField)136 TEST(SortKeyGeneratorTest, SortKeyGenerationForMissingField) {
137 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("b" << 1), nullptr);
138 auto sortKey = sortKeyGen->getSortKey(BSON("a" << 1), nullptr);
139 ASSERT_OK(sortKey.getStatus());
140 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << BSONNULL));
141 }
142
TEST(SortKeyGeneratorTest,SortKeyGenerationForMissingFieldInCompoundSortPattern)143 TEST(SortKeyGeneratorTest, SortKeyGenerationForMissingFieldInCompoundSortPattern) {
144 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << 1 << "b" << 1), nullptr);
145 auto sortKey = sortKeyGen->getSortKey(BSON("b" << 1), nullptr);
146 ASSERT_OK(sortKey.getStatus());
147 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << BSONNULL << "" << 1));
148 }
149
TEST(SortKeyGeneratorTest,SortKeyGenerationForMissingFieldInEmbeddedDocument)150 TEST(SortKeyGeneratorTest, SortKeyGenerationForMissingFieldInEmbeddedDocument) {
151 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a.b" << 1), nullptr);
152 auto sortKey = sortKeyGen->getSortKey(BSON("a" << BSON("c" << 1)), nullptr);
153 ASSERT_OK(sortKey.getStatus());
154 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << BSONNULL));
155 }
156
TEST(SortKeyGeneratorTest,SortKeyGenerationForMissingFieldInArrayElement)157 TEST(SortKeyGeneratorTest, SortKeyGenerationForMissingFieldInArrayElement) {
158 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a.b" << 1), nullptr);
159 auto sortKey = sortKeyGen->getSortKey(BSON("a" << BSON_ARRAY(BSONObj{})), nullptr);
160 ASSERT_OK(sortKey.getStatus());
161 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << BSONNULL));
162 }
163
TEST(SortKeyGeneratorTest,SortKeyGenerationForInvalidPath)164 TEST(SortKeyGeneratorTest, SortKeyGenerationForInvalidPath) {
165 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a.b" << 1), nullptr);
166 auto sortKey = sortKeyGen->getSortKey(BSON("a" << 1), nullptr);
167 ASSERT_OK(sortKey.getStatus());
168 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << BSONNULL));
169 }
170
171 DEATH_TEST(SortKeyGeneratorTest,
172 SortPatternComponentWithStringIsFatal,
173 "Invariant failure elt.type() == BSONType::Object") {
174 stdx::make_unique<SortKeyGenerator>(BSON("a"
175 << "foo"),
176 nullptr);
177 }
178
179 DEATH_TEST(SortKeyGeneratorTest,
180 SortPatternComponentWhoseObjectHasMultipleKeysIsFatal,
181 "Invariant failure elt.embeddedObject().nFields() == 1") {
182 stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
183 << "textScore"
184 << "extra"
185 << 1)),
186 nullptr);
187 }
188
189 DEATH_TEST(SortKeyGeneratorTest,
190 SortPatternComponentWithNonMetaObjectSortIsFatal,
191 "Invariant failure metaElem.fieldNameStringData() == \"$meta\"_sd") {
192 stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$unknown"
193 << "textScore")),
194 nullptr);
195 }
196
197 DEATH_TEST(SortKeyGeneratorTest,
198 SortPatternComponentWithUnknownMetaKeywordIsFatal,
199 "Invariant failure metaElem.valueStringData() == \"randVal\"_sd") {
200 stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
201 << "unknown")),
202 nullptr);
203 }
204
205 DEATH_TEST(SortKeyGeneratorTest,
206 NoMetadataWhenPatternHasMetaTextScoreIsFatal,
207 "Invariant failure metadata") {
208 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
209 << "textScore")),
210 nullptr);
211 uassertStatusOK(sortKeyGen->getSortKey(BSONObj{}, nullptr).getStatus());
212 }
213
214 DEATH_TEST(SortKeyGeneratorTest,
215 NoMetadataWhenPatternHasMetaRandValIsFatal,
216 "Invariant failure metadata") {
217 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
218 << "randVal")),
219 nullptr);
220 uassertStatusOK(sortKeyGen->getSortKey(BSONObj{}, nullptr).getStatus());
221 }
222
TEST(SortKeyGeneratorTest,CanGenerateKeysForTextScoreMetaSort)223 TEST(SortKeyGeneratorTest, CanGenerateKeysForTextScoreMetaSort) {
224 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
225 << "textScore")),
226 nullptr);
227 SortKeyGenerator::Metadata metadata;
228 metadata.textScore = 1.5;
229 auto sortKey = sortKeyGen->getSortKey(BSONObj{}, &metadata);
230 ASSERT_OK(sortKey.getStatus());
231 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 1.5));
232 }
233
TEST(SortKeyGeneratorTest,CanGenerateKeysForRandValMetaSort)234 TEST(SortKeyGeneratorTest, CanGenerateKeysForRandValMetaSort) {
235 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(BSON("a" << BSON("$meta"
236 << "randVal")),
237 nullptr);
238 SortKeyGenerator::Metadata metadata;
239 metadata.randVal = 0.3;
240 auto sortKey = sortKeyGen->getSortKey(BSONObj{}, &metadata);
241 ASSERT_OK(sortKey.getStatus());
242 ASSERT_BSONOBJ_EQ(sortKey.getValue(), BSON("" << 0.3));
243 }
244
TEST(SortKeyGeneratorTest,CanGenerateKeysForCompoundMetaSort)245 TEST(SortKeyGeneratorTest, CanGenerateKeysForCompoundMetaSort) {
246 BSONObj pattern = fromjson(
247 "{a: 1, b: {$meta: 'randVal'}, c: {$meta: 'textScore'}, d: -1, e: {$meta: 'textScore'}}");
248 auto sortKeyGen = stdx::make_unique<SortKeyGenerator>(pattern, nullptr);
249 SortKeyGenerator::Metadata metadata;
250 metadata.randVal = 0.3;
251 metadata.textScore = 1.5;
252 auto sortKey = sortKeyGen->getSortKey(BSON("a" << 4 << "d" << 5), &metadata);
253 ASSERT_OK(sortKey.getStatus());
254 ASSERT_BSONOBJ_EQ(sortKey.getValue(),
255 BSON("" << 4 << "" << 0.3 << "" << 1.5 << "" << 5 << "" << 1.5));
256 }
257
258 } // namespace
259 } // namespace mongo
260