Skip to content

Commit

Permalink
feat(NODE-3191): backport versioned api
Browse files Browse the repository at this point in the history
  • Loading branch information
emadum committed Jun 17, 2021
1 parent 8c8b4c3 commit 2862914
Show file tree
Hide file tree
Showing 95 changed files with 6,556 additions and 367 deletions.
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),
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

0 comments on commit 2862914

Please sign in to comment.