PYTHON-3288 Implement client side operation timeout (#954)
Add timeoutMS URI option and MongoClient keyword argument. Add provisional/beta pymongo.timeout() api to set a deadline for a block of operations.
This commit is contained in:
parent
6b088ffa4e
commit
890cd26e1a
@ -105,6 +105,9 @@ do
|
||||
crud|CRUD)
|
||||
cpjson crud/tests/ crud
|
||||
;;
|
||||
csot|CSOT|client-side-operations-timeout)
|
||||
cpjson client-side-operations-timeout/tests csot
|
||||
;;
|
||||
load-balancers|load_balancer)
|
||||
cpjson load-balancers/tests load_balancer
|
||||
;;
|
||||
@ -150,6 +153,7 @@ do
|
||||
;;
|
||||
uri|uri-options|uri_options)
|
||||
cpjson uri-options/tests uri_options
|
||||
cp "$SPECS"/source/uri-options/tests/*.pem $PYMONGO/test/uri_options
|
||||
;;
|
||||
stable-api|versioned-api)
|
||||
cpjson versioned-api/tests versioned-api
|
||||
|
||||
@ -22,6 +22,8 @@
|
||||
|
||||
The maximum wire protocol version PyMongo supports.
|
||||
|
||||
.. autofunction:: timeout
|
||||
|
||||
Sub-modules:
|
||||
|
||||
.. toctree::
|
||||
|
||||
@ -6,6 +6,13 @@ Changes in Version 4.2
|
||||
|
||||
.. warning:: PyMongo 4.2 drops support for Python 3.6: Python 3.7+ is now required.
|
||||
|
||||
PyMongo 4.2 brings a number of improvements including:
|
||||
|
||||
- Support for MongoDB 6.0.
|
||||
- Provisional (beta) support for :func:`pymongo.timeout` to apply a single timeout
|
||||
to an entire block of pymongo operations.
|
||||
- Beta support for Queryable Encryption with MongoDB 6.0.
|
||||
|
||||
Bug fixes
|
||||
.........
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
|
||||
"""Python driver for MongoDB."""
|
||||
|
||||
from typing import Tuple, Union
|
||||
from typing import ContextManager, Optional, Tuple, Union
|
||||
|
||||
ASCENDING = 1
|
||||
"""Ascending sort order."""
|
||||
@ -69,6 +69,7 @@ version = __version__
|
||||
|
||||
"""Current version of PyMongo."""
|
||||
|
||||
from pymongo import _csot
|
||||
from pymongo.collection import ReturnDocument # noqa: F401
|
||||
from pymongo.common import ( # noqa: F401
|
||||
MAX_SUPPORTED_WIRE_VERSION,
|
||||
@ -97,3 +98,47 @@ def has_c() -> bool:
|
||||
return True
|
||||
except ImportError:
|
||||
return False
|
||||
|
||||
|
||||
def timeout(seconds: Optional[float]) -> ContextManager:
|
||||
"""**(Provisional)** Apply the given timeout for a block of operations.
|
||||
|
||||
.. note:: :func:`~pymongo.timeout` is currently provisional. Backwards
|
||||
incompatible changes may occur before becoming officially supported.
|
||||
|
||||
Use :func:`~pymongo.timeout` in a with-statement::
|
||||
|
||||
with pymongo.timeout(5):
|
||||
client.db.coll.insert_one({})
|
||||
client.db.coll2.insert_one({})
|
||||
|
||||
When the with-statement is entered, a deadline is set for the entire
|
||||
block. When that deadline is exceeded, any blocking pymongo operation
|
||||
will raise a timeout exception. For example::
|
||||
|
||||
try:
|
||||
with pymongo.timeout(5):
|
||||
client.db.coll.insert_one({})
|
||||
time.sleep(5)
|
||||
# The deadline has now expired, the next operation will raise
|
||||
# a timeout exception.
|
||||
client.db.coll2.insert_one({})
|
||||
except (ServerSelectionTimeoutError, ExecutionTimeout, WTimeoutError,
|
||||
NetworkTimeout) as exc:
|
||||
print(f"block timed out: {exc!r}")
|
||||
|
||||
:Parameters:
|
||||
- `seconds`: A non-negative floating point number expressing seconds, or None.
|
||||
|
||||
:Raises:
|
||||
- :py:class:`ValueError`: When `seconds` is negative.
|
||||
|
||||
.. versionadded:: 4.2
|
||||
"""
|
||||
if not isinstance(seconds, (int, float, type(None))):
|
||||
raise TypeError("timeout must be None, an int, or a float")
|
||||
if seconds and seconds < 0:
|
||||
raise ValueError("timeout cannot be negative")
|
||||
if seconds is not None:
|
||||
seconds = float(seconds)
|
||||
return _csot._TimeoutContext(seconds)
|
||||
|
||||
80
pymongo/_csot.py
Normal file
80
pymongo/_csot.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Copyright 2022-present MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
||||
# may not use this file except in compliance with the License. You
|
||||
# may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied. See the License for the specific language governing
|
||||
# permissions and limitations under the License.
|
||||
|
||||
"""Internal helpers for CSOT."""
|
||||
|
||||
import time
|
||||
from contextvars import ContextVar
|
||||
from typing import Optional
|
||||
|
||||
TIMEOUT: ContextVar[Optional[float]] = ContextVar("TIMEOUT", default=None)
|
||||
RTT: ContextVar[float] = ContextVar("RTT", default=0.0)
|
||||
DEADLINE: ContextVar[float] = ContextVar("DEADLINE", default=float("inf"))
|
||||
|
||||
|
||||
def get_timeout() -> Optional[float]:
|
||||
return TIMEOUT.get(None)
|
||||
|
||||
|
||||
def get_rtt() -> float:
|
||||
return RTT.get()
|
||||
|
||||
|
||||
def get_deadline() -> float:
|
||||
return DEADLINE.get()
|
||||
|
||||
|
||||
def set_rtt(rtt: float) -> None:
|
||||
RTT.set(rtt)
|
||||
|
||||
|
||||
def set_timeout(timeout: Optional[float]) -> None:
|
||||
TIMEOUT.set(timeout)
|
||||
DEADLINE.set(time.monotonic() + timeout if timeout else float("inf"))
|
||||
|
||||
|
||||
def remaining() -> Optional[float]:
|
||||
if not get_timeout():
|
||||
return None
|
||||
return DEADLINE.get() - time.monotonic()
|
||||
|
||||
|
||||
def clamp_remaining(max_timeout: float) -> float:
|
||||
"""Return the remaining timeout clamped to a max value."""
|
||||
timeout = remaining()
|
||||
if timeout is None:
|
||||
return max_timeout
|
||||
return min(timeout, max_timeout)
|
||||
|
||||
|
||||
class _TimeoutContext(object):
|
||||
"""Internal timeout context manager.
|
||||
|
||||
Use :func:`pymongo.timeout` instead::
|
||||
|
||||
with client.timeout(0.5):
|
||||
client.test.test.insert_one({})
|
||||
"""
|
||||
|
||||
__slots__ = ("_timeout",)
|
||||
|
||||
def __init__(self, timeout: Optional[float]):
|
||||
self._timeout = timeout
|
||||
|
||||
def __enter__(self):
|
||||
set_timeout(self._timeout)
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
set_timeout(None)
|
||||
@ -330,6 +330,8 @@ class _Bulk(object):
|
||||
session._apply_to(cmd, retryable, ReadPreference.PRIMARY, sock_info)
|
||||
sock_info.send_cluster_time(cmd, session, client)
|
||||
sock_info.add_server_api(cmd)
|
||||
# CSOT: apply timeout before encoding the command.
|
||||
sock_info.apply_timeout(client, cmd)
|
||||
ops = islice(run.ops, run.idx_offset, None)
|
||||
|
||||
# Run as many ops as possible in one command.
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
|
||||
"""Tools to parse mongo client options."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from bson.codec_options import _parse_codec_options
|
||||
from pymongo import common
|
||||
from pymongo.auth import _build_credentials_tuple
|
||||
@ -195,6 +197,7 @@ class ClientOptions(object):
|
||||
self.__server_selector = options.get("server_selector", any_server_selector)
|
||||
self.__auto_encryption_opts = options.get("auto_encryption_opts")
|
||||
self.__load_balanced = options.get("loadbalanced")
|
||||
self.__timeout = options.get("timeoutms")
|
||||
|
||||
@property
|
||||
def _options(self):
|
||||
@ -260,6 +263,14 @@ class ClientOptions(object):
|
||||
"""A :class:`~pymongo.read_concern.ReadConcern` instance."""
|
||||
return self.__read_concern
|
||||
|
||||
@property
|
||||
def timeout(self) -> Optional[float]:
|
||||
"""The timeout.
|
||||
|
||||
..versionadded: 4.2
|
||||
"""
|
||||
return self.__timeout
|
||||
|
||||
@property
|
||||
def retry_writes(self):
|
||||
"""If this instance should retry supported write operations."""
|
||||
|
||||
@ -150,6 +150,7 @@ from bson.binary import Binary
|
||||
from bson.int64 import Int64
|
||||
from bson.son import SON
|
||||
from bson.timestamp import Timestamp
|
||||
from pymongo import _csot
|
||||
from pymongo.cursor import _SocketManager
|
||||
from pymongo.errors import (
|
||||
ConfigurationError,
|
||||
@ -826,7 +827,7 @@ class ClientSession:
|
||||
wc = opts.write_concern
|
||||
cmd = SON([(command_name, 1)])
|
||||
if command_name == "commitTransaction":
|
||||
if opts.max_commit_time_ms:
|
||||
if opts.max_commit_time_ms and _csot.get_timeout() is None:
|
||||
cmd["maxTimeMS"] = opts.max_commit_time_ms
|
||||
|
||||
# Transaction spec says that after the initial commit attempt,
|
||||
|
||||
@ -116,6 +116,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
session: Optional["ClientSession"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
encrypted_fields: Optional[Mapping[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
@ -198,6 +199,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference or database.read_preference,
|
||||
write_concern or database.write_concern,
|
||||
read_concern or database.read_concern,
|
||||
timeout if timeout is not None else database.timeout,
|
||||
)
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("name must be an instance of str")
|
||||
@ -390,6 +392,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> "Collection[_DocumentType]":
|
||||
"""Get a clone of this collection changing the specified settings.
|
||||
|
||||
@ -428,6 +431,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference or self.read_preference,
|
||||
write_concern or self.write_concern,
|
||||
read_concern or self.read_concern,
|
||||
timeout=timeout if timeout is not None else self.timeout,
|
||||
)
|
||||
|
||||
def bulk_write(
|
||||
|
||||
@ -339,6 +339,15 @@ def validate_timeout_or_none_or_zero(option: Any, value: Any) -> Optional[float]
|
||||
return validate_positive_float(option, value) / 1000.0
|
||||
|
||||
|
||||
def validate_timeoutms(option: Any, value: Any) -> Optional[float]:
|
||||
"""Validates a timeout specified in milliseconds returning
|
||||
a value in floating point seconds.
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
return validate_positive_float_or_zero(option, value) / 1000.0
|
||||
|
||||
|
||||
def validate_max_staleness(option: str, value: Any) -> int:
|
||||
"""Validates maxStalenessSeconds according to the Max Staleness Spec."""
|
||||
if value == -1 or value == "-1":
|
||||
@ -658,6 +667,7 @@ URI_OPTIONS_VALIDATOR_MAP: Dict[str, Callable[[Any, Any], Any]] = {
|
||||
"zlibcompressionlevel": validate_zlib_compression_level,
|
||||
"srvservicename": validate_string,
|
||||
"srvmaxhosts": validate_non_negative_integer,
|
||||
"timeoutms": validate_timeoutms,
|
||||
}
|
||||
|
||||
# Dictionary where keys are the names of URI options specific to pymongo,
|
||||
@ -821,8 +831,8 @@ class BaseObject(object):
|
||||
read_preference: _ServerMode,
|
||||
write_concern: WriteConcern,
|
||||
read_concern: ReadConcern,
|
||||
timeout: Optional[float],
|
||||
) -> None:
|
||||
|
||||
if not isinstance(codec_options, CodecOptions):
|
||||
raise TypeError("codec_options must be an instance of bson.codec_options.CodecOptions")
|
||||
self.__codec_options = codec_options
|
||||
@ -845,6 +855,12 @@ class BaseObject(object):
|
||||
raise TypeError("read_concern must be an instance of pymongo.read_concern.ReadConcern")
|
||||
self.__read_concern = read_concern
|
||||
|
||||
if not isinstance(timeout, (int, float, type(None))):
|
||||
raise TypeError("timeout must be None, an int, or a float")
|
||||
if timeout and timeout < 0:
|
||||
raise TypeError("timeout cannot be negative")
|
||||
self.__timeout = float(timeout) if timeout else None
|
||||
|
||||
@property
|
||||
def codec_options(self) -> CodecOptions:
|
||||
"""Read only access to the :class:`~bson.codec_options.CodecOptions`
|
||||
@ -894,6 +910,14 @@ class BaseObject(object):
|
||||
"""
|
||||
return self.__read_concern
|
||||
|
||||
@property
|
||||
def timeout(self) -> Optional[float]:
|
||||
"""Read only access to the timeout of this instance.
|
||||
|
||||
.. versionadded:: 4.2
|
||||
"""
|
||||
return self.__timeout
|
||||
|
||||
|
||||
class _CaseInsensitiveDictionary(abc.MutableMapping):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@ -75,6 +75,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
write_concern: Optional["WriteConcern"] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> None:
|
||||
"""Get a database by client and name.
|
||||
|
||||
@ -127,6 +128,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference or client.read_preference,
|
||||
write_concern or client.write_concern,
|
||||
read_concern or client.read_concern,
|
||||
timeout if timeout is not None else client.timeout,
|
||||
)
|
||||
|
||||
if not isinstance(name, str):
|
||||
@ -154,6 +156,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
write_concern: Optional["WriteConcern"] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> "Database[_DocumentType]":
|
||||
"""Get a clone of this database changing the specified settings.
|
||||
|
||||
@ -193,6 +196,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference or self.read_preference,
|
||||
write_concern or self.write_concern,
|
||||
read_concern or self.read_concern,
|
||||
timeout if timeout is not None else self.timeout,
|
||||
)
|
||||
|
||||
def __eq__(self, other: Any) -> bool:
|
||||
@ -241,6 +245,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
write_concern: Optional["WriteConcern"] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> Collection[_DocumentType]:
|
||||
"""Get a :class:`~pymongo.collection.Collection` with the given name
|
||||
and options.
|
||||
@ -280,7 +285,14 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
used.
|
||||
"""
|
||||
return Collection(
|
||||
self, name, False, codec_options, read_preference, write_concern, read_concern
|
||||
self,
|
||||
name,
|
||||
False,
|
||||
codec_options,
|
||||
read_preference,
|
||||
write_concern,
|
||||
read_concern,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
def create_collection(
|
||||
@ -291,6 +303,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
write_concern: Optional["WriteConcern"] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
session: Optional["ClientSession"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
encrypted_fields: Optional[Mapping[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> Collection[_DocumentType]:
|
||||
@ -421,6 +434,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
|
||||
write_concern,
|
||||
read_concern,
|
||||
session=s,
|
||||
timeout=timeout,
|
||||
encrypted_fields=encrypted_fields,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
|
||||
import contextlib
|
||||
import enum
|
||||
import socket
|
||||
import uuid
|
||||
import weakref
|
||||
from typing import Any, Mapping, Optional, Sequence
|
||||
@ -38,6 +39,7 @@ from bson.codec_options import CodecOptions
|
||||
from bson.errors import BSONError
|
||||
from bson.raw_bson import DEFAULT_RAW_BSON_OPTIONS, RawBSONDocument, _inflate_bson
|
||||
from bson.son import SON
|
||||
from pymongo import _csot
|
||||
from pymongo.daemon import _spawn_daemon
|
||||
from pymongo.encryption_options import AutoEncryptionOpts
|
||||
from pymongo.errors import (
|
||||
@ -47,6 +49,7 @@ from pymongo.errors import (
|
||||
ServerSelectionTimeoutError,
|
||||
)
|
||||
from pymongo.mongo_client import MongoClient
|
||||
from pymongo.network import BLOCKING_IO_ERRORS
|
||||
from pymongo.pool import PoolOptions, _configured_socket
|
||||
from pymongo.read_concern import ReadConcern
|
||||
from pymongo.ssl_support import get_ssl_context
|
||||
@ -119,9 +122,11 @@ class _EncryptionIO(MongoCryptCallback): # type: ignore
|
||||
False, # allow_invalid_hostnames
|
||||
False,
|
||||
) # disable_ocsp_endpoint_check
|
||||
# CSOT: set timeout for socket creation.
|
||||
connect_timeout = max(_csot.clamp_remaining(_KMS_CONNECT_TIMEOUT), 0.001)
|
||||
opts = PoolOptions(
|
||||
connect_timeout=_KMS_CONNECT_TIMEOUT,
|
||||
socket_timeout=_KMS_CONNECT_TIMEOUT,
|
||||
connect_timeout=connect_timeout,
|
||||
socket_timeout=connect_timeout,
|
||||
ssl_context=ctx,
|
||||
)
|
||||
host, port = parse_host(endpoint, _HTTPS_PORT)
|
||||
@ -129,10 +134,14 @@ class _EncryptionIO(MongoCryptCallback): # type: ignore
|
||||
try:
|
||||
conn.sendall(message)
|
||||
while kms_context.bytes_needed > 0:
|
||||
# CSOT: update timeout.
|
||||
conn.settimeout(max(_csot.clamp_remaining(_KMS_CONNECT_TIMEOUT), 0))
|
||||
data = conn.recv(kms_context.bytes_needed)
|
||||
if not data:
|
||||
raise OSError("KMS connection closed")
|
||||
kms_context.feed(data)
|
||||
except BLOCKING_IO_ERRORS:
|
||||
raise socket.timeout("timed out")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@ -300,6 +300,9 @@ class _Query(object):
|
||||
self._as_command = None
|
||||
self.exhaust = exhaust
|
||||
|
||||
def reset(self):
|
||||
self._as_command = None
|
||||
|
||||
def namespace(self):
|
||||
return "%s.%s" % (self.db, self.coll)
|
||||
|
||||
@ -320,7 +323,7 @@ class _Query(object):
|
||||
sock_info.validate_session(self.client, self.session)
|
||||
return use_find_cmd
|
||||
|
||||
def as_command(self, sock_info):
|
||||
def as_command(self, sock_info, apply_timeout=False):
|
||||
"""Return a find command document for this query."""
|
||||
# We use the command twice: on the wire and for command monitoring.
|
||||
# Generate it once, for speed and to avoid repeating side-effects.
|
||||
@ -356,6 +359,9 @@ class _Query(object):
|
||||
client = self.client
|
||||
if client._encrypter and not client._encrypter._bypass_auto_encryption:
|
||||
cmd = client._encrypter.encrypt(self.db, cmd, self.codec_options)
|
||||
# Support CSOT
|
||||
if apply_timeout:
|
||||
sock_info.apply_timeout(client, cmd)
|
||||
self._as_command = cmd, self.db
|
||||
return self._as_command
|
||||
|
||||
@ -371,7 +377,7 @@ class _Query(object):
|
||||
spec = self.spec
|
||||
|
||||
if use_cmd:
|
||||
spec = self.as_command(sock_info)[0]
|
||||
spec = self.as_command(sock_info, apply_timeout=True)[0]
|
||||
request_id, msg, size, _ = _op_msg(
|
||||
0,
|
||||
spec,
|
||||
@ -457,6 +463,9 @@ class _GetMore(object):
|
||||
self.exhaust = exhaust
|
||||
self.comment = comment
|
||||
|
||||
def reset(self):
|
||||
self._as_command = None
|
||||
|
||||
def namespace(self):
|
||||
return "%s.%s" % (self.db, self.coll)
|
||||
|
||||
@ -471,7 +480,7 @@ class _GetMore(object):
|
||||
sock_info.validate_session(self.client, self.session)
|
||||
return use_cmd
|
||||
|
||||
def as_command(self, sock_info):
|
||||
def as_command(self, sock_info, apply_timeout=False):
|
||||
"""Return a getMore command document for this query."""
|
||||
# See _Query.as_command for an explanation of this caching.
|
||||
if self._as_command is not None:
|
||||
@ -493,6 +502,9 @@ class _GetMore(object):
|
||||
client = self.client
|
||||
if client._encrypter and not client._encrypter._bypass_auto_encryption:
|
||||
cmd = client._encrypter.encrypt(self.db, cmd, self.codec_options)
|
||||
# Support CSOT
|
||||
if apply_timeout:
|
||||
sock_info.apply_timeout(client, cmd=None)
|
||||
self._as_command = cmd, self.db
|
||||
return self._as_command
|
||||
|
||||
@ -503,7 +515,7 @@ class _GetMore(object):
|
||||
ctx = sock_info.compression_context
|
||||
|
||||
if use_cmd:
|
||||
spec = self.as_command(sock_info)[0]
|
||||
spec = self.as_command(sock_info, apply_timeout=True)[0]
|
||||
if self.sock_mgr:
|
||||
flags = _OpMsg.EXHAUST_ALLOWED
|
||||
else:
|
||||
|
||||
@ -57,6 +57,7 @@ from bson.codec_options import DEFAULT_CODEC_OPTIONS, CodecOptions, TypeRegistry
|
||||
from bson.son import SON
|
||||
from bson.timestamp import Timestamp
|
||||
from pymongo import (
|
||||
_csot,
|
||||
client_session,
|
||||
common,
|
||||
database,
|
||||
@ -260,6 +261,10 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
replaced. Defaults to `None` (no limit).
|
||||
- `maxConnecting` (optional): The maximum number of connections that
|
||||
each pool can establish concurrently. Defaults to `2`.
|
||||
- `timeoutMS`: (integer or None) Controls how long (in
|
||||
milliseconds) the driver will wait when executing an operation
|
||||
(including retry attempts) before raising a timeout error.
|
||||
``0`` or ``None`` means no timeout.
|
||||
- `socketTimeoutMS`: (integer or None) Controls how long (in
|
||||
milliseconds) the driver will wait for a response after sending an
|
||||
ordinary (non-monitoring) database operation before concluding that
|
||||
@ -540,6 +545,9 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
|
||||
.. seealso:: The MongoDB documentation on `connections <https://dochub.mongodb.org/core/connections>`_.
|
||||
|
||||
.. versionchanged:: 4.2
|
||||
Added the ``timeoutMS`` keyword argument.
|
||||
|
||||
.. versionchanged:: 4.0
|
||||
|
||||
- Removed the fsync, unlock, is_locked, database_names, and
|
||||
@ -780,6 +788,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
options.read_preference,
|
||||
options.write_concern,
|
||||
options.read_concern,
|
||||
options.timeout,
|
||||
)
|
||||
|
||||
self._topology_settings = TopologySettings(
|
||||
@ -1273,6 +1282,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
)
|
||||
|
||||
def _cmd(session, server, sock_info, read_preference):
|
||||
operation.reset() # Reset op in case of retry.
|
||||
return server.run_operation(
|
||||
sock_info, operation, read_preference, self._event_listeners, unpack_res
|
||||
)
|
||||
@ -1303,6 +1313,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
max_wire_version = 0
|
||||
last_error: Optional[Exception] = None
|
||||
retrying = False
|
||||
multiple_retries = _csot.get_timeout() is not None
|
||||
|
||||
def is_retrying():
|
||||
return bulk.retrying if bulk else retrying
|
||||
@ -1350,7 +1361,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
retryable_error = exc.has_error_label("RetryableWriteError")
|
||||
if retryable_error:
|
||||
session._unpin()
|
||||
if is_retrying() or not retryable_error:
|
||||
if not retryable_error or (is_retrying() and not multiple_retries):
|
||||
raise
|
||||
if bulk:
|
||||
bulk.retrying = True
|
||||
@ -1371,6 +1382,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
)
|
||||
last_error: Optional[Exception] = None
|
||||
retrying = False
|
||||
multiple_retries = _csot.get_timeout() is not None
|
||||
|
||||
while True:
|
||||
try:
|
||||
@ -1394,12 +1406,12 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
# most likely be a waste of time.
|
||||
raise
|
||||
except ConnectionFailure as exc:
|
||||
if not retryable or retrying:
|
||||
if not retryable or (retrying and not multiple_retries):
|
||||
raise
|
||||
retrying = True
|
||||
last_error = exc
|
||||
except OperationFailure as exc:
|
||||
if not retryable or retrying:
|
||||
if not retryable or (retrying and not multiple_retries):
|
||||
raise
|
||||
if exc.code not in helpers._RETRYABLE_ERROR_CODES:
|
||||
raise
|
||||
@ -1922,6 +1934,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
read_preference: Optional[_ServerMode] = None,
|
||||
write_concern: Optional[WriteConcern] = None,
|
||||
read_concern: Optional["ReadConcern"] = None,
|
||||
timeout: Optional[float] = None,
|
||||
) -> database.Database[_DocumentType]:
|
||||
"""Get a :class:`~pymongo.database.Database` with the given name and
|
||||
options.
|
||||
@ -1972,7 +1985,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
|
||||
name = self.__default_database_name
|
||||
|
||||
return database.Database(
|
||||
self, name, codec_options, read_preference, write_concern, read_concern
|
||||
self, name, codec_options, read_preference, write_concern, read_concern, timeout
|
||||
)
|
||||
|
||||
def _database_default_options(self, name):
|
||||
|
||||
@ -21,7 +21,7 @@ import struct
|
||||
import time
|
||||
|
||||
from bson import _decode_all_selective
|
||||
from pymongo import helpers, message
|
||||
from pymongo import _csot, helpers, message, ssl_support
|
||||
from pymongo.common import MAX_MESSAGE_SIZE
|
||||
from pymongo.compression_support import _NO_COMPRESSION, decompress
|
||||
from pymongo.errors import (
|
||||
@ -59,6 +59,7 @@ def command(
|
||||
unacknowledged=False,
|
||||
user_fields=None,
|
||||
exhaust_allowed=False,
|
||||
write_concern=None,
|
||||
):
|
||||
"""Execute a command over the socket, or raise socket.error.
|
||||
|
||||
@ -115,6 +116,12 @@ def command(
|
||||
if client and client._encrypter and not client._encrypter._bypass_auto_encryption:
|
||||
spec = orig = client._encrypter.encrypt(dbname, spec, codec_options)
|
||||
|
||||
# Support CSOT
|
||||
if client:
|
||||
sock_info.apply_timeout(client, spec, write_concern)
|
||||
elif write_concern and not write_concern.is_server_default:
|
||||
spec["writeConcern"] = write_concern.document
|
||||
|
||||
if use_op_msg:
|
||||
flags = _OpMsg.MORE_TO_COME if unacknowledged else 0
|
||||
flags |= _OpMsg.EXHAUST_ALLOWED if exhaust_allowed else 0
|
||||
@ -198,11 +205,14 @@ _UNPACK_COMPRESSION_HEADER = struct.Struct("<iiB").unpack
|
||||
|
||||
def receive_message(sock_info, request_id, max_message_size=MAX_MESSAGE_SIZE):
|
||||
"""Receive a raw BSON message or raise socket.error."""
|
||||
timeout = sock_info.sock.gettimeout()
|
||||
if timeout:
|
||||
deadline = time.monotonic() + timeout
|
||||
if _csot.get_timeout():
|
||||
deadline = _csot.get_deadline()
|
||||
else:
|
||||
deadline = None
|
||||
timeout = sock_info.sock.gettimeout()
|
||||
if timeout:
|
||||
deadline = time.monotonic() + timeout
|
||||
else:
|
||||
deadline = None
|
||||
# Ignore the response's request id.
|
||||
length, _, response_to, op_code = _UNPACK_HEADER(
|
||||
_receive_data_on_socket(sock_info, 16, deadline)
|
||||
@ -271,6 +281,10 @@ def wait_for_read(sock_info, deadline):
|
||||
raise socket.timeout("timed out")
|
||||
|
||||
|
||||
# Errors raised by sockets (and TLS sockets) when in non-blocking mode.
|
||||
BLOCKING_IO_ERRORS = (BlockingIOError,) + ssl_support.BLOCKING_IO_ERRORS
|
||||
|
||||
|
||||
def _receive_data_on_socket(sock_info, length, deadline):
|
||||
buf = bytearray(length)
|
||||
mv = memoryview(buf)
|
||||
@ -278,7 +292,14 @@ def _receive_data_on_socket(sock_info, length, deadline):
|
||||
while bytes_read < length:
|
||||
try:
|
||||
wait_for_read(sock_info, deadline)
|
||||
# CSOT: Update timeout. When the timeout has expired perform one
|
||||
# final non-blocking recv. This helps avoid spurious timeouts when
|
||||
# the response is actually already buffered on the client.
|
||||
if _csot.get_timeout():
|
||||
sock_info.set_socket_timeout(max(deadline - time.monotonic(), 0))
|
||||
chunk_length = sock_info.sock.recv_into(mv[bytes_read:])
|
||||
except BLOCKING_IO_ERRORS:
|
||||
raise socket.timeout("timed out")
|
||||
except (IOError, OSError) as exc: # noqa: B014
|
||||
if _errno_from_exception(exc) == errno.EINTR:
|
||||
continue
|
||||
|
||||
@ -48,6 +48,8 @@ from cryptography.x509.oid import ExtendedKeyUsageOID as _ExtendedKeyUsageOID
|
||||
from requests import post as _post
|
||||
from requests.exceptions import RequestException as _RequestException
|
||||
|
||||
from pymongo import _csot
|
||||
|
||||
# Note: the functions in this module generally return 1 or 0. The reason
|
||||
# is simple. The entry point, ocsp_callback, is registered as a callback
|
||||
# with OpenSSL through PyOpenSSL. The callback must return 1 (success) or
|
||||
@ -235,12 +237,16 @@ def _get_ocsp_response(cert, issuer, uri, ocsp_response_cache):
|
||||
ocsp_response = ocsp_response_cache[ocsp_request]
|
||||
_LOGGER.debug("Using cached OCSP response.")
|
||||
except KeyError:
|
||||
# CSOT: use the configured timeout or 5 seconds, whichever is smaller.
|
||||
# Note that request's timeout works differently and does not imply an absolute
|
||||
# deadline: https://requests.readthedocs.io/en/stable/user/quickstart/#timeouts
|
||||
timeout = max(_csot.clamp_remaining(5), 0.001)
|
||||
try:
|
||||
response = _post(
|
||||
uri,
|
||||
data=ocsp_request.public_bytes(_Encoding.DER),
|
||||
headers={"Content-Type": "application/ocsp-request"},
|
||||
timeout=5,
|
||||
timeout=timeout,
|
||||
)
|
||||
except _RequestException as exc:
|
||||
_LOGGER.debug("HTTP request failed: %s", exc)
|
||||
|
||||
@ -27,7 +27,7 @@ from typing import Any, NoReturn, Optional
|
||||
|
||||
from bson import DEFAULT_CODEC_OPTIONS
|
||||
from bson.son import SON
|
||||
from pymongo import __version__, auth, helpers
|
||||
from pymongo import __version__, _csot, auth, helpers
|
||||
from pymongo.client_session import _validate_session_write_concern
|
||||
from pymongo.common import (
|
||||
MAX_BSON_SIZE,
|
||||
@ -46,6 +46,7 @@ from pymongo.errors import (
|
||||
ConfigurationError,
|
||||
ConnectionFailure,
|
||||
DocumentTooLarge,
|
||||
ExecutionTimeout,
|
||||
InvalidOperation,
|
||||
NetworkTimeout,
|
||||
NotPrimaryError,
|
||||
@ -557,6 +558,43 @@ class SocketInfo(object):
|
||||
self.pinned_txn = False
|
||||
self.pinned_cursor = False
|
||||
self.active = False
|
||||
self.last_timeout = self.opts.socket_timeout
|
||||
|
||||
def set_socket_timeout(self, timeout):
|
||||
"""Cache last timeout to avoid duplicate calls to sock.settimeout."""
|
||||
if timeout == self.last_timeout:
|
||||
return
|
||||
self.last_timeout = timeout
|
||||
self.sock.settimeout(timeout)
|
||||
|
||||
def apply_timeout(self, client, cmd, write_concern=None):
|
||||
# CSOT: use remaining timeout when set.
|
||||
timeout = _csot.remaining()
|
||||
if timeout is None:
|
||||
# Reset the socket timeout unless we're performing a streaming monitor check.
|
||||
if not self.more_to_come:
|
||||
self.set_socket_timeout(self.opts.socket_timeout)
|
||||
|
||||
if cmd and write_concern and not write_concern.is_server_default:
|
||||
cmd["writeConcern"] = write_concern.document
|
||||
return None
|
||||
# RTT validation.
|
||||
rtt = _csot.get_rtt()
|
||||
max_time_ms = timeout - rtt
|
||||
if max_time_ms < 0:
|
||||
# CSOT: raise an error without running the command since we know it will time out.
|
||||
errmsg = f"operation would exceed time limit, remaining timeout:{timeout:.5f} <= network round trip time:{rtt:.5f}"
|
||||
raise ExecutionTimeout(
|
||||
errmsg, 50, {"ok": 0, "errmsg": errmsg, "code": 50}, self.max_wire_version
|
||||
)
|
||||
if cmd is not None:
|
||||
cmd["maxTimeMS"] = int(max_time_ms * 1000)
|
||||
wc = write_concern.document if write_concern else {}
|
||||
wc.pop("wtimeout", None)
|
||||
if wc:
|
||||
cmd["writeConcern"] = wc
|
||||
self.set_socket_timeout(timeout)
|
||||
return timeout
|
||||
|
||||
def pin_txn(self):
|
||||
self.pinned_txn = True
|
||||
@ -602,7 +640,7 @@ class SocketInfo(object):
|
||||
awaitable = True
|
||||
# If connect_timeout is None there is no timeout.
|
||||
if self.opts.connect_timeout:
|
||||
self.sock.settimeout(self.opts.connect_timeout + heartbeat_frequency)
|
||||
self.set_socket_timeout(self.opts.connect_timeout + heartbeat_frequency)
|
||||
|
||||
if not performing_handshake and cluster_time is not None:
|
||||
cmd["$clusterTime"] = cluster_time
|
||||
@ -714,8 +752,6 @@ class SocketInfo(object):
|
||||
|
||||
if not (write_concern is None or write_concern.acknowledged or collation is None):
|
||||
raise ConfigurationError("Collation is unsupported for unacknowledged writes.")
|
||||
if write_concern and not write_concern.is_server_default:
|
||||
spec["writeConcern"] = write_concern.document
|
||||
|
||||
self.add_server_api(spec)
|
||||
if session:
|
||||
@ -748,6 +784,7 @@ class SocketInfo(object):
|
||||
unacknowledged=unacknowledged,
|
||||
user_fields=user_fields,
|
||||
exhaust_allowed=exhaust_allowed,
|
||||
write_concern=write_concern,
|
||||
)
|
||||
except (OperationFailure, NotPrimaryError):
|
||||
raise
|
||||
@ -978,7 +1015,13 @@ def _create_connection(address, options):
|
||||
_set_non_inheritable_non_atomic(sock.fileno())
|
||||
try:
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
sock.settimeout(options.connect_timeout)
|
||||
# CSOT: apply timeout to socket connect.
|
||||
timeout = _csot.remaining()
|
||||
if timeout is None:
|
||||
timeout = options.connect_timeout
|
||||
elif timeout <= 0:
|
||||
raise socket.timeout("timed out")
|
||||
sock.settimeout(timeout)
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, True)
|
||||
_set_keepalive_times(sock)
|
||||
sock.connect(sa)
|
||||
@ -1416,7 +1459,9 @@ class Pool:
|
||||
self.operation_count += 1
|
||||
|
||||
# Get a free socket or create one.
|
||||
if self.opts.wait_queue_timeout:
|
||||
if _csot.get_timeout():
|
||||
deadline = _csot.get_deadline()
|
||||
elif self.opts.wait_queue_timeout:
|
||||
deadline = time.monotonic() + self.opts.wait_queue_timeout
|
||||
else:
|
||||
deadline = None
|
||||
@ -1582,25 +1627,25 @@ class Pool:
|
||||
listeners.publish_connection_check_out_failed(
|
||||
self.address, ConnectionCheckOutFailedReason.TIMEOUT
|
||||
)
|
||||
timeout = _csot.get_timeout() or self.opts.wait_queue_timeout
|
||||
if self.opts.load_balanced:
|
||||
other_ops = self.active_sockets - self.ncursors - self.ntxns
|
||||
raise ConnectionFailure(
|
||||
"Timeout waiting for connection from the connection pool. "
|
||||
"maxPoolSize: %s, connections in use by cursors: %s, "
|
||||
"connections in use by transactions: %s, connections in use "
|
||||
"by other operations: %s, wait_queue_timeout: %s"
|
||||
"by other operations: %s, timeout: %s"
|
||||
% (
|
||||
self.opts.max_pool_size,
|
||||
self.ncursors,
|
||||
self.ntxns,
|
||||
other_ops,
|
||||
self.opts.wait_queue_timeout,
|
||||
timeout,
|
||||
)
|
||||
)
|
||||
raise ConnectionFailure(
|
||||
"Timed out while checking out a connection from connection pool. "
|
||||
"maxPoolSize: %s, wait_queue_timeout: %s"
|
||||
% (self.opts.max_pool_size, self.opts.wait_queue_timeout)
|
||||
"maxPoolSize: %s, timeout: %s" % (self.opts.max_pool_size, timeout)
|
||||
)
|
||||
|
||||
def __del__(self):
|
||||
|
||||
@ -82,7 +82,7 @@ def _is_ip_address(address):
|
||||
|
||||
# According to the docs for Connection.send it can raise
|
||||
# WantX509LookupError and should be retried.
|
||||
_RETRY_ERRORS = (_SSL.WantReadError, _SSL.WantWriteError, _SSL.WantX509LookupError)
|
||||
BLOCKING_IO_ERRORS = (_SSL.WantReadError, _SSL.WantWriteError, _SSL.WantX509LookupError)
|
||||
|
||||
|
||||
def _ragged_eof(exc):
|
||||
@ -106,7 +106,7 @@ class _sslConn(_SSL.Connection):
|
||||
while True:
|
||||
try:
|
||||
return call(*args, **kwargs)
|
||||
except _RETRY_ERRORS as exc:
|
||||
except BLOCKING_IO_ERRORS as exc:
|
||||
if isinstance(exc, _SSL.WantReadError):
|
||||
want_read = True
|
||||
want_write = False
|
||||
|
||||
@ -27,6 +27,9 @@ OP_NO_RENEGOTIATION = getattr(_ssl, "OP_NO_RENEGOTIATION", 0)
|
||||
HAS_SNI = getattr(_ssl, "HAS_SNI", False)
|
||||
IS_PYOPENSSL = False
|
||||
|
||||
# Errors raised by SSL sockets when in non-blocking mode.
|
||||
BLOCKING_IO_ERRORS = (_ssl.SSLWantReadError, _ssl.SSLWantWriteError)
|
||||
|
||||
# Base Exception class
|
||||
SSLError = _ssl.SSLError
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ if HAVE_SSL:
|
||||
HAS_SNI = _ssl.HAS_SNI
|
||||
IPADDR_SAFE = True
|
||||
SSLError = _ssl.SSLError
|
||||
BLOCKING_IO_ERRORS = _ssl.BLOCKING_IO_ERRORS
|
||||
|
||||
def get_ssl_context(
|
||||
certfile,
|
||||
@ -91,6 +92,7 @@ else:
|
||||
|
||||
HAS_SNI = False
|
||||
IPADDR_SAFE = False
|
||||
BLOCKING_IO_ERRORS = () # type: ignore
|
||||
|
||||
def get_ssl_context(*dummy): # type: ignore
|
||||
"""No ssl module, raise ConfigurationError."""
|
||||
|
||||
@ -23,7 +23,7 @@ import warnings
|
||||
import weakref
|
||||
from typing import Any
|
||||
|
||||
from pymongo import common, helpers, periodic_executor
|
||||
from pymongo import _csot, common, helpers, periodic_executor
|
||||
from pymongo.client_session import _ServerSessionPool
|
||||
from pymongo.errors import (
|
||||
ConfigurationError,
|
||||
@ -191,6 +191,13 @@ class Topology(object):
|
||||
with self._lock:
|
||||
self._ensure_opened()
|
||||
|
||||
def get_server_selection_timeout(self):
|
||||
# CSOT: use remaining timeout when set.
|
||||
timeout = _csot.remaining()
|
||||
if timeout is None:
|
||||
return self._settings.server_selection_timeout
|
||||
return timeout
|
||||
|
||||
def select_servers(self, selector, server_selection_timeout=None, address=None):
|
||||
"""Return a list of Servers matching selector, or time out.
|
||||
|
||||
@ -208,7 +215,7 @@ class Topology(object):
|
||||
`server_selection_timeout` if no matching servers are found.
|
||||
"""
|
||||
if server_selection_timeout is None:
|
||||
server_timeout = self._settings.server_selection_timeout
|
||||
server_timeout = self.get_server_selection_timeout()
|
||||
else:
|
||||
server_timeout = server_selection_timeout
|
||||
|
||||
@ -250,8 +257,7 @@ class Topology(object):
|
||||
self._description.check_compatible()
|
||||
return server_descriptions
|
||||
|
||||
def select_server(self, selector, server_selection_timeout=None, address=None):
|
||||
"""Like select_servers, but choose a random server if several match."""
|
||||
def _select_server(self, selector, server_selection_timeout=None, address=None):
|
||||
servers = self.select_servers(selector, server_selection_timeout, address)
|
||||
if len(servers) == 1:
|
||||
return servers[0]
|
||||
@ -261,6 +267,12 @@ class Topology(object):
|
||||
else:
|
||||
return server2
|
||||
|
||||
def select_server(self, selector, server_selection_timeout=None, address=None):
|
||||
"""Like select_servers, but choose a random server if several match."""
|
||||
server = self._select_server(selector, server_selection_timeout, address)
|
||||
_csot.set_rtt(server.description.round_trip_time)
|
||||
return server
|
||||
|
||||
def select_server_by_address(self, address, server_selection_timeout=None):
|
||||
"""Return a Server for "address", reconnecting if necessary.
|
||||
|
||||
@ -535,11 +547,11 @@ class Topology(object):
|
||||
if self._description.topology_type == TOPOLOGY_TYPE.Single:
|
||||
if not self._description.has_known_servers:
|
||||
self._select_servers_loop(
|
||||
any_server_selector, self._settings.server_selection_timeout, None
|
||||
any_server_selector, self.get_server_selection_timeout(), None
|
||||
)
|
||||
elif not self._description.readable_servers:
|
||||
self._select_servers_loop(
|
||||
readable_server_selector, self._settings.server_selection_timeout, None
|
||||
readable_server_selector, self.get_server_selection_timeout(), None
|
||||
)
|
||||
|
||||
session_timeout = self._description.logical_session_timeout_minutes
|
||||
|
||||
159
test/csot/bulkWrite.json
Normal file
159
test/csot/bulkWrite.json
Normal file
@ -0,0 +1,159 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for bulkWrite operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS applied to entire bulkWrite, not individual commands",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert",
|
||||
"update"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bulkWrite",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"requests": [
|
||||
{
|
||||
"insertOne": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"replaceOne": {
|
||||
"filter": {
|
||||
"_id": 1
|
||||
},
|
||||
"replacement": {
|
||||
"x": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"timeoutMS": 200
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "update",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"update": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
598
test/csot/change-streams.json
Normal file
598
test/csot/change-streams.json
Normal file
@ -0,0 +1,598 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for change streams",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
],
|
||||
"ignoreCommandMonitoringEvents": [
|
||||
"killCursors"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "error if maxAwaitTimeMS is greater than timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 5,
|
||||
"maxAwaitTimeMS": 10
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "error if maxAwaitTimeMS is equal to timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 5,
|
||||
"maxAwaitTimeMS": 5
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to initial aggregate",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"aggregate"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if maxAwaitTimeMS is not set",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"aggregate",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 1050
|
||||
},
|
||||
"saveResultAsEntity": "changeStream"
|
||||
},
|
||||
{
|
||||
"name": "iterateOnce",
|
||||
"object": "changeStream"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if maxAwaitTimeMS is set",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"aggregate",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 2,
|
||||
"maxAwaitTimeMS": 1
|
||||
},
|
||||
"saveResultAsEntity": "changeStream"
|
||||
},
|
||||
{
|
||||
"name": "iterateOnce",
|
||||
"object": "changeStream"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applies to full resume attempt in a next call",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 20
|
||||
},
|
||||
"saveResultAsEntity": "changeStream"
|
||||
},
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore",
|
||||
"aggregate"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 12,
|
||||
"errorCode": 7,
|
||||
"errorLabels": [
|
||||
"ResumableChangeStreamError"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "changeStream",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "change stream can be iterated again if previous iteration times out",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"maxAwaitTimeMS": 1,
|
||||
"timeoutMS": 100
|
||||
},
|
||||
"saveResultAsEntity": "changeStream"
|
||||
},
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 150
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "changeStream",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iterateOnce",
|
||||
"object": "changeStream"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore - failure",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createChangeStream",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMS": 10
|
||||
},
|
||||
"saveResultAsEntity": "changeStream"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "changeStream",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "aggregate",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"aggregate": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
239
test/csot/close-cursors.json
Normal file
239
test/csot/close-cursors.json
Normal file
@ -0,0 +1,239 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly when closing cursors",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent",
|
||||
"commandSucceededEvent",
|
||||
"commandFailedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 0
|
||||
},
|
||||
{
|
||||
"_id": 1
|
||||
},
|
||||
{
|
||||
"_id": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS is refreshed for close",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"batchSize": 2,
|
||||
"timeoutMS": 20
|
||||
},
|
||||
"saveResultAsEntity": "cursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "cursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "cursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "cursor",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
"object": "cursor"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "find"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "getMore"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"killCursors": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
},
|
||||
"commandName": "killCursors"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "killCursors"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS can be overridden for close",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "client",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"killCursors"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"batchSize": 2,
|
||||
"timeoutMS": 20
|
||||
},
|
||||
"saveResultAsEntity": "cursor"
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
"object": "cursor",
|
||||
"arguments": {
|
||||
"timeoutMS": 40
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "find"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"killCursors": "collection",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
},
|
||||
"commandName": "killCursors"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "killCursors"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
260
test/csot/command-execution.json
Normal file
260
test/csot/command-execution.json
Normal file
@ -0,0 +1,260 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly during command execution",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.9"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
},
|
||||
{
|
||||
"collectionName": "timeoutColl",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "maxTimeMS value in the command is less than timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": "alwaysOn",
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"hello",
|
||||
"isMaster"
|
||||
],
|
||||
"appName": "reduceMaxTimeMSTest",
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"uriOptions": {
|
||||
"appName": "reduceMaxTimeMSTest",
|
||||
"w": 1
|
||||
},
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "regularCollection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "timeoutCollection",
|
||||
"database": "database",
|
||||
"collectionName": "timeoutColl",
|
||||
"collectionOptions": {
|
||||
"timeoutMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "regularCollection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "timeoutCollection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "timeoutColl",
|
||||
"maxTimeMS": {
|
||||
"$$lte": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "command is not sent if RTT is greater than timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": "alwaysOn",
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"hello",
|
||||
"isMaster"
|
||||
],
|
||||
"appName": "rttTooHighTest",
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"uriOptions": {
|
||||
"appName": "rttTooHighTest",
|
||||
"w": 1
|
||||
},
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "regularCollection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "timeoutCollection",
|
||||
"database": "database",
|
||||
"collectionName": "timeoutColl",
|
||||
"collectionOptions": {
|
||||
"timeoutMS": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "regularCollection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "timeoutCollection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 2
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
191
test/csot/convenient-transactions.json
Normal file
191
test/csot/convenient-transactions.json
Normal file
@ -0,0 +1,191 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for the withTransaction API",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"session": {
|
||||
"id": "session",
|
||||
"client": "client"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "withTransaction raises a client-side error if timeoutMS is overridden inside the callback",
|
||||
"operations": [
|
||||
{
|
||||
"name": "withTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"callback": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
},
|
||||
"session": "session",
|
||||
"timeoutMS": 100
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is not refreshed for each operation in the callback",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "withTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"callback": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
},
|
||||
"session": "session"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 2
|
||||
},
|
||||
"session": "session"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
113
test/csot/cursors.json
Normal file
113
test/csot/cursors.json
Normal file
@ -0,0 +1,113 @@
|
||||
{
|
||||
"description": "tests for timeoutMS behavior that applies to all cursor types",
|
||||
"schemaVersion": "1.0",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client"
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "find errors if timeoutMode is set and timeoutMS is not",
|
||||
"operations": [
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "collection aggregate errors if timeoutMode is set and timeoutMS is not",
|
||||
"operations": [
|
||||
{
|
||||
"name": "aggregate",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "database aggregate errors if timeoutMode is set and timeoutMS is not",
|
||||
"operations": [
|
||||
{
|
||||
"name": "aggregate",
|
||||
"object": "database",
|
||||
"arguments": {
|
||||
"pipeline": [],
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "listCollections errors if timeoutMode is set and timeoutMS is not",
|
||||
"operations": [
|
||||
{
|
||||
"name": "listCollections",
|
||||
"object": "database",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "listIndexes errors if timeoutMode is set and timeoutMS is not",
|
||||
"operations": [
|
||||
{
|
||||
"name": "listIndexes",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
7179
test/csot/deprecated-options.json
Normal file
7179
test/csot/deprecated-options.json
Normal file
File diff suppressed because it is too large
Load Diff
181
test/csot/error-transformations.json
Normal file
181
test/csot/error-transformations.json
Normal file
@ -0,0 +1,181 @@
|
||||
{
|
||||
"description": "MaxTimeMSExpired server errors are transformed into a custom timeout error",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.0",
|
||||
"topologies": [
|
||||
"replicaset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"minServerVersion": "4.2",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 250
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "basic MaxTimeMSExpired error is transformed",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"errorCode": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "write concern error MaxTimeMSExpired is transformed",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"writeConcernError": {
|
||||
"code": 50,
|
||||
"errmsg": "maxTimeMS expired"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
5830
test/csot/global-timeoutMS.json
Normal file
5830
test/csot/global-timeoutMS.json
Normal file
File diff suppressed because it is too large
Load Diff
370
test/csot/gridfs-advanced.json
Normal file
370
test/csot/gridfs-advanced.json
Normal file
@ -0,0 +1,370 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for advanced GridFS API operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bucket": {
|
||||
"id": "bucket",
|
||||
"database": "database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "filesCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "chunksCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.chunks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "fs.files",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"length": 10,
|
||||
"chunkSize": 4,
|
||||
"uploadDate": {
|
||||
"$date": "1970-01-01T00:00:00.000Z"
|
||||
},
|
||||
"md5": "57d83cd477bfb1ccd975ab33d827a92b",
|
||||
"filename": "length-10",
|
||||
"contentType": "application/octet-stream",
|
||||
"aliases": [],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionName": "fs.chunks",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"files_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"n": 0,
|
||||
"data": {
|
||||
"$binary": {
|
||||
"base64": "ESIzRA==",
|
||||
"subType": "00"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for a rename",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"update"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rename",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"newFilename": "foo",
|
||||
"timeoutMS": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "update",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"update": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to update during a rename",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"update"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rename",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"newFilename": "foo"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "update",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"update": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS can be overridden for drop",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"drop"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drop",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"timeoutMS": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to files collection drop",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"drop"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drop",
|
||||
"object": "bucket",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "drop",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"drop": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to chunks collection drop",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"drop"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drop",
|
||||
"object": "bucket",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to drop as a whole, not individual parts",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"drop"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "drop",
|
||||
"object": "bucket",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
270
test/csot/gridfs-delete.json
Normal file
270
test/csot/gridfs-delete.json
Normal file
@ -0,0 +1,270 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for GridFS delete operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bucket": {
|
||||
"id": "bucket",
|
||||
"database": "database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "filesCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "chunksCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.chunks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "fs.files",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"length": 10,
|
||||
"chunkSize": 4,
|
||||
"uploadDate": {
|
||||
"$date": "1970-01-01T00:00:00.000Z"
|
||||
},
|
||||
"md5": "57d83cd477bfb1ccd975ab33d827a92b",
|
||||
"filename": "length-10",
|
||||
"contentType": "application/octet-stream",
|
||||
"aliases": [],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionName": "fs.chunks",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"files_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"n": 0,
|
||||
"data": {
|
||||
"$binary": {
|
||||
"base64": "ESIzRA==",
|
||||
"subType": "00"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for delete",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"delete"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"timeoutMS": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to delete against the files collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"delete"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "delete",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"delete": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to delete against the chunks collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"delete"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to entire delete, not individual parts",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"delete"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delete",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
344
test/csot/gridfs-download.json
Normal file
344
test/csot/gridfs-download.json
Normal file
@ -0,0 +1,344 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for GridFS download operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bucket": {
|
||||
"id": "bucket",
|
||||
"database": "database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "filesCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "chunksCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.chunks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "fs.files",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"length": 10,
|
||||
"chunkSize": 4,
|
||||
"uploadDate": {
|
||||
"$date": "1970-01-01T00:00:00.000Z"
|
||||
},
|
||||
"md5": "57d83cd477bfb1ccd975ab33d827a92b",
|
||||
"filename": "length-10",
|
||||
"contentType": "application/octet-stream",
|
||||
"aliases": [],
|
||||
"metadata": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionName": "fs.chunks",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"files_id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"n": 0,
|
||||
"data": {
|
||||
"$binary": {
|
||||
"base64": "ESIzRA==",
|
||||
"subType": "00"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for download",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "download",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
},
|
||||
"timeoutMS": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find to get files document",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "download",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find to get chunks",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "download",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.chunks",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to entire download, not individual parts",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "download",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"id": {
|
||||
"$oid": "000000000000000000000005"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.chunks",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
182
test/csot/gridfs-find.json
Normal file
182
test/csot/gridfs-find.json
Normal file
@ -0,0 +1,182 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for GridFS find operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bucket": {
|
||||
"id": "bucket",
|
||||
"database": "database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "filesCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "chunksCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.chunks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "fs.files",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
},
|
||||
{
|
||||
"collectionName": "fs.chunks",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for a find",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMS": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find command",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filter": {}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "fs.files",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
408
test/csot/gridfs-upload.json
Normal file
408
test/csot/gridfs-upload.json
Normal file
@ -0,0 +1,408 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for GridFS upload operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bucket": {
|
||||
"id": "bucket",
|
||||
"database": "database"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "filesCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "chunksCollection",
|
||||
"database": "database",
|
||||
"collectionName": "fs.chunks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "fs.files",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
},
|
||||
{
|
||||
"collectionName": "fs.chunks",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for upload",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
},
|
||||
"timeoutMS": 1000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to initial find on files collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to listIndexes on files collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"listIndexes"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to index creation for files collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"createIndexes"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to listIndexes on chunks collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"listIndexes"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to index creation for chunks collection",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"createIndexes"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to chunk insertion",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to creation of files document",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"skip": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 55
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to upload as a whole, not individual parts",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"listIndexes"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "upload",
|
||||
"object": "bucket",
|
||||
"arguments": {
|
||||
"filename": "filename",
|
||||
"source": {
|
||||
"$$hexBytes": "1122334455"
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
379
test/csot/legacy-timeouts.json
Normal file
379
test/csot/legacy-timeouts.json
Normal file
@ -0,0 +1,379 @@
|
||||
{
|
||||
"description": "legacy timeouts continue to work if timeoutMS is not set",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "socketTimeoutMS is not used to derive a maxTimeMS command field",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
],
|
||||
"uriOptions": {
|
||||
"socketTimeoutMS": 50000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"x": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "waitQueueTimeoutMS is not used to derive a maxTimeMS command field",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
],
|
||||
"uriOptions": {
|
||||
"waitQueueTimeoutMS": 50000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"x": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "wTimeoutMS is not used to derive a maxTimeMS command field",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
],
|
||||
"uriOptions": {
|
||||
"wTimeoutMS": 50000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"x": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
},
|
||||
"writeConcern": {
|
||||
"wtimeout": 50000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "maxTimeMS option is used directly as the maxTimeMS field on a command",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "estimatedDocumentCount",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"maxTimeMS": 50000
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "count",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"count": "coll",
|
||||
"maxTimeMS": 50000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "maxCommitTimeMS option is used directly as the maxTimeMS field on a commitTransaction command",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"session": {
|
||||
"id": "session",
|
||||
"client": "client",
|
||||
"sessionOptions": {
|
||||
"defaultTransactionOptions": {
|
||||
"maxCommitTimeMS": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1
|
||||
},
|
||||
"session": "session"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "commitTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"maxTimeMS": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
541
test/csot/non-tailable-cursors.json
Normal file
541
test/csot/non-tailable-cursors.json
Normal file
@ -0,0 +1,541 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for non-tailable cursors",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 10
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
],
|
||||
"ignoreCommandMonitoringEvents": [
|
||||
"killCursors"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 0
|
||||
},
|
||||
{
|
||||
"_id": 1
|
||||
},
|
||||
{
|
||||
"_id": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"collectionName": "aggregateOutputColl",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS applied to find if timeoutMode is cursor_lifetime",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "remaining timeoutMS applied to getMore if timeoutMode is unset",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 2
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "remaining timeoutMS applied to getMore if timeoutMode is cursor_lifetime",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime",
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 2
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find if timeoutMode is iteration",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "iteration"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if timeoutMode is iteration - success",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "iteration",
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if timeoutMode is iteration - failure",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "iteration",
|
||||
"batchSize": 2
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "aggregate with $out errors if timeoutMode is iteration",
|
||||
"operations": [
|
||||
{
|
||||
"name": "aggregate",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [
|
||||
{
|
||||
"$out": "aggregateOutputColl"
|
||||
}
|
||||
],
|
||||
"timeoutMS": 100,
|
||||
"timeoutMode": "iteration"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "aggregate with $merge errors if timeoutMode is iteration",
|
||||
"operations": [
|
||||
{
|
||||
"name": "aggregate",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"pipeline": [
|
||||
{
|
||||
"$merge": "aggregateOutputColl"
|
||||
}
|
||||
],
|
||||
"timeoutMS": 100,
|
||||
"timeoutMode": "iteration"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
3498
test/csot/override-collection-timeoutMS.json
Normal file
3498
test/csot/override-collection-timeoutMS.json
Normal file
File diff suppressed because it is too large
Load Diff
4622
test/csot/override-database-timeoutMS.json
Normal file
4622
test/csot/override-database-timeoutMS.json
Normal file
File diff suppressed because it is too large
Load Diff
3577
test/csot/override-operation-timeoutMS.json
Normal file
3577
test/csot/override-operation-timeoutMS.json
Normal file
File diff suppressed because it is too large
Load Diff
3042
test/csot/retryability-legacy-timeouts.json
Normal file
3042
test/csot/retryability-legacy-timeouts.json
Normal file
File diff suppressed because it is too large
Load Diff
5439
test/csot/retryability-timeoutMS.json
Normal file
5439
test/csot/retryability-timeoutMS.json
Normal file
File diff suppressed because it is too large
Load Diff
311
test/csot/sessions-inherit-timeoutMS.json
Normal file
311
test/csot/sessions-inherit-timeoutMS.json
Normal file
@ -0,0 +1,311 @@
|
||||
{
|
||||
"description": "sessions inherit timeoutMS from their parent MongoClient",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent",
|
||||
"commandSucceededEvent",
|
||||
"commandFailedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"session": {
|
||||
"id": "session",
|
||||
"client": "client"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS applied to commitTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"commitTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "commitTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "commitTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to abortTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"abortTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "abortTransaction",
|
||||
"object": "session"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "abortTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"abortTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "abortTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to withTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "withTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"callback": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
315
test/csot/sessions-override-operation-timeoutMS.json
Normal file
315
test/csot/sessions-override-operation-timeoutMS.json
Normal file
@ -0,0 +1,315 @@
|
||||
{
|
||||
"description": "timeoutMS can be overridden for individual session operations",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent",
|
||||
"commandSucceededEvent",
|
||||
"commandFailedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"session": {
|
||||
"id": "session",
|
||||
"client": "client"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS can be overridden for commitTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"commitTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"timeoutMS": 50
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "commitTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "commitTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to abortTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"abortTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "abortTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"timeoutMS": 50
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "abortTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"abortTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "abortTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to withTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "withTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"timeoutMS": 50,
|
||||
"callback": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
311
test/csot/sessions-override-timeoutMS.json
Normal file
311
test/csot/sessions-override-timeoutMS.json
Normal file
@ -0,0 +1,311 @@
|
||||
{
|
||||
"description": "timeoutMS can be overridden at the level of a ClientSession",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4",
|
||||
"topologies": [
|
||||
"replicaset",
|
||||
"sharded-replicaset"
|
||||
]
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent",
|
||||
"commandSucceededEvent",
|
||||
"commandFailedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
},
|
||||
{
|
||||
"session": {
|
||||
"id": "session",
|
||||
"client": "client",
|
||||
"sessionOptions": {
|
||||
"defaultTimeoutMS": 50
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "timeoutMS applied to commitTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"commitTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "commitTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "commitTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to abortTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"abortTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "abortTransaction",
|
||||
"object": "session"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandSucceededEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "abortTransaction",
|
||||
"databaseName": "admin",
|
||||
"command": {
|
||||
"abortTransaction": 1,
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "abortTransaction"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to withTransaction",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"insert"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "withTransaction",
|
||||
"object": "session",
|
||||
"arguments": {
|
||||
"callback": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "insert",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"insert": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandFailedEvent": {
|
||||
"commandName": "insert"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
422
test/csot/tailable-awaitData.json
Normal file
422
test/csot/tailable-awaitData.json
Normal file
@ -0,0 +1,422 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for tailable awaitData cursors",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 10
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"createOptions": {
|
||||
"capped": true,
|
||||
"size": 500
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"_id": 0
|
||||
},
|
||||
{
|
||||
"_id": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "error if timeoutMode is cursor_lifetime",
|
||||
"operations": [
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime",
|
||||
"cursorType": "tailableAwait"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "error if maxAwaitTimeMS is greater than timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait",
|
||||
"timeoutMS": 5,
|
||||
"maxAwaitTimeMS": 10
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "error if maxAwaitTimeMS is equal to timeoutMS",
|
||||
"operations": [
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait",
|
||||
"timeoutMS": 5,
|
||||
"maxAwaitTimeMS": 5
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": true,
|
||||
"maxTimeMS": {
|
||||
"$$exists": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if maxAwaitTimeMS is not set",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait",
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 1
|
||||
},
|
||||
"saveResultAsEntity": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": true,
|
||||
"maxTimeMS": {
|
||||
"$$exists": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore if maxAwaitTimeMS is set",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait",
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 1,
|
||||
"maxAwaitTimeMS": 1
|
||||
},
|
||||
"saveResultAsEntity": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": true,
|
||||
"maxTimeMS": {
|
||||
"$$exists": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore - failure",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailableAwait",
|
||||
"batchSize": 1
|
||||
},
|
||||
"saveResultAsEntity": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": true,
|
||||
"maxTimeMS": {
|
||||
"$$exists": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
312
test/csot/tailable-non-awaitData.json
Normal file
312
test/csot/tailable-non-awaitData.json
Normal file
@ -0,0 +1,312 @@
|
||||
{
|
||||
"description": "timeoutMS behaves correctly for tailable non-awaitData cursors",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "4.4"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "failPointClient",
|
||||
"useMultipleMongoses": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"client": {
|
||||
"id": "client",
|
||||
"uriOptions": {
|
||||
"timeoutMS": 10
|
||||
},
|
||||
"useMultipleMongoses": false,
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database",
|
||||
"client": "client",
|
||||
"databaseName": "test"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection",
|
||||
"database": "database",
|
||||
"collectionName": "coll"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll",
|
||||
"databaseName": "test",
|
||||
"createOptions": {
|
||||
"capped": true,
|
||||
"size": 500
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"_id": 0
|
||||
},
|
||||
{
|
||||
"_id": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "error if timeoutMode is cursor_lifetime",
|
||||
"operations": [
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"timeoutMode": "cursorLifetime",
|
||||
"cursorType": "tailable"
|
||||
},
|
||||
"expectError": {
|
||||
"isClientError": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS applied to find",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "find",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailable"
|
||||
},
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": {
|
||||
"$$exists": false
|
||||
},
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore - success",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"find",
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailable",
|
||||
"timeoutMS": 20,
|
||||
"batchSize": 1
|
||||
},
|
||||
"saveResultAsEntity": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": {
|
||||
"$$exists": false
|
||||
},
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS is refreshed for getMore - failure",
|
||||
"operations": [
|
||||
{
|
||||
"name": "failPoint",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"client": "failPointClient",
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 1
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"getMore"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 15
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"cursorType": "tailable",
|
||||
"batchSize": 1
|
||||
},
|
||||
"saveResultAsEntity": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "tailableCursor",
|
||||
"expectError": {
|
||||
"isTimeoutError": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "find",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"find": "coll",
|
||||
"tailable": true,
|
||||
"awaitData": {
|
||||
"$$exists": false
|
||||
},
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"commandName": "getMore",
|
||||
"databaseName": "test",
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": [
|
||||
"int",
|
||||
"long"
|
||||
]
|
||||
},
|
||||
"collection": "coll",
|
||||
"maxTimeMS": {
|
||||
"$$exists": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
32
test/test_csot.py
Normal file
32
test/test_csot.py
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright 2022-present MongoDB, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
"""Test the CSOT unified spec tests."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path[0:0] = [""]
|
||||
|
||||
from test import unittest
|
||||
from test.unified_format import generate_test_classes
|
||||
|
||||
# Location of JSON test specifications.
|
||||
TEST_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "csot")
|
||||
|
||||
# Generate unified tests.
|
||||
globals().update(generate_test_classes(TEST_PATH, module=__name__))
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -395,7 +395,7 @@ class TestIntegration(SpecRunner):
|
||||
"""Run the recordPrimary test operation."""
|
||||
self._previous_primary = self.scenario_client.primary
|
||||
|
||||
def wait_for_primary_change(self, timeout_ms):
|
||||
def wait_for_primary_change(self, timeout):
|
||||
"""Run the waitForPrimaryChange test operation."""
|
||||
|
||||
def primary_changed():
|
||||
@ -404,7 +404,6 @@ class TestIntegration(SpecRunner):
|
||||
return False
|
||||
return primary != self._previous_primary
|
||||
|
||||
timeout = timeout_ms / 1000.0
|
||||
wait_until(primary_changed, "change primary", timeout=timeout)
|
||||
|
||||
def wait(self, ms):
|
||||
|
||||
159
test/transactions/legacy/error-labels-blockConnection.json
Normal file
159
test/transactions/legacy/error-labels-blockConnection.json
Normal file
@ -0,0 +1,159 @@
|
||||
{
|
||||
"runOn": [
|
||||
{
|
||||
"minServerVersion": "4.2",
|
||||
"topology": [
|
||||
"replicaset",
|
||||
"sharded"
|
||||
]
|
||||
}
|
||||
],
|
||||
"database_name": "transaction-tests",
|
||||
"collection_name": "test",
|
||||
"data": [],
|
||||
"tests": [
|
||||
{
|
||||
"description": "add RetryableWriteError and UnknownTransactionCommitResult labels to connection errors",
|
||||
"clientOptions": {
|
||||
"socketTimeoutMS": 100
|
||||
},
|
||||
"failPoint": {
|
||||
"configureFailPoint": "failCommand",
|
||||
"mode": {
|
||||
"times": 2
|
||||
},
|
||||
"data": {
|
||||
"failCommands": [
|
||||
"commitTransaction"
|
||||
],
|
||||
"blockConnection": true,
|
||||
"blockTimeMS": 150
|
||||
}
|
||||
},
|
||||
"operations": [
|
||||
{
|
||||
"name": "startTransaction",
|
||||
"object": "session0"
|
||||
},
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection",
|
||||
"arguments": {
|
||||
"session": "session0",
|
||||
"document": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"insertedId": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session0",
|
||||
"result": {
|
||||
"errorLabelsContain": [
|
||||
"RetryableWriteError",
|
||||
"UnknownTransactionCommitResult"
|
||||
],
|
||||
"errorLabelsOmit": [
|
||||
"TransientTransactionError"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "commitTransaction",
|
||||
"object": "session0"
|
||||
}
|
||||
],
|
||||
"expectations": [
|
||||
{
|
||||
"command_started_event": {
|
||||
"command": {
|
||||
"insert": "test",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1
|
||||
}
|
||||
],
|
||||
"ordered": true,
|
||||
"readConcern": null,
|
||||
"lsid": "session0",
|
||||
"txnNumber": {
|
||||
"$numberLong": "1"
|
||||
},
|
||||
"startTransaction": true,
|
||||
"autocommit": false,
|
||||
"writeConcern": null
|
||||
},
|
||||
"command_name": "insert",
|
||||
"database_name": "transaction-tests"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command_started_event": {
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"lsid": "session0",
|
||||
"txnNumber": {
|
||||
"$numberLong": "1"
|
||||
},
|
||||
"startTransaction": null,
|
||||
"autocommit": false,
|
||||
"writeConcern": null
|
||||
},
|
||||
"command_name": "commitTransaction",
|
||||
"database_name": "admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command_started_event": {
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"lsid": "session0",
|
||||
"txnNumber": {
|
||||
"$numberLong": "1"
|
||||
},
|
||||
"startTransaction": null,
|
||||
"autocommit": false,
|
||||
"writeConcern": {
|
||||
"w": "majority",
|
||||
"wtimeout": 10000
|
||||
}
|
||||
},
|
||||
"command_name": "commitTransaction",
|
||||
"database_name": "admin"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command_started_event": {
|
||||
"command": {
|
||||
"commitTransaction": 1,
|
||||
"lsid": "session0",
|
||||
"txnNumber": {
|
||||
"$numberLong": "1"
|
||||
},
|
||||
"startTransaction": null,
|
||||
"autocommit": false,
|
||||
"writeConcern": {
|
||||
"w": "majority",
|
||||
"wtimeout": 10000
|
||||
}
|
||||
},
|
||||
"command_name": "commitTransaction",
|
||||
"database_name": "admin"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outcome": {
|
||||
"collection": {
|
||||
"data": [
|
||||
{
|
||||
"_id": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
{
|
||||
"description": "collectionData-createOptions-type",
|
||||
"schemaVersion": "1.9",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "foo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "foo",
|
||||
"databaseName": "foo",
|
||||
"createOptions": 0,
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "foo",
|
||||
"operations": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -18,8 +18,7 @@
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "foo",
|
||||
"foo": 0
|
||||
"collectionName": "foo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
{
|
||||
"description": "collectionOrDatabaseOptions-timeoutMS-type",
|
||||
"schemaVersion": "1.9",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "foo",
|
||||
"databaseOptions": {
|
||||
"timeoutMS": 4.5
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "foo",
|
||||
"operations": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
{
|
||||
"description": "expectedError-isTimeoutError-type",
|
||||
"schemaVersion": "1.9",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "foo",
|
||||
"operations": [
|
||||
{
|
||||
"name": "foo",
|
||||
"object": "client0",
|
||||
"expectError": {
|
||||
"isTimeoutError": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
{
|
||||
"description": "expectedEventsForClient-ignoreExtraEvents-type",
|
||||
"schemaVersion": "1.7",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "foo",
|
||||
"operations": [],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client0",
|
||||
"events": [],
|
||||
"ignoreExtraEvents": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
{
|
||||
"description": "collectionData-createOptions",
|
||||
"schemaVersion": "1.9",
|
||||
"runOnRequirements": [
|
||||
{
|
||||
"minServerVersion": "3.6"
|
||||
}
|
||||
],
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "database0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "coll0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll0",
|
||||
"databaseName": "database0",
|
||||
"createOptions": {
|
||||
"capped": true,
|
||||
"size": 512
|
||||
},
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1,
|
||||
"x": 11
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "collection is created with the correct options",
|
||||
"operations": [
|
||||
{
|
||||
"name": "runCommand",
|
||||
"object": "database0",
|
||||
"arguments": {
|
||||
"commandName": "collStats",
|
||||
"command": {
|
||||
"collStats": "coll0",
|
||||
"scale": 1
|
||||
}
|
||||
},
|
||||
"expectResult": {
|
||||
"capped": true,
|
||||
"maxSize": 512
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
{
|
||||
"description": "createEntities-operation",
|
||||
"schemaVersion": "1.9",
|
||||
"tests": [
|
||||
{
|
||||
"description": "createEntities operation",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createEntities",
|
||||
"object": "testRunner",
|
||||
"arguments": {
|
||||
"entities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client1",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database1",
|
||||
"client": "client1",
|
||||
"databaseName": "database1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection1",
|
||||
"database": "database1",
|
||||
"collectionName": "coll1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "deleteOne",
|
||||
"object": "collection1",
|
||||
"arguments": {
|
||||
"filter": {
|
||||
"_id": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client1",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"delete": "coll1",
|
||||
"deletes": [
|
||||
{
|
||||
"q": {
|
||||
"_id": 1
|
||||
},
|
||||
"limit": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"commandName": "delete",
|
||||
"databaseName": "database1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
{
|
||||
"description": "entity-cursor-iterateOnce",
|
||||
"schemaVersion": "1.9",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "database0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "coll0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"databaseName": "database0",
|
||||
"collectionName": "coll0",
|
||||
"documents": [
|
||||
{
|
||||
"_id": 1
|
||||
},
|
||||
{
|
||||
"_id": 2
|
||||
},
|
||||
{
|
||||
"_id": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "iterateOnce",
|
||||
"operations": [
|
||||
{
|
||||
"name": "createFindCursor",
|
||||
"object": "collection0",
|
||||
"arguments": {
|
||||
"filter": {},
|
||||
"batchSize": 2
|
||||
},
|
||||
"saveResultAsEntity": "cursor0"
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "cursor0",
|
||||
"expectResult": {
|
||||
"_id": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iterateUntilDocumentOrError",
|
||||
"object": "cursor0",
|
||||
"expectResult": {
|
||||
"_id": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iterateOnce",
|
||||
"object": "cursor0"
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client0",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"find": "coll0",
|
||||
"filter": {},
|
||||
"batchSize": 2
|
||||
},
|
||||
"commandName": "find",
|
||||
"databaseName": "database0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"getMore": {
|
||||
"$$type": "long"
|
||||
},
|
||||
"collection": "coll0"
|
||||
},
|
||||
"commandName": "getMore"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
{
|
||||
"description": "matches-lte-operator",
|
||||
"schemaVersion": "1.9",
|
||||
"createEntities": [
|
||||
{
|
||||
"client": {
|
||||
"id": "client0",
|
||||
"observeEvents": [
|
||||
"commandStartedEvent"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"database": {
|
||||
"id": "database0",
|
||||
"client": "client0",
|
||||
"databaseName": "database0Name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"collection": {
|
||||
"id": "collection0",
|
||||
"database": "database0",
|
||||
"collectionName": "coll0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"initialData": [
|
||||
{
|
||||
"collectionName": "coll0",
|
||||
"databaseName": "database0Name",
|
||||
"documents": []
|
||||
}
|
||||
],
|
||||
"tests": [
|
||||
{
|
||||
"description": "special lte matching operator",
|
||||
"operations": [
|
||||
{
|
||||
"name": "insertOne",
|
||||
"object": "collection0",
|
||||
"arguments": {
|
||||
"document": {
|
||||
"_id": 1,
|
||||
"y": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"expectEvents": [
|
||||
{
|
||||
"client": "client0",
|
||||
"events": [
|
||||
{
|
||||
"commandStartedEvent": {
|
||||
"command": {
|
||||
"insert": "coll0",
|
||||
"documents": [
|
||||
{
|
||||
"_id": {
|
||||
"$$lte": 1
|
||||
},
|
||||
"y": {
|
||||
"$$lte": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"commandName": "insert",
|
||||
"databaseName": "database0Name"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -42,6 +42,7 @@ from test.utils import (
|
||||
from test.version import Version
|
||||
from typing import Any
|
||||
|
||||
import pymongo
|
||||
from bson import SON, Code, DBRef, Decimal128, Int64, MaxKey, MinKey, json_util
|
||||
from bson.binary import Binary
|
||||
from bson.objectid import ObjectId
|
||||
@ -56,9 +57,13 @@ from pymongo.errors import (
|
||||
BulkWriteError,
|
||||
ConfigurationError,
|
||||
ConnectionFailure,
|
||||
ExecutionTimeout,
|
||||
InvalidOperation,
|
||||
NetworkTimeout,
|
||||
NotPrimaryError,
|
||||
PyMongoError,
|
||||
ServerSelectionTimeoutError,
|
||||
WriteConcernError,
|
||||
)
|
||||
from pymongo.monitoring import (
|
||||
_SENSITIVE_COMMANDS,
|
||||
@ -198,11 +203,16 @@ def parse_bulk_write_error_result(error):
|
||||
class NonLazyCursor(object):
|
||||
"""A find cursor proxy that creates the remote cursor when initialized."""
|
||||
|
||||
def __init__(self, find_cursor):
|
||||
def __init__(self, find_cursor, client):
|
||||
self.client = client
|
||||
self.find_cursor = find_cursor
|
||||
# Create the server side cursor.
|
||||
self.first_result = next(find_cursor, None)
|
||||
|
||||
@property
|
||||
def alive(self):
|
||||
return self.first_result is not None or self.find_cursor.alive
|
||||
|
||||
def __next__(self):
|
||||
if self.first_result is not None:
|
||||
first = self.first_result
|
||||
@ -210,8 +220,12 @@ class NonLazyCursor(object):
|
||||
return first
|
||||
return next(self.find_cursor)
|
||||
|
||||
# Added to support the iterateOnce operation.
|
||||
try_next = __next__
|
||||
|
||||
def close(self):
|
||||
self.find_cursor.close()
|
||||
self.client = None
|
||||
|
||||
|
||||
class EventListenerUtil(CMAPListener, CommandListener):
|
||||
@ -520,6 +534,11 @@ class MatchEvaluatorUtil(object):
|
||||
expected_lsid = self.test.entity_map.get_lsid_for_session(spec)
|
||||
self.test.assertEqual(expected_lsid, actual[key_to_compare])
|
||||
|
||||
def _operation_lte(self, spec, actual, key_to_compare):
|
||||
if key_to_compare not in actual:
|
||||
self.test.fail(f"Actual command is missing the {key_to_compare} field: {spec}")
|
||||
self.test.assertLessEqual(actual[key_to_compare], spec)
|
||||
|
||||
def _evaluate_special_operation(self, opname, spec, actual, key_to_compare):
|
||||
method_name = "_operation_%s" % (opname.strip("$"),)
|
||||
try:
|
||||
@ -710,7 +729,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
a class attribute ``TEST_SPEC``.
|
||||
"""
|
||||
|
||||
SCHEMA_VERSION = Version.from_string("1.7")
|
||||
SCHEMA_VERSION = Version.from_string("1.9")
|
||||
RUN_ON_LOAD_BALANCER = True
|
||||
RUN_ON_SERVERLESS = True
|
||||
TEST_SPEC: Any
|
||||
@ -730,6 +749,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
for i, collection_data in enumerate(initial_data):
|
||||
coll_name = collection_data["collectionName"]
|
||||
db_name = collection_data["databaseName"]
|
||||
opts = collection_data.get("createOptions", {})
|
||||
documents = collection_data["documents"]
|
||||
|
||||
# Setup the collection with as few majority writes as possible.
|
||||
@ -741,10 +761,12 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
else:
|
||||
wc = WriteConcern(w=1)
|
||||
if documents:
|
||||
if opts:
|
||||
db.create_collection(coll_name, **opts)
|
||||
db.get_collection(coll_name, write_concern=wc).insert_many(documents)
|
||||
else:
|
||||
# Ensure collection exists
|
||||
db.create_collection(coll_name, write_concern=wc)
|
||||
db.create_collection(coll_name, write_concern=wc, **opts)
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
@ -782,9 +804,26 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
"Dirty explicit session is discarded" in spec["description"]
|
||||
or "Dirty implicit session is discarded" in spec["description"]
|
||||
):
|
||||
raise unittest.SkipTest("MMAPv1 does not support retryWrites=True")
|
||||
self.skipTest("MMAPv1 does not support retryWrites=True")
|
||||
elif "Client side error in command starting transaction" in spec["description"]:
|
||||
raise unittest.SkipTest("Implement PYTHON-1894")
|
||||
self.skipTest("Implement PYTHON-1894")
|
||||
class_name = self.__class__.__name__.lower()
|
||||
description = spec["description"].lower()
|
||||
if "csot" in class_name:
|
||||
if "change" in description or "change" in class_name:
|
||||
self.skipTest("CSOT not implemented for watch()")
|
||||
if "cursors" in class_name:
|
||||
self.skipTest("CSOT not implemented for cursors")
|
||||
if "tailable" in class_name:
|
||||
self.skipTest("CSOT not implemented for tailable cursors")
|
||||
if "sessions" in class_name:
|
||||
self.skipTest("CSOT not implemented for sessions")
|
||||
if "withtransaction" in description:
|
||||
self.skipTest("CSOT not implemented for with_transaction")
|
||||
if "transaction" in class_name or "transaction" in description:
|
||||
self.skipTest("CSOT not implemented for transactions")
|
||||
if "socket timeout" in description:
|
||||
self.skipTest("CSOT not implemented for socket timeouts")
|
||||
|
||||
# Some tests need to be skipped based on the operations they try to run.
|
||||
for op in spec["operations"]:
|
||||
@ -801,10 +840,21 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
if not client_context.test_commands_enabled:
|
||||
if name == "failPoint" or name == "targetedFailPoint":
|
||||
self.skipTest("Test commands must be enabled to use fail points")
|
||||
if "timeoutMode" in op.get("arguments", {}):
|
||||
self.skipTest("PyMongo does not support timeoutMode")
|
||||
if name == "createEntities":
|
||||
self.maybe_skip_entity(op.get("arguments", {}).get("entities", []))
|
||||
|
||||
def maybe_skip_entity(self, entities):
|
||||
for entity in entities:
|
||||
entity_type = next(iter(entity))
|
||||
if entity_type == "bucket":
|
||||
self.skipTest("GridFS is not currently supported (PYTHON-2459)")
|
||||
|
||||
def process_error(self, exception, spec):
|
||||
is_error = spec.get("isError")
|
||||
is_client_error = spec.get("isClientError")
|
||||
is_timeout_error = spec.get("isTimeoutError")
|
||||
error_contains = spec.get("errorContains")
|
||||
error_code = spec.get("errorCode")
|
||||
error_code_name = spec.get("errorCodeName")
|
||||
@ -825,6 +875,15 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
else:
|
||||
self.assertNotIsInstance(exception, PyMongoError)
|
||||
|
||||
if is_timeout_error:
|
||||
# TODO: PYTHON-3291 Implement error transformation.
|
||||
if isinstance(exception, WriteConcernError):
|
||||
self.assertEqual(exception.code, 50)
|
||||
else:
|
||||
self.assertIsInstance(
|
||||
exception, (NetworkTimeout, ExecutionTimeout, ServerSelectionTimeoutError)
|
||||
)
|
||||
|
||||
if error_contains:
|
||||
if isinstance(exception, BulkWriteError):
|
||||
errmsg = str(exception.details).lower()
|
||||
@ -925,15 +984,21 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
self.__raise_if_unsupported("find", target, Collection)
|
||||
if "filter" not in kwargs:
|
||||
self.fail('createFindCursor requires a "filter" argument')
|
||||
cursor = NonLazyCursor(target.find(*args, **kwargs))
|
||||
cursor = NonLazyCursor(target.find(*args, **kwargs), target.database.client)
|
||||
self.addCleanup(cursor.close)
|
||||
return cursor
|
||||
|
||||
def _collectionOperation_count(self, target, *args, **kwargs):
|
||||
self.skipTest("PyMongo does not support collection.count()")
|
||||
|
||||
def _collectionOperation_listIndexes(self, target, *args, **kwargs):
|
||||
if "batch_size" in kwargs:
|
||||
self.skipTest("PyMongo does not support batch_size for list_indexes")
|
||||
return target.list_indexes(*args, **kwargs)
|
||||
|
||||
def _collectionOperation_listIndexNames(self, target, *args, **kwargs):
|
||||
self.skipTest("PyMongo does not support list_index_names")
|
||||
|
||||
def _sessionOperation_withTransaction(self, target, *args, **kwargs):
|
||||
if client_context.storage_engine == "mmapv1":
|
||||
self.skipTest("MMAPv1 does not support document-level locking")
|
||||
@ -946,13 +1011,21 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
self.__raise_if_unsupported("startTransaction", target, ClientSession)
|
||||
return target.start_transaction(*args, **kwargs)
|
||||
|
||||
def _cursor_iterateOnce(self, target, *args, **kwargs):
|
||||
self.__raise_if_unsupported("iterateOnce", target, NonLazyCursor, ChangeStream)
|
||||
return target.try_next()
|
||||
|
||||
def _changeStreamOperation_iterateUntilDocumentOrError(self, target, *args, **kwargs):
|
||||
self.__raise_if_unsupported("iterateUntilDocumentOrError", target, ChangeStream)
|
||||
return next(target)
|
||||
|
||||
def _cursor_iterateUntilDocumentOrError(self, target, *args, **kwargs):
|
||||
self.__raise_if_unsupported("iterateUntilDocumentOrError", target, NonLazyCursor)
|
||||
return next(target)
|
||||
while target.alive:
|
||||
try:
|
||||
return next(target)
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
def _cursor_close(self, target, *args, **kwargs):
|
||||
self.__raise_if_unsupported("close", target, NonLazyCursor)
|
||||
@ -960,6 +1033,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
|
||||
def run_entity_operation(self, spec):
|
||||
target = self.entity_map[spec["object"]]
|
||||
client = target
|
||||
opname = spec["name"]
|
||||
opargs = spec.get("arguments")
|
||||
expect_error = spec.get("expectError")
|
||||
@ -977,20 +1051,26 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
spec, arguments, camel_to_snake(opname), self.entity_map, self.run_operations
|
||||
)
|
||||
else:
|
||||
arguments = tuple()
|
||||
arguments = {}
|
||||
|
||||
if isinstance(target, MongoClient):
|
||||
method_name = "_clientOperation_%s" % (opname,)
|
||||
client = target
|
||||
elif isinstance(target, Database):
|
||||
method_name = "_databaseOperation_%s" % (opname,)
|
||||
client = target.client
|
||||
elif isinstance(target, Collection):
|
||||
method_name = "_collectionOperation_%s" % (opname,)
|
||||
client = target.database.client
|
||||
elif isinstance(target, ChangeStream):
|
||||
method_name = "_changeStreamOperation_%s" % (opname,)
|
||||
client = target._client
|
||||
elif isinstance(target, NonLazyCursor):
|
||||
method_name = "_cursor_%s" % (opname,)
|
||||
client = target.client
|
||||
elif isinstance(target, ClientSession):
|
||||
method_name = "_sessionOperation_%s" % (opname,)
|
||||
client = target._client
|
||||
elif isinstance(target, GridFSBucket):
|
||||
raise NotImplementedError
|
||||
else:
|
||||
@ -1007,7 +1087,17 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
cmd = functools.partial(method, target)
|
||||
|
||||
try:
|
||||
result = cmd(**dict(arguments))
|
||||
# TODO: PYTHON-3289 apply inherited timeout by default.
|
||||
inherit_timeout = getattr(target, "timeout", None)
|
||||
# CSOT: Translate the spec test "timeout" arg into pymongo's context timeout API.
|
||||
if "timeout" in arguments or inherit_timeout is not None:
|
||||
timeout = arguments.pop("timeout", None)
|
||||
if timeout is None:
|
||||
timeout = inherit_timeout
|
||||
with pymongo.timeout(timeout):
|
||||
result = cmd(**dict(arguments))
|
||||
else:
|
||||
result = cmd(**dict(arguments))
|
||||
except Exception as exc:
|
||||
# Ignore all operation errors but to avoid masking bugs don't
|
||||
# ignore things like TypeError and ValueError.
|
||||
@ -1057,6 +1147,9 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
self.addCleanup(client.close)
|
||||
self.__set_fail_point(client=client, command_args=spec["failPoint"])
|
||||
|
||||
def _testOperation_createEntities(self, spec):
|
||||
self.entity_map.create_entities_from_spec(spec["entities"], uri=self._uri)
|
||||
|
||||
def _testOperation_assertSessionTransactionState(self, spec):
|
||||
session = self.entity_map[spec["session"]]
|
||||
expected_state = getattr(_TxnState, spec["state"].upper())
|
||||
@ -1245,6 +1338,7 @@ class UnifiedSpecTestMixinV1(IntegrationTest):
|
||||
raise unittest.SkipTest("%s" % (skip_reason,))
|
||||
|
||||
# process createEntities
|
||||
self._uri = uri
|
||||
self.entity_map = EntityMapUtil(self)
|
||||
self.entity_map.create_entities_from_spec(self.TEST_SPEC.get("createEntities", []), uri=uri)
|
||||
# process initialData
|
||||
@ -1309,7 +1403,7 @@ def generate_test_classes(
|
||||
class_name_prefix="",
|
||||
expected_failures=[], # noqa: B006
|
||||
bypass_test_generation_errors=False,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
"""Method for generating test classes. Returns a dictionary where keys are
|
||||
the names of test classes and values are the test class objects."""
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"tests": [
|
||||
{
|
||||
"description": "Valid connection and timeout options are parsed correctly",
|
||||
"uri": "mongodb://example.com/?appname=URI-OPTIONS-SPEC-TEST&connectTimeoutMS=20000&heartbeatFrequencyMS=5000&localThresholdMS=3000&maxIdleTimeMS=50000&replicaSet=uri-options-spec&retryWrites=true&serverSelectionTimeoutMS=15000&socketTimeoutMS=7500",
|
||||
"uri": "mongodb://example.com/?appname=URI-OPTIONS-SPEC-TEST&connectTimeoutMS=20000&heartbeatFrequencyMS=5000&localThresholdMS=3000&maxIdleTimeMS=50000&replicaSet=uri-options-spec&retryWrites=true&serverSelectionTimeoutMS=15000&socketTimeoutMS=7500&timeoutMS=100",
|
||||
"valid": true,
|
||||
"warning": false,
|
||||
"hosts": null,
|
||||
@ -16,7 +16,8 @@
|
||||
"replicaSet": "uri-options-spec",
|
||||
"retryWrites": true,
|
||||
"serverSelectionTimeoutMS": 15000,
|
||||
"socketTimeoutMS": 7500
|
||||
"socketTimeoutMS": 7500,
|
||||
"timeoutMS": 100
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -238,6 +239,35 @@
|
||||
"hosts": null,
|
||||
"auth": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"description": "timeoutMS=0",
|
||||
"uri": "mongodb://example.com/?timeoutMS=0",
|
||||
"valid": true,
|
||||
"warning": false,
|
||||
"hosts": null,
|
||||
"auth": null,
|
||||
"options": {
|
||||
"timeoutMS": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Non-numeric timeoutMS causes a warning",
|
||||
"uri": "mongodb://example.com/?timeoutMS=invalid",
|
||||
"valid": true,
|
||||
"warning": true,
|
||||
"hosts": null,
|
||||
"auth": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"description": "Too low timeoutMS causes a warning",
|
||||
"uri": "mongodb://example.com/?timeoutMS=-2",
|
||||
"valid": true,
|
||||
"warning": true,
|
||||
"hosts": null,
|
||||
"auth": null,
|
||||
"options": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -44,15 +44,6 @@
|
||||
"tlsAllowInvalidCertificates": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "Invalid tlsAllowInvalidCertificates causes a warning",
|
||||
"uri": "mongodb://example.com/?tlsAllowInvalidCertificates=invalid",
|
||||
"valid": true,
|
||||
"warning": true,
|
||||
"hosts": null,
|
||||
"auth": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"description": "tlsAllowInvalidHostnames is parsed correctly",
|
||||
"uri": "mongodb://example.com/?tlsAllowInvalidHostnames=true",
|
||||
|
||||
@ -35,6 +35,7 @@ from bson.objectid import ObjectId
|
||||
from bson.son import SON
|
||||
from pymongo import MongoClient, monitoring, operations, read_preferences
|
||||
from pymongo.collection import ReturnDocument
|
||||
from pymongo.cursor import CursorType
|
||||
from pymongo.errors import ConfigurationError, OperationFailure
|
||||
from pymongo.hello import HelloCompat
|
||||
from pymongo.monitoring import _SENSITIVE_COMMANDS
|
||||
@ -651,6 +652,9 @@ def parse_collection_options(opts):
|
||||
|
||||
if "readConcern" in opts:
|
||||
opts["read_concern"] = ReadConcern(**dict(opts.pop("readConcern")))
|
||||
|
||||
if "timeoutMS" in opts:
|
||||
opts["timeout"] = int(opts.pop("timeoutMS")) / 1000.0
|
||||
return opts
|
||||
|
||||
|
||||
@ -988,6 +992,10 @@ def parse_spec_options(opts):
|
||||
if "readConcern" in opts:
|
||||
opts["read_concern"] = ReadConcern(**dict(opts.pop("readConcern")))
|
||||
|
||||
if "timeoutMS" in opts:
|
||||
assert isinstance(opts["timeoutMS"], int)
|
||||
opts["timeout"] = int(opts.pop("timeoutMS")) / 1000.0
|
||||
|
||||
if "maxTimeMS" in opts:
|
||||
opts["max_time_ms"] = opts.pop("maxTimeMS")
|
||||
|
||||
@ -1041,6 +1049,8 @@ def prepare_spec_arguments(spec, arguments, opname, entity_map, with_txn_callbac
|
||||
# Aggregate uses "batchSize", while find uses batch_size.
|
||||
elif (arg_name == "batchSize" or arg_name == "allowDiskUse") and opname == "aggregate":
|
||||
continue
|
||||
elif arg_name == "timeoutMode":
|
||||
raise unittest.SkipTest("PyMongo does not support timeoutMode")
|
||||
# Requires boolean returnDocument.
|
||||
elif arg_name == "returnDocument":
|
||||
arguments[c2s] = getattr(ReturnDocument, arguments.pop(arg_name).upper())
|
||||
@ -1090,5 +1100,13 @@ def prepare_spec_arguments(spec, arguments, opname, entity_map, with_txn_callbac
|
||||
arguments["index_or_name"] = arguments.pop(arg_name)
|
||||
elif opname == "rename" and arg_name == "to":
|
||||
arguments["new_name"] = arguments.pop(arg_name)
|
||||
elif arg_name == "cursorType":
|
||||
cursor_type = arguments.pop(arg_name)
|
||||
if cursor_type == "tailable":
|
||||
arguments["cursor_type"] = CursorType.TAILABLE
|
||||
elif cursor_type == "tailableAwait":
|
||||
arguments["cursor_type"] = CursorType.TAILABLE
|
||||
else:
|
||||
assert False, f"Unsupported cursorType: {cursor_type}"
|
||||
else:
|
||||
arguments[c2s] = arguments.pop(arg_name)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user