3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
20 from cmframework.apis.cmupdate import CMUpdate
21 from cmframework.lib.cmupdateimpl import CMUpdateImpl
22 from cmframework.apis.cmerror import CMError
25 class CMUpdateImplTest(unittest.TestCase):
26 @mock.patch('cmframework.lib.cmupdateimpl.CMPluginLoader')
27 @mock.patch('cmframework.lib.cmupdateimpl.CMManage')
28 @mock.patch('cmframework.lib.cmupdateimpl.logging')
29 def test_init(self, mock_logging, mock_client, mock_pluginloader):
30 mock_pluginloader.return_value.load.return_value = ({}, None)
32 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
33 'test_client_lib_impl_module', 'test_verbose_logger')
35 mock_pluginloader.assert_called_once_with('test_plugin_path')
36 mock_client.assert_called_once_with('test_server_ip',
38 'test_client_lib_impl_module',
39 'test_verbose_logger')
42 def _test__read_dependency_file_incorrect(file_name):
43 if file_name == 'test_plugin_path/test_handler_a.deps':
45 if file_name == 'test_plugin_path/test_handler_b.deps':
48 @mock.patch.object(CMUpdateImpl, '_read_dependency_file')
49 @mock.patch('cmframework.lib.cmupdateimpl.CMPluginLoader')
50 @mock.patch('cmframework.lib.cmupdateimpl.CMManage')
51 @mock.patch('cmframework.lib.cmupdateimpl.logging')
52 def test_init_missing_handler_in_dependencies(self,
56 mock__read_dependency_file):
57 mock_pluginloader.return_value.load.return_value = ({}, None)
58 mock__read_dependency_file.side_effect = \
59 CMUpdateImplTest._test__read_dependency_file_incorrect
61 test_handler_a_module = mock.MagicMock()
62 test_handler_a_class = mock.MagicMock()
63 test_handler_a_class.return_value.__str__.return_value = 'test_handler_a'
64 setattr(test_handler_a_module, 'test_handler_a', test_handler_a_class)
66 mock_pluginloader.return_value.load.return_value = \
67 ({'test_handler_a': test_handler_a_module}, None)
69 with self.assertRaises(CMError) as context:
70 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
71 'test_client_lib_impl_module', 'test_verbose_logger')
73 test_handler_b_module = mock.MagicMock()
74 test_handler_b_class = mock.MagicMock()
75 test_handler_b_class.return_value.__str__.return_value = 'test_handler_b'
76 setattr(test_handler_b_module, 'test_handler_b', test_handler_b_class)
78 mock_pluginloader.return_value.load.return_value = \
79 ({'test_handler_b': test_handler_b_module}, None)
81 with self.assertRaises(CMError) as context:
82 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
83 'test_client_lib_impl_module', 'test_verbose_logger')
85 mock_client.assert_not_called()
88 def _test__read_dependency_file(file_name):
89 if file_name == 'test_plugin_path/test_handler_a.deps':
90 return ([], ['test_handler_b'])
91 if file_name == 'test_plugin_path/test_handler_b.deps':
92 return (['test_handler_a'], [])
93 if file_name == 'test_plugin_path/test_handler_c.deps':
94 return (['test_handler_b'], ['test_handler_a'])
97 def _test_update_func_a(confman):
98 CMUpdateImplTest._test_update_func_calls.append('test_handler_a')
99 if str(confman) == 'raise exception':
100 raise Exception('test_update_exception')
103 def _test_update_func_b(confman):
104 CMUpdateImplTest._test_update_func_calls.append('test_handler_b')
107 def _test_update_func_c(confman):
108 confman.get_config.return_value = {'test_properties': '_test_update_func_c properties'}
109 CMUpdateImplTest._test_update_func_calls.append('test_handler_c')
111 def _setup_test_handlers(self, mock_pluginloader, mock__read_dependency_file, mock_sorter):
112 CMUpdateImplTest._test_update_func_calls = []
114 test_handler_a_module = mock.MagicMock()
115 test_handler_a_class = mock.MagicMock()
116 test_handler_a_class.return_value.__str__.return_value = 'test_handler_a'
117 test_handler_a_class.return_value.update.side_effect = CMUpdateImplTest._test_update_func_a
118 setattr(test_handler_a_module, 'test_handler_a', test_handler_a_class)
120 test_handler_b_module = mock.MagicMock()
121 test_handler_b_class = mock.MagicMock()
122 test_handler_b_class.return_value.__str__.return_value = 'test_handler_b'
123 test_handler_b_class.return_value.update.side_effect = CMUpdateImplTest._test_update_func_b
124 setattr(test_handler_b_module, 'test_handler_b', test_handler_b_class)
126 test_handler_c_module = mock.MagicMock()
127 test_handler_c_class = mock.MagicMock()
128 test_handler_c_class.return_value.__str__.return_value = 'test_handler_c'
129 test_handler_c_class.return_value.update.side_effect = CMUpdateImplTest._test_update_func_c
130 setattr(test_handler_c_module, 'test_handler_c', test_handler_c_class)
132 mock_pluginloader.return_value.load.return_value = \
133 ({'test_handler_a': test_handler_a_module,
134 'test_handler_b': test_handler_b_module,
135 'test_handler_c': test_handler_c_module}, None)
137 mock__read_dependency_file.side_effect = CMUpdateImplTest._test__read_dependency_file
139 mock_sorter.return_value.sort.return_value = ['test_handler_c',
143 return (test_handler_a_class, test_handler_b_class, test_handler_c_class)
145 @mock.patch.object(CMUpdateImpl, '_read_dependency_file')
146 @mock.patch('cmframework.lib.cmupdateimpl.CMDependencySort')
147 @mock.patch('cmframework.lib.cmupdateimpl.CMPluginLoader')
148 @mock.patch('cmframework.lib.cmupdateimpl.CMManage')
149 @mock.patch('cmframework.lib.cmupdateimpl.logging')
150 def test_update(self,
155 mock__read_dependency_file):
156 test_handler_a_class, test_handler_b_class, test_handler_c_class = \
157 self._setup_test_handlers(mock_pluginloader, mock__read_dependency_file, mock_sorter)
159 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
160 'test_client_lib_impl_module', 'test_verbose_logger')
162 mock_confman = mock.MagicMock()
163 mock_confman.__str__.return_value = 'confman'
164 mock_confman.get_config.return_value = {'test_properties': 'some properties'}
166 updater.update(mock_confman)
168 sorter_after_graph = mock_sorter.call_args[0][0]
169 assert len(sorter_after_graph) == 3
170 assert 'test_handler_a' in sorter_after_graph
171 assert 'test_handler_b' in sorter_after_graph
172 assert 'test_handler_c' in sorter_after_graph
173 assert sorter_after_graph['test_handler_a'] == ['test_handler_b']
174 assert sorter_after_graph['test_handler_b'] == []
175 assert sorter_after_graph['test_handler_c'] == ['test_handler_a']
177 sorter_before_graph = mock_sorter.call_args[0][1]
178 assert len(sorter_before_graph) == 3
179 assert 'test_handler_a' in sorter_before_graph
180 assert 'test_handler_b' in sorter_before_graph
181 assert 'test_handler_c' in sorter_before_graph
182 assert sorter_before_graph['test_handler_a'] == []
183 assert sorter_before_graph['test_handler_b'] == ['test_handler_a']
184 assert sorter_before_graph['test_handler_c'] == ['test_handler_b']
186 mock_sorter.return_value.sort.assert_called_once()
188 test_handler_a_class.return_value.update.assert_called_once_with(mock_confman)
189 test_handler_b_class.return_value.update.assert_called_once_with(mock_confman)
190 test_handler_c_class.return_value.update.assert_called_once_with(mock_confman)
192 assert CMUpdateImplTest._test_update_func_calls == \
193 mock_sorter.return_value.sort.return_value
195 mock_client.return_value.set_properties.assert_called_once_with(
196 {'test_properties': '_test_update_func_c properties'}, True)
198 @mock.patch.object(CMUpdateImpl, '_read_dependency_file')
199 @mock.patch('cmframework.lib.cmupdateimpl.ConfigManager')
200 @mock.patch('cmframework.lib.cmupdateimpl.CMDependencySort')
201 @mock.patch('cmframework.lib.cmupdateimpl.CMPluginLoader')
202 @mock.patch('cmframework.lib.cmupdateimpl.CMManage')
203 @mock.patch('cmframework.lib.cmupdateimpl.logging')
204 def test_update_no_confman(self,
210 mock__read_dependency_file):
211 test_handler_a_class, test_handler_b_class, test_handler_c_class = \
212 self._setup_test_handlers(mock_pluginloader, mock__read_dependency_file, mock_sorter)
214 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
215 'test_client_lib_impl_module', 'test_verbose_logger')
219 test_handler_a_class.return_value.update.assert_called_once_with(
220 mock_configmanager.return_value)
221 test_handler_b_class.return_value.update.assert_called_once_with(
222 mock_configmanager.return_value)
223 test_handler_c_class.return_value.update.assert_called_once_with(
224 mock_configmanager.return_value)
227 mock_configmanager.assert_called_once_with(
228 mock_client.return_value.get_properties.return_value)
231 assert CMUpdateImplTest._test_update_func_calls == \
232 mock_sorter.return_value.sort.return_value
234 @mock.patch.object(CMUpdateImpl, '_read_dependency_file')
235 @mock.patch('cmframework.lib.cmupdateimpl.ConfigManager')
236 @mock.patch('cmframework.lib.cmupdateimpl.CMDependencySort')
237 @mock.patch('cmframework.lib.cmupdateimpl.CMPluginLoader')
238 @mock.patch('cmframework.lib.cmupdateimpl.CMManage')
239 @mock.patch('cmframework.lib.cmupdateimpl.logging')
240 def test_update_exception(self,
246 mock__read_dependency_file):
247 test_handler_a_class, test_handler_b_class, test_handler_c_class = \
248 self._setup_test_handlers(mock_pluginloader, mock__read_dependency_file, mock_sorter)
250 updater = CMUpdate('test_plugin_path', 'test_server_ip', 'test_server_port',
251 'test_client_lib_impl_module', 'test_verbose_logger')
253 mock_confman = mock.MagicMock()
254 mock_confman.__str__.return_value = 'raise exception'
256 with self.assertRaises(Exception) as context:
257 updater.update(mock_confman)
259 # TODO:verify plugin(s) before exception are called.
260 mock_logging.warning.assert_called_with('Update handler %s failed: %s',
262 'test_update_exception')
264 @mock.patch('cmframework.lib.cmupdateimpl.logging')
265 def test_dependency_files(self, mock_logging):
266 with mock.patch('cmframework.lib.cmupdateimpl.open', create=True) as mock_open:
267 mock_open.return_value = mock.MagicMock(spec=file)
268 file_handle = mock_open.return_value.__enter__.return_value
270 file_handle.readline.side_effect = IOError('File not found')
271 before, after = CMUpdateImpl._read_dependency_file('testexception: not existing')
274 mock_logging.debug.assert_called_with('Dependency file %s not found.',
275 'testexception: not existing')
277 file_handle.readline.side_effect = [None]
278 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
282 file_handle.readline.side_effect = ['foo', 'bar', None]
283 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
287 file_handle.readline.side_effect = ['Before: a, b', 'After: c, d', None]
288 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
289 assert before == ['a', 'b']
290 assert after == ['c', 'd']
292 file_handle.readline.side_effect = ['foo',
298 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
299 assert before == ['a', 'b']
300 assert after == ['c', 'd']
302 file_handle.readline.side_effect = ['After: c, d', 'Before: a, b', None]
303 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
304 assert before == ['a', 'b']
305 assert after == ['c', 'd']
307 file_handle.readline.side_effect = ['Before:a,b', 'After:c,d', None]
308 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
309 assert before == ['a', 'b']
310 assert after == ['c', 'd']
312 file_handle.readline.side_effect = ['Before: a, b ', 'After: c, d ', None]
313 before, after = CMUpdateImpl._read_dependency_file('./test_deps/1.deps')
314 assert before == ['a', 'b']
315 assert after == ['c', 'd']
317 if __name__ == '__main__':