33udocker unit tests: NVIDIA mode
44"""
55
6+ import collections
7+
68from unittest import TestCase , main
79from unittest .mock import patch , Mock
810from udocker .config import Config
911from udocker .engine .nvidia import NvidiaMode
10- import collections
1112
1213collections .Callable = collections .abc .Callable
1314
1415
1516class 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
263354if __name__ == '__main__' :
264355 main ()
0 commit comments