123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- #!/usr/bin/env python
- '''
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- '''
- import pprint
- from unittest import TestCase
- import threading
- import tempfile
- import time
- from threading import Thread
- from PythonExecutor import PythonExecutor
- from AmbariConfig import AmbariConfig
- from mock.mock import MagicMock, patch
- class TestPythonExecutor(TestCase):
- @patch("shell.kill_process_with_children")
- def test_watchdog_1(self, kill_process_with_children_mock):
- """
- Tests whether watchdog works
- """
- subproc_mock = self.Subprocess_mockup()
- executor = PythonExecutor("/tmp", AmbariConfig().getConfig())
- _, tmpoutfile = tempfile.mkstemp()
- _, tmperrfile = tempfile.mkstemp()
- _, tmpstrucout = tempfile.mkstemp()
- PYTHON_TIMEOUT_SECONDS = 0.1
- kill_process_with_children_mock.side_effect = lambda pid : subproc_mock.terminate()
- def launch_python_subprocess_method(command, tmpout, tmperr):
- subproc_mock.tmpout = tmpout
- subproc_mock.tmperr = tmperr
- return subproc_mock
- executor.launch_python_subprocess = launch_python_subprocess_method
- runShellKillPgrp_method = MagicMock()
- runShellKillPgrp_method.side_effect = lambda python : python.terminate()
- executor.runShellKillPgrp = runShellKillPgrp_method
- subproc_mock.returncode = None
- thread = Thread(target = executor.run_file, args = ("fake_puppetFile",
- ["arg1", "arg2"], tmpoutfile, tmperrfile, PYTHON_TIMEOUT_SECONDS, tmpstrucout))
- thread.start()
- time.sleep(0.1)
- subproc_mock.finished_event.wait()
- self.assertEquals(subproc_mock.was_terminated, True, "Subprocess should be terminated due to timeout")
- def test_watchdog_2(self):
- """
- Tries to catch false positive watchdog invocations
- """
- subproc_mock = self.Subprocess_mockup()
- executor = PythonExecutor("/tmp", AmbariConfig().getConfig())
- _, tmpoutfile = tempfile.mkstemp()
- _, tmperrfile = tempfile.mkstemp()
- _, tmpstrucout = tempfile.mkstemp()
- PYTHON_TIMEOUT_SECONDS = 5
- def launch_python_subprocess_method(command, tmpout, tmperr):
- subproc_mock.tmpout = tmpout
- subproc_mock.tmperr = tmperr
- return subproc_mock
- executor.launch_python_subprocess = launch_python_subprocess_method
- runShellKillPgrp_method = MagicMock()
- runShellKillPgrp_method.side_effect = lambda python : python.terminate()
- executor.runShellKillPgrp = runShellKillPgrp_method
- subproc_mock.returncode = 0
- thread = Thread(target = executor.run_file, args = ("fake_puppetFile", ["arg1", "arg2"],
- tmpoutfile, tmperrfile,
- PYTHON_TIMEOUT_SECONDS, tmpstrucout))
- thread.start()
- time.sleep(0.1)
- subproc_mock.should_finish_event.set()
- subproc_mock.finished_event.wait()
- self.assertEquals(subproc_mock.was_terminated, False, "Subprocess should not be terminated before timeout")
- self.assertEquals(subproc_mock.returncode, 0, "Subprocess should not be terminated before timeout")
- def test_execution_results(self):
- subproc_mock = self.Subprocess_mockup()
- executor = PythonExecutor("/tmp", AmbariConfig().getConfig())
- _, tmpoutfile = tempfile.mkstemp()
- _, tmperrfile = tempfile.mkstemp()
- _, tmpstroutfile = tempfile.mkstemp()
- PYTHON_TIMEOUT_SECONDS = 5
- def launch_python_subprocess_method(command, tmpout, tmperr):
- subproc_mock.tmpout = tmpout
- subproc_mock.tmperr = tmperr
- return subproc_mock
- executor.launch_python_subprocess = launch_python_subprocess_method
- runShellKillPgrp_method = MagicMock()
- runShellKillPgrp_method.side_effect = lambda python : python.terminate()
- executor.runShellKillPgrp = runShellKillPgrp_method
- subproc_mock.returncode = 0
- subproc_mock.should_finish_event.set()
- result = executor.run_file("file", ["arg1", "arg2"], tmpoutfile, tmperrfile, PYTHON_TIMEOUT_SECONDS, tmpstroutfile)
- self.assertEquals(result, {'exitcode': 0, 'stderr': 'Dummy err', 'stdout': 'Dummy output',
- 'structuredOut': {'msg': 'Unable to read structured output from ' + tmpstroutfile}})
- def test_is_successfull(self):
- executor = PythonExecutor("/tmp", AmbariConfig().getConfig())
- executor.python_process_has_been_killed = False
- self.assertTrue(executor.isSuccessfull(0))
- self.assertFalse(executor.isSuccessfull(1))
- executor.python_process_has_been_killed = True
- self.assertFalse(executor.isSuccessfull(0))
- self.assertFalse(executor.isSuccessfull(1))
- def test_python_command(self):
- executor = PythonExecutor("/tmp", AmbariConfig().getConfig())
- command = executor.python_command("script", ["script_param1"])
- self.assertEqual(3, len(command))
- self.assertTrue("python" in command[0])
- self.assertEquals("script", command[1])
- self.assertEquals("script_param1", command[2])
- pprint.pprint(command)
- class Subprocess_mockup():
- """
- It's not trivial to use PyMock instead of class here because we need state
- and complex logics
- """
- returncode = 0
- started_event = threading.Event()
- should_finish_event = threading.Event()
- finished_event = threading.Event()
- was_terminated = False
- tmpout = None
- tmperr = None
- pid=-1
- def communicate(self):
- self.started_event.set()
- self.tmpout.write("Dummy output")
- self.tmpout.flush()
- self.tmperr.write("Dummy err")
- self.tmperr.flush()
- self.should_finish_event.wait()
- self.finished_event.set()
- pass
- def terminate(self):
- self.was_terminated = True
- self.returncode = 17
- self.should_finish_event.set()
|