| OLD | NEW |
| (Empty) | |
| 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. |
| 4 |
| 5 import collections |
| 6 import fcntl |
| 7 import os |
| 8 import sys |
| 9 import unittest |
| 10 |
| 11 from testing_support import auto_stub |
| 12 from infra.libs.service_utils import daemon |
| 13 |
| 14 |
| 15 Stat = collections.namedtuple('Stat', ['st_ino']) |
| 16 |
| 17 |
| 18 class TestFlock(auto_stub.TestCase): |
| 19 def setUp(self): |
| 20 super(TestFlock, self).setUp() |
| 21 |
| 22 # daemon.flock() only works on linux/osx, so set 'linux' here if we're |
| 23 # testing in windows. The OS calls are mocked so it will still work. If |
| 24 # windows support is added, remove this mock entirely. |
| 25 self.mock(sys, 'platform', 'linux2') |
| 26 |
| 27 def _mock_basic_fs_calls(self): |
| 28 """Mocks os.open, os.close as well as os.fstat.""" |
| 29 def _noop_handler(*_args, **_kwargs): |
| 30 return 1 |
| 31 |
| 32 def _noop_os_close(*_args, **_kwargs): |
| 33 pass |
| 34 |
| 35 def _noop_fstat(*_args, **_kwargs): |
| 36 return Stat(st_ino=45678) |
| 37 |
| 38 self.mock(os, 'open', _noop_handler) |
| 39 self.mock(os, 'close', _noop_os_close) |
| 40 self.mock(os, 'fstat', _noop_fstat) |
| 41 |
| 42 def _set_lock_status(self, success=True): |
| 43 """Mocks os.fcntl and whether the mock succeeds or not.""" |
| 44 def _lock_status(_fd, flags, **_kwargs): |
| 45 if flags != fcntl.LOCK_UN: # We don't care if unlock fails. |
| 46 if not success: |
| 47 raise IOError('Couldn\'t get lock.') |
| 48 |
| 49 self.mock(fcntl, 'lockf', _lock_status) |
| 50 |
| 51 def _set_stat_status(self, success=True, matching=True): |
| 52 """Mocks os.stat, sets its success and if st_ino matches os.fstat mock.""" |
| 53 def _stat_handler(*_args, **_kwargs): |
| 54 if not success: |
| 55 raise OSError('Not found.') |
| 56 if matching: |
| 57 return Stat(st_ino=45678) |
| 58 return Stat(st_ino=67890) |
| 59 |
| 60 self.mock(os, 'stat', _stat_handler) |
| 61 |
| 62 def _set_unlink_status(self, success=True): |
| 63 """Mocks os.unlink and sets whether it succeeds or not.""" |
| 64 def _unlink_handler(*_args, **_kwargs): |
| 65 if not success: |
| 66 raise OSError('Not found.') |
| 67 |
| 68 self.mock(os, 'unlink', _unlink_handler) |
| 69 |
| 70 #### Tests. |
| 71 |
| 72 def testGetLock(self): |
| 73 self._mock_basic_fs_calls() |
| 74 self._set_lock_status() |
| 75 self._set_stat_status() |
| 76 self._set_unlink_status() |
| 77 with daemon.flock('bogus') as acquired: |
| 78 self.assertTrue(acquired) |
| 79 |
| 80 def testDontGetLock(self): |
| 81 self._mock_basic_fs_calls() |
| 82 self._set_lock_status(success=False) |
| 83 self._set_stat_status() |
| 84 self._set_unlink_status() |
| 85 with daemon.flock('bogus') as acquired: |
| 86 self.assertFalse(acquired) |
| 87 |
| 88 def testFileDeletedAfterLockAcquired(self): |
| 89 """Test that we abort if we acquire a lock but the file has been deleted.""" |
| 90 self._mock_basic_fs_calls() |
| 91 self._set_lock_status() |
| 92 self._set_stat_status(success=False) |
| 93 self._set_unlink_status() |
| 94 with daemon.flock('bogus') as acquired: |
| 95 self.assertFalse(acquired) |
| 96 |
| 97 def testLockfileRecreated(self): |
| 98 """Test that we abort if a new lockfile is created under us.""" |
| 99 self._mock_basic_fs_calls() |
| 100 self._set_lock_status() |
| 101 self._set_stat_status(matching=False) |
| 102 self._set_unlink_status() |
| 103 with daemon.flock('bogus') as acquired: |
| 104 self.assertFalse(acquired) |
| 105 |
| 106 def testDeleteWhenDone(self): |
| 107 """Test that we delete the lockfile when we're done.""" |
| 108 data = {'count': 0} |
| 109 def _mock_unlink(*_args, **_kwargs): |
| 110 data['count'] += 1 |
| 111 self.mock(os, 'unlink', _mock_unlink) |
| 112 self._mock_basic_fs_calls() |
| 113 self._set_lock_status() |
| 114 self._set_stat_status() |
| 115 with daemon.flock('bogus') as _: |
| 116 pass |
| 117 self.assertEqual(data['count'], 1) |
| 118 |
| 119 |
| 120 def testUnlinkFailureDoesntBreak(self): |
| 121 """Test that a failing unlink doesn't break us.""" |
| 122 self._mock_basic_fs_calls() |
| 123 self._set_lock_status() |
| 124 self._set_stat_status() |
| 125 self._set_unlink_status(success=False) |
| 126 with daemon.flock('bogus') as _: |
| 127 pass |
| 128 |
| 129 |
| 130 class TestTimeout(auto_stub.TestCase): |
| 131 def setUp(self): |
| 132 super(TestTimeout, self).setUp() |
| 133 |
| 134 # daemon.add_timeout() only works on linux, so set 'linux' here if we're |
| 135 # testing in windows/osx. If windows or osx support is added, change |
| 136 # accordingly. |
| 137 self.mock(sys, 'platform', 'linux2') |
| 138 |
| 139 def testAddTimeout(self): |
| 140 self.assertEqual( |
| 141 ['timeout', '600', 'echo', 'hey'], |
| 142 daemon.add_timeout(['echo', 'hey'], 600)) |
| OLD | NEW |