summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorJoel Redman <joel.redman@mongodb.com>2022-09-27 16:19:20 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-27 17:30:37 +0000
commit03d5afb49317b85f322ff8f902e72037467cdbcd (patch)
tree878ca2baa139d9de3592ec331b6c95ba841f3b88 /jstests
parentc2b252ae8d3508aa2bbea016d9ad84f7e1424f2e (diff)
downloadmongo-03d5afb49317b85f322ff8f902e72037467cdbcd.tar.gz
SERVER-66469 Fix correctness when filtering on dates before the epoch
Diffstat (limited to 'jstests')
-rw-r--r--jstests/core/timeseries/timeseries_filter_extended_range.js185
1 files changed, 185 insertions, 0 deletions
diff --git a/jstests/core/timeseries/timeseries_filter_extended_range.js b/jstests/core/timeseries/timeseries_filter_extended_range.js
new file mode 100644
index 00000000000..86dc112dbe0
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_filter_extended_range.js
@@ -0,0 +1,185 @@
+/**
+ * Test that find/match type queries work properly on dates ouside the 32 bit epoch range,
+ * [1970-01-01 00:00:00 UTC - 2038-01-29 03:13:07 UTC].
+ *
+ * @tags: [
+ * requires_fcv_62,
+ * # We need a timeseries collection.
+ * requires_timeseries,
+ * ]
+ */
+
+(function() {
+"use strict";
+const timeFieldName = "time";
+
+/*
+ * Creates a collection, populates it, runs the `query` and ensures that the result set
+ * is equal to `results`.
+ *
+ * If overflow is set we create a document with dates above the 32 bit range (year 2040)
+ * If underflow is set, we create a document with dates below the 32 bit range (year 1965)
+ */
+function runTest(underflow, overflow, query, results) {
+ // Setup our DB & our collections.
+ const tsColl = db.getCollection(jsTestName());
+ tsColl.drop();
+
+ assert.commandWorked(
+ db.createCollection(tsColl.getName(), {timeseries: {timeField: timeFieldName}}));
+
+ const dates = [
+ // If underflow, we want to insert a date that would fall below the epoch
+ // i.e. 1970-01-01 00:00:00 UTC. Otherwise we use a date within the epoch.
+ {[timeFieldName]: underflow ? new Date("1965-01-01") : new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ // If overflow, we want to insert a date that would use more than 32 bit milliseconds after
+ // the epoch. This overflow will occur 2038-01-29 03:13:07 UTC. Otherwise we go slightly
+ // before the end of the 32 bit epoch.
+ {[timeFieldName]: overflow ? new Date("2040-01-01") : new Date("2030-01-01")}
+ ];
+ assert.commandWorked(tsColl.insert(dates));
+
+ // Make sure the expected results are in the correct order for comparison below.
+ function cmpTimeFields(a, b) {
+ return (b[timeFieldName].getTime() - a[timeFieldName].getTime());
+ }
+ results.sort(cmpTimeFields);
+
+ const pipeline = [{$match: query}, {$project: {_id: 0, [timeFieldName]: 1}}];
+
+ // Verify agg pipeline. We don't want to go through a plan that encourages a sort order to
+ // avoid BUS and index selection, so we sort after gathering the results.
+ const aggActuals = tsColl.aggregate(pipeline).toArray();
+ aggActuals.sort(cmpTimeFields);
+ assert.docEq(aggActuals, results);
+
+ // Verify the equivalent find command. We again don't want to go through a plan that
+ // encourages a sort order to avoid BUS and index selection, so we sort after gathering the
+ // results.
+ let findActuals = tsColl.find(query, {_id: 0, [timeFieldName]: 1}).toArray();
+ findActuals.sort(cmpTimeFields);
+ assert.docEq(findActuals, results);
+}
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$eq: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1980-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$eq: new Date("2040-01-01")}},
+ [{[timeFieldName]: new Date("2040-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$eq: new Date("1965-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}]);
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+runTest(true,
+ true,
+ {[timeFieldName]: {$lt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
+
+runTest(false,
+ false,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
+runTest(false,
+ true,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
+runTest(true,
+ false,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
+runTest(true,
+ true,
+ {[timeFieldName]: {$gt: new Date("1980-01-01")}},
+ [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
+
+runTest(false, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(false, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1971-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(true, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+runTest(true, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ {[timeFieldName]: new Date("1980-01-01")}
+]);
+
+runTest(false, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2030-01-01")}
+]);
+runTest(false, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")}
+]);
+runTest(true, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2030-01-01")}
+]);
+runTest(true, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1980-01-01")},
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")}
+]);
+
+// Verify ranges that straddle the lower epoch work properly
+runTest(
+ true, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
+ {[timeFieldName]: new Date("1965-01-01")},
+ {[timeFieldName]: new Date("1975-01-01")},
+ ]);
+
+runTest(
+ false, true, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}}, [
+ {[timeFieldName]: new Date("1995-01-01")},
+ {[timeFieldName]: new Date("2040-01-01")},
+ ]);
+
+// TODO: SERVER-69952 Literals outside the epoch are currently compared to _id, generally,
+// so we cannot match against them. This will have to be fixed in a similar manner by determining
+// whether the compared dates can be outside the epoch range and not relying on _id in that case.
+//
+// The following scenarios fail:
+// runTest(
+// false, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
+// {[timeFieldName]: new Date("1971-01-01")},
+// {[timeFieldName]: new Date("1975-01-01")},
+// ]);
+// runTest(
+// false, false, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}},
+// [
+// {[timeFieldName]: new Date("1995-01-01")},
+// {[timeFieldName]: new Date("2030-01-01")},
+// ]);
+})(); \ No newline at end of file