forked from mopidy/mopidy
/
test_playback.py
228 lines (177 loc) · 6.76 KB
/
test_playback.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
from __future__ import absolute_import, unicode_literals
import mock
import pytest
import requests.exceptions
import responses
from mopidy import exceptions
from mopidy.audio import scan
from mopidy.stream import actor
TIMEOUT = 1000
PLAYLIST_URI = 'http://example.com/listen.m3u'
STREAM_URI = 'http://example.com/stream.mp3'
BODY = """
#EXTM3U
http://example.com/stream.mp3
http://foo.bar/baz
""".strip()
@pytest.fixture
def config():
return {
'proxy': {},
'stream': {
'timeout': TIMEOUT,
'metadata_blacklist': [],
'protocols': ['http'],
},
'file': {
'enabled': False
},
}
@pytest.fixture
def audio():
return mock.Mock()
@pytest.yield_fixture
def scanner():
patcher = mock.patch.object(scan, 'Scanner')
yield patcher.start()()
patcher.stop()
@pytest.fixture
def backend(audio, config, scanner):
return actor.StreamBackend(audio=audio, config=config)
@pytest.fixture
def provider(backend):
return backend.playback
class TestTranslateURI(object):
@responses.activate
def test_audio_stream_returns_same_uri(self, scanner, provider):
scanner.scan.side_effect = [
# Set playable to False to test detection by mimetype
mock.Mock(mime='audio/mpeg', playable=False),
]
result = provider.translate_uri(STREAM_URI)
scanner.scan.assert_called_once_with(STREAM_URI, timeout=mock.ANY)
assert result == STREAM_URI
@responses.activate
def test_playable_ogg_stream_is_not_considered_a_playlist(
self, scanner, provider):
scanner.scan.side_effect = [
# Set playable to True to ignore detection as possible playlist
mock.Mock(mime='application/ogg', playable=True),
]
result = provider.translate_uri(STREAM_URI)
scanner.scan.assert_called_once_with(STREAM_URI, timeout=mock.ANY)
assert result == STREAM_URI
@responses.activate
def test_text_playlist_with_mpeg_stream(
self, scanner, provider, caplog):
scanner.scan.side_effect = [
# Scanning playlist
mock.Mock(mime='text/foo', playable=False),
# Scanning stream
mock.Mock(mime='audio/mpeg', playable=True),
]
responses.add(
responses.GET, PLAYLIST_URI,
body=BODY, content_type='audio/x-mpegurl')
result = provider.translate_uri(PLAYLIST_URI)
assert scanner.scan.mock_calls == [
mock.call(PLAYLIST_URI, timeout=mock.ANY),
mock.call(STREAM_URI, timeout=mock.ANY),
]
assert result == STREAM_URI
# Check logging to ensure debuggability
assert 'Unwrapping stream from URI: %s' % PLAYLIST_URI
assert 'Parsed playlist (%s)' % PLAYLIST_URI in caplog.text()
assert 'Unwrapping stream from URI: %s' % STREAM_URI
assert (
'Unwrapped potential audio/mpeg stream: %s' % STREAM_URI
in caplog.text())
# Check proper Requests session setup
assert responses.calls[0].request.headers['User-Agent'].startswith(
'Mopidy-Stream/')
@responses.activate
def test_xml_playlist_with_mpeg_stream(self, scanner, provider):
scanner.scan.side_effect = [
# Scanning playlist
mock.Mock(mime='application/xspf+xml', playable=False),
# Scanning stream
mock.Mock(mime='audio/mpeg', playable=True),
]
responses.add(
responses.GET, PLAYLIST_URI,
body=BODY, content_type='application/xspf+xml')
result = provider.translate_uri(PLAYLIST_URI)
assert scanner.scan.mock_calls == [
mock.call(PLAYLIST_URI, timeout=mock.ANY),
mock.call(STREAM_URI, timeout=mock.ANY),
]
assert result == STREAM_URI
@responses.activate
def test_scan_fails_but_playlist_parsing_succeeds(
self, scanner, provider, caplog):
scanner.scan.side_effect = [
# Scanning playlist
exceptions.ScannerError('some failure'),
# Scanning stream
mock.Mock(mime='audio/mpeg', playable=True),
]
responses.add(
responses.GET, PLAYLIST_URI,
body=BODY, content_type='audio/x-mpegurl')
result = provider.translate_uri(PLAYLIST_URI)
assert 'Unwrapping stream from URI: %s' % PLAYLIST_URI
assert (
'GStreamer failed scanning URI (%s)' % PLAYLIST_URI
in caplog.text())
assert 'Parsed playlist (%s)' % PLAYLIST_URI in caplog.text()
assert (
'Unwrapped potential audio/mpeg stream: %s' % STREAM_URI
in caplog.text())
assert result == STREAM_URI
@responses.activate
def test_scan_fails_and_playlist_parsing_fails(
self, scanner, provider, caplog):
scanner.scan.side_effect = exceptions.ScannerError('some failure')
responses.add(
responses.GET, STREAM_URI,
body=b'some audio data', content_type='audio/mpeg')
result = provider.translate_uri(STREAM_URI)
assert 'Unwrapping stream from URI: %s' % STREAM_URI
assert (
'GStreamer failed scanning URI (%s)' % STREAM_URI
in caplog.text())
assert (
'Failed parsing URI (%s) as playlist; found potential stream.'
% STREAM_URI in caplog.text())
assert result == STREAM_URI
@responses.activate
def test_failed_download_returns_none(self, scanner, provider, caplog):
scanner.scan.side_effect = [
mock.Mock(mime='text/foo', playable=False)
]
responses.add(
responses.GET, PLAYLIST_URI,
body=requests.exceptions.HTTPError('Kaboom'))
result = provider.translate_uri(PLAYLIST_URI)
assert result is None
assert (
'Unwrapping stream from URI (%s) failed: '
'error downloading URI' % PLAYLIST_URI) in caplog.text()
@responses.activate
def test_playlist_references_itself(self, scanner, provider, caplog):
scanner.scan.side_effect = [
mock.Mock(mime='text/foo', playable=False)
]
responses.add(
responses.GET, PLAYLIST_URI,
body=BODY.replace(STREAM_URI, PLAYLIST_URI),
content_type='audio/x-mpegurl')
result = provider.translate_uri(PLAYLIST_URI)
assert 'Unwrapping stream from URI: %s' % PLAYLIST_URI in caplog.text()
assert (
'Parsed playlist (%s) and found new URI: %s'
% (PLAYLIST_URI, PLAYLIST_URI)) in caplog.text()
assert (
'Unwrapping stream from URI (%s) failed: '
'playlist referenced itself' % PLAYLIST_URI) in caplog.text()
assert result is None