summaryrefslogtreecommitdiff
path: root/jstests/core/timeseries/timeseries_collmod.js
blob: 18ae48a421f27d22f92b26460ba2382198e237f6 (plain)
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/**
 * This tests which collMod options are allowed on a time-series collection.
 *
 * @tags: [
 *   # Behavior clarified in binVersion 6.1
 *   requires_fcv_61,
 *   # collMod is not retryable
 *   requires_non_retryable_commands,
 *   # We need a timeseries collection.
 *   requires_timeseries,
 * ]
 */

(function() {
'use strict';

load("jstests/core/timeseries/libs/timeseries.js");

const collName = "timeseries_collmod";
const coll = db.getCollection(collName);
const bucketMaxSpanSecondsHours = 60 * 60 * 24 * 30;
const bucketRoundingSecondsHours = 60 * 60 * 24;
const bucketingValueMax = 86400 * 365;  // Seconds in a year.
const idlInvalidValueError = 51024;

coll.drop();
assert.commandWorked(
    db.createCollection(collName, {timeseries: {timeField: "time", granularity: 'seconds'}}));
assert.commandWorked(coll.createIndex({"time": 1}));

// Tries to convert a time-series secondary index to TTL index.
assert.commandFailedWithCode(
    db.runCommand(
        {"collMod": collName, "index": {"keyPattern": {"time": 1}, "expireAfterSeconds": 100}}),
    ErrorCodes.InvalidOptions);

// Successfully hides a time-series secondary index.
assert.commandWorked(
    db.runCommand({"collMod": collName, "index": {"keyPattern": {"time": 1}, "hidden": true}}));

// Tries to set the validator for a time-series collection.
assert.commandFailedWithCode(
    db.runCommand({"collMod": collName, "validator": {required: ["time"]}}),
    ErrorCodes.InvalidOptions);

// Tries to set the validationLevel for a time-series collection.
assert.commandFailedWithCode(db.runCommand({"collMod": collName, "validationLevel": "moderate"}),
                             ErrorCodes.InvalidOptions);

// Tries to set the validationAction for a time-series collection.
assert.commandFailedWithCode(db.runCommand({"collMod": collName, "validationAction": "warn"}),
                             ErrorCodes.InvalidOptions);

// Tries to modify the view for a time-series collection.
assert.commandFailedWithCode(db.runCommand({"collMod": collName, "viewOn": "foo", "pipeline": []}),
                             ErrorCodes.InvalidOptions);

// Successfully sets 'expireAfterSeconds' for a time-series collection.
assert.commandWorked(db.runCommand({"collMod": collName, "expireAfterSeconds": 60}));

// Successfully sets the granularity to a higher value for a time-series collection.
assert.commandWorked(
    db.runCommand({"collMod": collName, "timeseries": {"granularity": "minutes"}}));

// Tries to set current granularity to a lower value.
assert.commandFailedWithCode(
    db.runCommand({"collMod": collName, "timeseries": {"granularity": "seconds"}}),
    ErrorCodes.InvalidOptions);

// Successfully sets the granularity to a higher value for a time-series collection.
assert.commandWorked(db.runCommand({"collMod": collName, "timeseries": {"granularity": "hours"}}));

// collMod against the underlying buckets collection should fail: not allowed to target the buckets
// collection.
assert.commandFailedWithCode(
    db.runCommand(
        {"collMod": ("system.buckets." + collName), "timeseries": {"granularity": "hours"}}),
    [ErrorCodes.InvalidNamespace, 6201808 /* mongos error code */]);

if (TimeseriesTest.timeseriesScalabilityImprovementsEnabled(db.getMongo())) {
    // Tries to set one seconds parameter without the other (bucketMaxSpanSeconds or
    // bucketRoundingSeconds).
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {"bucketMaxSpanSeconds": bucketMaxSpanSecondsHours}
    }),
                                 ErrorCodes.InvalidOptions);
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {"bucketRoundingSeconds": bucketRoundingSecondsHours}
    }),
                                 ErrorCodes.InvalidOptions);

    // Tries to set bucketMaxSpanSeconds and bucketRoundingSeconds to a value less than the current
    // maxSpanSeconds.
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "bucketMaxSpanSeconds": bucketRoundingSecondsHours,
            "bucketRoundingSeconds": bucketRoundingSecondsHours
        }
    }),
                                 ErrorCodes.InvalidOptions);

    // Expect setting the bucketMaxSpanSeconds corresponding to the granularity default value to
    // succeed.
    assert.commandWorked(db.runCommand({
        "collMod": collName,
        "timeseries": {"granularity": "hours", "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours}
    }));

    // Tries to set bucketMaxSpanSeconds and bucketRoundingSeconds with different values
    // corresponding to the granularity default values. This should fail since they are not equal.
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "granularity": "hours",
            "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours,
            "bucketRoundingSeconds": bucketRoundingSecondsHours
        }
    }),
                                 ErrorCodes.InvalidOptions);

    // Tries to set bucketMaxSpanSeconds and bucketRoundingSeconds with different values.
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours + 1,
            "bucketRoundingSeconds": bucketRoundingSecondsHours + 1
        }
    }),
                                 ErrorCodes.InvalidOptions);

    // Tries to set granularity, bucketMaxSpanSeconds and bucketRoundingSeconds with different
    // values from their default (60 * 60 * 24 and 60 * 60).
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "granularity": "hours",
            "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours + 1,
            "bucketRoundingSeconds": bucketRoundingSecondsHours + 1
        }
    }),
                                 ErrorCodes.InvalidOptions);

    // Successfully sets bucketMaxSpanSeconds, bucketRoundingSeconds and granularity to an equal
    // value. This accepts the 3 parameters because they are the same as the current set values.
    assert.commandWorked(db.runCommand({
        "collMod": collName,
        "timeseries": {"granularity": "hours", "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours}
    }));

    // Successfully sets the bucketMaxSpanSeconds and bucketRoundingSeconds to a higher value for a
    // timeseries collection. The granularity is currently set to 'hours' for this collection so we
    // should be able to increase the value of bucketMaxSpanSeconds by one.
    assert.commandWorked(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "bucketMaxSpanSeconds": bucketMaxSpanSecondsHours + 1,
            "bucketRoundingSeconds": bucketMaxSpanSecondsHours + 1
        }
    }));

    // Verify seconds was correctly set on the collection and granularity removed since a custom
    // value was added.
    let collections = assert.commandWorked(db.runCommand({listCollections: 1})).cursor.firstBatch;

    let collectionEntry =
        collections.find(entry => entry.name === 'system.buckets.' + coll.getName());
    assert(collectionEntry);

    assert.eq(collectionEntry.options.timeseries.bucketRoundingSeconds,
              bucketMaxSpanSecondsHours + 1);
    assert.eq(collectionEntry.options.timeseries.bucketMaxSpanSeconds,
              bucketMaxSpanSecondsHours + 1);
    assert.isnull(collectionEntry.options.timeseries.granularity);

    collectionEntry = collections.find(entry => entry.name === coll.getName());
    assert(collectionEntry);
    assert.eq(collectionEntry.options.timeseries.bucketRoundingSeconds,
              bucketMaxSpanSecondsHours + 1);
    assert.eq(collectionEntry.options.timeseries.bucketMaxSpanSeconds,
              bucketMaxSpanSecondsHours + 1);
    assert.isnull(collectionEntry.options.timeseries.granularity);

    coll.drop();
    // Create timeseries collection with custom maxSpanSeconds and bucketRoundingSeconds.
    assert.commandWorked(db.createCollection(
        collName,
        {timeseries: {timeField: "time", bucketMaxSpanSeconds: 200, bucketRoundingSeconds: 200}}));

    // Successfully sets granularity from a collection created with custom maxSpanSeconds and
    // bucketRoundingSeconds since the default values for 'minutes' are greater than the previous
    // seconds.
    assert.commandWorked(
        db.runCommand({"collMod": collName, "timeseries": {"granularity": "minutes"}}));

    // Fails to set bucketMaxSpanSeconds and bucketRoundingSeconds past the bucketing limit.
    assert.commandFailedWithCode(db.runCommand({
        "collMod": collName,
        "timeseries": {
            "bucketMaxSpanSeconds": bucketingValueMax + 1,
            "bucketRoundingSeconds": bucketingValueMax + 1
        }
    }),
                                 idlInvalidValueError);

    // Successfully set the bucketMaxSpanSeconds and bucketRoundingSeconds to the limit.
    assert.commandWorked(db.runCommand({
        "collMod": collName,
        "timeseries":
            {"bucketMaxSpanSeconds": bucketingValueMax, "bucketRoundingSeconds": bucketingValueMax}
    }));

    // No-op command should succeed with empty time-series options.
    assert.commandWorked(db.runCommand({"collMod": collName, "timeseries": {}}));
}
})();