summaryrefslogtreecommitdiff
path: root/jstests/multiVersion/genericSetFCVUsage/view_definition_feature_compatibility_version.js
blob: be72a724237864f5f395fd6ceaf25d94834e14e6 (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
/**
 * Test that mongod will not allow creation of a view using new aggregation features when the
 * feature compatibility version is older than the latest version.
 *
 * We restart mongod during the test and expect it to have the same data after restarting.
 * @tags: [requires_persistence]
 */

(function() {
"use strict";

load("jstests/libs/feature_compatibility_version.js");

const testName = "view_definition_feature_compatibility_version_multiversion";
const dbpath = MongoRunner.dataPath + testName;

// The 'pipelinesWithNewFeatures' array should be populated with aggregation pipelines that use
// aggregation features new in the latest version of mongod. This test ensures that a view
// definition accepts the new aggregation feature when the feature compatibility version is the
// latest version, and rejects it when the feature compatibility version is the last-stable
// version.
const pipelinesWithNewFeatures = [];

let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest"});
assert.neq(null, conn, "mongod was unable to start up");
let testDB = conn.getDB(testName);

// Explicitly set feature compatibility version to the latest version.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}));

// Test that we are able to create a new view with any of the new features.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandWorked(
        testDB.createView("firstView" + i, "coll", pipe),
        `Expected to be able to create view with pipeline ${tojson(pipe)} while in FCV` +
            ` ${latestFCV}`));

// Test that we are able to create a new view with any of the new features.
pipelinesWithNewFeatures.forEach(function(pipe, i) {
    assert(testDB["firstView" + i].drop(), `Drop of view with pipeline ${tojson(pipe)} failed`);
    assert.commandWorked(testDB.createView("firstView" + i, "coll", []));
    assert.commandWorked(
        testDB.runCommand({collMod: "firstView" + i, viewOn: "coll", pipeline: pipe}),
        `Expected to be able to modify view to use pipeline ${tojson(pipe)} while in FCV` +
            ` ${latestFCV}`);
});

// Create an empty view which we will attempt to update to use new query features while the
// feature compatibility version is the last-stable version.
assert.commandWorked(testDB.createView("emptyView", "coll", []));

// Set the feature compatibility version to the last-stable version.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: lastStableFCV}));

// Read against an existing view using new query features should not fail.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandWorked(testDB.runCommand({find: "firstView" + i}),
                                      `Failed to query view with pipeline ${tojson(pipe)}`));

// Trying to create a new view using new query features should fail.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandFailedWithCode(
        testDB.createView("view_fail" + i, "coll", pipe),
        ErrorCodes.QueryFeatureNotAllowed,
        `Expected *not* to be able to create view with pipeline ${tojson(pipe)} while in FCV` +
            ` ${lastStableFCV}`));

// Trying to update existing view to use new query features should also fail.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandFailedWithCode(
        testDB.runCommand({collMod: "emptyView", viewOn: "coll", pipeline: pipe}),
        ErrorCodes.QueryFeatureNotAllowed,
        `Expected *not* to be able to modify view to use pipeline ${tojson(pipe)} while in` +
            `FCV ${lastStableFCV}`));

MongoRunner.stopMongod(conn);

// Starting up the last-stable version of mongod with new query features will succeed.
conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "last-stable", noCleanData: true});
assert.neq(null,
           conn,
           `version ${MongoRunner.getBinVersionFor("last-stable")} of mongod was` +
               " unable to start up");
testDB = conn.getDB(testName);

// Reads will fail against views with new query features when running the last-stable version.
// Not checking the code returned on failure as it is not uniform across the various
// 'pipeline' arguments tested.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandFailed(
        testDB.runCommand({find: "firstView" + i}),
        `Expected read against view with pipeline ${tojson(pipe)} to fail on version` +
            ` ${MongoRunner.getBinVersionFor("last-stable")}`));

// Test that a read against a view that does not contain new query features succeeds.
assert.commandWorked(testDB.runCommand({find: "emptyView"}));

MongoRunner.stopMongod(conn);

// Starting up the latest version of mongod should succeed, even though the feature
// compatibility version is still set to the last-stable version.
conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest", noCleanData: true});
assert.neq(null, conn, "mongod was unable to start up");
testDB = conn.getDB(testName);

// Read against an existing view using new query features should not fail.
pipelinesWithNewFeatures.forEach(
    (pipe, i) => assert.commandWorked(testDB.runCommand({find: "firstView" + i}),
                                      `Failed to query view with pipeline ${tojson(pipe)}`));

// Set the feature compatibility version back to the latest version.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}));

pipelinesWithNewFeatures.forEach(function(pipe, i) {
    assert.commandWorked(testDB.runCommand({find: "firstView" + i}),
                         `Failed to query view with pipeline ${tojson(pipe)}`);
    // Test that we are able to create a new view with any of the new features.
    assert.commandWorked(
        testDB.createView("secondView" + i, "coll", pipe),
        `Expected to be able to create view with pipeline ${tojson(pipe)} while in FCV` +
            ` ${latestFCV}`);

    // Test that we are able to update an existing view to use any of the new features.
    assert(testDB["secondView" + i].drop(), `Drop of view with pipeline ${tojson(pipe)} failed`);
    assert.commandWorked(testDB.createView("secondView" + i, "coll", []));
    assert.commandWorked(
        testDB.runCommand({collMod: "secondView" + i, viewOn: "coll", pipeline: pipe}),
        `Expected to be able to modify view to use pipeline ${tojson(pipe)} while in FCV` +
            ` ${latestFCV}`);
});

// Set the feature compatibility version to the last-stable version and then restart with
// internalValidateFeaturesAsMaster=false.
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: lastStableFCV}));
MongoRunner.stopMongod(conn);
conn = MongoRunner.runMongod({
    dbpath: dbpath,
    binVersion: "latest",
    noCleanData: true,
    setParameter: "internalValidateFeaturesAsMaster=false"
});
assert.neq(null, conn, "mongod was unable to start up");
testDB = conn.getDB(testName);

pipelinesWithNewFeatures.forEach(function(pipe, i) {
    // Even though the feature compatibility version is the last-stable version, we should still
    // be able to create a view using new query features, because
    // internalValidateFeaturesAsMaster is false.
    assert.commandWorked(
        testDB.createView("thirdView" + i, "coll", pipe),
        `Expected to be able to create view with pipeline ${tojson(pipe)} while in FCV` +
            ` ${lastStableFCV} with internalValidateFeaturesAsMaster=false`);

    // We should also be able to modify a view to use new query features.
    assert(testDB["thirdView" + i].drop(), `Drop of view with pipeline ${tojson(pipe)} failed`);
    assert.commandWorked(testDB.createView("thirdView" + i, "coll", []));
    assert.commandWorked(
        testDB.runCommand({collMod: "thirdView" + i, viewOn: "coll", pipeline: pipe}),
        `Expected to be able to modify view to use pipeline ${tojson(pipe)} while in FCV` +
            ` ${lastStableFCV} with internalValidateFeaturesAsMaster=false`);
});

MongoRunner.stopMongod(conn);

// Starting up the last-stable version of mongod with new query features should succeed.
conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "last-stable", noCleanData: true});
assert.neq(null,
           conn,
           `version ${MongoRunner.getBinVersionFor("last-stable")} of mongod was` +
               " unable to start up");
testDB = conn.getDB(testName);

// Existing views with new query features can be dropped.
pipelinesWithNewFeatures.forEach((pipe, i) =>
                                     assert(testDB["firstView" + i].drop(),
                                            `Drop of view with pipeline ${tojson(pipe)} failed`));
assert(testDB.system.views.drop(), "Drop of system.views collection failed");

MongoRunner.stopMongod(conn);
}());