Skip to content

Commit d35e1e0

Browse files
committed
add unit tests for nvidia file copy logic
1 parent cecce40 commit d35e1e0

1 file changed

Lines changed: 110 additions & 19 deletions

File tree

tests/unit/test_nvidia.py

Lines changed: 110 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@
33
udocker unit tests: NVIDIA mode
44
"""
55

6+
import collections
7+
68
from unittest import TestCase, main
79
from unittest.mock import patch, Mock
810
from udocker.config import Config
911
from udocker.engine.nvidia import NvidiaMode
10-
import collections
1112

1213
collections.Callable = collections.abc.Callable
1314

1415

1516
class NvidiaModeTestCase(TestCase):
16-
"""Test PRootEngine() class for containers execution."""
17+
"""Test NvidiaMode() class for nvidia mode setup."""
1718

1819
def setUp(self):
1920
Config().getconf()
@@ -32,6 +33,11 @@ def tearDown(self):
3233
self.lrepo.stop()
3334
self.cdcont.stop()
3435

36+
def _reset_mocks(self,*mocks):
37+
"""Reset mocks."""
38+
for mock in mocks:
39+
mock.reset_mock()
40+
3541
def test_01_init(self):
3642
"""Test01 NvidiaMode() constructor."""
3743
cdir = "/" + self.cont_id
@@ -53,54 +59,105 @@ def test_02__files_exist(self, mock_exists):
5359

5460
@patch('udocker.engine.nvidia.Msg')
5561
@patch('udocker.engine.nvidia.os.access')
56-
@patch('udocker.engine.nvidia.stat')
5762
@patch('udocker.engine.nvidia.shutil.copy2')
63+
@patch('udocker.engine.nvidia.stat')
5864
@patch('udocker.engine.nvidia.os.symlink')
5965
@patch('udocker.engine.nvidia.os.readlink')
6066
@patch('udocker.engine.nvidia.os.chmod')
6167
@patch('udocker.engine.nvidia.os.makedirs')
68+
@patch('udocker.engine.nvidia.os.path.exists')
6269
@patch('udocker.engine.nvidia.os.path.isdir')
63-
@patch('udocker.engine.nvidia.os.path.dirname')
6470
@patch('udocker.engine.nvidia.os.remove')
71+
@patch('udocker.engine.nvidia.os.stat')
6572
@patch('udocker.engine.nvidia.os.path.islink')
6673
@patch('udocker.engine.nvidia.os.path.isfile')
67-
def test_03__copy_files(self, mock_isfile, mock_islink, mock_rm,
68-
mock_dirname, mock_isdir, mock_mkdir, mock_chmod,
69-
mock_readln, mock_symln, mock_copy2, mock_stat,
70-
mock_access, mock_msg):
74+
@patch('udocker.engine.nvidia.os.path.realpath')
75+
def test_03__copy_files(self, mock_realpath, mock_isfile, mock_islink,
76+
mock_stat, mock_rm, mock_isdir, mock_exists,
77+
mock_mkdir, mock_chmod, mock_readln, mock_symln,
78+
mock_statmod, mock_copy2, mock_access, mock_msg):
7179
"""Test03 NvidiaMode._copy_files."""
7280
hsrc_dir = "/usr/lib"
73-
cdst_dir = "/hone/.udocker/cont/ROOT/usr/lib"
81+
cdst_dir = "/home/.udocker/cont/ROOT/usr/lib"
7482
flist = ["a"]
83+
os_stat_result = Mock()
84+
os_stat_result.st_mode = 0o100777
85+
mock_stat.return_value = os_stat_result
86+
nvmode = NvidiaMode(self.local, self.cont_id)
87+
88+
# Test force = False
7589
force = False
7690
mock_msg.level = 0
91+
92+
# Case 1: nvidia file already exists, force = False
7793
mock_isfile.side_effect = [True, False]
7894
mock_islink.side_effect = [True, False]
7995
mock_rm.return_value = None
80-
nvmode = NvidiaMode(self.local, self.cont_id)
8196
status = nvmode._copy_files(hsrc_dir, cdst_dir, flist, force)
82-
self.assertFalse(status)
97+
self.assertFalse(status) # should return False
8398
self.assertTrue(mock_isfile.called)
99+
self._reset_mocks(mock_isfile)
84100

101+
# Case 2: symlink to a file in the same directory
102+
mock_isfile.side_effect = [False, False]
103+
mock_islink.side_effect = [False, True]
104+
mock_isdir.side_effect = [True, False]
105+
mock_mkdir.return_value = None
106+
mock_chmod.return_value = 644
107+
mock_statmod.side_effect = [444, 222]
108+
mock_readln.return_value = "libOpenCL.so.1.0.0"
109+
mock_symln.return_value = None
110+
status = nvmode._copy_files(hsrc_dir, cdst_dir, flist, force)
111+
self.assertTrue(status)
112+
self.assertTrue(mock_isdir.called)
113+
self.assertTrue(mock_mkdir.called)
114+
self.assertTrue(mock_chmod.called)
115+
self.assertTrue(mock_islink.called)
116+
self.assertTrue(mock_symln.called) # should create symlink
117+
self.assertFalse(mock_copy2.called)
118+
self._reset_mocks(mock_isdir, mock_mkdir, mock_chmod, mock_islink, mock_symln, mock_copy2)
119+
120+
# Case 3: symlink to a file in another directory
121+
mock_isfile.side_effect = [False, False]
122+
mock_islink.side_effect = [False, True]
123+
mock_isdir.side_effect = [True, False]
124+
mock_readln.return_value = "/usr/xxx"
125+
mock_realpath.return_value = "/usr/lib/x86_64/xxx"
126+
mock_exists.return_value = False
127+
mock_copy2.return_value = None
128+
mock_statmod.side_effect = [444, 222, 111, 111]
129+
mock_access.return_value = False
130+
mock_chmod.side_effect = [644, 755]
131+
status = nvmode._copy_files(hsrc_dir, cdst_dir, flist, force)
132+
self.assertTrue(status)
133+
self.assertTrue(mock_copy2.called) # should copy file
134+
self._reset_mocks(mock_copy2, mock_mkdir)
135+
136+
# Case 4: srcname not exists
137+
mock_isfile.side_effect = [False, False]
138+
mock_islink.side_effect = [False, False]
139+
mock_isdir.side_effect = [False, False]
140+
status = nvmode._copy_files(hsrc_dir, cdst_dir, flist, force)
141+
self.assertTrue(status)
142+
self.assertFalse(mock_mkdir.called) # srcname not exists, should not mkdir
143+
self._reset_mocks(mock_mkdir, mock_rm, mock_isfile)
144+
145+
# Test force = True
85146
force = True
86147
mock_msg.level = 0
87148
mock_isfile.side_effect = [True, True]
88149
mock_islink.side_effect = [True, False]
89-
mock_dirname.side_effect = [None, None]
150+
mock_isdir.side_effect = [True, True]
90151
mock_rm.return_value = None
91-
mock_isdir.return_value = True
92152
mock_mkdir.return_value = None
93153
mock_chmod.side_effect = [644, 755]
94-
mock_readln.return_value = "/usr/xxx"
95-
mock_symln.return_value = None
96154
mock_copy2.return_value = None
97-
mock_stat.side_effect = [444, 222, 111, 111]
98-
mock_access.return_value = False
99-
nvmode = NvidiaMode(self.local, self.cont_id)
155+
mock_statmod.side_effect = [444, 222, 111, 111]
156+
mock_access.return_value = True
100157
status = nvmode._copy_files(hsrc_dir, cdst_dir, flist, force)
101158
self.assertTrue(status)
159+
self.assertTrue(mock_rm.called) # should remove existing file
102160
self.assertTrue(mock_isfile.called)
103-
self.assertTrue(mock_rm.called)
104161

105162
@patch('udocker.engine.nvidia.glob.glob')
106163
def test_04__get_nvidia_libs(self, mock_glob):
@@ -259,6 +316,40 @@ def test_12_get_devices(self, mock_glob):
259316
status = nvmode.get_devices()
260317
self.assertEqual(status, Config().conf['nvi_dev_list'])
261318

319+
@patch('udocker.engine.nvidia.os.chmod')
320+
@patch('udocker.engine.nvidia.os.access')
321+
@patch('udocker.engine.nvidia.os.stat')
322+
@patch('udocker.engine.nvidia.shutil.copy2')
323+
@patch('udocker.engine.nvidia.stat')
324+
@patch('udocker.engine.nvidia.os.path.exists')
325+
def test_13__copy_single_file(self, mock_exists, mock_statmod, mock_copy2,
326+
mock_stat, mock_access, mock_chmod):
327+
"""Test13 NvidiaMode._copy_single_file."""
328+
src = "/usr/lib/libnvidia.so"
329+
dst = "/home/.udocker/cont/usr/lib/libnvidia.so"
330+
os_stat_result = Mock()
331+
os_stat_result.st_mode = 0o100777
332+
mock_stat.return_value = os_stat_result
333+
nvmode = NvidiaMode(self.local, self.cont_id)
334+
335+
mock_copy2.return_value = None
336+
mock_statmod.side_effect = [444, 222, 111, 111]
337+
mock_access.return_value = True
338+
mock_chmod.return_value = 644
339+
340+
# Case 1: dst file exists
341+
mock_exists.return_value = True
342+
nvmode._copy_single_file(src, dst)
343+
self.assertTrue(mock_exists.called)
344+
self.assertFalse(mock_copy2.called) # should not overwrite
345+
self._reset_mocks(mock_exists, mock_copy2)
346+
347+
# Case 2: dst file does not exist
348+
mock_exists.return_value = False
349+
nvmode._copy_single_file(src, dst)
350+
self.assertTrue(mock_copy2.called) # should copy file
351+
self.assertTrue(mock_chmod.called)
352+
262353

263354
if __name__ == '__main__':
264355
main()

0 commit comments

Comments
 (0)