def test_perms_block_panic_stop(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_break, \ mock.patch('sys.stdout', new=StringIO()): oneoff.panic_stop(True) self.assertEqual(fail_break.exception.code, 2)
def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-run-statefile-mods.test.txt' self.pe_patcher = mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True) self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user) self.pe_patcher.start()
def test_perms_block_disable(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_disable, \ mock.patch('sys.stdout', new=StringIO()): oneoff.disable(False, int(time.time() + 60), 'failure testing') self.assertEqual(fail_disable.exception.code, 2)
def test_nothing_to_do(self): ''' Test that we do nothing if there aren't locks to break. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_operating', return_value=True), \ self.assertRaises(SystemExit) as fail_break, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: oneoff.break_all_locks(2) self.assertIn('There are no locks', fake_out.getvalue()) self.assertEqual(fail_break.exception.code, 0)
def test_init_sudo(self): ''' Verify that the self object handles user edge-cases ''' original_sudo = os.environ.get('SUDO_USER') original_user = os.environ.get('USER') os.environ.pop('SUDO_USER', None) os.environ.pop('USER', None) obj_unknown = PuppetctlExecution() self.assertEqual(obj_unknown.invoking_user, 'UNKNOWN') os.environ['USER'] = '******' obj_user = PuppetctlExecution() self.assertEqual(obj_user.invoking_user, 'someguy') os.environ['SUDO_USER'] = '******' obj_sudo = PuppetctlExecution() self.assertEqual(obj_sudo.invoking_user, 'otherguy') os.environ['USER'] = original_user # no cover begins here because the resets vary based on who you tested as. # This is just to put the house back in order. if original_sudo is None: # pragma: no cover os.environ.pop('SUDO_USER', None) else: # pragma: no cover os.environ['SUDO_USER'] = original_sudo
def test_plain_init(self): ''' Verify that the class inits with no parameters ''' library = PuppetctlExecution() self.assertEqual( library.puppet_bin_path, library.defaults.get('puppet_bin_path') + ':/bin:/usr/bin') self.assertIsInstance(library.lastrunfile, str) self.assertEqual(library.lastrunfile, library.defaults.get('lastrunfile')) self.assertEqual(library.agent_catalog_run_lockfile, library.defaults.get('agent_catalog_run_lockfile')) self.assertIsInstance(library.invoking_user, str) self.assertIsInstance(library.logging_tag, str) self.assertIsInstance(library.statefile_object, PuppetctlStatefile)
def test_execution_allargs_pos(self): ''' Verify that the class inits positionally ''' library = PuppetctlExecution('/tmp/somestate1', '/somepath1:/bin', '/opt/here1/last_run_summary.yaml', '/tmp/a.lock') self.assertEqual(library.puppet_bin_path, '/somepath1:/bin:/usr/bin') self.assertEqual(library.lastrunfile, '/opt/here1/last_run_summary.yaml') self.assertEqual(library.agent_catalog_run_lockfile, '/tmp/a.lock') self.assertIsInstance(library.invoking_user, str) self.assertIsInstance(library.logging_tag, str) self.assertIsInstance(library.statefile_object, PuppetctlStatefile) self.assertEqual(library.statefile_object.state_file, '/tmp/somestate1')
def test_execution_allargs_kwargs(self): ''' Verify that the class inits with kwargs ''' library = PuppetctlExecution( state_file='/tmp/somestate2', puppet_bin_path='/somepath2', lastrunfile='/opt/puppet/somewhere2/last_run_summary.yaml', agent_catalog_run_lockfile='/tmp/my.lck') self.assertEqual(library.puppet_bin_path, '/somepath2:/bin:/usr/bin') self.assertEqual(library.lastrunfile, '/opt/puppet/somewhere2/last_run_summary.yaml') self.assertEqual(library.agent_catalog_run_lockfile, '/tmp/my.lck') self.assertIsInstance(library.invoking_user, str) self.assertIsInstance(library.logging_tag, str) self.assertIsInstance(library.statefile_object, PuppetctlStatefile) self.assertEqual(library.statefile_object.state_file, '/tmp/somestate2')
class TestExecutionPanicStop(unittest.TestCase): ''' Class of tests about executing puppetctl panic_stop commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-panic_stop-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format(self.library.invoking_user) def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # pragma: no cover # we likely never created the file. pass def test_perms_block_panic_stop(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_break, \ mock.patch('sys.stdout', new=StringIO()): oneoff.panic_stop(True) self.assertEqual(fail_break.exception.code, 2) def test_panic_stop_nothing_to_do(self): ''' Test that 'panic_stop' handles no-processes-to-kill nicely. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', return_value={}), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(False) self.assertIn("No running 'puppet agent' found", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 0) def test_panic_stop_well_behaved(self): ''' Test that 'panic_stop' leaves quietly if a process exits cleanly. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'123': 'test-puppet agent'}, {}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(False) mock_kill.assert_called_once_with(123, signal.SIGTERM) mock_sleep.assert_called_once_with(2) self.assertIn("Sending SIGTERM to pid 123 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("No running 'puppet agent' found", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 0) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'234': 'test-puppet agent'}, {}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(True) mock_kill.assert_called_once_with(234, signal.SIGTERM) mock_sleep.assert_not_called() self.assertIn("Sending SIGTERM to pid 234 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("No running 'puppet agent' found", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 0) def test_panic_stop_stubborn(self): ''' Test that 'panic_stop' fires a kill if term wasn't enough. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'123': 'test-puppet agent'}, {'123': 'test-puppet agent'}, {}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(False) mock_kill.assert_any_call(123, signal.SIGTERM) mock_sleep.assert_any_call(2) # the non-force pause mock_kill.assert_called_with(123, signal.SIGKILL) mock_sleep.assert_any_call(1) # the mandatory pause after the kill signal self.assertIn("Sending SIGTERM to pid 123 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("Sending SIGKILL to pid 123 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("No running 'puppet agent' found", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 0) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'234': 'test-puppet agent'}, {'234': 'test-puppet agent'}, {}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(True) mock_kill.assert_any_call(234, signal.SIGTERM) mock_kill.assert_called_with(234, signal.SIGKILL) mock_sleep.assert_any_call(1) # the mandatory pause after the kill signal self.assertIn("Sending SIGTERM to pid 234 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("Sending SIGKILL to pid 234 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("No running 'puppet agent' found", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 0) def test_panic_stop_zombies(self): ''' Test that 'panic_stop' complains if a process outlives a sigkill. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'123': 'test-puppet agent'}, {'123': 'test-puppet agent'}, {'123': 'test-puppet agent'}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(False) mock_kill.assert_any_call(123, signal.SIGTERM) mock_sleep.assert_any_call(2) # the non-force pause mock_kill.assert_called_with(123, signal.SIGKILL) mock_sleep.assert_any_call(1) # the mandatory pause after the kill signal self.assertIn("Sending SIGTERM to pid 123 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("Sending SIGKILL to pid 123 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("pid 123 / 'test-puppet agent' did NOT die", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 1) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', side_effect=[{'234': 'test-puppet agent'}, {'234': 'test-puppet agent'}, {'234': 'test-puppet agent'}]), \ self.assertRaises(SystemExit) as exit_panicstop, \ mock.patch('os.kill') as mock_kill, \ mock.patch('time.sleep') as mock_sleep, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.panic_stop(True) mock_kill.assert_any_call(234, signal.SIGTERM) mock_kill.assert_called_with(234, signal.SIGKILL) mock_sleep.assert_any_call(1) # the mandatory pause after the kill signal self.assertIn("Sending SIGTERM to pid 234 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("Sending SIGKILL to pid 234 / 'test-puppet agent'", fake_out.getvalue()) self.assertIn("pid 234 / 'test-puppet agent' did NOT die", fake_out.getvalue()) self.assertEqual(exit_panicstop.exception.code, 1)
class TestExecutionStatusPuppetctl(unittest.TestCase): ''' Class of tests about executing puppetctl status commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-status-puppet-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user) def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # we likely never created the file. pass def test_status_puppetctl_nolocks(self): ''' Test the status of puppetctl, no locks. Valid with or without root. ''' result = self.library._status_of_puppetctl() self.assertIn('message', result) self.assertIn('Puppet is enabled and in operating mode', result['message']) self.assertIn('color', result) self.assertIsNone(result['color']) def test_status_puppetctl_disable(self): ''' Test the status of puppetctl, disable lock. Valid with or without root. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled it') result = self.library._status_of_puppetctl() self.assertIn('message', result) self.assertIn('Puppet has been disabled', result['message']) self.assertIn('somebody2', result['message']) self.assertIn('I disabled it', result['message']) self.assertIn('color', result) self.assertIsNotNone(result['color']) def test_status_puppetctl_nooperate(self): ''' Test the status of puppetctl, noop lock. Valid with or without root. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 30 * 60, 'I nooped it') result = self.library._status_of_puppetctl() self.assertIn('message', result) self.assertIn('Puppet is in nooperate mode', result['message']) self.assertIn('somebody3', result['message']) self.assertIn('I nooped it', result['message']) self.assertIn('color', result) self.assertIsNotNone(result['color']) def test_status_puppetctl_multilock(self): ''' Test the status of puppetctl, noop and disable locks. Valid with or without root. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled it') self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 30 * 60, 'I nooped it') result = self.library._status_of_puppetctl() self.assertIn('message', result) self.assertIn('Puppet has been disabled', result['message']) self.assertIn('somebody2', result['message']) self.assertIn('I disabled it', result['message']) self.assertIn('Puppet is in nooperate mode', result['message']) self.assertIn('somebody3', result['message']) self.assertIn('I nooped it', result['message']) self.assertIn('color', result) self.assertIsNotNone(result['color']) def test_lock_status_call(self): ''' This is not an interesting test. The real work is done in _status_of_puppetctl, so this is just for coverage. ''' with mock.patch('sys.stdout', new=StringIO()), \ mock.patch.object(PuppetctlExecution, '_status_of_puppetctl') as mock_pc: self.library.lock_status() mock_pc.assert_called_once() def test_motd_status_call(self): ''' Make sure that we print nothing when there's no errors. ''' with mock.patch('sys.stdout', new=StringIO()), \ self.assertRaises(SystemExit) as mock_motd, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_status_of_puppetctl', return_value={'message': 'foo', 'color': None, 'disable': 0, 'nooperate': 0}) as mock_pc: self.library.motd_status() mock_pc.assert_called_once() self.assertEqual('', fake_out.getvalue()) self.assertEqual(mock_motd.exception.code, 0) with mock.patch('sys.stdout', new=StringIO()), \ self.assertRaises(SystemExit) as mock_motd, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_status_of_puppetctl', return_value={'message': 'foo', 'color': '1;31', 'disable': 1, 'nooperate': 0}) as mock_pc: self.library.motd_status() mock_pc.assert_called_once() self.assertIn('foo', fake_out.getvalue()) self.assertEqual(mock_motd.exception.code, 0)
def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/unused-statefile.txt' self.library = PuppetctlExecution(self.test_statefile)
class TestExecutionStatusPuppet(unittest.TestCase): ''' Class of tests about executing puppetctl status commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-status-puppetctl-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format(self.library.invoking_user) def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # we likely never created the file. pass def test_parse_lastrunfile(self): ''' Run our test files through _parse_puppet_lastrunfile ''' devnull = open(os.devnull, 'w') retcode = subprocess.call(['ruby', '--version'], env={'PATH': self.library.puppet_bin_path}, stdout=devnull) if retcode != 0: # pragma: no cover self.skipTest('Cannot test without the puppet ruby environment') devnull.close() mydir = os.path.dirname(__file__) cleanfile = os.path.join(mydir, 'last_run_summary', 'clean_last_run_summary.yaml') cleancodes = self.library._parse_puppet_lastrunfile(cleanfile) # The values here are visually copied from the files in test/last_run_summary/* age = int(time.time()) - 1586995296 nearage = [age-1, age, age+1] self.assertIn(cleancodes['age'], nearage) self.assertEqual(cleancodes['errors'], 0) self.assertEqual(cleancodes['config'], 'a294ac4f4fcd5264e5246df0787757a74fc3d966') onefailfile = os.path.join(mydir, 'last_run_summary', 'fail_one_last_run_summary.yaml') onefailcodes = self.library._parse_puppet_lastrunfile(onefailfile) # The values here are visually copied from the files in test/last_run_summary/* age = int(time.time()) - 1587278457 nearage = [age-1, age, age+1] self.assertIn(onefailcodes['age'], nearage) self.assertEqual(onefailcodes['errors'], 1) self.assertEqual(onefailcodes['config'], '3a3d5827a1637456d360f888462d2aa0dbd975f6') def test_status_puppet(self): ''' Emulate testing the status of puppet ''' with mock.patch('os.geteuid', return_value=0), \ mock.patch('os.path.exists', return_value=True), \ mock.patch.object(PuppetctlExecution, '_parse_puppet_lastrunfile') as mock_parse: self.library._status_of_puppet('/tmp/pretend-i-exist.txt') mock_parse.assert_called_once_with('/tmp/pretend-i-exist.txt') def test_status_puppet_nonroot(self): ''' Emulate testing the status of puppet when not root ''' with mock.patch('os.geteuid', return_value=1006), \ mock.patch('os.path.exists', return_value=True), \ mock.patch.object(PuppetctlExecution, '_parse_puppet_lastrunfile') as mock_parse: self.library._status_of_puppet('/tmp/pretend-i-exist.txt') mock_parse.assert_not_called() def test_status_puppet_nofile(self): ''' Emulate testing the status of puppet when the file doesn't exist ''' with mock.patch('os.geteuid', return_value=0), \ mock.patch('os.path.exists', return_value=False), \ mock.patch.object(PuppetctlExecution, '_parse_puppet_lastrunfile') as mock_parse: self.library._status_of_puppet('/tmp/pretend-i-exist.txt') mock_parse.assert_not_called() def test_main_status_call(self): ''' This is not an interesting test. The real work is done in _status_of_puppet and _status_of_puppetctl, so this is just for coverage. ''' with self.assertRaises(SystemExit) as status_run: with mock.patch('sys.stdout', new=StringIO()), \ mock.patch.object(PuppetctlExecution, '_status_of_puppet') as mock_p, \ mock.patch.object(PuppetctlExecution, '_status_of_puppetctl') as mock_pc: self.library.status() self.assertIn(status_run.exception.code, [0, 1]) mock_p.assert_called_once() mock_pc.assert_called_once() def test_puppet_process_detect(self): ''' Test our detection of a running puppet process. ''' # If we're not root, we can't check. with mock.patch('os.geteuid', return_value=1006): result = self.library._puppet_processes_running('/tmp/whocares.txt') self.assertEqual(result, {}) # If we are root, and the file isn't there, we can't do anything. with mock.patch('os.geteuid', return_value=0): result = self.library._puppet_processes_running('/tmp/whocares.txt') self.assertEqual(result, {}) # Make a sample lock, that we'll use on the rest of the tests. sample_pid = '13579' test_lockfile = '/tmp/process_detect_pid.lock' with open(test_lockfile, 'w') as writelock: writelock.write(sample_pid) fake_os_stat = os.stat('/') # All future checks have root privs with mock.patch('os.geteuid', return_value=0): with mock.patch.object(six.moves.builtins, 'open', mock.mock_open(read_data='not_a_pid')): result = self.library._puppet_processes_running(test_lockfile) self.assertEqual(result, {}) # Pretend we get something from the lockfile, but the command # has exited between then and the time we look in /proc. with mock.patch('os.stat', side_effect=OSError): result = self.library._puppet_processes_running(test_lockfile) self.assertEqual(result, {}) # Pretend that the pid in the lockfile is somehow a process # not owned by root. with mock.patch('os.stat') as mock_oss: mock_oss.return_value.st_uid.return_value = 1020 result = self.library._puppet_processes_running(test_lockfile) self.assertEqual(result, {}) # All future tests have a pid, a root-owned process in /proc... with mock.patch('os.stat', return_value=fake_os_stat): # ... and because we're about to take over the 'open' call, we have # to replace the inital call from where we read the pid the first time. # This makes the handlers messy to read. # # Pretend that the proc has disappeared in the sliver of # time between the time we stat'ed it. with mock.patch.object(six.moves.builtins, 'open') as mopen: handlers = (mock.mock_open(read_data=sample_pid).return_value, IOError) mopen.side_effect = handlers result = self.library._puppet_processes_running(test_lockfile) self.assertEqual(result, {}) # Pretend that the proc is somehow not puppet. with mock.patch.object(six.moves.builtins, 'open') as mopen: handlers = (mock.mock_open(read_data=sample_pid).return_value, mock.mock_open(read_data='echo\0some\0string\0').return_value) mopen.side_effect = handlers result = self.library._puppet_processes_running(test_lockfile) self.assertEqual(result, {}) # FINALLY. Pretend that this was an actual puppet run. with mock.patch.object(six.moves.builtins, 'open') as mopen: handlers = (mock.mock_open(read_data=sample_pid).return_value, mock.mock_open(read_data=('/opt/puppetlabs/puppet/bin/ruby\0' '/opt/puppetlabs/puppet/bin/puppet\0' 'agent\0--verbose\0--onetime\0' '--no-daemonize\0--no-splay\0' '')).return_value) mopen.side_effect = handlers result = self.library._puppet_processes_running(test_lockfile) self.assertIn(sample_pid, result) self.assertIn('puppet agent', result[sample_pid])
def setUp(self): ''' Preparing test rig ''' self.library = PuppetctlExecution('/tmp/does-not-matter.status.txt')
class TestExecutionStatusBool(unittest.TestCase): ''' Class of tests about is-enabled and is-operating puppetctl commands. ''' # Here in the setup, override our statefile object's read command. # We fully test that in another test suite, so assume it works and # just let us shoot out the dict that would come from that func. # Since the state file is the basis of all our decisionmaking, # stomping that one function should cover all our state worries. def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/unused-statefile.txt' self.library = PuppetctlExecution(self.test_statefile) def tearDown(self): ''' Cleanup test rig ''' os.remove(self.test_statefile) def test_is_enabled(self, ): ''' Test the is_enabled function ''' self.assertTrue(self.library.is_enabled()) self.assertTrue(self.library.is_enabled('somebody1')) self.assertTrue(self.library.is_enabled('somebody2')) self.assertTrue(self.library.is_enabled('somebody3')) now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled 1h') self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 90 * 60, 'I nooped 2h') self.assertFalse(self.library.is_enabled()) self.assertTrue(self.library.is_enabled('somebody1')) self.assertFalse(self.library.is_enabled('somebody2')) self.assertTrue(self.library.is_enabled('somebody3')) def test_is_operating(self, ): ''' Test the is_operating function ''' self.assertTrue(self.library.is_operating()) self.assertTrue(self.library.is_operating('somebody1')) self.assertTrue(self.library.is_operating('somebody2')) self.assertTrue(self.library.is_operating('somebody3')) now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled 1h') self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 90 * 60, 'I nooped 2h') self.assertFalse(self.library.is_operating()) self.assertTrue(self.library.is_operating('somebody1')) self.assertTrue(self.library.is_operating('somebody2')) self.assertFalse(self.library.is_operating('somebody3'))
class TestExecutionStatics(unittest.TestCase): ''' Class of tests about PuppetctlExecution's static method. ''' def setUp(self): ''' Preparing test rig ''' self.library = PuppetctlExecution('/tmp/does-not-matter.status.txt') def test_dhms(self): ''' Test the dhms function for various times ''' self.assertEqual(self.library.dhms(0), '0s') self.assertEqual(self.library.dhms(30), '30s') self.assertEqual(self.library.dhms(60), '1m') self.assertEqual(self.library.dhms(90), '1m 30s') self.assertEqual(self.library.dhms(60*60), '1h') self.assertEqual(self.library.dhms(61*60), '1h 1m') self.assertEqual(self.library.dhms(61*60+20), '1h 1m 20s') self.assertEqual(self.library.dhms(11*60*60), '11h') self.assertEqual(self.library.dhms(24*60*60), '1d') def test_log(self): ''' test the syslog call of log ''' with mock.patch('syslog.openlog') as mock_openlog, \ mock.patch('syslog.syslog') as mock_syslog: self.library.syslog = mock_syslog self.library.log('foo bar baz') mock_openlog.assert_called_once_with(self.library.logging_tag) mock_syslog.assert_called_once_with('foo bar baz') def test_log_print_to_log(self): ''' test that log_print calls what it should ''' with mock.patch.object(PuppetctlExecution, 'log') as mock_log, \ mock.patch.object(PuppetctlExecution, 'color_print') as mock_print: # we don't care what it prints, just that it tries to. with mock.patch('sys.stdout', new=StringIO()): self.library.log_print('foo', '1;31') mock_log.assert_called_once_with('foo') mock_print.assert_called_once_with('foo', '1;31') def test_color_print_notty(self): ''' test that color_print handles a notty ''' # Order matters here: isatty comes second since we are touching stdout twice. with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch('sys.stdout.isatty', return_value=False): self.library.color_print('bar') self.assertEqual(fake_out.getvalue(), 'puppetctl: bar\n') def test_color_print_tty(self): ''' test that color_print handles a tty ''' # Order matters here: isatty comes second since we are touching stdout twice. with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch('sys.stdout.isatty', return_value=True): self.library.color_print('baz') self.assertEqual(fake_out.getvalue(), 'baz\n') def test_color_print_tty_color(self): ''' test that color_print handles a tty with color ''' # Order matters here: isatty comes second since we are touching stdout twice. with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch('sys.stdout.isatty', return_value=True): self.library.color_print('quux', '1;31') self.assertEqual(fake_out.getvalue(), '\033[1;31mquux\033[0m\n') def test_error_print(self): ''' Test if error_print works correctly ''' # most of the testing here is actually done by log_print with self.assertRaises(SystemExit) as error_print, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.error_print('some test message') self.assertIn('some test message', fake_out.getvalue()) self.assertEqual(error_print.exception.code, 2)
class TestExecutionEnable(unittest.TestCase): ''' Class of tests about executing puppetctl enable commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-enable-statefile-mods.test.txt' self.pe_patcher = mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True) self.sf_patcher = mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True) self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format(self.library.invoking_user) self.pe_patcher.start() self.sf_patcher.start() def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # pragma: no cover # we likely never created the file. pass self.pe_patcher.stop() self.sf_patcher.stop() def test_perms_block_enable(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_enable, \ mock.patch('sys.stdout', new=StringIO()): oneoff.enable() self.assertEqual(fail_enable.exception.code, 2) def test_enable_nolocks(self): ''' Test that "enable" does nothing when there are no locks. ''' with mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.enable() self.assertIn('Puppet is already enabled.', fake_out.getvalue()) def test_enable_not_our_locks_1(self): ''' Test that "enable" does nothing when we have no locks, but others disable. ''' now = int(time.time()) self.library.statefile_object.add_lock('somebody2', 'disable', now+30*60, 'I disabled 1h') self.library.statefile_object.add_lock('somebody3', 'nooperate', now+90*60, 'I nooped 2h') with mock.patch('sys.stdout', new=StringIO()) as fake_out: with mock.patch.object(PuppetctlExecution, 'lock_status') as mock_status: self.library.enable() self.assertIn('Puppet is already enabled for ', fake_out.getvalue()) self.assertIn(', but other users have puppet disabled.', fake_out.getvalue()) mock_status.assert_called_once_with() def test_enable_not_our_locks_2(self): ''' Test that "enable" does nothing when we have no locks, but root does. ''' now = int(time.time()) self.library.statefile_object.add_lock('root', 'disable', now+30*60, 'I disabled 1h') with mock.patch('sys.stdout', new=StringIO()) as fake_out: with mock.patch.object(PuppetctlExecution, 'lock_status') as mock_status: self.library.enable() self.assertIn('Puppet is already enabled for ', fake_out.getvalue()) self.assertIn(', but root has puppet disabled.', fake_out.getvalue()) mock_status.assert_called_once_with() def test_enable_not_our_locks_3(self): ''' Test that "enable" does nothing when we have no locks, but others noop. ''' now = int(time.time()) self.library.statefile_object.add_lock('somebody3', 'nooperate', now+90*60, 'I nooped 2h') with mock.patch('sys.stdout', new=StringIO()) as fake_out: with mock.patch.object(PuppetctlExecution, 'lock_status') as mock_status: self.library.enable() self.assertIn('Puppet is already enabled for ', fake_out.getvalue()) self.assertIn(', but other users have puppet in noop mode.', fake_out.getvalue()) mock_status.assert_called_once_with() def test_enable_disable_mylock(self): ''' Test that "enable" wants to enable when it's my lock. ''' now = int(time.time()) self.library.statefile_object.add_lock(self.library.invoking_user, 'disable', now+30*60, 'It is my lock') with mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.enable() self.assertIn('Puppet has been enabled.', fake_out.getvalue()) def test_enable_noop_mylock(self): ''' Test that "enable" assists, but doesn't enable, when there's a noop lock. ''' now = int(time.time()) self.library.statefile_object.add_lock(self.library.invoking_user, 'nooperate', now+30*60, 'It is my lock') with mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.enable() self.assertIn('Puppet is enabled, but is in nooperate mode.', fake_out.getvalue()) def test_enable_fails_remove_lock(self): ''' Test that "enable" complains if it can't remove the lock. ''' now = int(time.time()) self.library.statefile_object.add_lock(self.library.invoking_user, 'disable', now+30*60, 'It is my lock') with mock.patch.object(PuppetctlStatefile, 'remove_lock', return_value=False), \ self.assertRaises(SystemExit) as lockfail, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: self.library.enable() self.assertIn('Unable to remove', fake_out.getvalue()) self.assertEqual(lockfail.exception.code, 2)
class TestExecutionRun(unittest.TestCase): ''' Class of tests about executing puppetctl run commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-run-statefile-mods.test.txt' self.pe_patcher = mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True) self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user) self.pe_patcher.start() def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # pragma: no cover # we likely never created the file. pass self.pe_patcher.stop() def test_perms_block_run(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_run, \ mock.patch('sys.stdout', new=StringIO()): oneoff.run([]) self.assertEqual(fail_run.exception.code, 2) def test_run_nolocks(self): ''' Test that "run" fires when there are no locks. ''' with mock.patch('os.execvpe') as mock_exec: self.library.run([]) my_env = os.environ my_env['PATH'] = self.library.puppet_bin_path mock_exec.assert_called_once_with('puppet', [ 'puppet', 'agent', '--verbose', '--onetime', '--no-daemonize', '--no-splay' ], env=my_env) def test_run_nolocks_with_args(self): ''' Test that "run" passes args along. ''' with mock.patch('os.execvpe') as mock_exec: self.library.run(['--nonsense1', '--shenanigans2']) my_env = os.environ my_env['PATH'] = self.library.puppet_bin_path mock_exec.assert_called_once_with('puppet', [ 'puppet', 'agent', '--verbose', '--onetime', '--no-daemonize', '--no-splay', '--nonsense1', '--shenanigans2' ], env=my_env) def test_run_not_our_locks(self): ''' Test that "run" does nothing when we have no locks, but others do. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled 1h') self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 90 * 60, 'I nooped 2h') with self.assertRaises(SystemExit) as fail_run: with mock.patch('sys.stdout', new=StringIO()): self.library.run([]) self.assertEqual(fail_run.exception.code, 0) # We don't test the stdout result here because of isatty and py2. # We could extend this once we're pure py3 def test_run_disable_lock_tty(self): ''' Test that "run" does nothing when I have a lock, and tells me. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'disable', now + 30 * 60, 'It is my lock') with self.assertRaises(SystemExit) as fail_run: # Order matters here: isatty comes second since we are touching stdout twice. with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch('sys.stdout.isatty', return_value=True): self.library.run([]) self.assertEqual(fail_run.exception.code, 0) self.assertIn('Puppet has been disabled', fake_out.getvalue()) def test_run_disable_lock_notty(self): ''' Test that "run" does nothing when I have a lock, and is silent ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'disable', now + 30 * 60, 'It is my lock') with self.assertRaises(SystemExit) as fail_run: # Order matters here: isatty comes second since we are touching stdout twice. with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch('sys.stdout.isatty', return_value=False): self.library.run([]) self.assertEqual(fail_run.exception.code, 0) self.assertIn('Puppet has been disabled', fake_out.getvalue()) def test_run_noop_lock(self): ''' Test that "run" fires noop mode I have a noop lock. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'nooperate', now + 30 * 60, 'It is my lock') with mock.patch('os.execvpe') as mock_exec: self.library.run([]) my_env = os.environ my_env['PATH'] = self.library.puppet_bin_path mock_exec.assert_called_once_with('puppet', [ 'puppet', 'agent', '--verbose', '--onetime', '--no-daemonize', '--no-splay', '--noop' ], env=my_env)
class TestExecutionNooperate(unittest.TestCase): ''' Class of tests about executing puppetctl nooperate commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-nooperate-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user) def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # pragma: no cover # we likely never created the file. pass def test_permissions_block_noop(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False): with self.assertRaises(SystemExit) as fail_nooperate, \ mock.patch('sys.stdout', new=StringIO()): oneoff.nooperate(False, int(time.time() + 60), 'failure testing') self.assertEqual(fail_nooperate.exception.code, 2) def test_noop_nolocks(self): ''' Test that "nooperate" noops when there are no locks. ''' with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', return_value={}), \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='') self.assertIn('Puppet is in nooperate mode', fake_out.getvalue()) def test_noop_nolocks_puppetrun(self): ''' Test that "nooperate" noops when there are no locks but puppet is running ''' with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_puppet_processes_running', return_value={'2468': 'mock-puppet agent --no-splay'}), \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='') self.assertIn('mock-puppet agent --no-splay', fake_out.getvalue()) self.assertIn( 'If you need to stop an active puppet run from finishing', fake_out.getvalue()) self.assertIn('Puppet is in nooperate mode', fake_out.getvalue()) def test_noop_not_our_locks(self): ''' Test that "nooperate" noops when we have no locks, but others do. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock('somebody2', 'disable', now + 30 * 60, 'I disabled 1h') self.library.statefile_object.add_lock('somebody3', 'nooperate', now + 90 * 60, 'I nooped 2h') with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='') self.assertIn('Puppet is in nooperate mode', fake_out.getvalue()) def test_noop_disable_mylock(self): ''' Test that "nooperate" refuses to noop when I have a disable. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'disable', now + 30 * 60, 'It is my lock') with self.assertRaises(SystemExit) as catch_noforce, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='') self.assertIn('must be enabled to enter nooperate mode', fake_out.getvalue()) self.assertEqual(catch_noforce.exception.code, 2) def test_noop_force_mylock(self): ''' Test that "nooperate" noops when I force a lock. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'nooperate', now + 30 * 60, 'old lock') with mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=True, expiry=int(time.time()) + 60 * 60, message='new lock') self.assertIn('Puppet is in nooperate mode', fake_out.getvalue()) self.assertIn('new lock', fake_out.getvalue()) def test_noop_noop_mylock(self): ''' Test that "nooperate" doesn't act when there's a noop lock. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'nooperate', now + 30 * 60, 'old lock') with self.assertRaises(SystemExit) as catch_noforce, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='new lock') self.assertIn('Puppet is already in nooperate mode', fake_out.getvalue()) self.assertEqual(catch_noforce.exception.code, 1) def test_noop_fail_add_lock(self): ''' Test that "nooperate" complains if it can't add a lock ''' with mock.patch.object(PuppetctlStatefile, 'add_lock', return_value=False), \ self.assertRaises(SystemExit) as lockfail, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=False, expiry=int(time.time()) + 60 * 60, message='lock') self.assertEqual(lockfail.exception.code, 2) self.assertIn('Unable to add lock', fake_out.getvalue()) def test_noop_failremovenoop(self): ''' Test that "nooperate" complains if it can't override noop locks. ''' now = int(time.time()) with mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): self.library.statefile_object.add_lock(self.library.invoking_user, 'nooperate', now + 30 * 60, 'It is my lock') with mock.patch.object(PuppetctlStatefile, 'remove_lock', return_value=False), \ self.assertRaises(SystemExit) as lockfail, \ mock.patch('sys.stdout', new=StringIO()) as fake_out, \ mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True): self.library.nooperate(force=True, expiry=int(time.time()) + 60 * 60, message='new lock') self.assertIn('Unable to remove', fake_out.getvalue()) self.assertEqual(lockfail.exception.code, 2)
def test_init_statefile_kwarg(self): ''' Verify the object was initialized with a state file, kwarg arg ''' library = PuppetctlExecution(state_file=self.test_statefile) self.assertEqual(library.statefile_object.state_file, self.test_statefile)
def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-nooperate-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user)
class TestExecutionBreakAllLocks(unittest.TestCase): ''' Class of tests about executing puppetctl break_all_locks commands. ''' def setUp(self): ''' Preparing test rig ''' self.test_statefile = '/tmp/exec-break_all_locks-statefile-mods.test.txt' self.library = PuppetctlExecution(self.test_statefile) self.library.logging_tag = 'testingpuppetctl[{}]'.format( self.library.invoking_user) def tearDown(self): ''' Cleanup test rig ''' try: os.remove(self.test_statefile) except OSError: # pragma: no cover # we likely never created the file. pass def test_nothing_to_do(self): ''' Test that we do nothing if there aren't locks to break. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_operating', return_value=True), \ self.assertRaises(SystemExit) as fail_break, \ mock.patch('sys.stdout', new=StringIO()) as fake_out: oneoff.break_all_locks(2) self.assertIn('There are no locks', fake_out.getvalue()) self.assertEqual(fail_break.exception.code, 0) def test_perms_block_break(self): ''' Test that non-root can't run the important functions. ''' oneoff = PuppetctlExecution(self.test_statefile) with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=False), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=False), \ self.assertRaises(SystemExit) as fail_break, \ mock.patch('sys.stdout', new=StringIO()): oneoff.break_all_locks(2) self.assertEqual(fail_break.exception.code, 2) def test_break_bad_parameters(self): ''' Test that 'break_all_locks' fails if double-force isn't applied. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=False): with self.assertRaises(SystemExit) as fail_break_weak_force0, \ mock.patch('sys.stdout', new=StringIO()): self.library.break_all_locks(0) self.assertEqual(fail_break_weak_force0.exception.code, 2) with self.assertRaises(SystemExit) as fail_break_weak_force1, \ mock.patch('sys.stdout', new=StringIO()): self.library.break_all_locks(1) self.assertEqual(fail_break_weak_force1.exception.code, 2) with self.assertRaises(SystemExit) as fail_break_weirdparam, \ mock.patch('sys.stdout', new=StringIO()): self.library.break_all_locks(True) self.assertEqual(fail_break_weirdparam.exception.code, 2) def test_break_good_no_write(self): ''' Test that 'break_all_locks' fails if somehow we can't write the file. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=False), \ mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=False): with self.assertRaises(SystemExit) as fail_break_writing, \ mock.patch('time.sleep'), \ mock.patch('sys.stdout', new=StringIO()): self.library.break_all_locks(2) self.assertEqual(fail_break_writing.exception.code, 2) def test_break_good(self): ''' Test that 'break_all_locks' can work. ''' with mock.patch.object(PuppetctlExecution, '_allowed_to_run_command', return_value=True), \ mock.patch.object(PuppetctlExecution, 'is_enabled', return_value=False), \ mock.patch.object(PuppetctlStatefile, '_allowed_to_write_statefile', return_value=True): # make sure there's a file there, or our reset count will be > 1 # below during the actual test. self.library.statefile_object.reset_state_file() # "Hey, you're not testing with locks!" Yeah. Since we're stomping all # locks it doesn't really matter what was in it before. with mock.patch.object(PuppetctlStatefile, 'reset_state_file') as mock_reset, \ mock.patch('time.sleep'), \ mock.patch('sys.stdout', new=StringIO()): self.library.break_all_locks(2) mock_reset.assert_called_once_with()