-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_setup.py
More file actions
312 lines (239 loc) · 12.1 KB
/
Copy pathtest_setup.py
File metadata and controls
312 lines (239 loc) · 12.1 KB
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
#!/usr/bin/env python3
"""
Unit tests for setup.py - Yandex Disk Python setup functionality
"""
import unittest
import tempfile
import os
import shutil
from unittest.mock import patch, MagicMock, mock_open
from pathlib import Path
# Add the current directory to the path so we can import setup
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import click.testing
from setup import YandexDiskSetup
class TestYandexDiskSetup(unittest.TestCase):
def setUp(self):
"""Set up test environment"""
self.temp_dir = tempfile.mkdtemp()
self.setup = YandexDiskSetup()
# Override paths for testing
self.setup.script_dir = Path(self.temp_dir)
self.setup.ya_disk_root = os.path.join(self.temp_dir, 'Public')
self.setup.env_file = Path(self.temp_dir) / "environment"
self.setup.service_menu_dirs = [
Path(self.temp_dir) / "servicemenus1",
Path(self.temp_dir) / "servicemenus2"
]
self.setup.bin_dir = Path(self.temp_dir) / "bin"
# Ensure tests do not create symlinks under the real HOME
from unittest.mock import patch as _patch
self._home_patcher = _patch('pathlib.Path.home', return_value=Path(self.temp_dir))
self._home_patcher.start()
def tearDown(self):
"""Clean up test environment"""
try:
self._home_patcher.stop()
except Exception:
pass
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_init(self):
"""Test YandexDiskSetup initialization"""
self.assertEqual(self.setup.ya_disk_relative, "yaDisk")
self.assertEqual(self.setup.inbox_relative, "Media")
self.assertIsInstance(self.setup.service_menu_dirs, list)
@patch('builtins.print')
def test_print_status(self, mock_print):
"""Test status printing"""
self.setup.print_status("Test message")
mock_print.assert_called_once_with("[SETUP] Test message")
@patch('subprocess.run')
@patch('os.remove')
def test_set_global_environment_variable_new(self, mock_remove, mock_subprocess):
"""Test setting environment variable when file doesn't exist"""
# Mock successful subprocess call
mock_subprocess.return_value = None
# Mock file operations
with patch('builtins.open', mock_open()) as mock_file:
self.setup.set_global_environment_variable()
# Should attempt to write to temp file and copy with sudo
mock_file.assert_called()
mock_subprocess.assert_called_once()
mock_remove.assert_called_once()
@patch('subprocess.run')
@patch('os.remove')
def test_set_global_environment_variable_existing(self, mock_remove, mock_subprocess):
"""Test updating existing environment variable"""
# Create existing environment file
self.setup.env_file.touch()
self.setup.env_file.write_text("PATH=/usr/bin\nYA_DISK_ROOT=/old/path\nOTHER=value\n")
mock_subprocess.return_value = None
with patch('builtins.open', mock_open()) as mock_file:
self.setup.set_global_environment_variable()
mock_subprocess.assert_called_once()
mock_remove.assert_called_once()
def test_update_script_variables(self):
"""Test updating script variables (Python version doesn't need updates)"""
# Create mock ydmenu.py file (the method checks for this file)
ydmenu_file = self.setup.script_dir / "ydmenu.py"
ydmenu_file.write_text("#!/usr/bin/env python3\n")
with patch.object(self.setup, 'print_status') as mock_print:
self.setup.update_script_variables()
# Should print status messages indicating no changes needed
mock_print.assert_any_call("Set local script-scoped vars")
mock_print.assert_any_call("Python script already configured to use environment variables")
mock_print.assert_any_call("Python version uses ydpublish-python.desktop (no modifications needed)")
def test_create_symlinks(self):
"""Test creating symlinks"""
# Create source files
desktop_source = self.setup.script_dir / "ydpublish-python.desktop"
script_source = self.setup.script_dir / "ydmenu.py"
wrapper_source = self.setup.script_dir / "ydmenu-py-env"
desktop_source.touch()
script_source.touch()
wrapper_source.touch()
with patch.object(self.setup, 'print_status'):
self.setup.create_symlinks()
# Check that bin directory was created
self.assertTrue(self.setup.bin_dir.exists())
# Check that service menu directories were created
for service_dir in self.setup.service_menu_dirs:
self.assertTrue(service_dir.exists())
desktop_link = service_dir / "ydpublish-python.desktop"
self.assertTrue(desktop_link.is_symlink())
# Check that script symlink was created
script_link = self.setup.bin_dir / "ydmenu.py"
self.assertTrue(script_link.is_symlink())
# Check that Python wrapper symlink was created
wrapper_link = Path.home() / "bin" / "ydmenu-py-env"
self.assertTrue(wrapper_link.is_symlink())
def test_create_symlinks_with_existing_backup(self):
"""Test creating symlinks when backup already exists"""
# Create source file
desktop_source = self.setup.script_dir / "ydpublish-python.desktop"
desktop_source.touch()
# Create existing desktop file and backup
service_dir = self.setup.service_menu_dirs[0]
service_dir.mkdir(parents=True)
existing_desktop = service_dir / "ydpublish-python.desktop"
existing_backup = service_dir / "ydpublish-python.desktop.bak"
existing_desktop.touch()
existing_backup.touch()
with patch.object(self.setup, 'print_status') as mock_print:
self.setup.create_symlinks()
# Should mention backup already exists
mock_print.assert_any_call(f"Backup already exists: {existing_backup}")
# Should remove existing file and create symlink
self.assertTrue(existing_desktop.is_symlink())
def test_create_directories(self):
"""Test creating necessary directories"""
with patch.object(self.setup, 'print_status'):
self.setup.create_directories()
ya_disk_path = Path(self.setup.ya_disk_root) / self.setup.ya_disk_relative
stream_path = ya_disk_path / self.setup.inbox_relative
self.assertTrue(ya_disk_path.exists())
self.assertTrue(stream_path.exists())
@patch('subprocess.run')
def test_setup_virtual_environment_new(self, mock_subprocess):
"""Test setting up new virtual environment"""
requirements_file = self.setup.script_dir / "requirements.txt"
requirements_file.write_text("click>=8.0.0\nPyQt5>=5.15.0\n")
mock_subprocess.return_value = None
with patch.object(self.setup, 'print_status'):
self.setup.setup_virtual_environment()
# Should call venv creation and pip install
self.assertEqual(mock_subprocess.call_count, 2)
@patch('subprocess.run')
def test_setup_virtual_environment_existing(self, mock_subprocess):
"""Test setup when virtual environment already exists"""
# Create existing venv directory
venv_dir = self.setup.script_dir / "venv"
venv_dir.mkdir()
requirements_file = self.setup.script_dir / "requirements.txt"
requirements_file.write_text("click>=8.0.0\n")
mock_subprocess.return_value = None
with patch.object(self.setup, 'print_status'):
self.setup.setup_virtual_environment()
# Should only call pip install (not venv creation)
self.assertEqual(mock_subprocess.call_count, 1)
@patch('shutil.which')
def test_verify_dependencies_all_present(self, mock_which):
"""Test dependency verification when all dependencies are present"""
mock_which.return_value = "/usr/bin/mock"
with patch.object(self.setup, 'print_status'):
result = self.setup.verify_dependencies()
self.assertTrue(result)
@patch('shutil.which')
def test_verify_dependencies_missing(self, mock_which):
"""Test dependency verification when some dependencies are missing"""
def which_side_effect(cmd):
if cmd == 'yandex-disk':
return None # Missing
return "/usr/bin/mock"
mock_which.side_effect = which_side_effect
with patch.object(self.setup, 'print_status') as mock_print:
result = self.setup.verify_dependencies()
self.assertFalse(result)
# Should print missing commands
mock_print.assert_any_call("Missing required commands: yandex-disk")
class TestYandexDiskSetupIntegration(unittest.TestCase):
"""Integration tests for setup functionality"""
def setUp(self):
self.temp_dir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.temp_dir, ignore_errors=True)
@patch('setup.YandexDiskSetup.verify_dependencies')
@patch('setup.YandexDiskSetup.setup_virtual_environment')
@patch('setup.YandexDiskSetup.create_directories')
@patch('setup.YandexDiskSetup.set_global_environment_variable')
@patch('setup.YandexDiskSetup.update_script_variables')
@patch('setup.YandexDiskSetup.create_symlinks')
def test_main_successful_setup(self, mock_symlinks, mock_update, mock_env,
mock_dirs, mock_venv, mock_deps):
"""Test successful complete setup"""
mock_deps.return_value = True
from setup import main
# Test the click command
runner = click.testing.CliRunner()
result = runner.invoke(main, ['--ya-disk-root', self.temp_dir])
self.assertEqual(result.exit_code, 0)
# Verify all setup steps were called
mock_deps.assert_called_once()
mock_venv.assert_called_once()
mock_dirs.assert_called_once()
mock_env.assert_called_once()
mock_update.assert_called_once()
mock_symlinks.assert_called_once()
@patch('setup.YandexDiskSetup.verify_dependencies')
def test_main_check_deps_only(self, mock_deps):
"""Test dependency check only mode"""
mock_deps.return_value = True
from setup import main
runner = click.testing.CliRunner()
result = runner.invoke(main, ['--check-deps'])
self.assertEqual(result.exit_code, 0)
mock_deps.assert_called_once()
@patch('setup.YandexDiskSetup.verify_dependencies')
def test_main_check_deps_failure(self, mock_deps):
"""Test dependency check failure"""
mock_deps.return_value = False
from setup import main
runner = click.testing.CliRunner()
result = runner.invoke(main, ['--check-deps'])
self.assertEqual(result.exit_code, 1)
@patch('setup.YandexDiskSetup.verify_dependencies')
@patch('setup.YandexDiskSetup.setup_virtual_environment')
def test_main_skip_env(self, mock_venv, mock_deps):
"""Test setup with skip environment flag"""
mock_deps.return_value = True
from setup import main
with patch('setup.YandexDiskSetup.set_global_environment_variable') as mock_env:
runner = click.testing.CliRunner()
result = runner.invoke(main, ['--skip-env'])
# Environment setup should not be called
mock_env.assert_not_called()
self.assertEqual(result.exit_code, 0)
if __name__ == '__main__':
# Run with verbose output
unittest.main(verbosity=2)