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
run
to start the server, and alwaysclose
it 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
: passTrue
to autorespond{'ok': 1}
to ismaster requests, or pass a dict orOpReply
.ssl
: passTrue
to require SSL.min_wire_version
: the minWireVersion to include in ismaster responses ifauto_ismaster
is True, default 0.max_wire_version
: the maxWireVersion to include in ismaster responses ifauto_ismaster
is 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.
matcher
is aMatcher
or 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
,hangup
and 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
subscribe
better 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_err
on the currently enqueued request.
-
got
(*args, **kwargs)¶ Does
request
match 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
Request
and assert it matches.Returns None if the server is stopped.
Pass a
Request
or request pattern to specify what client request to expect. See the tutorial for examples. Passtimeout
as a keyword argument to override this server’srequest_timeout
.
-
port
¶ The listening port.
-
receive
(*args, **kwargs)¶ Pop the next
Request
and assert it matches.Returns None if the server is stopped.
Pass a
Request
or request pattern to specify what client request to expect. See the tutorial for examples. Passtimeout
as a keyword argument to override this server’srequest_timeout
.
-
receives
(*args, **kwargs)¶ Pop the next
Request
and assert it matches.Returns None if the server is stopped.
Pass a
Request
or request pattern to specify what client request to expect. See the tutorial for examples. Passtimeout
as 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
MockupDB
that the mongo shell can connect to.Call
run
on the returned server, and clean it up withstop
.If
all_ok
is 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
autoresponds
handler.
-
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
autoresponds
handler.
-
flags
¶ The request flags or None.
-
hangup
()¶ Close the connection.
Returns True so it is suitable as an
autoresponds
handler.
-
matches
(*args, **kwargs)¶ True if this matches a message spec.
-
namespace
¶ The operation namespace or None.
-
replies
(*args, **kwargs)¶ Send an
OpReply
to 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
autoresponds
handler.
-
reply
(*args, **kwargs)¶ Send an
OpReply
to 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
autoresponds
handler.
-
request_id
¶ The request id or None.
-
send
(*args, **kwargs)¶ Send an
OpReply
to 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
autoresponds
handler.
-
sends
(*args, **kwargs)¶ Send an
OpReply
to 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
autoresponds
handler.
-
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
autoresponds
handler.
-
-
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
MockupDB
to 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
Request
objects.Initialized with a message spec.
Used by
receives
to assert the client sent the expected request, and bygot
to test if it did and returnTrue
orFalse
. Used byautoresponds
to match requests with autoresponses.-
matches
(*args, **kwargs)¶ Test if a request matches a message spec.
Returns
True
orFalse
.
-