|
1
|
|
|
#!/usr/bin/env python |
|
2
|
|
|
|
|
3
|
|
|
"""Unit tests for the dtb.user module.""" |
|
4
|
|
|
|
|
5
|
|
|
import unittest |
|
6
|
|
|
from unittest.mock import patch, Mock, call |
|
7
|
|
|
|
|
8
|
|
|
import os |
|
9
|
|
|
import tempfile |
|
10
|
|
|
import shutil |
|
11
|
|
|
|
|
12
|
|
|
from dtb.user import User, get_current |
|
13
|
|
|
|
|
14
|
|
|
from dtb.test import FILES |
|
15
|
|
|
|
|
16
|
|
|
FAKESONG = os.path.join(FILES, 'FakeSong.mp3') |
|
17
|
|
|
FAKELINK = os.path.join(FILES, 'abc123.yml') |
|
18
|
|
|
FAKEFILE = os.path.join(FILES, 'FakeFile.yml') |
|
19
|
|
|
BROKENLINK = os.path.join(FILES, 'broken.yml') |
|
20
|
|
|
|
|
21
|
|
|
|
|
22
|
|
|
class MockSong(Mock): |
|
23
|
|
|
"""Mock Song class.""" |
|
24
|
|
|
|
|
25
|
|
|
link = Mock() |
|
26
|
|
|
|
|
27
|
|
|
|
|
28
|
|
|
class TestUser(unittest.TestCase): # pylint: disable=R0904 |
|
29
|
|
|
"""Unit tests for the User class.""" # pylint: disable=C0103,W0212 |
|
30
|
|
|
|
|
31
|
|
|
INFOS = [('PC', 'MrTemp'), |
|
32
|
|
|
('PC', 'MrTemp2'), |
|
33
|
|
|
('PC', 'MrTemp3')] |
|
34
|
|
|
|
|
35
|
|
|
@classmethod |
|
36
|
|
|
@patch('dtb.user.get_info', Mock(side_effect=INFOS)) |
|
37
|
|
|
def setUpClass(cls): |
|
38
|
|
|
cls.root = tempfile.mkdtemp() |
|
39
|
|
|
cls.downloads = tempfile.mkdtemp() |
|
40
|
|
|
cls.name = 'TempUser' |
|
41
|
|
|
cls.user = User.new(cls.root, cls.name, downloads=cls.downloads) |
|
42
|
|
|
cls.user2 = User.new(cls.root, cls.name + '2') |
|
43
|
|
|
cls.user3 = User.new(cls.root, cls.name + '3') |
|
44
|
|
|
with open(os.path.join(cls.root, 'desktop.ini'), 'w'): |
|
45
|
|
|
pass # create a "junk" file in the share directory |
|
46
|
|
|
|
|
47
|
|
|
@classmethod |
|
48
|
|
|
def tearDownClass(cls): |
|
49
|
|
|
shutil.rmtree(cls.root) |
|
50
|
|
|
shutil.rmtree(cls.downloads) |
|
51
|
|
|
|
|
52
|
|
|
def test_new_duplicate(self): |
|
53
|
|
|
"""Verify a user cannot be created twice.""" |
|
54
|
|
|
self.assertRaises(EnvironmentError, User.new, self.root, self.name) |
|
55
|
|
|
|
|
56
|
|
|
# https://github.com/jacebrowning/dropthebeat/issues/1 |
|
57
|
|
|
def test_new_folder_exists(self): |
|
58
|
|
|
"""Verify a user can be created when their friend directory exists.""" |
|
59
|
|
|
name = 'FolderExists' |
|
60
|
|
|
os.mkdir(os.path.join(self.user.path, name)) |
|
61
|
|
|
user = User.new(self.root, name) |
|
62
|
|
|
try: |
|
63
|
|
|
pass |
|
64
|
|
|
finally: |
|
65
|
|
|
user.delete() |
|
66
|
|
|
|
|
67
|
|
|
def test_add_old_format(self): |
|
68
|
|
|
"""Verify a user can be added to an old format.""" |
|
69
|
|
|
root = tempfile.mkdtemp() |
|
70
|
|
|
try: |
|
71
|
|
|
with patch('dtb.user.get_info', Mock(return_value=self.INFOS[0])): |
|
72
|
|
|
user = User.new(root, 'TempUser') |
|
73
|
|
|
open(user.path_info, 'w').close() # blank the file |
|
74
|
|
|
with patch('dtb.user.get_info', Mock(return_value=self.INFOS[1])): |
|
75
|
|
|
user2 = User.add(root, 'TempUser') |
|
76
|
|
|
self.assertEqual(1, len(user2.info)) |
|
77
|
|
|
finally: |
|
78
|
|
|
shutil.rmtree(root) |
|
79
|
|
|
|
|
80
|
|
|
def test_str(self): |
|
81
|
|
|
"""Verify a user can be converted to a string.""" |
|
82
|
|
|
text = str(os.path.join(self.root, self.name)) |
|
83
|
|
|
self.assertEqual(text, str(self.user)) |
|
84
|
|
|
|
|
85
|
|
|
def test_cmp(self): |
|
86
|
|
|
"""Verify users can be compared.""" |
|
87
|
|
|
self.assertEqual(self.user, self.user) |
|
88
|
|
|
self.assertNotEqual(self.user, self.user2) |
|
89
|
|
|
|
|
90
|
|
|
def test_name(self): |
|
91
|
|
|
"""Verify a user's name is correct.""" |
|
92
|
|
|
self.assertEqual(self.name, self.user.name) |
|
93
|
|
|
|
|
94
|
|
|
def test_root(self): |
|
95
|
|
|
"""Verify a user's root path is correct.""" |
|
96
|
|
|
self.assertEqual(self.root, self.user.root) |
|
97
|
|
|
|
|
98
|
|
|
def test_path_private(self): |
|
99
|
|
|
"""Verify a user's private path is correct.""" |
|
100
|
|
|
path = os.path.join(self.root, self.name, '.dtb') |
|
101
|
|
|
self.assertEqual(path, self.user.path_private) |
|
102
|
|
|
self.assertTrue(os.path.isdir(path)) |
|
103
|
|
|
|
|
104
|
|
|
def test_path_drops(self): |
|
105
|
|
|
"""Verify a user's drops path is correct.""" |
|
106
|
|
|
path = os.path.join(self.root, self.name, '.dtb', 'drops') |
|
107
|
|
|
self.assertEqual(path, self.user.path_drops) |
|
108
|
|
|
self.assertTrue(os.path.isdir(path)) |
|
109
|
|
|
|
|
110
|
|
|
def test_path_info(self): |
|
111
|
|
|
"""Verify a user's info path is correct.""" |
|
112
|
|
|
path = os.path.join(self.root, self.name, '.dtb', 'info.yml') |
|
113
|
|
|
self.assertEqual(path, self.user.path_info) |
|
114
|
|
|
self.assertTrue(os.path.isfile(path)) |
|
115
|
|
|
|
|
116
|
|
|
def test_path_library(self): |
|
117
|
|
|
"""Verify a user's library path is correct.""" |
|
118
|
|
|
path = os.path.join(self.root, self.name, '.dtb', 'library.sqlite3') |
|
119
|
|
|
self.assertEqual(path, self.user.path_library) |
|
120
|
|
|
# TODO: add this test when library support is added |
|
121
|
|
|
# self.assertTrue(os.path.isfile(path)) |
|
122
|
|
|
|
|
123
|
|
|
def test_path_reuests(self): |
|
124
|
|
|
"""Verify a user's requests path is correct.""" |
|
125
|
|
|
path = os.path.join(self.root, self.name, '.dtb', 'requests.yml') |
|
126
|
|
|
self.assertEqual(path, self.user.path_requests) |
|
127
|
|
|
self.assertTrue(os.path.isfile(path)) |
|
128
|
|
|
|
|
129
|
|
|
def test_path_settings(self): |
|
130
|
|
|
"""Verify a user's settings path is correct.""" |
|
131
|
|
|
path = os.path.join(self.root, self.name, '.dtb', 'settings.yml') |
|
132
|
|
|
self.assertEqual(path, self.user.path_settings) |
|
133
|
|
|
self.assertTrue(os.path.isfile(path)) |
|
134
|
|
|
|
|
135
|
|
|
@patch('dtb.user.get_info', Mock(return_value=INFOS[0])) |
|
136
|
|
|
def test_path_downloads(self): |
|
137
|
|
|
"""Verify a user's downloads path is correct.""" |
|
138
|
|
|
path = self.downloads |
|
139
|
|
|
self.assertEqual(path, self.user.path_downloads) |
|
140
|
|
|
self.assertTrue(os.path.isdir(path)) |
|
141
|
|
|
|
|
142
|
|
|
@patch('dtb.user.get_info', Mock(return_value=INFOS[0])) |
|
143
|
|
|
def test_path_downloads_set(self): |
|
144
|
|
|
"""Verify a user's downloads path can be set.""" |
|
145
|
|
|
temp = tempfile.mkdtemp() |
|
146
|
|
|
try: |
|
147
|
|
|
self.user.path_downloads = temp |
|
148
|
|
|
self.assertEqual(temp, self.user.path_downloads) |
|
149
|
|
|
finally: |
|
150
|
|
|
shutil.rmtree(temp) |
|
151
|
|
|
|
|
152
|
|
|
@patch('dtb.user.get_info', Mock(return_value=INFOS[0])) |
|
153
|
|
|
def test_path_downloads_set_old_format(self): |
|
154
|
|
|
"""Verify a user's downloads path can be set (from an old format).""" |
|
155
|
|
|
open(self.user.path_info, 'w').close() # blank the file |
|
156
|
|
|
temp = tempfile.mkdtemp() |
|
157
|
|
|
try: |
|
158
|
|
|
self.user.path_downloads = temp |
|
159
|
|
|
self.assertEqual(temp, self.user.path_downloads) |
|
160
|
|
|
finally: |
|
161
|
|
|
shutil.rmtree(temp) |
|
162
|
|
|
|
|
163
|
|
|
def test_info(self): |
|
164
|
|
|
"""Verify a user's info is correct.""" |
|
165
|
|
|
self.assertEqual([('PC', 'MrTemp')], self.user.info) |
|
166
|
|
|
|
|
167
|
|
|
def test_friends(self): |
|
168
|
|
|
"""Verify a user's friends are correct.""" |
|
169
|
|
|
friends = list(self.user.friends) |
|
170
|
|
|
self.assertEqual(2, len(friends)) |
|
171
|
|
|
self.assertIsInstance(friends[0], User) |
|
172
|
|
|
|
|
173
|
|
|
def test_incoming(self): |
|
174
|
|
|
"""Verify a user's incoming songs are correct.""" |
|
175
|
|
|
path = os.path.join(self.user.path, 'TempUser2', '_a_song') |
|
176
|
|
|
open(path, 'w').close() # touch the file |
|
177
|
|
|
try: |
|
178
|
|
|
songs = list(self.user.incoming) |
|
179
|
|
|
self.assertEqual(1, len(songs)) |
|
180
|
|
|
self.assertEqual('TempUser2', songs[0].friendname) |
|
181
|
|
|
finally: |
|
182
|
|
|
os.remove(path) |
|
183
|
|
|
|
|
184
|
|
|
def test_incoming_zero(self): |
|
185
|
|
|
"""Verify there can be zero incoming songs.""" |
|
186
|
|
|
songs = list(self.user.incoming) |
|
187
|
|
|
self.assertEqual(0, len(songs)) |
|
188
|
|
|
|
|
189
|
|
|
def test_outgoing(self): |
|
190
|
|
|
"""Verify a user's outgoing songs are correct.""" |
|
191
|
|
|
path = os.path.join(self.user2.path, self.name, '_a_song') |
|
192
|
|
|
open(path, 'w').close() # touch the file |
|
193
|
|
|
try: |
|
194
|
|
|
songs = list(self.user.outgoing) |
|
195
|
|
|
self.assertEqual(1, len(songs)) |
|
196
|
|
|
self.assertEqual(self.user2.name, songs[0].friendname) |
|
197
|
|
|
finally: |
|
198
|
|
|
os.remove(path) |
|
199
|
|
|
|
|
200
|
|
|
def test_outgoing_zero(self): |
|
201
|
|
|
"""Verify there can be zero incoming songs.""" |
|
202
|
|
|
songs = list(self.user.outgoing) |
|
203
|
|
|
self.assertEqual(0, len(songs)) |
|
204
|
|
|
|
|
205
|
|
|
def test_cleanup_unlinked(self): |
|
206
|
|
|
"""Verify a user's directory can be cleaned.""" |
|
207
|
|
|
path = os.path.join(self.user.path_drops, '_a_song') |
|
208
|
|
|
path2 = os.path.join(self.user2.path, self.name, '_a_song2') |
|
209
|
|
|
open(path, 'w').close() # touch the file |
|
210
|
|
|
open(path2, 'w').close() # touch the file |
|
211
|
|
|
try: |
|
212
|
|
|
self.assertEqual(1, len(os.listdir(self.user.path_drops))) |
|
213
|
|
|
self.user.cleanup() |
|
214
|
|
|
self.assertEqual(0, len(os.listdir(self.user.path_drops))) |
|
215
|
|
|
finally: |
|
216
|
|
|
os.remove(path2) |
|
217
|
|
|
|
|
218
|
|
|
# https://github.com/jacebrowning/dropthebeat/issues/5 |
|
219
|
|
|
def test_cleanup_empty_dirs(self): |
|
220
|
|
|
"""Verify empty directories are deleted during cleanup.""" |
|
221
|
|
|
empty = os.path.join(self.user.path, 'empty') |
|
222
|
|
|
os.mkdir(empty) |
|
223
|
|
|
empty2 = os.path.join(self.root, 'empty') |
|
224
|
|
|
os.mkdir(empty2) |
|
225
|
|
|
self.assertTrue(os.path.exists(empty)) |
|
226
|
|
|
self.assertTrue(os.path.exists(empty2)) |
|
227
|
|
|
self.user.cleanup() |
|
228
|
|
|
self.assertFalse(os.path.exists(empty)) |
|
229
|
|
|
self.assertFalse(os.path.exists(empty2)) |
|
230
|
|
|
|
|
231
|
|
|
@patch('dtb.user.Song', MockSong) |
|
232
|
|
|
def test_recommend(self,): |
|
233
|
|
|
"""Verify a user can recommend a song.""" |
|
234
|
|
|
self.user.recommend(FAKESONG) |
|
235
|
|
|
path2 = os.path.join(self.user2.path, self.name) |
|
236
|
|
|
path3 = os.path.join(self.user3.path, self.name) |
|
237
|
|
|
self.assertEqual(2, len(MockSong.link.call_args_list)) |
|
238
|
|
|
self.assertIn(call(path2), MockSong.link.call_args_list) |
|
239
|
|
|
self.assertIn(call(path3), MockSong.link.call_args_list) |
|
240
|
|
|
|
|
241
|
|
|
def test_request(self): |
|
242
|
|
|
"""Verify a user can request a song.""" |
|
243
|
|
|
# TODO: update this test when feature implemented |
|
244
|
|
|
self.assertRaises(NotImplementedError, self.user.request, None) |
|
245
|
|
|
|
|
246
|
|
|
def test_check(self): |
|
247
|
|
|
"""Verify a user can be checked.""" |
|
248
|
|
|
self.user.check() |
|
249
|
|
|
|
|
250
|
|
|
def test_check_file_error(self): |
|
251
|
|
|
"""Verify a user fails the check with a missing files.""" |
|
252
|
|
|
user = User.new(self.root, '_temp') |
|
253
|
|
|
try: |
|
254
|
|
|
os.remove(user.path_info) |
|
255
|
|
|
self.assertRaises(ValueError, user.check) |
|
256
|
|
|
finally: |
|
257
|
|
|
user.delete() |
|
258
|
|
|
|
|
259
|
|
|
def test_check_folder_error(self): |
|
260
|
|
|
"""Verify a user fails the check with a missing folders.""" |
|
261
|
|
|
user = User.new(self.root, '_temp') |
|
262
|
|
|
try: |
|
263
|
|
|
shutil.rmtree(user.path_drops) |
|
264
|
|
|
self.assertRaises(ValueError, user.check) |
|
265
|
|
|
finally: |
|
266
|
|
|
user.delete() |
|
267
|
|
|
|
|
268
|
|
|
def test_delete(self): |
|
269
|
|
|
"""Verify a user can be deleted.""" |
|
270
|
|
|
user = User.new(self.root, '_temp') |
|
271
|
|
|
self.assertTrue(os.path.isdir(user.path)) |
|
272
|
|
|
user.delete() |
|
273
|
|
|
self.assertFalse(os.path.isdir(user.path)) |
|
274
|
|
|
|
|
275
|
|
|
@patch('dtb.user.get_info', Mock(return_value=INFOS[0])) |
|
276
|
|
|
def test_get_current(self): |
|
277
|
|
|
"""Verify the current user can be retrieved.""" |
|
278
|
|
|
os.mkdir(os.path.join(self.root, 'empty')) |
|
279
|
|
|
user = get_current(self.root) |
|
280
|
|
|
self.assertEqual(self.user, user) |
|
281
|
|
|
|
|
282
|
|
|
def test_get_current_error(self): |
|
283
|
|
|
"""Verify an error occurs when the user cannot be found.""" |
|
284
|
|
|
self.assertRaises(EnvironmentError, get_current, self.root) |
|
285
|
|
|
|
|
286
|
|
|
# https://github.com/jacebrowning/dropthebeat/issues/3 |
|
287
|
|
|
def test_multiple_computers(self): |
|
288
|
|
|
"""Verify a user can use multiple computers.""" |
|
289
|
|
|
infos = [('pc1', 'name'), ('pc2', 'name'), ('pc2', 'name')] |
|
290
|
|
|
root = tempfile.mkdtemp() |
|
291
|
|
|
downloads = tempfile.mkdtemp() |
|
292
|
|
|
try: |
|
293
|
|
|
with patch('dtb.user.get_info', Mock(side_effect=infos)): |
|
294
|
|
|
user = User.new(root, 'name', downloads=downloads) |
|
295
|
|
|
user2 = User.add(root, 'name') |
|
296
|
|
|
user3 = User.add(root, 'name') |
|
297
|
|
|
self.assertEqual(user, user2) |
|
298
|
|
|
self.assertEqual(user, user3) |
|
299
|
|
|
finally: |
|
300
|
|
|
shutil.rmtree(root) |
|
301
|
|
|
|
|
302
|
|
|
|
|
303
|
|
|
if __name__ == '__main__': |
|
304
|
|
|
unittest.main() |
|
305
|
|
|
|