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 always close 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 from run.
  • verbose: if True, 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: pass True to autorespond {'ok': 1} to ismaster requests, or pass a dict or OpReply.
  • ssl: pass True to require SSL.
  • min_wire_version: the minWireVersion to include in ismaster responses if auto_ismaster is True, default 0.
  • max_wire_version: the maxWireVersion to include in ismaster responses if auto_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 a Matcher or a command name, or an instance of OpInsert, 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.

fail(*args, **kwargs)

Call fail on the currently enqueued request.

gets(*args, **kwargs)

Synonym for receives.

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()
hangs_up()

Synonym for hangup.

hangup()

Call hangup on the currently enqueued request.

host

The listening hostname.

label

Label for logging, or None.

ok(*args, **kwargs)

Synonym for replies.

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. Pass timeout as a keyword argument to override this server’s request_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. Pass timeout as a keyword argument to override this server’s request_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. Pass timeout as a keyword argument to override this server’s request_timeout.

replies(*args, **kwargs)

Call reply on the currently enqueued request.

reply(*args, **kwargs)

Call reply on the currently enqueued request.

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 with server.pop() or the current request remains enqueued. Better to reply with server.pop().replies() than server.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.

send(*args, **kwargs)

Call reply on the currently enqueued request.

sends(*args, **kwargs)

Call reply on the currently enqueued request.

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.

wait(*args, **kwargs)

Synonym for got.

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 with stop.

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.

hangs_up()

Synonym for hangup.

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.

ok(*args, **kwargs)

Synonym for replies.

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.

server

The MockupDB server.

slave_ok

True if the SlaveOkay wire protocol flag is set.

slave_okay

Synonym for slave_ok.

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.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpQuery or Command.

Takes the client message as bytes, the client and server socket objects, and the client request id.

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.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpGetMore.

Takes the client message as bytes, the client and server socket objects, and the client request id.

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.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpInsert.

Takes the client message as bytes, the client and server socket objects, and the client request id.

class mockupdb.OpUpdate(*args, **kwargs)

A legacy OP_UPDATE the client executes on the server.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpUpdate.

Takes the client message as bytes, the client and server socket objects, and the client request id.

class mockupdb.OpDelete(*args, **kwargs)

A legacy OP_DELETE the client executes on the server.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpDelete.

Takes the client message as bytes, the client and server socket objects, and the client request id.

class mockupdb.OpReply(*args, **kwargs)

An OP_REPLY reply from MockupDB to the client.

docs

The reply documents, if any.

reply_bytes(request)

Take a Request and return an OP_REPLY message as bytes.

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.

slave_okay

Synonym for slave_ok.

classmethod unpack(msg, client, server, request_id)

Parse message and return an OpMsg.

Takes the client message as bytes, the client and server socket objects, and the client request id.

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 by got to test if it did and return True or False. Used by autoresponds to match requests with autoresponses.

matches(*args, **kwargs)

Test if a request matches a message spec.

Returns True or False.

prototype

The prototype Request used to match actual requests with.