Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / tools / telemetry / catapult_base / dependency_manager / dependency_manager_unittest.py
blob0a7ab0e521661db9d88d4edd0a43be4efdf94b94
1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 import os
6 import stat
7 import unittest
9 import mock
11 from catapult_base import dependency_manager
12 from catapult_base import cloud_storage
13 from catapult_base.dependency_manager import exceptions
16 class DependencyManagerTest(unittest.TestCase):
17 @mock.patch(
18 'catapult_base.dependency_manager.DependencyManager._UpdateDependencies')
19 def testInit(self, update_mock):
20 self.assertRaises(ValueError, dependency_manager.DependencyManager, None)
21 self.assertFalse(update_mock.call_args)
22 self.assertRaises(ValueError, dependency_manager.DependencyManager,
23 'config_file?')
24 self.assertFalse(update_mock.call_args)
26 dependency_manager.DependencyManager([])
27 self.assertFalse(update_mock.call_args)
29 dependency_manager.DependencyManager(['config_file'])
30 update_mock.called_once_with_args('config_file')
31 update_mock.reset_mock()
33 dependency_manager.DependencyManager(
34 ['config_file1', 'config_file2', 'config_file3', 'config_file4'])
35 expected_calls = [mock.call('config_file1'), mock.call('config_file2'),
36 mock.call('config_file3'), mock.call('config_file4')]
37 update_mock.assert_has_calls(expected_calls, any_order=True)
38 update_mock.reset_mock()
41 @mock.patch('os.path')
42 @mock.patch('catapult_base.support_binaries.FindPath')
43 @mock.patch(
44 'catapult_base.dependency_manager.DependencyManager._GetDependencyInfo')
45 @mock.patch(
46 'catapult_base.dependency_manager.DependencyManager._CloudStoragePath')
47 @mock.patch('catapult_base.dependency_manager.DependencyManager._LocalPath')
48 def testFetchPathUnititializedDependency(
49 self, local_path_mock, cs_path_mock, dep_info_mock, sb_find_path_mock,
50 path_mock):
51 dep_manager = dependency_manager.DependencyManager([])
52 self.assertFalse(local_path_mock.call_args)
53 self.assertFalse(cs_path_mock.call_args)
54 self.assertFalse(sb_find_path_mock.call_args)
55 sb_path = 'sb_path'
56 local_path = 'local_path'
57 cs_path = 'cs_path'
58 local_path_mock.return_value = local_path
59 cs_path_mock.return_value = cs_path
60 sb_find_path_mock.return_value = sb_path
61 dep_info_mock.return_value = None
63 # Empty lookup_dict
64 with self.assertRaises(exceptions.NoPathFoundError):
65 dep_manager.FetchPath('dep', 'plat_arch_x86')
66 dep_info_mock.reset_mock()
68 found_path = dep_manager.FetchPath(
69 'dep', 'plat_arch_x86', try_support_binaries=True)
70 self.assertEqual(sb_path, found_path)
71 self.assertFalse(local_path_mock.call_args)
72 self.assertFalse(cs_path_mock.call_args)
73 dep_info_mock.assert_called_once_with('dep', 'plat_arch_x86')
74 sb_find_path_mock.assert_called_once_with('dep', 'arch_x86', 'plat')
75 local_path_mock.reset_mock()
76 cs_path_mock.reset_mock()
77 sb_find_path_mock.reset_mock()
78 dep_info_mock.reset_mock()
80 # Non-empty lookup dict that doesn't contain the dependency we're looking
81 # for.
82 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
83 'dep2': mock.MagicMock()}
84 with self.assertRaises(exceptions.NoPathFoundError):
85 dep_manager.FetchPath('dep', 'plat_arch_x86')
86 dep_info_mock.reset_mock()
88 found_path = dep_manager.FetchPath(
89 'dep', 'plat_arch_x86', try_support_binaries=True)
90 self.assertEqual(sb_path, found_path)
91 self.assertFalse(local_path_mock.call_args)
92 self.assertFalse(cs_path_mock.call_args)
93 dep_info_mock.assert_called_once_with('dep', 'plat_arch_x86')
94 sb_find_path_mock.assert_called_once_with('dep', 'arch_x86', 'plat')
95 local_path_mock.reset_mock()
96 cs_path_mock.reset_mock()
97 sb_find_path_mock.reset_mock()
99 @mock.patch('os.path')
100 @mock.patch('catapult_base.support_binaries.FindPath')
101 @mock.patch(
102 'catapult_base.dependency_manager.DependencyManager._GetDependencyInfo')
103 @mock.patch(
104 'catapult_base.dependency_manager.DependencyManager._CloudStoragePath')
105 @mock.patch('catapult_base.dependency_manager.DependencyManager._LocalPath')
106 def testFetchPathLocalFile(self, local_path_mock, cs_path_mock, dep_info_mock,
107 sb_find_path_mock, path_mock):
108 dep_manager = dependency_manager.DependencyManager([])
109 self.assertFalse(local_path_mock.call_args)
110 self.assertFalse(cs_path_mock.call_args)
111 self.assertFalse(sb_find_path_mock.call_args)
112 sb_path = 'sb_path'
113 local_path = 'local_path'
114 cs_path = 'cs_path'
115 dep_info = 'dep_info'
116 local_path_mock.return_value = local_path
117 cs_path_mock.return_value = cs_path
118 sb_find_path_mock.return_value = sb_path
119 # The DependencyInfo returned should be passed through to LocalPath.
120 dep_info_mock.return_value = dep_info
123 # Non-empty lookup dict that contains the dependency we're looking for.
124 # Local path exists.
125 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
126 'dep2': mock.MagicMock()}
127 path_mock.exists.return_value = True
128 found_path = dep_manager.FetchPath('dep1', 'plat')
130 self.assertEqual(local_path, found_path)
131 local_path_mock.assert_called_with('dep_info')
132 dep_info_mock.assert_called_once_with('dep1', 'plat')
133 self.assertFalse(cs_path_mock.call_args)
134 self.assertFalse(sb_find_path_mock.call_args)
135 # If the below assert fails, the ordering assumption that determined the
136 # path_mock return values is incorrect, and should be updated.
137 path_mock.exists.assert_called_once_with('local_path')
138 local_path_mock.reset_mock()
139 cs_path_mock.reset_mock()
140 sb_find_path_mock.reset_mock()
141 dep_info_mock.reset_mock()
144 @mock.patch('os.path')
145 @mock.patch('catapult_base.support_binaries.FindPath')
146 @mock.patch(
147 'catapult_base.dependency_manager.DependencyManager._GetDependencyInfo')
148 @mock.patch(
149 'catapult_base.dependency_manager.DependencyManager._CloudStoragePath')
150 @mock.patch('catapult_base.dependency_manager.DependencyManager._LocalPath')
151 def testFetchPathRemoteFile(self, local_path_mock, cs_path_mock,
152 dep_info_mock, sb_find_path_mock, path_mock):
153 dep_manager = dependency_manager.DependencyManager([])
154 self.assertFalse(local_path_mock.call_args)
155 self.assertFalse(cs_path_mock.call_args)
156 self.assertFalse(sb_find_path_mock.call_args)
157 local_path = 'local_path'
158 cs_path = 'cs_path'
159 dep_info = 'dep_info'
160 cs_path_mock.return_value = cs_path
161 dep_info_mock.return_value = dep_info
163 # Non-empty lookup dict that contains the dependency we're looking for.
164 # Local path doesn't exist, but cloud_storage_path is downloaded.
165 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
166 'dep2': mock.MagicMock()}
167 path_mock.exists.side_effect = [False, True]
168 local_path_mock.return_value = local_path
169 found_path = dep_manager.FetchPath('dep1', 'plat')
171 self.assertEqual(cs_path, found_path)
172 local_path_mock.assert_called_with(dep_info)
173 dep_info_mock.assert_called_once_with('dep1', 'plat')
174 cs_path_mock.assert_called_once_with(dep_info)
175 self.assertFalse(sb_find_path_mock.call_args)
176 # If the below assert fails, the ordering assumption that determined the
177 # path_mock return values is incorrect, and should be updated.
178 path_mock.exists.assert_has_calls([mock.call(local_path),
179 mock.call(cs_path)], any_order=False)
180 local_path_mock.reset_mock()
181 cs_path_mock.reset_mock()
182 sb_find_path_mock.reset_mock()
183 dep_info_mock.reset_mock()
185 # Non-empty lookup dict that contains the dependency we're looking for.
186 # Local path isn't found, but cloud_storage_path is downloaded.
187 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
188 'dep2': mock.MagicMock()}
189 path_mock.exists.side_effect = [True]
190 local_path_mock.return_value = None
191 found_path = dep_manager.FetchPath('dep1', 'plat')
193 self.assertEqual(cs_path, found_path)
194 local_path_mock.assert_called_with(dep_info)
195 cs_path_mock.assert_called_once_with(dep_info)
196 dep_info_mock.assert_called_once_with('dep1', 'plat')
197 self.assertFalse(sb_find_path_mock.call_args)
198 # If the below assert fails, the ordering assumption that determined the
199 # path_mock return values is incorrect, and should be updated.
200 path_mock.exists.assert_has_calls([mock.call(local_path),
201 mock.call(cs_path)], any_order=False)
203 @mock.patch('os.path')
204 @mock.patch('catapult_base.support_binaries.FindPath')
205 @mock.patch(
206 'catapult_base.dependency_manager.DependencyManager._GetDependencyInfo')
207 @mock.patch(
208 'catapult_base.dependency_manager.DependencyManager._CloudStoragePath')
209 @mock.patch('catapult_base.dependency_manager.DependencyManager._LocalPath')
210 def testFetchPathError(self, local_path_mock, cs_path_mock, dep_info_mock,
211 sb_find_path_mock, path_mock):
212 dep_manager = dependency_manager.DependencyManager([])
213 self.assertFalse(local_path_mock.call_args)
214 self.assertFalse(cs_path_mock.call_args)
215 self.assertFalse(sb_find_path_mock.call_args)
216 local_path_mock.return_value = None
217 cs_path_mock.return_value = None
218 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
219 'dep2': mock.MagicMock()}
220 # Non-empty lookup dict that contains the dependency we're looking for.
221 # Local path doesn't exist, and cloud_storage path wasn't successfully
222 # found.
223 self.assertRaises(exceptions.NoPathFoundError,
224 dep_manager.FetchPath, 'dep1', 'plat')
226 cs_path_mock.side_effect = cloud_storage.CredentialsError
227 self.assertRaises(cloud_storage.CredentialsError,
228 dep_manager.FetchPath, 'dep1', 'plat')
230 cs_path_mock.side_effect = cloud_storage.CloudStorageError
231 self.assertRaises(cloud_storage.CloudStorageError,
232 dep_manager.FetchPath, 'dep1', 'plat')
234 cs_path_mock.side_effect = cloud_storage.PermissionError
235 self.assertRaises(cloud_storage.PermissionError,
236 dep_manager.FetchPath, 'dep1', 'plat')
238 @mock.patch('os.path')
239 @mock.patch('catapult_base.support_binaries.FindLocallyBuiltPath')
240 @mock.patch(
241 'catapult_base.dependency_manager.DependencyManager._GetDependencyInfo')
242 @mock.patch('catapult_base.dependency_manager.DependencyManager._LocalPath')
243 def testLocalPath(self, local_path_mock, dep_info_mock, sb_find_path_mock,
244 path_mock):
245 dep_manager = dependency_manager.DependencyManager([])
246 self.assertFalse(local_path_mock.call_args)
247 self.assertFalse(sb_find_path_mock.call_args)
248 sb_path = 'sb_path'
249 local_path = 'local_path'
250 dep_info = 'dep_info'
251 local_path_mock.return_value = local_path
252 sb_find_path_mock.return_value = sb_path
254 # GetDependencyInfo should return None when missing from the lookup dict.
255 dep_info_mock.return_value = None
257 # Empty lookup_dict
258 with self.assertRaises(exceptions.NoPathFoundError):
259 dep_manager.LocalPath('dep', 'plat')
260 dep_info_mock.reset_mock()
262 found_path = dep_manager.LocalPath(
263 'dep', 'plat', try_support_binaries=True)
264 self.assertEqual(sb_path, found_path)
265 self.assertFalse(local_path_mock.call_args)
266 sb_find_path_mock.assert_called_once_with('dep')
267 dep_info_mock.assert_called_once_with('dep', 'plat')
268 local_path_mock.reset_mock()
269 sb_find_path_mock.reset_mock()
270 dep_info_mock.reset_mock()
272 # Non-empty lookup dict that doesn't contain the dependency we're looking
273 # for.
274 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
275 'dep2': mock.MagicMock()}
276 with self.assertRaises(exceptions.NoPathFoundError):
277 dep_manager.LocalPath('dep', 'plat')
278 dep_info_mock.reset_mock()
280 found_path = dep_manager.LocalPath(
281 'dep', 'plat', try_support_binaries=True)
282 self.assertEqual(sb_path, found_path)
283 self.assertFalse(local_path_mock.call_args)
284 sb_find_path_mock.assert_called_once_with('dep')
285 dep_info_mock.assert_called_once_with('dep', 'plat')
286 local_path_mock.reset_mock()
287 sb_find_path_mock.reset_mock()
288 dep_info_mock.reset_mock()
290 # The DependencyInfo returned should be passed through to LocalPath.
291 dep_info_mock.return_value = dep_info
293 # Non-empty lookup dict that contains the dependency we're looking for.
294 # Local path exists.
295 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
296 'dep2': mock.MagicMock()}
297 path_mock.exists.return_value = True
298 found_path = dep_manager.LocalPath('dep1', 'plat')
300 self.assertEqual(local_path, found_path)
301 local_path_mock.assert_called_with('dep_info')
302 self.assertFalse(sb_find_path_mock.call_args)
303 # If the below assert fails, the ordering assumption that determined the
304 # path_mock return values is incorrect, and should be updated.
305 path_mock.exists.assert_called_once_with('local_path')
306 dep_info_mock.assert_called_once_with('dep1', 'plat')
307 local_path_mock.reset_mock()
308 sb_find_path_mock.reset_mock()
309 dep_info_mock.reset_mock()
311 # Non-empty lookup dict that contains the dependency we're looking for.
312 # Local path is found but doesn't exist.
313 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
314 'dep2': mock.MagicMock()}
315 path_mock.exists.return_value = False
316 local_path_mock.return_value = local_path
317 self.assertRaises(exceptions.NoPathFoundError,
318 dep_manager.LocalPath, 'dep1', 'plat')
320 # Non-empty lookup dict that contains the dependency we're looking for.
321 # Local path isn't found.
322 dep_manager._lookup_dict = {'dep1': mock.MagicMock(),
323 'dep2': mock.MagicMock()}
324 local_path_mock.return_value = None
325 self.assertRaises(exceptions.NoPathFoundError,
326 dep_manager.LocalPath, 'dep1', 'plat')
328 def testInitialUpdateDependencies(self):
329 dep_manager = dependency_manager.DependencyManager([])
331 # Empty BaseConfig.
332 dep_manager._lookup_dict = {}
333 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
334 base_config_mock.IterDependencyInfo.return_value = iter([])
335 dep_manager._UpdateDependencies(base_config_mock)
336 self.assertFalse(dep_manager._lookup_dict)
338 # One dependency/platform in a BaseConfig.
339 dep_manager._lookup_dict = {}
340 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
341 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
342 dep = 'dependency'
343 plat = 'platform'
344 dep_info.dependency = dep
345 dep_info.platform = plat
346 base_config_mock.IterDependencyInfo.return_value = iter([dep_info])
347 expected_lookup_dict = {dep: {plat: dep_info}}
348 dep_manager._UpdateDependencies(base_config_mock)
349 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
350 self.assertFalse(dep_info.Update.called)
352 # One dependency multiple platforms in a BaseConfig.
353 dep_manager._lookup_dict = {}
354 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
355 dep = 'dependency'
356 plat1 = 'platform1'
357 plat2 = 'platform2'
358 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
359 dep_info1.dependency = dep
360 dep_info1.platform = plat1
361 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
362 dep_info2.dependency = dep
363 dep_info2.platform = plat2
364 base_config_mock.IterDependencyInfo.return_value = iter([dep_info1,
365 dep_info2])
366 expected_lookup_dict = {dep: {plat1: dep_info1,
367 plat2: dep_info2}}
368 dep_manager._UpdateDependencies(base_config_mock)
369 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
370 self.assertFalse(dep_info1.Update.called)
371 self.assertFalse(dep_info2.Update.called)
373 # Multiple dependencies, multiple platforms in a BaseConfig.
374 dep_manager._lookup_dict = {}
375 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
376 dep1 = 'dependency1'
377 dep2 = 'dependency2'
378 plat1 = 'platform1'
379 plat2 = 'platform2'
380 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
381 dep_info1.dependency = dep1
382 dep_info1.platform = plat1
383 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
384 dep_info2.dependency = dep1
385 dep_info2.platform = plat2
386 dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
387 dep_info3.dependency = dep2
388 dep_info3.platform = plat2
389 base_config_mock.IterDependencyInfo.return_value = iter(
390 [dep_info1, dep_info2, dep_info3])
391 expected_lookup_dict = {dep1: {plat1: dep_info1,
392 plat2: dep_info2},
393 dep2: {plat2: dep_info3}}
394 dep_manager._UpdateDependencies(base_config_mock)
395 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
396 self.assertFalse(dep_info1.Update.called)
397 self.assertFalse(dep_info2.Update.called)
398 self.assertFalse(dep_info3.Update.called)
400 def testFollowupUpdateDependenciesNoOverlap(self):
401 dep_manager = dependency_manager.DependencyManager([])
402 dep = 'dependency'
403 dep1 = 'dependency1'
404 dep2 = 'dependency2'
405 dep3 = 'dependency3'
406 plat1 = 'platform1'
407 plat2 = 'platform2'
408 plat3 = 'platform3'
409 dep_info_a = mock.MagicMock(spec=dependency_manager.DependencyInfo)
410 dep_info_a.dependency = dep1
411 dep_info_a.platform = plat1
412 dep_info_b = mock.MagicMock(spec=dependency_manager.DependencyInfo)
413 dep_info_b.dependency = dep1
414 dep_info_b.platform = plat2
415 dep_info_c = mock.MagicMock(spec=dependency_manager.DependencyInfo)
416 dep_info_c.dependency = dep
417 dep_info_c.platform = plat1
419 start_lookup_dict = {dep: {plat1: dep_info_a,
420 plat2: dep_info_b},
421 dep1: {plat1: dep_info_c}}
422 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
424 # Empty BaseConfig.
425 dep_manager._lookup_dict = start_lookup_dict.copy()
426 base_config_mock.IterDependencyInfo.return_value = iter([])
427 dep_manager._UpdateDependencies(base_config_mock)
428 self.assertEqual(start_lookup_dict, dep_manager._lookup_dict)
430 # One dependency/platform in a BaseConfig.
431 dep_manager._lookup_dict = start_lookup_dict.copy()
432 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
433 dep_info.dependency = dep3
434 dep_info.platform = plat1
435 base_config_mock.IterDependencyInfo.return_value = iter([dep_info])
436 expected_lookup_dict = {dep: {plat1: dep_info_a,
437 plat2: dep_info_b},
438 dep1: {plat1: dep_info_c},
439 dep3: {plat3: dep_info}}
441 dep_manager._UpdateDependencies(base_config_mock)
442 self.assertItemsEqual(expected_lookup_dict, dep_manager._lookup_dict)
443 self.assertFalse(dep_info.Update.called)
444 self.assertFalse(dep_info_a.Update.called)
445 self.assertFalse(dep_info_b.Update.called)
446 self.assertFalse(dep_info_c.Update.called)
448 # One dependency multiple platforms in a BaseConfig.
449 dep_manager._lookup_dict = start_lookup_dict.copy()
450 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
451 dep_info1.dependency = dep2
452 dep_info1.platform = plat1
453 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
454 dep_info2.dependency = dep2
455 dep_info2.platform = plat2
456 base_config_mock.IterDependencyInfo.return_value = iter([dep_info1,
457 dep_info2])
458 expected_lookup_dict = {dep: {plat1: dep_info_a,
459 plat2: dep_info_b},
460 dep1: {plat1: dep_info_c},
461 dep2: {plat1: dep_info1,
462 plat2: dep_info2}}
463 dep_manager._UpdateDependencies(base_config_mock)
464 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
465 self.assertFalse(dep_info1.Update.called)
466 self.assertFalse(dep_info2.Update.called)
467 self.assertFalse(dep_info_a.Update.called)
468 self.assertFalse(dep_info_b.Update.called)
469 self.assertFalse(dep_info_c.Update.called)
471 # Multiple dependencies, multiple platforms in a BaseConfig.
472 dep_manager._lookup_dict = start_lookup_dict.copy()
473 dep1 = 'dependency1'
474 plat1 = 'platform1'
475 plat2 = 'platform2'
476 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
477 dep_info1.dependency = dep2
478 dep_info1.platform = plat1
479 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
480 dep_info2.dependency = dep2
481 dep_info2.platform = plat2
482 dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
483 dep_info3.dependency = dep3
484 dep_info3.platform = plat2
485 base_config_mock.IterDependencyInfo.return_value = iter(
486 [dep_info1, dep_info2, dep_info3])
487 expected_lookup_dict = {dep: {plat1: dep_info_a,
488 plat2: dep_info_b},
489 dep1: {plat1: dep_info_c},
490 dep2: {plat1: dep_info1,
491 plat2: dep_info2},
492 dep3: {plat2: dep_info3}}
493 dep_manager._UpdateDependencies(base_config_mock)
494 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
495 self.assertFalse(dep_info1.Update.called)
496 self.assertFalse(dep_info2.Update.called)
497 self.assertFalse(dep_info3.Update.called)
498 self.assertFalse(dep_info_a.Update.called)
499 self.assertFalse(dep_info_b.Update.called)
500 self.assertFalse(dep_info_c.Update.called)
502 # Ensure the testing data wasn't corrupted.
503 self.assertEqual(start_lookup_dict,
504 {dep: {plat1: dep_info_a,
505 plat2: dep_info_b},
506 dep1: {plat1: dep_info_c}})
508 def testFollowupUpdateDependenciesWithCollisions(self):
509 dep_manager = dependency_manager.DependencyManager([])
510 dep = 'dependency'
511 dep1 = 'dependency1'
512 dep2 = 'dependency2'
513 plat1 = 'platform1'
514 plat2 = 'platform2'
515 dep_info_a = mock.MagicMock(spec=dependency_manager.DependencyInfo)
516 dep_info_a.dependency = dep1
517 dep_info_a.platform = plat1
518 dep_info_b = mock.MagicMock(spec=dependency_manager.DependencyInfo)
519 dep_info_b.dependency = dep1
520 dep_info_b.platform = plat2
521 dep_info_c = mock.MagicMock(spec=dependency_manager.DependencyInfo)
522 dep_info_c.dependency = dep
523 dep_info_c.platform = plat1
525 start_lookup_dict = {dep: {plat1: dep_info_a,
526 plat2: dep_info_b},
527 dep1: {plat1: dep_info_c}}
528 base_config_mock = mock.MagicMock(spec=dependency_manager.BaseConfig)
530 # One dependency/platform.
531 dep_manager._lookup_dict = start_lookup_dict.copy()
532 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
533 dep_info.dependency = dep
534 dep_info.platform = plat1
535 base_config_mock.IterDependencyInfo.return_value = iter([dep_info])
536 expected_lookup_dict = {dep: {plat1: dep_info_a,
537 plat2: dep_info_b},
538 dep1: {plat1: dep_info_c}}
540 dep_manager._UpdateDependencies(base_config_mock)
541 self.assertItemsEqual(expected_lookup_dict, dep_manager._lookup_dict)
542 dep_info_a.Update.assert_called_once_with(dep_info)
543 self.assertFalse(dep_info.Update.called)
544 self.assertFalse(dep_info_b.Update.called)
545 self.assertFalse(dep_info_c.Update.called)
546 dep_info_a.reset_mock()
547 dep_info_b.reset_mock()
548 dep_info_c.reset_mock()
550 # One dependency multiple platforms in a BaseConfig.
551 dep_manager._lookup_dict = start_lookup_dict.copy()
552 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
553 dep_info1.dependency = dep1
554 dep_info1.platform = plat1
555 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
556 dep_info2.dependency = dep2
557 dep_info2.platform = plat2
558 base_config_mock.IterDependencyInfo.return_value = iter([dep_info1,
559 dep_info2])
560 expected_lookup_dict = {dep: {plat1: dep_info_a,
561 plat2: dep_info_b},
562 dep1: {plat1: dep_info_c},
563 dep2: {plat2: dep_info2}}
564 dep_manager._UpdateDependencies(base_config_mock)
565 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
566 self.assertFalse(dep_info1.Update.called)
567 self.assertFalse(dep_info2.Update.called)
568 self.assertFalse(dep_info_a.Update.called)
569 self.assertFalse(dep_info_b.Update.called)
570 dep_info_c.Update.assert_called_once_with(dep_info1)
571 dep_info_a.reset_mock()
572 dep_info_b.reset_mock()
573 dep_info_c.reset_mock()
575 # Multiple dependencies, multiple platforms in a BaseConfig.
576 dep_manager._lookup_dict = start_lookup_dict.copy()
577 dep1 = 'dependency1'
578 plat1 = 'platform1'
579 plat2 = 'platform2'
580 dep_info1 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
581 dep_info1.dependency = dep
582 dep_info1.platform = plat1
583 dep_info2 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
584 dep_info2.dependency = dep1
585 dep_info2.platform = plat1
586 dep_info3 = mock.MagicMock(spec=dependency_manager.DependencyInfo)
587 dep_info3.dependency = dep2
588 dep_info3.platform = plat2
589 base_config_mock.IterDependencyInfo.return_value = iter(
590 [dep_info1, dep_info2, dep_info3])
591 expected_lookup_dict = {dep: {plat1: dep_info_a,
592 plat2: dep_info_b},
593 dep1: {plat1: dep_info_c},
594 dep2: {plat2: dep_info3}}
595 dep_manager._UpdateDependencies(base_config_mock)
596 self.assertEqual(expected_lookup_dict, dep_manager._lookup_dict)
597 self.assertFalse(dep_info1.Update.called)
598 self.assertFalse(dep_info2.Update.called)
599 self.assertFalse(dep_info3.Update.called)
600 self.assertFalse(dep_info_b.Update.called)
601 dep_info_a.Update.assert_called_once_with(dep_info1)
602 dep_info_c.Update.assert_called_once_with(dep_info2)
604 # Collision error.
605 dep_manager._lookup_dict = start_lookup_dict.copy()
606 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
607 dep_info.dependency = dep
608 dep_info.platform = plat1
609 base_config_mock.IterDependencyInfo.return_value = iter([dep_info])
610 dep_info_a.Update.side_effect = ValueError
611 self.assertRaises(ValueError,
612 dep_manager._UpdateDependencies, base_config_mock)
614 # Ensure the testing data wasn't corrupted.
615 self.assertEqual(start_lookup_dict,
616 {dep: {plat1: dep_info_a,
617 plat2: dep_info_b},
618 dep1: {plat1: dep_info_c}})
620 def testGetDependencyInfo(self):
621 dep_manager = dependency_manager.DependencyManager([])
622 self.assertFalse(dep_manager._lookup_dict)
624 # No dependencies in the dependency manager.
625 self.assertEqual(None, dep_manager._GetDependencyInfo('missing_dep',
626 'missing_plat'))
628 dep_manager._lookup_dict = {'dep1': {'plat1': 'dep_info11',
629 'plat2': 'dep_info12',
630 'plat3': 'dep_info13'},
631 'dep2': {'plat1': 'dep_info11',
632 'plat2': 'dep_info21',
633 'plat3': 'dep_info23',
634 'default': 'dep_info2d'},
635 'dep3': {'plat1': 'dep_info31',
636 'plat2': 'dep_info32',
637 'default': 'dep_info3d'}}
638 # Dependency not in the dependency manager.
639 self.assertEqual(None, dep_manager._GetDependencyInfo(
640 'missing_dep', 'missing_plat'))
641 # Dependency in the dependency manager, but not the platform. No default.
642 self.assertEqual(None, dep_manager._GetDependencyInfo(
643 'dep1', 'missing_plat'))
644 # Dependency in the dependency manager, but not the platform, but a default
645 # exists.
646 self.assertEqual('dep_info2d', dep_manager._GetDependencyInfo(
647 'dep2', 'missing_plat'))
648 # Dependency and platform in the dependency manager. A default exists.
649 self.assertEqual('dep_info23', dep_manager._GetDependencyInfo(
650 'dep2', 'plat3'))
651 # Dependency and platform in the dependency manager. No default exists.
652 self.assertEqual('dep_info12', dep_manager._GetDependencyInfo(
653 'dep1', 'plat2'))
656 @mock.patch('os.path.exists')
657 def testLocalPathHelper(self, exists_mock):
658 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
660 # There is no local path for the given dependency.
661 dep_info.local_paths = {}
662 self.assertEqual(None,
663 dependency_manager.DependencyManager._LocalPath(dep_info))
665 # There is a local path for the given dependency, but it doesn't exist.
666 exists_mock.side_effect = [False]
667 dep_info.local_paths = {'local_path0'}
668 self.assertEqual(None,
669 dependency_manager.DependencyManager._LocalPath(dep_info))
670 exists_mock.assert_called_once_with('local_path0')
671 exists_mock.reset_mock()
673 # There is a local path for the given dependency, and it does exist.
674 exists_mock.side_effect = [True]
675 dep_info.local_paths = {'local_path0'}
676 self.assertEqual('local_path0',
677 dependency_manager.DependencyManager._LocalPath(dep_info))
678 exists_mock.assert_called_once_with('local_path0')
679 exists_mock.reset_mock()
681 # There are multiple local paths for the given dependency, and the first one
682 # exists.
683 exists_mock.side_effect = [True]
684 dep_info.local_paths = {'local_path0', 'local_path1', 'local_path2'}
685 self.assertEqual('local_path0',
686 dependency_manager.DependencyManager._LocalPath(dep_info))
687 exists_mock.assert_called_once_with('local_path0')
688 exists_mock.reset_mock()
690 # There are multiple local paths for the given dependency, and the first one
691 # doesn't exist but the second one does.
692 exists_mock.side_effect = [False, True]
693 dep_info.local_paths = {'local_path0', 'local_path1', 'local_path2'}
694 self.assertEqual('local_path1',
695 dependency_manager.DependencyManager._LocalPath(dep_info))
696 expected_calls = [mock.call('local_path0'), mock.call('local_path1')]
697 exists_mock.assert_has_calls(expected_calls, any_order=False)
698 exists_mock.reset_mock()
700 # There are multiple local paths for the given dependency, and the first and
701 # second ones don't exist but the third one does.
702 exists_mock.side_effect = [False, False, True]
703 dep_info.local_paths = {'local_path0', 'local_path1', 'local_path2'}
704 self.assertEqual('local_path2',
705 dependency_manager.DependencyManager._LocalPath(dep_info))
706 expected_calls = [mock.call('local_path0'), mock.call('local_path1'),
707 mock.call('local_path2')]
708 exists_mock.assert_has_calls(expected_calls, any_order=False)
709 exists_mock.reset_mock()
711 # There are multiple local paths for the given dependency, but none of them
712 # exist.
713 exists_mock.side_effect = [False, False, False]
714 dep_info.local_paths = {'local_path0', 'local_path1', 'local_path2'}
715 self.assertEqual(None,
716 dependency_manager.DependencyManager._LocalPath(dep_info))
717 expected_calls = [mock.call('local_path0'), mock.call('local_path1'),
718 mock.call('local_path2')]
719 exists_mock.assert_has_calls(expected_calls, any_order=False)
720 exists_mock.reset_mock()
723 @mock.patch('os.path.exists')
724 @mock.patch('os.chmod')
725 @mock.patch(
726 'catapult_base.cloud_storage.GetIfHashChanged')
727 def testCloudStoragePathMissingData(
728 self, cs_get_mock, chmod_mock, exists_mock):
729 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
730 cs_remote_path = 'cs_remote_path'
731 cs_hash = 'cs_hash'
732 cs_bucket = 'cs_bucket'
733 download_path = 'download_path'
735 # No dependency info.
736 self.assertEqual(
737 None, dependency_manager.DependencyManager._CloudStoragePath(None))
739 # There is no cloud_storage information for the dependency.
740 dep_info.cs_remote_path = None
741 dep_info.cs_hash = None
742 dep_info.cs_bucket = None
743 dep_info.download_path = None
744 self.assertEqual(
745 None, dependency_manager.DependencyManager._CloudStoragePath(dep_info))
747 # There is no cloud_storage remote_path the dependency.
748 dep_info.cs_remote_path = None
749 dep_info.cs_hash = cs_hash
750 dep_info.cs_bucket = cs_bucket
751 dep_info.download_path = download_path
752 self.assertEqual(
753 None, dependency_manager.DependencyManager._CloudStoragePath(dep_info))
755 # There is no cloud_storage hash for the dependency.
756 dep_info.cs_remote_path = cs_remote_path
757 dep_info.cs_hash = None
758 dep_info.cs_bucket = cs_bucket
759 dep_info.download_path = download_path
760 self.assertEqual(
761 None, dependency_manager.DependencyManager._CloudStoragePath(dep_info))
763 # There is no cloud_storage bucket for the dependency.
764 dep_info.cs_remote_path = cs_remote_path
765 dep_info.cs_hash = cs_hash
766 dep_info.cs_bucket = None
767 dep_info.download_path = download_path
768 self.assertEqual(
769 None, dependency_manager.DependencyManager._CloudStoragePath(dep_info))
771 # There is no download_path for the dependency.
772 dep_info.cs_remote_path = cs_remote_path
773 dep_info.cs_hash = cs_hash
774 dep_info.cs_bucket = cs_bucket
775 dep_info.download_path = None
776 self.assertEqual(
777 None, dependency_manager.DependencyManager._CloudStoragePath(dep_info))
779 @mock.patch('os.path.exists')
780 @mock.patch('os.chmod')
781 @mock.patch(
782 'catapult_base.cloud_storage.GetIfHashChanged')
783 def testCloudStoragePath(self, cs_get_mock, chmod_mock, exists_mock):
784 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
785 cs_remote_path = 'cs_remote_path'
786 cs_hash = 'cs_hash'
787 cs_bucket = 'cs_bucket'
788 download_path = 'download_path'
790 # All of the needed information is given, and the downloaded path exists
791 # after calling cloud storage.
792 dep_info.cs_remote_path = cs_remote_path
793 dep_info.cs_hash = cs_hash
794 dep_info.cs_bucket = cs_bucket
795 dep_info.download_path = download_path
796 exists_mock.return_value = True
797 self.assertEqual(
798 os.path.abspath(download_path),
799 dependency_manager.DependencyManager._CloudStoragePath(dep_info))
800 chmod_mock.assert_called_once_with(
801 download_path,
802 stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP)
804 # All of the needed information is given, but the downloaded path doesn't
805 # exists after calling cloud storage.
806 dep_info.cs_remote_path = cs_remote_path
807 dep_info.cs_hash = cs_hash
808 dep_info.cs_bucket = cs_bucket
809 dep_info.download_path = download_path
810 exists_mock.return_value = False
811 with mock.patch(
812 'catapult_base.dependency_manager.dependency_manager.os.makedirs'):
813 self.assertRaises(
814 exceptions.FileNotFoundError,
815 dependency_manager.DependencyManager._CloudStoragePath, dep_info)
816 exists_mock.assert_called_with(download_path)
818 @mock.patch('os.path.exists')
819 @mock.patch(
820 'catapult_base.cloud_storage.GetIfHashChanged')
821 def testCloudStoragePathCloudStorageErrors(self, cs_get_mock, exists_mock):
822 dep_info = mock.MagicMock(spec=dependency_manager.DependencyInfo)
823 dep_info.download_path = 'download_path'
825 cs_get_mock.side_effect = cloud_storage.CloudStorageError
826 self.assertRaises(
827 cloud_storage.CloudStorageError,
828 dependency_manager.DependencyManager._CloudStoragePath, dep_info)
830 cs_get_mock.side_effect = cloud_storage.ServerError
831 self.assertRaises(
832 cloud_storage.ServerError,
833 dependency_manager.DependencyManager._CloudStoragePath, dep_info)
835 cs_get_mock.side_effect = cloud_storage.NotFoundError
836 self.assertRaises(
837 cloud_storage.NotFoundError,
838 dependency_manager.DependencyManager._CloudStoragePath, dep_info)
840 cs_get_mock.side_effect = cloud_storage.PermissionError
841 self.assertRaises(
842 cloud_storage.PermissionError,
843 dependency_manager.DependencyManager._CloudStoragePath, dep_info)
845 cs_get_mock.side_effect = cloud_storage.CredentialsError
846 self.assertRaises(
847 cloud_storage.CredentialsError,
848 dependency_manager.DependencyManager._CloudStoragePath, dep_info)