Codebase list python-mockupdb / f8b9ed3
New upstream version 1.8.0 Ondřej Nový 3 years ago
13 changed file(s) with 281 addition(s) and 120 deletion(s). Raw diff Collapse all Expand all
44 Development Lead
55 ----------------
66
7 * A. Jesse Jiryu Davis <jesse@mongodb.com>
7 * A\. Jesse Jiryu Davis <jesse@mongodb.com>
88
99 Contributors
1010 ------------
1111
12 * Sean Purcell
1213 * George Wilson
1314 * Shane Harvey
11
22 Changelog
33 =========
4
5 Next Release
6 ------------
7
8 MockupDB supports Python 3.4 through 3.8; it no longer supports Python 2.6 or
9 Python 3.3.
10
11 New method ``MockupDB.append_responder`` to add an autoresponder of last resort.
12
13 Fix a bug in ``interactive_server`` with ``all_ok=True``. It had returned an
14 empty isMaster response, causing drivers to throw errors like "Server at
15 localhost:27017 reports wire version 0, but this version of PyMongo requires at
16 least 2 (MongoDB 2.6)."
17
18 Stop logging "OSError: [WinError 10038] An operation was attempted on something
19 that is not a socket" on Windows after a client disconnects.
20
21 Parse OP_MSGs with any number of sections in any order. This allows write
22 commands from the mongo shell, which sends sections in the opposite order from
23 drivers. Handle OP_MSGs with checksums, such as those sent by the mongo shell
24 beginning in 4.2.
425
526 1.7.0 (2018-12-02)
627 ------------------
9898 2. If the pull request adds functionality, the docs should be updated. Put
9999 your new functionality into a function with a docstring, and add the
100100 feature to the list in README.rst.
101 3. The pull request should work for Python 2.6, 2.7, 3.3, and 3.4. Check that
101 3. The pull request should work for Python 2.7 and 3.4+. Check that
102102 tests pass in all versions with `tox`.
103103
104104 Tips
0 Metadata-Version: 1.1
0 Metadata-Version: 1.2
11 Name: mockupdb
2 Version: 1.7.0
2 Version: 1.8.0
33 Summary: MongoDB Wire Protocol server library
44 Home-page: https://github.com/ajdavis/mongo-mockup-db
55 Author: A. Jesse Jiryu Davis
66 Author-email: jesse@mongodb.com
77 License: Apache License, Version 2.0
8 Description-Content-Type: UNKNOWN
98 Description: ========
109 MockupDB
1110 ========
2019
2120 Changelog
2221 =========
22
23 Next Release
24 ------------
25
26 MockupDB supports Python 3.4 through 3.8; it no longer supports Python 2.6 or
27 Python 3.3.
28
29 New method ``MockupDB.append_responder`` to add an autoresponder of last resort.
30
31 Fix a bug in ``interactive_server`` with ``all_ok=True``. It had returned an
32 empty isMaster response, causing drivers to throw errors like "Server at
33 localhost:27017 reports wire version 0, but this version of PyMongo requires at
34 least 2 (MongoDB 2.6)."
35
36 Stop logging "OSError: [WinError 10038] An operation was attempted on something
37 that is not a socket" on Windows after a client disconnects.
38
39 Parse OP_MSGs with any number of sections in any order. This allows write
40 commands from the mongo shell, which sends sections in the opposite order from
41 drivers. Handle OP_MSGs with checksums, such as those sent by the mongo shell
42 beginning in 4.2.
2343
2444 1.7.0 (2018-12-02)
2545 ------------------
141161 Classifier: License :: OSI Approved :: Apache Software License
142162 Classifier: Natural Language :: English
143163 Classifier: Programming Language :: Python :: 2
144 Classifier: Programming Language :: Python :: 2.6
145164 Classifier: Programming Language :: Python :: 2.7
146165 Classifier: Programming Language :: Python :: 3
147 Classifier: Programming Language :: Python :: 3.3
148166 Classifier: Programming Language :: Python :: 3.4
167 Classifier: Programming Language :: Python :: 3.5
168 Classifier: Programming Language :: Python :: 3.6
169 Classifier: Programming Language :: Python :: 3.7
170 Classifier: Programming Language :: Python :: 3.8
171 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
5656 default_role = 'py:obj'
5757
5858 doctest_global_setup = """
59 try:
60 from collections import OrderedDict
61 except:
62 from ordereddict import OrderedDict # Python 2.6, "pip install ordereddict"
59 from collections import OrderedDict
6360 from mockupdb import *
6461 """
6562
33
44 Install MockupDB with pip:
55
6 $ python -m pip install mongo-mockup-db
6 $ python -m pip install mockupdb
1919 >>> server = MockupDB()
2020 >>> port = server.run() # Returns the TCP port number it listens on.
2121 >>> from pymongo import MongoClient
22 >>> client = MongoClient(server.uri)
22 >>> client = MongoClient(server.uri, connectTimeoutMS=999999)
2323
2424 When the client connects it calls the "ismaster" command, then blocks until
25 the server responds. MockupDB receives the "ismaster" command but does not
26 respond until you tell it to:
25 the server responds. By default it throws an error if the server doesn't
26 respond in 10 seconds, so set a longer timeout.
27
28 MockupDB receives the "ismaster" command but does not respond until you tell it
29 to:
2730
2831 >>> request = server.receives()
2932 >>> request.command_name
1818
1919 __author__ = 'A. Jesse Jiryu Davis'
2020 __email__ = 'jesse@mongodb.com'
21 __version__ = '1.7.0'
21 __version__ = '1.8.0'
2222
2323 import atexit
2424 import contextlib
2626 import errno
2727 import functools
2828 import inspect
29 import operator
2930 import os
3031 import random
3132 import select
3839 import weakref
3940 import sys
4041 from codecs import utf_8_decode as _utf_8_decode
42 from collections import OrderedDict
4143
4244 try:
4345 from queue import Queue, Empty
4850 from collections.abc import Mapping
4951 except:
5052 from collections import Mapping
51
52 try:
53 from collections import OrderedDict
54 except:
55 from ordereddict import OrderedDict # Python 2.6, "pip install ordereddict"
5653
5754 try:
5855 from io import StringIO
202199 self._event = threading.Event()
203200
204201 def result(self, timeout=None):
205 self._event.wait(timeout)
206 # wait() always returns None in Python 2.6.
207 if not self._event.is_set():
202 if not self._event.wait(timeout):
208203 raise AssertionError('timed out waiting for Future')
209204 return self._result
210205
274269
275270 OP_MSG_FLAGS = OrderedDict([
276271 ('checksumPresent', 1),
277 ('moreToCome', 2)])
272 ('moreToCome', 2),
273 ('exhaustAllowed', 16)])
274
275 _ALL_OP_MSG_FLAGS = functools.reduce(operator.or_, OP_MSG_FLAGS.values())
278276
279277 _UNPACK_BYTE = struct.Struct("<b").unpack
280278 _UNPACK_INT = struct.Struct("<i").unpack
627625 Takes the client message as bytes, the client and server socket objects,
628626 and the client request id.
629627 """
628 payload_document = OrderedDict()
630629 flags, = _UNPACK_UINT(msg[:4])
631630 pos = 4
632 first_payload_type, = _UNPACK_BYTE(msg[pos:pos + 1])
633 pos += 1
634 first_payload_size, = _UNPACK_INT(msg[pos:pos + 4])
635 if flags != 0 and flags != 2:
636 raise ValueError('OP_MSG flag must be 0 or 2 not %r' % (flags,))
637 if first_payload_type != 0:
638 raise ValueError('First OP_MSG payload type must be 0 not %r' % (
639 first_payload_type,))
640
641 # Parse the initial document and add the optional payload type 1.
642 payload_document = bson.decode_all(msg[pos:pos + first_payload_size],
643 CODEC_OPTIONS)[0]
644 pos += first_payload_size
645 if len(msg) != pos:
631 if flags & ~_ALL_OP_MSG_FLAGS:
632 raise ValueError(
633 'OP_MSG flags has reserved bits set.'
634 ' Allowed flags: 0x%x. Provided flags: 0x%x' % (
635 _ALL_OP_MSG_FLAGS, flags))
636
637 checksum_present = flags & OP_MSG_FLAGS['checksumPresent']
638 checksum = None
639 if checksum_present:
640 msg_len_without_checksum = len(msg) - 4
641 else:
642 msg_len_without_checksum = len(msg)
643
644 while pos < msg_len_without_checksum:
646645 payload_type, = _UNPACK_BYTE(msg[pos:pos + 1])
647646 pos += 1
648 if payload_type != 1:
649 raise ValueError('Second OP_MSG payload type must be 1 not %r'
650 % (payload_type,))
651 section_size, = _UNPACK_INT(msg[pos:pos + 4])
652 if len(msg) != pos + section_size:
653 raise ValueError('More than two OP_MSG sections unsupported')
654 pos += 4
655 identifier, pos = _get_c_string(msg, pos)
656 documents = bson.decode_all(msg[pos:], CODEC_OPTIONS)
657 payload_document[identifier] = documents
647 payload_size, = _UNPACK_INT(msg[pos:pos + 4])
648 if payload_type == 0:
649 doc = bson.decode_all(msg[pos:pos + payload_size],
650 CODEC_OPTIONS)[0]
651 payload_document.update(doc)
652 pos += payload_size
653 elif payload_type == 1:
654 section_size, = _UNPACK_INT(msg[pos:pos + 4])
655 pos += 4
656 identifier, pos = _get_c_string(msg, pos)
657 # Section starts w/ 4-byte size prefix, identifier ends w/ nil.
658 documents_len = section_size - len(identifier) - 1 - 4
659 documents = bson.decode_all(msg[pos:pos + documents_len],
660 CODEC_OPTIONS)
661 payload_document[identifier] = documents
662 pos += documents_len
663
664 remaining = len(msg) - pos
665 if checksum_present:
666 if remaining != 4:
667 raise ValueError(
668 'OP_MSG has checksumPresent flag set, expected 4 bytes'
669 ' remaining but have %d bytes remaining' % (remaining,))
670
671 checksum = _UNPACK_UINT(msg[pos:pos+4])[0]
672 else:
673 if remaining != 0:
674 raise ValueError(
675 'OP_MSG has no checksumPresent flag, expected 0 bytes'
676 ' remaining but have %d bytes remaining' % (remaining,))
658677
659678 database = payload_document['$db']
660679 return OpMsg(payload_document, namespace=database, flags=flags,
661 _client=client, request_id=request_id,
680 _client=client, request_id=request_id, checksum=checksum,
662681 _server=server)
663682
664683 def __init__(self, *args, **kwargs):
684 checksum = kwargs.pop('checksum', None)
665685 super(OpMsg, self).__init__(*args, **kwargs)
686 self._checksum = checksum
666687 if len(self._docs) > 1:
667688 raise_args_err('OpMsg too many documents', ValueError)
668689
671692 """True if this OpMsg can read from a secondary."""
672693 read_preference = self.doc.get('$readPreference')
673694 return read_preference and read_preference.get('mode') != 'primary'
695
696 @property
697 def checksum(self):
698 """The provided checksum, if set, else None."""
699 return self._checksum
674700
675701 slave_okay = slave_ok
676702 """Synonym for `.slave_ok`."""
14961522 >>> client.close()
14971523 >>> s.stop()
14981524 """
1525 return self._insert_responder("top", matcher, *args, **kwargs)
1526
1527 subscribe = autoresponds
1528 """Synonym for `.autoresponds`."""
1529
1530 @_synchronized
1531 def append_responder(self, matcher, *args, **kwargs):
1532 """Add a responder of last resort.
1533
1534 Like `.autoresponds`, but instead of adding a responder to the top of
1535 the stack, add it to the bottom. This responder will be called if no
1536 others match.
1537 """
1538 return self._insert_responder("bottom", matcher, *args, **kwargs)
1539
1540 def _insert_responder(self, where, matcher, *args, **kwargs):
14991541 responder = _AutoResponder(self, matcher, *args, **kwargs)
1500 self._autoresponders.append(responder)
1542 if where == "top":
1543 self._autoresponders.append(responder)
1544 elif where == "bottom":
1545 self._autoresponders.insert(0, responder)
1546 else:
1547 raise RuntimeError("Invalid 'where': %r" % (where,))
1548
15011549 try:
15021550 request = self._request_q.peek(block=False)
15031551 except Empty:
15071555 self._request_q.get_nowait() # Pop it.
15081556
15091557 return responder
1510
1511 subscribe = autoresponds
1512 """Synonym for `.autoresponds`."""
15131558
15141559 @_synchronized
15151560 def cancel_responder(self, responder):
16141659 server_thread.start()
16151660 except socket.error as error:
16161661 if error.errno not in (
1617 errno.EAGAIN, errno.EBADF, errno.EWOULDBLOCK):
1662 errno.EAGAIN, errno.EBADF, errno.ENOTSOCK,
1663 errno.EWOULDBLOCK):
16181664 raise
16191665 except select.error as error:
1620 if error.args[0] == errno.EBADF:
1666 if error.args[0] in (errno.EBADF, errno.ENOTSOCK):
16211667 # Closed.
16221668 break
16231669 else:
16421688 else:
16431689 self._request_q.put(request)
16441690 except socket.error as error:
1645 if error.errno in (errno.ECONNRESET, errno.EBADF):
1691 if error.errno in (errno.ECONNRESET, errno.EBADF,
1692 errno.ENOTSOCK):
16461693 # We hung up, or the client did.
16471694 break
16481695 raise
16491696 except select.error as error:
1650 if error.args[0] == errno.EBADF:
1697 if error.args[0] in (errno.EBADF, errno.ENOTSOCK):
16511698 # Closed.
16521699 break
16531700 else:
20152062 auto_ismaster=True,
20162063 uds_path=uds_path)
20172064 if all_ok:
2018 server.autoresponds({})
2065 server.append_responder({})
20192066 server.autoresponds('whatsmyuri', you='localhost:12345')
20202067 server.autoresponds({'getLog': 'startupWarnings'},
20212068 log=['hello from %s!' % name])
00 -----BEGIN PRIVATE KEY-----
1 MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAK53miP9GczBWXnq
2 NxHwQkgVqsDuesjwJbWilMK4gf3fjnf2PN3qDpnGbZbPD0ij8975pIKtSPoDycFm
3 A8Mogip0yU2Lv2lL56CWthSBftOFDL2CWIsmuuURFXZPiVLtLytfI9oLASZFlywW
4 Cs83qEDTvdW8VoVhVsxV1JFDnpXLAgMBAAECgYBoGBgxrMt97UazhNkCrPT/CV5t
5 6lv8E7yMGMrlOyzkCkR4ssQyK3o2qbutJTGbR6czvIM5LKbD9Qqlh3ZrNHokWmTR
6 VQQpJxt8HwP5boQvwRHg9+KSGr4JvRko1qxFs9C7Bzjt4r9VxdjhwZPdy0McGI/z
7 yPXyQHjqBayrHV1EwQJBANorfCKeIxLhH3LAeUZuRS8ACldJ2N1kL6Ov43/v+0S/
8 OprQeBTODuTds3sv7FCT1aYDTOe6JLNOwN2i4YVOMBsCQQDMuCozrwqftD17D06P
9 9+lRXUekY5kFBs5j28Xnl8t8jnuxsXtQUTru660LD0QrmDNSauhpEmlpJknicnGt
10 hmwRAkEA12MI6bBPlir0/jgxQqxI1w7mJqj8Vg27zpEuO7dzzLoyJHddpcSNBbwu
11 npaAakiZK42klj26T9+XHvjYRuAbMwJBAJ5WnwWEkGH/pUHGEAyYQdSVojDKe/MA
12 Vae0tzguFswK5C8GyArSGRPsItYYA7D4MlG/sGx8Oh2C6MiFndkJzBECQDcP1y4r
13 Qsek151t1zArLKH4gG5dQAeZ0Lc2VeC4nLMUqVwrHcZDdd1RzLlSaH3j1MekFVfT
14 6v6rrcNLEVbeuk4=
1 MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+DyBLgFcu8SJ/
2 yHzppcxcTqLxMA+iMiTsqMpELEMxENSt5102reD9vkjEQPXW7oAZof4Dx+qOSe8n
3 kSSLaDYjyvnoy7XBajZbQjksP7gBR2Cl8wISrGS3+atZ5uPMl6N6dFI4HvXIcDBx
4 XnH+VkV6iyhO9aCmQI6jkQD1vJkg3J4jEJ3IDulqbzhk7tnSv4Hrs345TcbWrmB3
5 bcs+rCPfGxDfVyimCtbt478iEl/Im5Cz+ectNOrCZ++Xb6459qQ0v8CV04rUorwg
6 gT+/2GgCN+8ZlvDmqE6dy539TZq+ZfrpRAviqxUFvVWIXzg5PyX8K3Vk2of6rcck
7 Q8epO5/bAgMBAAECggEAP32EF1S/SyIomTFbcR3+39MxIYshndhMd3aHYzC6HXj2
8 40VH4U1CvOFFI7JjrbIsvuNbnN264F+YccpNv/hHJbvXskni5MLbd67utHZwvJSg
9 l69PQPewCblw4W59KMp7RRv4n2DQUG4R8L1RLVqaiS5Vf9MUIJWuULvO60heixg0
10 jmKkmCX2QBoQW/j5C7Bprdzo8DLNX84EPe0K6+pqCUVbz/E/66kJ/i76a47wRIec
11 YPlZaeZ0AIPqZ+QigC5ZaKwbIo6wFMoaCavBTY53w48pWPi/LL6I0ACsAihv0Zlt
12 Ik4nk6cSSC+mtc9GPZSp4Dq5svvkl8D6RIpYwCT9yQKBgQDk2fEi1JqTvt78Zuxu
13 A+MQQJtNoSQmkYByCTUy/4+y71Yz6cHfR0n0vpwOSv7CNPmuC3sQ5Fo7+FsNMTAI
14 +riIjybtgenN9ljgLHHcoPN2E++NEQUCwvJgYyyfPV9rAAHNN62d+Inu3XZf3rPh
15 uvuN3JJB6D1UQU2xinNu9LjL/QKBgQDUmxcYsfc/WNd/zQXJ31TeS5bFe6tSGwVO
16 +3XYfVmq4Vi8HAef6a5mjKybqEyrOpn7WPMWL2lLa6bcoA2785zN+uqe9whm0uup
17 FydnyFr5Cjr+yptCfR7b8jj7syT+MvVUacOu/Vt2x3g8cr8QUuUbiIPKqQqb4UEY
18 2HKEPrdmtwKBgHcZgWgqEyRPEodzHRqIRVSA+xIkicbUtG8koZ4f6G4sJsWvoukL
19 lc6coGTD3N+/aC2O5gY9gURylRhBgAk8SmsvbQfwM3iv+0L3fm5fCTVrXKEiuWPd
20 hvxowKFC9HSgNU/S6TUsUsSQVvm/0gfpIt+KakeIkNpXfhKmxjp5e+8VAoGBAKxd
21 1LrbxhWgpI5jnTbOjtLuu5z+J6aYa5ReQGu1LNZifnt7yh626QMRN/u21fnYt/BU
22 bDhnVdmkvJKQXLItzsocjM02gKREinT7ZaI5iK/xwGTDxF6CbFtrpRFDa1F/5PB8
23 Ev8zP00saOmxKgBFBKRu6FKM/CHm3M0U5rsa0bw/AoGBANknEpinPgmMDjPOJmZp
24 i+BQTKwQirxaFWPHs/89RXsIPg5kfnMw9Pz3QmaVsV17+4dRaDqNhXiw0ZkSAPsX
25 gWyI+6AmOFsnPBrFs/Ne7fjo33reuGIvUrtWIpYRyKvohDAmcEDFTS/DGmhQsya/
26 e+K9MCpuenwOBs+mL9EPPS9s
1527 -----END PRIVATE KEY-----
1628 -----BEGIN CERTIFICATE-----
17 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
3349 -----END CERTIFICATE-----
0 Metadata-Version: 1.1
0 Metadata-Version: 1.2
11 Name: mockupdb
2 Version: 1.7.0
2 Version: 1.8.0
33 Summary: MongoDB Wire Protocol server library
44 Home-page: https://github.com/ajdavis/mongo-mockup-db
55 Author: A. Jesse Jiryu Davis
66 Author-email: jesse@mongodb.com
77 License: Apache License, Version 2.0
8 Description-Content-Type: UNKNOWN
98 Description: ========
109 MockupDB
1110 ========
2019
2120 Changelog
2221 =========
22
23 Next Release
24 ------------
25
26 MockupDB supports Python 3.4 through 3.8; it no longer supports Python 2.6 or
27 Python 3.3.
28
29 New method ``MockupDB.append_responder`` to add an autoresponder of last resort.
30
31 Fix a bug in ``interactive_server`` with ``all_ok=True``. It had returned an
32 empty isMaster response, causing drivers to throw errors like "Server at
33 localhost:27017 reports wire version 0, but this version of PyMongo requires at
34 least 2 (MongoDB 2.6)."
35
36 Stop logging "OSError: [WinError 10038] An operation was attempted on something
37 that is not a socket" on Windows after a client disconnects.
38
39 Parse OP_MSGs with any number of sections in any order. This allows write
40 commands from the mongo shell, which sends sections in the opposite order from
41 drivers. Handle OP_MSGs with checksums, such as those sent by the mongo shell
42 beginning in 4.2.
2343
2444 1.7.0 (2018-12-02)
2545 ------------------
141161 Classifier: License :: OSI Approved :: Apache Software License
142162 Classifier: Natural Language :: English
143163 Classifier: Programming Language :: Python :: 2
144 Classifier: Programming Language :: Python :: 2.6
145164 Classifier: Programming Language :: Python :: 2.7
146165 Classifier: Programming Language :: Python :: 3
147 Classifier: Programming Language :: Python :: 3.3
148166 Classifier: Programming Language :: Python :: 3.4
167 Classifier: Programming Language :: Python :: 3.5
168 Classifier: Programming Language :: Python :: 3.6
169 Classifier: Programming Language :: Python :: 3.7
170 Classifier: Programming Language :: Python :: 3.8
171 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
77 except ImportError:
88 from distutils.core import setup
99
10 if sys.version_info[:2] < (2, 7):
11 raise RuntimeError("Python version >= 2.7 required.")
1012
1113 with open('README.rst') as readme_file:
1214 readme = readme_file.read()
1416 with open('CHANGELOG.rst') as changelog_file:
1517 changelog = changelog_file.read().replace('.. :changelog:', '')
1618
17 requirements = ['pymongo>=3']
18 test_requirements = []
19
20 if sys.version_info[:2] == (2, 6):
21 requirements.append('ordereddict')
22 test_requirements.append('unittest2')
23
2419 setup(
2520 name='mockupdb',
26 version='1.7.0',
21 version='1.8.0',
2722 description="MongoDB Wire Protocol server library",
2823 long_description=readme + '\n\n' + changelog,
2924 author="A. Jesse Jiryu Davis",
3227 packages=['mockupdb'],
3328 package_dir={'mockupdb': 'mockupdb'},
3429 include_package_data=True,
35 install_requires=requirements,
30 install_requires=['pymongo>=3'],
3631 license="Apache License, Version 2.0",
3732 zip_safe=False,
3833 keywords=["mongo", "mongodb", "wire protocol", "mockupdb", "mock"],
34 python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*",
3935 classifiers=[
4036 'Development Status :: 5 - Production/Stable',
4137 'Intended Audience :: Developers',
4238 "License :: OSI Approved :: Apache Software License",
4339 'Natural Language :: English',
4440 "Programming Language :: Python :: 2",
45 'Programming Language :: Python :: 2.6',
46 'Programming Language :: Python :: 2.7',
47 'Programming Language :: Python :: 3',
48 'Programming Language :: Python :: 3.3',
49 'Programming Language :: Python :: 3.4',
41 "Programming Language :: Python :: 2.7",
42 "Programming Language :: Python :: 3",
43 "Programming Language :: Python :: 3.4",
44 "Programming Language :: Python :: 3.5",
45 "Programming Language :: Python :: 3.6",
46 "Programming Language :: Python :: 3.7",
47 "Programming Language :: Python :: 3.8",
5048 ],
5149 test_suite='tests',
52 tests_require=test_requirements
50 tests_require=[]
5351 )
00 # -*- coding: utf-8 -*-
1
2 import unittest
3
4 try:
5 import unittest2 as unittest
6 except ImportError:
7 pass
88 import ssl
99 import sys
1010 import tempfile
11 import unittest
12 from struct import Struct
1113
1214 if sys.version_info[0] < 3:
1315 from io import BytesIO as StringIO
1921 except ImportError:
2022 from Queue import Queue
2123
22 from bson import (Binary, Code, DBRef, Decimal128, MaxKey, MinKey, ObjectId,
23 Regex, SON, Timestamp)
24 from bson import (Binary, BSON, Code, DBRef, Decimal128, MaxKey, MinKey,
25 ObjectId, Regex, SON, Timestamp)
2426 from bson.codec_options import CodecOptions
2527 from pymongo import MongoClient, message, WriteConcern
2628
2729 from mockupdb import (go, going, Command, CommandBase, Matcher, MockupDB,
28 Request, OpInsert, OpMsg, OpQuery, QUERY_FLAGS)
29 from tests import unittest # unittest2 on Python 2.6.
30 Request, OpInsert, OP_MSG_FLAGS, OpMsg, OpQuery,
31 QUERY_FLAGS)
3032
3133
3234 @contextlib.contextmanager
367369 self.assertEqual(3, response['ok'])
368370
369371
372 class TestOpMsg(unittest.TestCase):
373 def setUp(self):
374 self.server = MockupDB(auto_ismaster={'maxWireVersion': 6})
375 self.server.run()
376 self.addCleanup(self.server.stop)
377 self.client = MongoClient(self.server.uri)
378
379 def test_flags(self):
380 doc = SON([('foo', 1), ('$db', 'mydb')])
381 obj = BSON.encode(doc)
382
383 for flag_name, flag_bit in OP_MSG_FLAGS.items():
384 # MockupDB strips 16-byte header then calls unpack on body.
385 message_body = b''.join([
386 Struct('<I').pack(flag_bit), # flagBits
387 Struct('<b').pack(0), # section kind
388 obj,
389 ])
390
391 if flag_name == 'checksumPresent':
392 message_body += Struct('<I').pack(1234)
393
394 op_msg = OpMsg.unpack(msg=message_body,
395 client=None,
396 server=None,
397 request_id=0)
398
399 self.assertEqual(op_msg.flags, flag_bit)
400 self.assertEqual(op_msg.doc, doc)
401 self.assertEqual(op_msg.namespace, 'mydb')
402
403 if flag_name == 'checksumPresent':
404 self.assertEqual(op_msg.checksum, 1234)
405 else:
406 self.assertEqual(op_msg.checksum, None)
407
408
370409 if __name__ == '__main__':
371410 unittest.main()