forked from mongodb/mongo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommon_utils.js
137 lines (124 loc) · 6.13 KB
/
common_utils.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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/**
* Utility functions that are common for both mocked and e2e search tests.
*/
/**
* Checks that the explain object for a sharded search query contains the correct "protocolVersion".
* Checks 'metaPipeline' and 'sortSpec' if it's provided.
* * @param {Object} result the results from running coll.explain().aggregate([[$search: ....],
* ...])
* @param {string} searchType ex. "$search", "$searchMeta"
* @param {Object} metaPipeline
* @param {NumberInt()} protocolVersion To check the value of the protocolVersion, the value
* returned from explain will be wrapped with NumberInt(). The default value to check is 1 since
* mongot currently always returns 1 for its protocolVersion.
* @param {Object} sortSpec
*/
export function verifyShardsPartExplainOutput({
result,
searchType,
metaPipeline = null,
protocolVersion = NumberInt(1),
sortSpec = null,
}) {
// Checks index 0 of 'shardsPart' since $search, $searchMeta need to come first in the pipeline
assert(result.splitPipeline.shardsPart[0][searchType].hasOwnProperty(
"metadataMergeProtocolVersion"));
assert(result.splitPipeline.shardsPart[0][searchType].hasOwnProperty("mergingPipeline"));
assert.eq(
NumberInt(result.splitPipeline.shardsPart[0][searchType].metadataMergeProtocolVersion),
protocolVersion);
if (metaPipeline) {
assert.eq(result.splitPipeline.shardsPart[0][searchType].mergingPipeline, metaPipeline);
}
if (sortSpec) {
assert(result.splitPipeline.shardsPart[0][searchType].hasOwnProperty("sortSpec"));
assert.eq(result.splitPipeline.shardsPart[0][searchType].sortSpec, sortSpec);
}
}
/**
* Helper to create an explain object that getAggPlanStages() can be used on.
*
* @param {Object} unionSubExplain The explain output for the $unionWith sub pipeline. Given an
* unionWithStage, accessed with unionWithStage.$unionWith.pipeline.
*
* @returns explain object that getAggPlanStages() can be called to retrieve stages.
*/
export function prepareUnionWithExplain(unionSubExplain) {
if (unionSubExplain.hasOwnProperty("stages") || unionSubExplain.hasOwnProperty("shards") ||
unionSubExplain.hasOwnProperty("queryPlanner")) {
return unionSubExplain;
}
// In the case that the pipeline doesn't have "stages", "shards", or "queryPlanner", the explain
// output is an array of stages. We return {stages: []} to replicate what a normal explain does.
assert(
Array.isArray(unionSubExplain),
"We expect the input is an array here. If this is not an array, this function needs to be " +
"updated in order to replicate a non-unionWith explain object. " +
tojson(unionSubExplain));
// The first stage of the explain array should be a initial mongot stage.
assert(Object.keys(unionSubExplain[0]).includes("$_internalSearchMongotRemote") ||
Object.keys(unionSubExplain[0]).includes("$searchMeta") ||
Object.keys(unionSubExplain[0]).includes("$vectorSearch"),
"The first stage of the array should be a mongot stage.");
return {stages: unionSubExplain};
}
const mongotStages =
["$_internalSearchMongotRemote", "$searchMeta", "$_internalSearchIdLookup", "$vectorSearch"];
/**
* Validates that the mongot stage from the explain output includes the required execution metrics.
*
* @param {Object} stage The object representing a mongot stage ($_internalSearchMongotRemote,
* $searchMeta, $_internalSearchIdLookup) from explain output.
* @param {string} stageType ex. "$_internalSearchMongotRemote" , "$searchMeta",
* "$_internalSearchIdLookup", "$vectorSearch"
* @param {string} verbosity The verbosity of explain. "nReturned" and "executionTimeMillisEstimate"
* will not be checked for 'queryPlanner' verbosity "
* @param {NumberLong} nReturned The number of documents that should be returned in the
* mongot stage. Optional for "queryPlanner" verbosity.
* @param {Object} explain The explain object that the stage should contain.
* @param {Boolean} isE2E True if this function is being called for an e2e test. Since an e2e test
* uses an actual mongot, we don't know the value of the explain object and cannot check it.
* @param {NumberLong} numFiltered optional, The number of documents filtered out by the idLookup
* stage.
*/
export function validateMongotStageExplainExecutionStats({
stage,
stageType,
verbosity,
nReturned = null,
explain = null,
isE2E = false,
numFiltered = null
}) {
assert(mongotStages.includes(stageType),
"stageType must be a mongot stage found in mongotStages.");
assert(stage[stageType],
"Given stage isn't the expected stage. " + stageType + " is not found.");
const isIdLookup = stageType === "$_internalSearchIdLookup";
if (verbosity != "queryPlanner") {
assert(stage.hasOwnProperty("nReturned"));
assert.eq(nReturned, stage["nReturned"]);
assert(stage.hasOwnProperty("executionTimeMillisEstimate"));
if (isIdLookup) {
const idLookupStage = stage["$_internalSearchIdLookup"];
assert(idLookupStage.hasOwnProperty("totalDocsExamined"), idLookupStage);
assert.eq(idLookupStage["totalDocsExamined"], nReturned, idLookupStage);
assert(idLookupStage.hasOwnProperty("totalKeysExamined"), idLookupStage);
assert.eq(idLookupStage["totalKeysExamined"], nReturned, idLookupStage);
}
}
// Non $_internalSearchIdLookup mongot stages must contain an explain object.
if (!isIdLookup) {
const explainStage = stage[stageType];
assert(explainStage.hasOwnProperty("explain"), explainStage);
// We don't know the actual value of the explain object for e2e tests and can't check it.
if (!isE2E) {
assert(explain, "Explain is null but needs to be provided for initial mongot stage.");
assert.eq(explain, explainStage["explain"]);
if (numFiltered) {
assert(explainStage.hasOwnProperty("numDocsFilteredByIdLookup"), explainStage);
assert.eq(explainStage["numDocsFilteredByIdLookup"], numFiltered);
}
}
}
}