def test_handle_decoded_payload_jid_queue_addition(self): ''' Tests that the _handle_decoded_payload function adds a jid to the minion's jid_queue when the new jid isn't already present in the jid_queue. ''' mock_jid = 11111 mock_opts = {'cachedir': '', 'extension_modules': '', 'minion_jid_queue_hwm': 100} mock_data = {'fun': 'foo.bar', 'jid': mock_jid} mock_jid_queue = [123, 456] try: minion = salt.minion.Minion(mock_opts, jid_queue=copy.copy(mock_jid_queue), io_loop=tornado.ioloop.IOLoop()) # Assert that the minion's jid_queue attribute matches the mock_jid_queue as a baseline # This can help debug any test failures if the _handle_decoded_payload call fails. self.assertEqual(minion.jid_queue, mock_jid_queue) # Call the _handle_decoded_payload function and update the mock_jid_queue to include the new # mock_jid. The mock_jid should have been added to the jid_queue since the mock_jid wasn't # previously included. The minion's jid_queue attribute and the mock_jid_queue should be equal. minion._handle_decoded_payload(mock_data) mock_jid_queue.append(mock_jid) self.assertEqual(minion.jid_queue, mock_jid_queue) finally: minion.destroy()
def test_handle_decoded_payload_jid_queue_reduced_minion_jid_queue_hwm(self): ''' Tests that the _handle_decoded_payload function removes a jid from the minion's jid_queue when the minion's jid_queue high water mark (minion_jid_queue_hwm) is hit. ''' mock_opts = {'cachedir': '', 'extension_modules': '', 'minion_jid_queue_hwm': 2} mock_data = {'fun': 'foo.bar', 'jid': 789} mock_jid_queue = [123, 456] try: minion = salt.minion.Minion(mock_opts, jid_queue=copy.copy(mock_jid_queue), io_loop=tornado.ioloop.IOLoop()) # Assert that the minion's jid_queue attribute matches the mock_jid_queue as a baseline # This can help debug any test failures if the _handle_decoded_payload call fails. self.assertEqual(minion.jid_queue, mock_jid_queue) # Call the _handle_decoded_payload function and check that the queue is smaller by one item # and contains the new jid minion._handle_decoded_payload(mock_data) self.assertEqual(len(minion.jid_queue), 2) self.assertEqual(minion.jid_queue, [456, 789]) finally: minion.destroy()
def test_handle_decoded_payload_jid_match_in_jid_queue(self): ''' Tests that the _handle_decoded_payload function returns when a jid is given that is already present in the jid_queue. Note: This test doesn't contain all of the patch decorators above the function like the other tests for _handle_decoded_payload below. This is essential to this test as the call to the function must return None BEFORE any of the processes are spun up because we should be avoiding firing duplicate jobs. ''' mock_opts = {'cachedir': '', 'extension_modules': ''} mock_data = {'fun': 'foo.bar', 'jid': 123} mock_jid_queue = [123] try: minion = salt.minion.Minion(mock_opts, jid_queue=copy.copy(mock_jid_queue), io_loop=tornado.ioloop.IOLoop()) ret = minion._handle_decoded_payload(mock_data) self.assertEqual(minion.jid_queue, mock_jid_queue) self.assertIsNone(ret) finally: minion.destroy()
def test_handle_decoded_payload_jid_match_in_jid_queue(): """ Tests that the _handle_decoded_payload function returns when a jid is given that is already present in the jid_queue. Note: This test doesn't contain all of the patch decorators above the function like the other tests for _handle_decoded_payload below. This is essential to this test as the call to the function must return None BEFORE any of the processes are spun up because we should be avoiding firing duplicate jobs. """ mock_opts = salt.config.DEFAULT_MINION_OPTS.copy() mock_data = {"fun": "foo.bar", "jid": 123} mock_jid_queue = [123] minion = salt.minion.Minion( mock_opts, jid_queue=copy.copy(mock_jid_queue), io_loop=salt.ext.tornado.ioloop.IOLoop(), ) try: ret = minion._handle_decoded_payload(mock_data).result() assert minion.jid_queue == mock_jid_queue assert ret is None finally: minion.destroy()
def test_reinit_crypto_on_fork(def_mock): """ Ensure salt.utils.crypt.reinit_crypto() is executed when forking for new job """ mock_opts = salt.config.DEFAULT_MINION_OPTS.copy() mock_opts["multiprocessing"] = True io_loop = salt.ext.tornado.ioloop.IOLoop() io_loop.make_current() minion = salt.minion.Minion(mock_opts, io_loop=io_loop) job_data = {"jid": "test-jid", "fun": "test.ping"} def mock_start(self): # pylint: disable=comparison-with-callable assert (len([ x for x in self._after_fork_methods if x[0] == salt.utils.crypt.reinit_crypto ]) == 1) # pylint: enable=comparison-with-callable with patch.object(salt.utils.process.SignalHandlingProcess, "start", mock_start): io_loop.run_sync(lambda: minion._handle_decoded_payload(job_data))
def test_process_count_max(self): """ Tests that the _handle_decoded_payload function does not spawn more than the configured amount of processes, as per process_count_max. """ with patch("salt.minion.Minion.ctx", MagicMock(return_value={})), patch( "salt.utils.process.SignalHandlingProcess.start", MagicMock(return_value=True), ), patch( "salt.utils.process.SignalHandlingProcess.join", MagicMock(return_value=True), ), patch( "salt.utils.minion.running", MagicMock(return_value=[]) ), patch( "salt.ext.tornado.gen.sleep", MagicMock(return_value=salt.ext.tornado.concurrent.Future()), ): process_count_max = 10 mock_opts = salt.config.DEFAULT_MINION_OPTS.copy() mock_opts["__role"] = "minion" mock_opts["minion_jid_queue_hwm"] = 100 mock_opts["process_count_max"] = process_count_max io_loop = salt.ext.tornado.ioloop.IOLoop() minion = salt.minion.Minion(mock_opts, jid_queue=[], io_loop=io_loop) try: # mock gen.sleep to throw a special Exception when called, so that we detect it class SleepCalledException(Exception): """Thrown when sleep is called""" salt.ext.tornado.gen.sleep.return_value.set_exception( SleepCalledException() ) # up until process_count_max: gen.sleep does not get called, processes are started normally for i in range(process_count_max): mock_data = {"fun": "foo.bar", "jid": i} io_loop.run_sync( lambda data=mock_data: minion._handle_decoded_payload(data) ) self.assertEqual( salt.utils.process.SignalHandlingProcess.start.call_count, i + 1 ) self.assertEqual(len(minion.jid_queue), i + 1) salt.utils.minion.running.return_value += [i] # above process_count_max: gen.sleep does get called, JIDs are created but no new processes are started mock_data = {"fun": "foo.bar", "jid": process_count_max + 1} self.assertRaises( SleepCalledException, lambda: io_loop.run_sync( lambda: minion._handle_decoded_payload(mock_data) ), ) self.assertEqual( salt.utils.process.SignalHandlingProcess.start.call_count, process_count_max, ) self.assertEqual(len(minion.jid_queue), process_count_max + 1) finally: minion.destroy()