|
29 | 29 | "(twisted is not available for python >= 3.0 && python < 3.3)") |
30 | 30 | TWISTED_MISSING = True |
31 | 31 |
|
| 32 | +if sys.version_info >= (3, 5): |
| 33 | + # asyncio would be available in 3.4, but it's not supported by mpd.asyncio |
| 34 | + import asyncio |
| 35 | +else: |
| 36 | + asyncio = None |
| 37 | + |
32 | 38 | try: |
33 | 39 | import mock |
34 | 40 | except ImportError: |
@@ -905,6 +911,125 @@ def success(result): |
905 | 911 |
|
906 | 912 | self.protocol.close().addCallback(success) |
907 | 913 |
|
| 914 | +class AsyncMockServer: |
| 915 | + def __init__(self): |
| 916 | + self._output = asyncio.Queue() |
| 917 | + self._expectations = [] |
| 918 | + |
| 919 | + def get_streams(self): |
| 920 | + result = asyncio.Future() |
| 921 | + result.set_result((self, self)) |
| 922 | + return result |
| 923 | + |
| 924 | + def readline(self): |
| 925 | + # directly passing around the awaitable |
| 926 | + return self._output.get() |
| 927 | + |
| 928 | + def write(self, data): |
| 929 | + try: |
| 930 | + next_write = self._expectations[0][0][0] |
| 931 | + except IndexError: |
| 932 | + self.error("Data written to mock even though none expected: %r" % data) |
| 933 | + if next_write == data: |
| 934 | + self._expectations[0][0].pop(0) |
| 935 | + self._feed() |
| 936 | + else: |
| 937 | + self.error("Mock got %r, expected %r" % (data, next_write)) |
| 938 | + |
| 939 | + def error(self, message): |
| 940 | + raise AssertionError(message) |
| 941 | + |
| 942 | + def _feed(self): |
| 943 | + if len(self._expectations[0][0]) == 0: |
| 944 | + _, response_lines = self._expectations.pop(0) |
| 945 | + for l in response_lines: |
| 946 | + self._output.put_nowait(l) |
| 947 | + |
| 948 | + def expect_exchange(self, request_lines, response_lines): |
| 949 | + self._expectations.append((request_lines, response_lines)) |
| 950 | + self._feed() |
| 951 | + |
| 952 | +@unittest.skipIf(asyncio is None, "requires asyncio to be available") |
| 953 | +class TestAsyncioMPD(unittest.TestCase): |
| 954 | + def init_client(self, odd_hello=None): |
| 955 | + import mpd.asyncio |
| 956 | + |
| 957 | + self.loop = asyncio.get_event_loop() |
| 958 | + |
| 959 | + self.mockserver = AsyncMockServer() |
| 960 | + asyncio.open_connection = mock.MagicMock(return_value=self.mockserver.get_streams()) |
| 961 | + |
| 962 | + if odd_hello is None: |
| 963 | + hello_lines = [b'OK MPD mocker\n'] |
| 964 | + else: |
| 965 | + hello_lines = odd_hello |
| 966 | + |
| 967 | + self.mockserver.expect_exchange([], hello_lines) |
| 968 | + |
| 969 | + self.client = mpd.asyncio.MPDClient() |
| 970 | + self._await(self.client.connect(TEST_MPD_HOST, TEST_MPD_PORT, loop=self.loop)) |
| 971 | + |
| 972 | + asyncio.open_connection.assert_called_with(TEST_MPD_HOST, TEST_MPD_PORT, loop=self.loop) |
| 973 | + |
| 974 | + def _await(self, future): |
| 975 | + return self.loop.run_until_complete(future) |
| 976 | + |
| 977 | + def test_oddhello(self): |
| 978 | + self.assertRaises(mpd.base.ProtocolError, self.init_client, odd_hello=[b'NOT OK\n']) |
| 979 | + |
| 980 | + @unittest.skip("This test would add 5 seconds of idling to the run") |
| 981 | + def test_noresponse(self): |
| 982 | + self.assertRaises(mpd.base.ConnectionError, self.init_client, odd_hello=[]) |
| 983 | + |
| 984 | + def test_status(self): |
| 985 | + self.init_client() |
| 986 | + |
| 987 | + self.mockserver.expect_exchange([b"status\n"], [ |
| 988 | + b"volume: 70\n", |
| 989 | + b"repeat: 0\n", |
| 990 | + b"random: 1\n", |
| 991 | + b"single: 0\n", |
| 992 | + b"consume: 0\n", |
| 993 | + b"playlist: 416\n", |
| 994 | + b"playlistlength: 7\n", |
| 995 | + b"mixrampdb: 0.000000\n", |
| 996 | + b"state: play\n", |
| 997 | + b"song: 4\n", |
| 998 | + b"songid: 19\n", |
| 999 | + b"time: 28:403\n", |
| 1000 | + b"elapsed: 28.003\n", |
| 1001 | + b"bitrate: 465\n", |
| 1002 | + b"duration: 403.066\n", |
| 1003 | + b"audio: 44100:16:2\n", |
| 1004 | + b"OK\n", |
| 1005 | + ]) |
| 1006 | + |
| 1007 | + status = self._await(self.client.status()) |
| 1008 | + self.assertEqual(status, { |
| 1009 | + 'audio': '44100:16:2', |
| 1010 | + 'bitrate': '465', |
| 1011 | + 'consume': '0', |
| 1012 | + 'duration': '403.066', |
| 1013 | + 'elapsed': '28.003', |
| 1014 | + 'mixrampdb': '0.000000', |
| 1015 | + 'playlist': '416', |
| 1016 | + 'playlistlength': '7', |
| 1017 | + 'random': '1', |
| 1018 | + 'repeat': '0', |
| 1019 | + 'single': '0', |
| 1020 | + 'song': '4', |
| 1021 | + 'songid': '19', |
| 1022 | + 'state': 'play', |
| 1023 | + 'time': '28:403', |
| 1024 | + 'volume': '70', |
| 1025 | + }) |
| 1026 | + |
| 1027 | + def test_mocker(self): |
| 1028 | + """Does the mock server refuse unexpected writes?""" |
| 1029 | + self.init_client() |
| 1030 | + |
| 1031 | + self.mockserver.expect_exchange([b"expecting odd things\n"], [b""]) |
| 1032 | + self.assertRaises(AssertionError, self._await, self.client.status()) |
908 | 1033 |
|
909 | 1034 | if __name__ == '__main__': |
910 | 1035 | unittest.main() |
0 commit comments