1 | #!/usr/bin/env python |
||
2 | |||
3 | """Tests for the dtb.cli module.""" |
||
4 | |||
5 | import unittest |
||
6 | from unittest.mock import patch, Mock |
||
7 | |||
8 | import os |
||
9 | import tempfile |
||
10 | import shutil |
||
11 | import logging |
||
12 | |||
13 | import yaml |
||
0 ignored issues
–
show
|
|||
14 | |||
15 | from dtb.cli import main |
||
16 | |||
17 | from dtb.tests import ENV, REASON, FAKESONG |
||
18 | |||
19 | if __name__ == '__main__': |
||
20 | os.environ[ENV] = '1' |
||
21 | |||
22 | |||
23 | @unittest.skipUnless(os.getenv(ENV), REASON) # pylint: disable=R0904 |
||
24 | class TestCLI(unittest.TestCase): # pylint: disable=R0904 |
||
25 | """Integration tests for the 'dtb' command-line interface.""" |
||
26 | |||
27 | def setUp(self): |
||
28 | self.cwd = os.getcwd() |
||
29 | self.root = tempfile.mkdtemp() |
||
30 | self.downloads = tempfile.mkdtemp() |
||
31 | os.chdir(self.root) |
||
32 | |||
33 | def tearDown(self): |
||
34 | os.chdir(self.cwd) |
||
35 | shutil.rmtree(self.downloads) |
||
36 | shutil.rmtree(self.root) |
||
37 | |||
38 | @staticmethod |
||
39 | def log(msg): |
||
40 | """Header for logging.""" |
||
41 | text = '\n\n' |
||
42 | text += '#' * 79 + '\n' |
||
43 | text += '# ' + msg + '\n' |
||
44 | text += '#' * 79 + '\n' |
||
45 | logging.info(text) |
||
46 | |||
47 | def set_downloads(self, name): |
||
48 | """Change the downloads directory for the user.""" |
||
49 | path = os.path.join(self.root, name, '.dtb', 'info.yml') |
||
50 | with open(path, 'r') as infile: |
||
51 | text = infile.read() |
||
52 | data = yaml.load(text) |
||
53 | data[0]['downloads'] = self.downloads |
||
54 | text = yaml.dump(data) |
||
55 | with open(path, 'w') as outfile: |
||
56 | outfile.write(text) |
||
57 | |||
58 | def dtb(self, *args): |
||
59 | """Run the CLI with string arguments.""" |
||
60 | args += ('--root', self.root, '-v') |
||
61 | logging.info("$ {}".format(' '.join(args))) |
||
62 | main(args) |
||
63 | |||
64 | def ls(self, path, filename, expected=True): # pylint:disable=C0103 |
||
65 | """Display files in a directory and assert a filename exists.""" |
||
66 | logging.info("$ ls {}".format(path)) |
||
67 | filenames = os.listdir(path) |
||
68 | for fname in filenames: |
||
69 | logging.info(fname) |
||
70 | if expected: |
||
71 | self.assertIn(filename, filenames) |
||
72 | else: |
||
73 | self.assertNotIn(filename, filenames) |
||
74 | |||
75 | def cat(self, path, expected): |
||
76 | """Assert the contents of a file.""" |
||
77 | with open(path, 'r') as infile: |
||
78 | actual = infile.read() |
||
79 | self.assertEqual(expected, actual) |
||
80 | |||
81 | def test_recommend_download(self): |
||
82 | """Verify a song can be shared and downloaded.""" |
||
83 | self.log("downloading a shared song") |
||
84 | # Create users |
||
85 | self.dtb('--new', 'JaneDoe') |
||
86 | self.dtb('--new', 'JohnDoe') |
||
87 | self.dtb('--new', 'JaceBrowning') |
||
88 | # Modify their download directory |
||
89 | self.set_downloads('JaneDoe') |
||
90 | self.set_downloads('JohnDoe') |
||
91 | self.set_downloads('JaceBrowning') |
||
92 | # Share a song |
||
93 | self.dtb('--share', FAKESONG, '--test', 'JaceBrowning') |
||
94 | # Show the shared song |
||
95 | self.dtb('--outgoing', '--test', 'JaceBrowning') |
||
96 | # Download the shared song (1) |
||
97 | self.dtb('--incoming', '--test', 'JaneDoe') |
||
98 | self.dtb('--test', 'JaneDoe') |
||
99 | self.ls(self.downloads, 'FakeSong.mp3') |
||
100 | os.remove(os.path.join(self.downloads, 'FakeSong.mp3')) |
||
101 | # Download the shared song (2) |
||
102 | self.dtb('--incoming', '--test', 'JohnDoe') |
||
103 | self.dtb('--test', 'JohnDoe') |
||
104 | self.ls(self.downloads, 'FakeSong.mp3') |
||
105 | # Show that no more songs are shared |
||
106 | self.dtb('--outgoing', '--test', 'JaceBrowning') |
||
107 | # Check the log |
||
108 | self.ls(self.downloads, 'dtb.log') |
||
109 | self.cat(os.path.join(self.downloads, 'dtb.log'), |
||
110 | "FakeSong.mp3 from JaceBrowning\n" |
||
111 | "FakeSong.mp3 from JaceBrowning\n") |
||
112 | |||
113 | def test_recommend_download_no_log(self): |
||
114 | """Verify a song can be shared and downloaded.""" |
||
115 | self.log("downloading a shared song without a log") |
||
116 | # Create users |
||
117 | self.dtb('--new', 'JaneDoe') |
||
118 | self.dtb('--new', 'JohnDoe') |
||
119 | # Modify their download directory |
||
120 | self.set_downloads('JaneDoe') |
||
121 | self.set_downloads('JohnDoe') |
||
122 | # Share a song |
||
123 | self.dtb('--share', FAKESONG, '--test', 'JaneDoe') |
||
124 | # Download the shared song |
||
125 | self.dtb('--no-log', '--test', 'JohnDoe') |
||
126 | # Check for no long |
||
127 | self.ls(self.downloads, 'dtb.log', expected=False) |
||
128 | |||
129 | @patch('time.sleep', Mock(side_effect=KeyboardInterrupt)) |
||
130 | def test_interrupt_daemon(self): |
||
131 | """Verify the daemon can be interrupted.""" |
||
132 | self.log("interrupting the daemon") |
||
133 | # Create user |
||
134 | self.dtb('--new', 'JaceBrowning') |
||
135 | # Run the daemon |
||
136 | self.assertIs(None, self.dtb('--daemon')) |
||
137 | |||
138 | def test_duplicate_users(self): |
||
139 | """Verify duplicate users cannot be created.""" |
||
140 | self.log("creating a duplicate user") |
||
141 | # Create user |
||
142 | self.dtb('--new', 'JaceBrowning') |
||
143 | # Create user again |
||
144 | self.assertRaises(SystemExit, self.dtb, '--new', 'JaceBrowning') |
||
145 | |||
146 | def test_deleting_users(self): |
||
147 | """Verify users can be deleted.""" |
||
148 | self.log("deleting a user") |
||
149 | # Create user |
||
150 | self.dtb('--new', 'JaceBrowning') |
||
151 | # Delete user |
||
152 | self.dtb('--delete') |
||
153 | |||
154 | @patch('dtb.gui._LAUNCH', False) |
||
155 | def test_launch_gui(self): |
||
156 | """Verify the GUI can be launched.""" |
||
157 | self.log("launching the GUI") |
||
158 | # Create user |
||
159 | self.dtb('--new', 'JaceBrowning') |
||
160 | # Launch the GUI |
||
161 | self.dtb('--gui') |
||
162 | |||
163 | |||
164 | @patch('dtb.cli._run', Mock(return_value=True)) # pylint: disable=R0904 |
||
165 | class TestLogging(unittest.TestCase): # pylint: disable=R0904 |
||
166 | """Integration tests for logging levels.""" |
||
167 | |||
168 | def test_verbose_0(self): |
||
169 | """Verify verbose level 0 can be set.""" |
||
170 | self.assertIs(None, main([])) |
||
171 | |||
172 | def test_verbose_1(self): |
||
173 | """Verify verbose level 1 can be set.""" |
||
174 | self.assertIs(None, main(['-v'])) |
||
175 | |||
176 | def test_verbose_2(self): |
||
177 | """Verify verbose level 2 can be set.""" |
||
178 | self.assertIs(None, main(['-v', '-v'])) |
||
179 | |||
180 | def test_verbose_3(self): |
||
181 | """Verify verbose level 3 can be set.""" |
||
182 | self.assertIs(None, main(['-v', '-v', '-v'])) |
||
183 | |||
184 | |||
185 | if __name__ == '__main__': |
||
186 | logging.basicConfig(format="%(message)s", level=logging.INFO) |
||
187 | unittest.main() |
||
188 |
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.py
files in your module folders. Make sure that you place one file in each sub-folder.