def test_chef_poking(self, mocker):
        """
        Test interval-based chef poking.
        """
        test_interval = 3
        kitchen = DumplingKitchen(
            dumpling_queue=mocker.Mock(),
            chef_poke_interval=test_interval,
        )
        mocker.patch.object(kitchen, '_put_dumpling_on_queue')

        # _poke_chefs() runs in an infinite loop which we need to break out of.
        # We do that by setting a side effect on the mocked call to sleep()
        # which will raise a RuntimeError. This doesn't interfere with being
        # able to determine the value passed to sleep().
        mock_sleep = mocker.patch(
            'netdumplings.dumplingkitchen.sleep', side_effect=RuntimeError
        )

        # Set up two valid chefs. One of them returns a dumpling when poked and
        # and the other one doesn't.
        mock_chef_with_interval_dumpling = mocker.Mock()
        mock_chef_with_no_interval_dumpling = mocker.Mock()

        dumpling_interval_handler = (
            mock_chef_with_interval_dumpling.interval_handler
        )
        no_dumpling_interval_handler = (
            mock_chef_with_no_interval_dumpling.interval_handler
        )

        dumpling_interval_handler.return_value = 'dumpling'
        no_dumpling_interval_handler.return_value = None

        kitchen._chefs = [
            mock_chef_with_interval_dumpling,
            mock_chef_with_no_interval_dumpling,
        ]

        # Run once through the poker infinite loop.
        with pytest.raises(RuntimeError):
            kitchen._poke_chefs(test_interval)

        # Check that we were asked to sleep by the test interval.
        mock_sleep.assert_called_once_with(test_interval)

        # Check that the two interval handlers were invoked, and that the one
        # that returned a dumpling resulted in that dumpling being sent.
        dumpling_interval_handler.assert_called_once_with(
            interval=test_interval
        )
        no_dumpling_interval_handler.assert_called_once_with(
            interval=test_interval
        )

        kitchen._put_dumpling_on_queue.assert_called_once_with(
            mock_chef_with_interval_dumpling,
            'dumpling',
            DumplingDriver.interval,
        )
    def test_chef_poking(self, mocker):
        """
        Test interval-based chef poking.
        """
        test_interval = 3
        kitchen = DumplingKitchen(
            dumpling_queue=mocker.Mock(),
            chef_poke_interval=test_interval,
        )
        mocker.patch.object(kitchen, '_put_dumpling_on_queue')

        # _poke_chefs() runs in an infinite loop which we need to break out of.
        # We do that by setting a side effect on the mocked call to sleep()
        # which will raise a RuntimeError. This doesn't interfere with being
        # able to determine the value passed to sleep().
        mock_sleep = mocker.patch('netdumplings.dumplingkitchen.sleep',
                                  side_effect=RuntimeError)

        # Set up two valid chefs. One of them returns a dumpling when poked and
        # and the other one doesn't.
        mock_chef_with_interval_dumpling = mocker.Mock()
        mock_chef_with_no_interval_dumpling = mocker.Mock()

        dumpling_interval_handler = (
            mock_chef_with_interval_dumpling.interval_handler)
        no_dumpling_interval_handler = (
            mock_chef_with_no_interval_dumpling.interval_handler)

        dumpling_interval_handler.return_value = 'dumpling'
        no_dumpling_interval_handler.return_value = None

        kitchen._chefs = [
            mock_chef_with_interval_dumpling,
            mock_chef_with_no_interval_dumpling,
        ]

        # Run once through the poker infinite loop.
        with pytest.raises(RuntimeError):
            kitchen._poke_chefs(test_interval)

        # Check that we were asked to sleep by the test interval.
        mock_sleep.assert_called_once_with(test_interval)

        # Check that the two interval handlers were invoked, and that the one
        # that returned a dumpling resulted in that dumpling being sent.
        dumpling_interval_handler.assert_called_once_with(
            interval=test_interval)
        no_dumpling_interval_handler.assert_called_once_with(
            interval=test_interval)

        kitchen._put_dumpling_on_queue.assert_called_once_with(
            mock_chef_with_interval_dumpling,
            'dumpling',
            DumplingDriver.interval,
        )
    def test_chef_poking_with_broken_handler(self, mocker):
        """
        Test interval-based chef poking where one of the handlers raises an
        exception, which should result in an exception-level log entry being
        created but the processing being otherwise unaffected.
        """
        test_interval = 3
        kitchen = DumplingKitchen(
            dumpling_queue=mocker.Mock(),
            chef_poke_interval=test_interval,
        )
        mocker.patch.object(kitchen, '_put_dumpling_on_queue')
        mocker.patch.object(kitchen, '_logger')

        mocker.patch(
            'netdumplings.dumplingkitchen.sleep', side_effect=RuntimeError
        )

        # Set up one valid chefs which returns an interval dumpling, and one
        # chef which raises an exception in its interval handler.
        # and the other one doesn't.
        mock_chef_with_interval_dumpling = mocker.Mock()
        mock_chef_with_interval_error = mocker.Mock()

        dumpling_interval_handler = (
            mock_chef_with_interval_dumpling.interval_handler
        )
        error_interval_handler = (
            mock_chef_with_interval_error.interval_handler
        )

        dumpling_interval_handler.return_value = 'dumpling'
        error_interval_handler.side_effect = KeyError

        kitchen._chefs = [
            mock_chef_with_interval_dumpling,
            mock_chef_with_interval_error,
        ]

        # Run once through the poker infinite loop.
        with pytest.raises(RuntimeError):
            kitchen._poke_chefs(test_interval)

        # Check that the valid dumpling was sent, and that we logged an
        # exception for the other chef.
        kitchen._put_dumpling_on_queue.assert_called_once_with(
            mock_chef_with_interval_dumpling,
            'dumpling',
            DumplingDriver.interval,
        )
        kitchen._logger.exception.assert_called_once()
    def test_chef_poking_with_broken_handler(self, mocker):
        """
        Test interval-based chef poking where one of the handlers raises an
        exception, which should result in an exception-level log entry being
        created but the processing being otherwise unaffected.
        """
        test_interval = 3
        kitchen = DumplingKitchen(
            dumpling_queue=mocker.Mock(),
            chef_poke_interval=test_interval,
        )
        mocker.patch.object(kitchen, '_put_dumpling_on_queue')
        mocker.patch.object(kitchen, '_logger')

        mocker.patch('netdumplings.dumplingkitchen.sleep',
                     side_effect=RuntimeError)

        # Set up one valid chefs which returns an interval dumpling, and one
        # chef which raises an exception in its interval handler.
        # and the other one doesn't.
        mock_chef_with_interval_dumpling = mocker.Mock()
        mock_chef_with_interval_error = mocker.Mock()

        dumpling_interval_handler = (
            mock_chef_with_interval_dumpling.interval_handler)
        error_interval_handler = (
            mock_chef_with_interval_error.interval_handler)

        dumpling_interval_handler.return_value = 'dumpling'
        error_interval_handler.side_effect = KeyError

        kitchen._chefs = [
            mock_chef_with_interval_dumpling,
            mock_chef_with_interval_error,
        ]

        # Run once through the poker infinite loop.
        with pytest.raises(RuntimeError):
            kitchen._poke_chefs(test_interval)

        # Check that the valid dumpling was sent, and that we logged an
        # exception for the other chef.
        kitchen._put_dumpling_on_queue.assert_called_once_with(
            mock_chef_with_interval_dumpling,
            'dumpling',
            DumplingDriver.interval,
        )
        kitchen._logger.exception.assert_called_once()