API Reference¶
Simulate a MongoDB server, for use in unittests.
-
class
mockupdb.MockupDB(port=None, verbose=False, request_timeout=10, auto_ismaster=None, ssl=False, min_wire_version=0, max_wire_version=6, uds_path=None)¶ A simulated mongod or mongos.
Call
runto start the server, and alwayscloseit to avoid exceptions during interpreter shutdown.See the tutorial for comprehensive examples.
Optional parameters: port: listening port number. If not specified, choose some unused port and return the port number fromrun.verbose: ifTrue, print requests and replies to stdout.request_timeout: seconds to wait for the next client request, or else assert. Default 10 seconds. Pass int(1e6) to disable.auto_ismaster: passTrueto autorespond{'ok': 1}to ismaster requests, or pass a dict orOpReply.ssl: passTrueto require SSL.min_wire_version: the minWireVersion to include in ismaster responses ifauto_ismasteris True, default 0.max_wire_version: the maxWireVersion to include in ismaster responses ifauto_ismasteris True, default 6.uds_path: a Unix domain socket path. MockupDB will attempt to delete the path if it already exists.
-
address¶ The listening (host, port).
-
address_string¶ The listening “host:port”.
-
append_responder(*args, **kwargs)¶ Add a responder of last resort.
Like
autoresponds, but instead of adding a responder to the top of the stack, add it to the bottom. This responder will be called if no others match.
-
autoresponds(*args, **kwargs)¶ Send a canned reply to all matching client requests.
matcheris aMatcheror a command name, or an instance ofOpInsert,OpQuery, etc.>>> s = MockupDB() >>> port = s.run() >>> >>> from pymongo import MongoClient >>> client = MongoClient(s.uri) >>> responder = s.autoresponds('ismaster', maxWireVersion=6) >>> client.admin.command('ismaster') == {'ok': 1, 'maxWireVersion': 6} True
The remaining arguments are a message spec:
>>> # ok >>> responder = s.autoresponds('bar', ok=0, errmsg='err') >>> client.db.command('bar') Traceback (most recent call last): ... OperationFailure: command SON([('bar', 1)]) on namespace db.$cmd failed: err >>> responder = s.autoresponds(OpMsg('find', 'collection'), ... {'cursor': {'id': 0, 'firstBatch': [{'_id': 1}, {'_id': 2}]}}) >>> # ok >>> list(client.db.collection.find()) == [{'_id': 1}, {'_id': 2}] True >>> responder = s.autoresponds(OpMsg('find', 'collection'), ... {'cursor': {'id': 0, 'firstBatch': [{'a': 1}, {'a': 2}]}}) >>> # bad >>> list(client.db.collection.find()) == [{'a': 1}, {'a': 2}] True
Remove an autoresponder like:
>>> responder.cancel()
If the request currently at the head of the queue matches, it is popped and replied to. Future matching requests skip the queue.
>>> future = go(client.db.command, 'baz') >>> # bad >>> responder = s.autoresponds('baz', {'key': 'value'}) >>> future() == {'ok': 1, 'key': 'value'} True
Responders are applied in order, most recently added first, until one matches:
>>> responder = s.autoresponds('baz') >>> client.db.command('baz') == {'ok': 1} True >>> responder.cancel() >>> # The previous responder takes over again. >>> client.db.command('baz') == {'ok': 1, 'key': 'value'} True
You can pass a request handler in place of the message spec. Return True if you handled the request:
>>> responder = s.autoresponds('baz', lambda r: r.ok(a=2))
The standard
Request.ok,replies,fail,hangupand so on all return True to make them suitable as handler functions.>>> client.db.command('baz') == {'ok': 1, 'a': 2} True
If the request is not handled, it is checked against the remaining responders, or enqueued if none match.
You can pass the handler as the only argument so it receives all requests. For example you could log them, then return None to allow other handlers to run:
>>> def logger(request): ... if not request.matches('ismaster'): ... print('logging: %r' % request) >>> responder = s.autoresponds(logger) >>> client.db.command('baz') == {'ok': 1, 'a': 2} logging: OpMsg({"baz": 1, "$db": "db", "$readPreference": {"mode": "primaryPreferred"}}, namespace="db") True
The synonym
subscribebetter expresses your intent if your handler never returns True:>>> subscriber = s.subscribe(logger)
-
cancel_responder(*args, **kwargs)¶ Cancel a responder that was registered with
autoresponds.
-
command_err(*args, **kwargs)¶ Call
command_erron the currently enqueued request.
-
got(*args, **kwargs)¶ Does
requestmatch the given message spec?>>> s = MockupDB(auto_ismaster=True) >>> port = s.run() >>> s.got(timeout=0) # No request enqueued. False >>> from pymongo import MongoClient >>> client = MongoClient(s.uri) >>> future = go(client.db.command, 'foo') >>> s.got('foo') True >>> s.got(OpMsg('foo', namespace='db')) True >>> s.got(OpMsg('foo', key='value')) False >>> s.ok() >>> future() == {'ok': 1} True >>> s.stop()
-
host¶ The listening hostname.
-
label¶ Label for logging, or None.
-
pop(*args, **kwargs)¶ Pop the next
Requestand assert it matches.Returns None if the server is stopped.
Pass a
Requestor request pattern to specify what client request to expect. See the tutorial for examples. Passtimeoutas a keyword argument to override this server’srequest_timeout.
-
port¶ The listening port.
-
receive(*args, **kwargs)¶ Pop the next
Requestand assert it matches.Returns None if the server is stopped.
Pass a
Requestor request pattern to specify what client request to expect. See the tutorial for examples. Passtimeoutas a keyword argument to override this server’srequest_timeout.
-
receives(*args, **kwargs)¶ Pop the next
Requestand assert it matches.Returns None if the server is stopped.
Pass a
Requestor request pattern to specify what client request to expect. See the tutorial for examples. Passtimeoutas a keyword argument to override this server’srequest_timeout.
-
request¶ The currently enqueued
Request, or None.Warning
This property is useful to check what the current request is, but the pattern
server.request.replies()is dangerous: you must follow it withserver.pop()or the current request remains enqueued. Better to reply withserver.pop().replies()thanserver.request.replies()or any variation on it.
-
requests_count¶ Number of requests this server has received.
Includes autoresponded requests.
-
run(*args, **kwargs)¶ Begin serving. Returns the bound port, or 0 for domain socket.
-
running¶ If this server is started and not stopped.
-
stop(*args, **kwargs)¶ Stop serving. Always call this to clean up after yourself.
-
subscribe(*args, **kwargs)¶ Synonym for
autoresponds.
-
uri¶ Connection string to pass to
MongoClient.
-
verbose¶ If verbose logging is turned on.
-
mockupdb.go(fn, *args, **kwargs)¶ Launch an operation on a thread and get a handle to its future result.
>>> from time import sleep >>> def print_sleep_print(duration): ... sleep(duration) ... print('hello from background thread') ... sleep(duration) ... print('goodbye from background thread') ... return 'return value' ... >>> future = go(print_sleep_print, 0.1) >>> sleep(0.15) hello from background thread >>> print('main thread') main thread >>> result = future() goodbye from background thread >>> result 'return value'
-
mockupdb.going(*args, **kwds)¶ Launch a thread and wait for its result before exiting the code block.
>>> with going(lambda: 'return value') as future: ... pass >>> future() # Won't block, the future is ready by now. 'return value'
Or discard the result:
>>> with going(lambda: "don't care"): ... pass
If an exception is raised within the context, the result is lost:
>>> with going(lambda: 'return value') as future: ... assert 1 == 0 Traceback (most recent call last): ... AssertionError
-
mockupdb.wait_until(predicate, success_description, timeout=10)¶ Wait up to 10 seconds (by default) for predicate to be true.
E.g.:
- wait_until(lambda: client.primary == (‘a’, 1),
- ‘connect to the primary’)
If the lambda-expression isn’t true after 10 seconds, we raise AssertionError(“Didn’t ever connect to the primary”).
Returns the predicate’s first true value.
-
mockupdb.interactive_server(port=27017, verbose=True, all_ok=False, name='MockupDB', ssl=False, uds_path=None)¶ A
MockupDBthat the mongo shell can connect to.Call
runon the returned server, and clean it up withstop.If
all_okis True, replies {ok: 1} to anything unmatched by a specific responder.
-
class
mockupdb.Request(*args, **kwargs)¶ Base class for
Command,OpMsg, and so on.Some useful asserts you can do in tests:
>>> {'_id': 0} in OpInsert({'_id': 0}) True >>> {'_id': 1} in OpInsert({'_id': 0}) False >>> {'_id': 1} in OpInsert([{'_id': 0}, {'_id': 1}]) True >>> {'_id': 1} == OpInsert([{'_id': 0}, {'_id': 1}])[1] True >>> 'field' in OpMsg(field=1) True >>> 'field' in OpMsg() False >>> 'field' in OpMsg('ismaster') False >>> OpMsg(ismaster=False)['ismaster'] is False True
-
assert_matches(*args, **kwargs)¶ Assert this matches a message spec.
Returns self.
-
client_port¶ Client connection’s TCP port.
-
command_err(code=1, errmsg='MockupDB command failure', *args, **kwargs)¶ Error reply to a command.
Returns True so it is suitable as an
autorespondshandler.
-
doc¶ The request document, if there is exactly one.
Use this for queries, commands, and legacy deletes. Legacy writes may have many documents, OP_GET_MORE and OP_KILL_CURSORS have none.
-
docs¶ The request documents, if any.
-
fail(err='MockupDB query failure', *args, **kwargs)¶ Reply to a query with the QueryFailure flag and an ‘$err’ key.
Returns True so it is suitable as an
autorespondshandler.
-
flags¶ The request flags or None.
-
hangup()¶ Close the connection.
Returns True so it is suitable as an
autorespondshandler.
-
matches(*args, **kwargs)¶ True if this matches a message spec.
-
namespace¶ The operation namespace or None.
-
replies(*args, **kwargs)¶ Send an
OpReplyto the client.The default reply to a command is
{'ok': 1}, otherwise the default is empty (no documents).Returns True so it is suitable as an
autorespondshandler.
-
reply(*args, **kwargs)¶ Send an
OpReplyto the client.The default reply to a command is
{'ok': 1}, otherwise the default is empty (no documents).Returns True so it is suitable as an
autorespondshandler.
-
request_id¶ The request id or None.
-
send(*args, **kwargs)¶ Send an
OpReplyto the client.The default reply to a command is
{'ok': 1}, otherwise the default is empty (no documents).Returns True so it is suitable as an
autorespondshandler.
-
sends(*args, **kwargs)¶ Send an
OpReplyto the client.The default reply to a command is
{'ok': 1}, otherwise the default is empty (no documents).Returns True so it is suitable as an
autorespondshandler.
-
slave_ok¶ True if the SlaveOkay wire protocol flag is set.
-
-
class
mockupdb.Command(*args, **kwargs)¶ A command the client executes on the server.
-
replies_to_gle(**kwargs)¶ Send a getlasterror response.
Defaults to
{ok: 1, err: null}. Add or override values by passing keyword arguments.Returns True so it is suitable as an
autorespondshandler.
-
-
class
mockupdb.OpQuery(*args, **kwargs)¶ A query (besides a command) the client executes on the server.
>>> OpQuery({'i': {'$gt': 2}}, fields={'j': False}) OpQuery({"i": {"$gt": 2}}, fields={"j": false})
-
fields¶ Client query’s fields selector or None.
-
num_to_return¶ Client query’s numToReturn or None.
-
num_to_skip¶ Client query’s numToSkip or None.
-
-
class
mockupdb.OpGetMore(**kwargs)¶ An OP_GET_MORE the client executes on the server.
-
cursor_id¶ The client message’s cursorId field.
-
num_to_return¶ The client message’s numToReturn field.
-
-
class
mockupdb.OpKillCursors(**kwargs)¶ An OP_KILL_CURSORS the client executes on the server.
-
cursor_ids¶ List of cursor ids the client wants to kill.
-
classmethod
unpack(msg, client, server, _)¶ Parse message and return an
OpKillCursors.Takes the client message as bytes, the client and server socket objects, and the client request id.
-
-
class
mockupdb.OpInsert(*args, **kwargs)¶ A legacy OP_INSERT the client executes on the server.
-
class
mockupdb.OpUpdate(*args, **kwargs)¶ A legacy OP_UPDATE the client executes on the server.
-
class
mockupdb.OpDelete(*args, **kwargs)¶ A legacy OP_DELETE the client executes on the server.
-
class
mockupdb.OpReply(*args, **kwargs)¶ An OP_REPLY reply from
MockupDBto the client.-
docs¶ The reply documents, if any.
-
update(*args, **kwargs)¶ Update the document. Same as
dict().update().>>> reply = OpReply({'ismaster': True}) >>> reply.update(maxWireVersion=3) >>> reply.doc['maxWireVersion'] 3 >>> reply.update({'maxWriteBatchSize': 10, 'msg': 'isdbgrid'})
-
-
class
mockupdb.OpMsg(*args, **kwargs)¶ An OP_MSG request the client executes on the server.
-
checksum¶ The provided checksum, if set, else None.
-
command_name¶ The command name or None.
>>> OpMsg({'count': 'collection'}).command_name 'count' >>> OpMsg('aggregate', 'collection', cursor=absent).command_name 'aggregate'
-
slave_ok¶ True if this OpMsg can read from a secondary.
-
-
class
mockupdb.Matcher(*args, **kwargs)¶ Matches a subset of
Requestobjects.Initialized with a message spec.
Used by
receivesto assert the client sent the expected request, and bygotto test if it did and returnTrueorFalse. Used byautorespondsto match requests with autoresponses.-
matches(*args, **kwargs)¶ Test if a request matches a message spec.
Returns
TrueorFalse.
-