Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-3191): backport versioned api #2850

Merged
merged 8 commits into from
Jun 25, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ functions:
MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} \
AUTH=${AUTH} SSL=${SSL} \
ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \
REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \
bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh
- command: expansions.update
params:
Expand Down Expand Up @@ -111,8 +112,10 @@ functions:
rm -f ./prepare_client_encryption.sh
fi

AUTH=${AUTH} SSL=${SSL} UNIFIED=${UNIFIED} MONGODB_URI="${MONGODB_URI}" \
NODE_VERSION=${NODE_VERSION} SKIP_DEPS=1 NO_EXIT=1 \
MONGODB_URI="${MONGODB_URI}" \
AUTH=${AUTH} SSL=${SSL} UNIFIED=${UNIFIED} \
MONGODB_API_VERSION="${MONGODB_API_VERSION}" \
NODE_VERSION=${NODE_VERSION} SKIP_DEPS=${SKIP_DEPS|1} NO_EXIT=${NO_EXIT|1} \
bash ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh
run checks:
- command: shell.exec
Expand Down Expand Up @@ -1144,6 +1147,23 @@ tasks:
- func: run tests
vars:
UNIFIED: 1
- name: test-latest-server-v1-api
tags:
- latest
- server
- v1-api
commands:
- func: install dependencies
- func: bootstrap mongo-orchestration
vars:
VERSION: latest
TOPOLOGY: server
REQUIRE_API_VERSION: '1'
- func: run tests
vars:
MONGODB_API_VERSION: '1'
UNIFIED: 1
NO_EXIT: ''
- name: test-atlas-connectivity
tags:
- atlas-connect
Expand Down Expand Up @@ -1616,6 +1636,7 @@ buildvariants:
- test-2.6-server-unified
- test-2.6-replica_set-unified
- test-2.6-sharded_cluster-unified
- test-latest-server-v1-api
- test-atlas-connectivity
- test-auth-kerberos-legacy
- test-auth-kerberos-unified
Expand Down Expand Up @@ -1726,6 +1747,7 @@ buildvariants:
- test-2.6-server-unified
- test-2.6-replica_set-unified
- test-2.6-sharded_cluster-unified
- test-latest-server-v1-api
- test-atlas-connectivity
- test-auth-kerberos-legacy
- test-auth-kerberos-unified
Expand Down Expand Up @@ -1901,6 +1923,7 @@ buildvariants:
- test-3.2-server-unified
- test-3.2-replica_set-unified
- test-3.2-sharded_cluster-unified
- test-latest-server-v1-api
- test-atlas-connectivity
- test-auth-kerberos-legacy
- test-auth-kerberos-unified
Expand Down
7 changes: 5 additions & 2 deletions .evergreen/config.yml.in
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ functions:
MONGODB_VERSION=${VERSION} TOPOLOGY=${TOPOLOGY} \
AUTH=${AUTH} SSL=${SSL} \
ORCHESTRATION_FILE=${ORCHESTRATION_FILE} \
REQUIRE_API_VERSION=${REQUIRE_API_VERSION} \
bash ${DRIVERS_TOOLS}/.evergreen/run-orchestration.sh
# run-orchestration generates expansion file with the MONGODB_URI for the cluster
- command: expansions.update
Expand Down Expand Up @@ -130,8 +131,10 @@ functions:
rm -f ./prepare_client_encryption.sh
fi

AUTH=${AUTH} SSL=${SSL} UNIFIED=${UNIFIED} MONGODB_URI="${MONGODB_URI}" \
NODE_VERSION=${NODE_VERSION} SKIP_DEPS=1 NO_EXIT=1 \
MONGODB_URI="${MONGODB_URI}" \
AUTH=${AUTH} SSL=${SSL} UNIFIED=${UNIFIED} \
MONGODB_API_VERSION="${MONGODB_API_VERSION}" \
NODE_VERSION=${NODE_VERSION} SKIP_DEPS=${SKIP_DEPS|1} NO_EXIT=${NO_EXIT|1} \
bash ${PROJECT_DIRECTORY}/.evergreen/run-tests.sh

"run checks":
Expand Down
24 changes: 24 additions & 0 deletions .evergreen/generate_evergreen_tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ const OPERATING_SYSTEMS = [
)
);

// TODO: NODE-3060: enable skipped tests on windows
const WINDOWS_SKIP_TAGS = new Set([
'atlas-connect',
'auth'
Expand Down Expand Up @@ -113,6 +114,29 @@ MONGODB_VERSIONS.forEach(mongoVersion => {
BASE_TASKS.push(makeTask({ mongoVersion, topology }))
);
});
BASE_TASKS.push({
name: `test-latest-server-v1-api`,
tags: ['latest', 'server', 'v1-api'],
commands: [
{ func: 'install dependencies' },
{
func: 'bootstrap mongo-orchestration',
vars: {
VERSION: 'latest',
TOPOLOGY: 'server',
REQUIRE_API_VERSION: '1'
}
},
{
func: 'run tests',
vars: {
MONGODB_API_VERSION: '1',
UNIFIED: 1,
NO_EXIT: ''
}
}
]
});

TASKS.push(
{
Expand Down
2 changes: 1 addition & 1 deletion .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,4 @@ nvm use 12
npm run build:unified
nvm use "$NODE_VERSION"

MONGODB_UNIFIED_TOPOLOGY=${UNIFIED} MONGODB_URI=${MONGODB_URI} npm run ${TEST_NPM_SCRIPT}
MONGODB_API_VERSION=${MONGODB_API_VERSION} MONGODB_UNIFIED_TOPOLOGY=${UNIFIED} MONGODB_URI=${MONGODB_URI} npm run ${TEST_NPM_SCRIPT}
41 changes: 34 additions & 7 deletions lib/cmap/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class Connection extends EventEmitter {
this.port = options.port || 27017;
this.monitorCommands =
typeof options.monitorCommands === 'boolean' ? options.monitorCommands : false;
this.serverApi = options.serverApi;

this.closed = false;
this.destroyed = false;

Expand Down Expand Up @@ -170,33 +172,58 @@ class Connection extends EventEmitter {
});
}

applyApiVersion(options) {
if (this.serverApi) {
options.serverApi = this.serverApi;
}
return options;
}

// Wire protocol methods
command(ns, cmd, options, callback) {
wp.command(makeServerTrampoline(this), ns, cmd, options, callback);
if (typeof options === 'function') {
callback = options;
options = {};
}
wp.command(makeServerTrampoline(this), ns, cmd, this.applyApiVersion(options), callback);
}

query(ns, cmd, cursorState, options, callback) {
wp.query(makeServerTrampoline(this), ns, cmd, cursorState, options, callback);
wp.query(
makeServerTrampoline(this),
ns,
cmd,
cursorState,
this.applyApiVersion(options),
callback
);
}

getMore(ns, cursorState, batchSize, options, callback) {
wp.getMore(makeServerTrampoline(this), ns, cursorState, batchSize, options, callback);
wp.getMore(
makeServerTrampoline(this),
ns,
cursorState,
batchSize,
this.applyApiVersion(options),
callback
);
}

killCursors(ns, cursorState, callback) {
wp.killCursors(makeServerTrampoline(this), ns, cursorState, callback);
wp.killCursors(makeServerTrampoline(this), ns, cursorState, this.applyApiVersion({}), callback);
}

insert(ns, ops, options, callback) {
wp.insert(makeServerTrampoline(this), ns, ops, options, callback);
wp.insert(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
}

update(ns, ops, options, callback) {
wp.update(makeServerTrampoline(this), ns, ops, options, callback);
wp.update(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
}

remove(ns, ops, options, callback) {
wp.remove(makeServerTrampoline(this), ns, ops, options, callback);
wp.remove(makeServerTrampoline(this), ns, ops, this.applyApiVersion(options), callback);
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/cmap/connection_pool.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const VALID_POOL_OPTIONS = new Set([
'ssl',
'bson',
'connectionType',
'serverApi',
'monitorCommands',
'socketTimeout',
'credentials',
Expand Down
2 changes: 1 addition & 1 deletion lib/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -1524,7 +1524,7 @@ Collection.prototype.count = deprecate(function(query, options, callback) {

return executeOperation(
this.s.topology,
new EstimatedDocumentCountOperation(this, query, options),
new CountDocumentsOperation(this, query, options),
nbbeeken marked this conversation as resolved.
Show resolved Hide resolved
callback
);
}, 'collection.count is deprecated, and will be removed in a future version.' +
Expand Down
8 changes: 7 additions & 1 deletion lib/core/connection/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ function performInitialHandshake(conn, options, _callback) {
return;
}

if ('isWritablePrimary' in response) {
// Provide pre-hello-style response document.
response.ismaster = response.isWritablePrimary;
}

const supportedServerErr = checkSupportedServer(response, options);
if (supportedServerErr) {
callback(supportedServerErr);
Expand Down Expand Up @@ -158,11 +163,12 @@ function performInitialHandshake(conn, options, _callback) {

function prepareHandshakeDocument(authContext, callback) {
const options = authContext.options;
const serverApi = authContext.connection.serverApi;
const compressors =
options.compression && options.compression.compressors ? options.compression.compressors : [];

const handshakeDoc = {
ismaster: true,
[serverApi ? 'hello' : 'ismaster']: true,
client: options.metadata || makeClientMetadata(options),
compression: compressors
};
Expand Down
8 changes: 7 additions & 1 deletion lib/core/sdam/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,9 @@ function checkServer(monitor, callback) {
const maxAwaitTimeMS = monitor.options.heartbeatFrequencyMS;
const topologyVersion = monitor[kServer].description.topologyVersion;
const isAwaitable = topologyVersion != null;
const serverApi = monitor[kConnection].serverApi;

const cmd = { ismaster: true };
const cmd = { [serverApi ? 'hello' : 'ismaster']: true };
const options = { socketTimeout: connectTimeoutMS };

if (isAwaitable) {
Expand All @@ -228,6 +229,11 @@ function checkServer(monitor, callback) {
const isMaster = result.result;
const rttPinger = monitor[kRTTPinger];

if ('isWritablePrimary' in isMaster) {
// Provide pre-hello-style response document.
isMaster.ismaster = isMaster.isWritablePrimary;
}

const duration =
isAwaitable && rttPinger ? rttPinger.roundTripTime : calculateDurationInMs(start);

Expand Down
2 changes: 2 additions & 0 deletions lib/core/sdam/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ class Server extends EventEmitter {
credentials: options.credentials,
topology
};
this.serverApi = options.serverApi;

// create the connection pool
// NOTE: this used to happen in `connect`, we supported overriding pool options there
Expand Down Expand Up @@ -245,6 +246,7 @@ class Server extends EventEmitter {
if (typeof options === 'function') {
(callback = options), (options = {}), (options = options || {});
}
options.serverApi = this.serverApi;

if (this.s.state === STATE_CLOSING || this.s.state === STATE_CLOSED) {
callback(new MongoError('server is closed'));
Expand Down
7 changes: 6 additions & 1 deletion lib/core/sdam/topology.js
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class Topology extends EventEmitter {
// timer management
connectionTimers: new Set()
};
this.serverApi = options.serverApi;

if (options.srvHost) {
this.s.srvPoller =
Expand Down Expand Up @@ -495,7 +496,11 @@ class Topology extends EventEmitter {
this.command(
'admin.$cmd',
{ endSessions: sessions },
{ readPreference: ReadPreference.primaryPreferred, noResponse: true },
{
readPreference: ReadPreference.primaryPreferred,
noResponse: true,
serverApi: this.serverApi
},
() => {
// intentionally ignored, per spec
if (typeof callback === 'function') callback();
Expand Down
5 changes: 5 additions & 0 deletions lib/core/uri_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,11 @@ function parseQueryString(query, options) {
}

const normalizedKey = key.toLowerCase();
if (normalizedKey === 'serverapi') {
throw new MongoParseError(
'URI cannot contain `serverApi`, it can only be passed to the client'
);
}
const parsedValue = FILE_PATH_OPTIONS.has(normalizedKey)
? value
: parseQueryStringItemValue(normalizedKey, value);
Expand Down
12 changes: 12 additions & 0 deletions lib/core/wireprotocol/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ function _command(server, ns, cmd, options, callback) {
const serverClusterTime = server.clusterTime;
let clusterTime = serverClusterTime;
let finalCmd = Object.assign({}, cmd);

const serverApi = options.serverApi;
if (serverApi) {
finalCmd.apiVersion = serverApi.version || serverApi;
if (serverApi.strict != null) {
finalCmd.apiStrict = serverApi.strict;
}
if (serverApi.deprecationErrors != null) {
finalCmd.apiDeprecationErrors = serverApi.deprecationErrors;
}
}

if (hasSessionSupport(server) && session) {
const sessionClusterTime = session.clusterTime;
if (
Expand Down
5 changes: 3 additions & 2 deletions lib/core/wireprotocol/kill_cursors.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ const maxWireVersion = require('../utils').maxWireVersion;
const emitWarning = require('../utils').emitWarning;
const command = require('./command');

function killCursors(server, ns, cursorState, callback) {
function killCursors(server, ns, cursorState, options, callback) {
callback = typeof callback === 'function' ? callback : () => {};
options = options || {};

const cursorId = cursorState.cursorId;

if (maxWireVersion(server) < 4) {
Expand Down Expand Up @@ -45,7 +47,6 @@ function killCursors(server, ns, cursorState, callback) {
cursors: [cursorId]
};

const options = {};
if (typeof cursorState.session === 'object') options.session = cursorState.session;

command(server, ns, killCursorCmd, options, (err, result) => {
Expand Down
1 change: 1 addition & 0 deletions lib/mongo_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ const validOptions = require('./operations/connect').validOptions;
* @property {number} [numberOfRetries] (**default**: 5) The number of retries for a tailable cursor
* @property {boolean} [auto_reconnect] (**default**: true) Enable auto reconnecting for single server instances
* @property {boolean} [monitorCommands] (**default**: false) Enable command monitoring for this client
* @property {string|ServerApi} [serverApi] (**default**: undefined) The server API version
* @property {number} [minSize] If present, the connection pool will be initialized with minSize connections, and will never dip below minSize connections
* @property {boolean} [useNewUrlParser] (**default**: true) Determines whether or not to use the new url parser. Enables the new, spec-compliant, url parser shipped in the core driver. This url parser fixes a number of problems with the original parser, and aims to outright replace that parser in the near future. Defaults to true, and must be explicitly set to false to use the legacy url parser.
* @property {boolean} [useUnifiedTopology] Enables the new unified topology layer
Expand Down
1 change: 1 addition & 0 deletions lib/operations/connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ const validOptionNames = [
'auto_reconnect',
'minSize',
'monitorCommands',
'serverApi',
'retryWrites',
'retryReads',
'useNewUrlParser',
Expand Down
Loading