def test_file_watcher_argument_some_values_with_forking(
            self, mock_get_reloader):
        server_getter = mock.MagicMock()

        sys.argv = [
            '/path/to/example_service/standalone.py', '--use-file-watcher',
            'pysoa', '-f', '5'
        ]

        standalone.simple_main(server_getter)  # type: ignore

        server_getter.assert_called_once_with()
        self.assertFalse(server_getter.return_value.main.called)

        assert mock_get_reloader.call_count == 1
        assert mock_get_reloader.call_args_list[0][0][0] in ('', 'pytest',
                                                             'coverage')
        assert mock_get_reloader.call_args_list[0][0][1] == ['pysoa']
        assert mock_get_reloader.call_args_list[0][1]['signal_forks'] is True

        self.assertEqual(1, mock_get_reloader.return_value.main.call_count)
        self.assertEqual(
            5, mock_get_reloader.return_value.main.call_args_list[0][0][1]
            [0].fork_processes)
        self.assertEqual(
            server_getter.return_value,
            mock_get_reloader.return_value.main.call_args_list[0][0][1][1],
        )
Example #2
0
    def test_no_arguments(self):
        server_getter = mock.MagicMock()

        sys.argv = ['/path/to/example_service/standalone.py']

        standalone.simple_main(server_getter)

        server_getter.assert_called_once_with()
        server_getter.return_value.main.assert_called_once_with()
Example #3
0
    def test_only_forking_limited(self, mock_cpu_count, mock_process):
        server_getter = mock.MagicMock()

        mock_cpu_count.return_value = 1

        sys.argv = ['/path/to/example_service/standalone.py', '-f', '10']

        prev_sigint = prev_sigterm = prev_sighup = False
        try:
            prev_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN)
            prev_sigterm = signal.signal(signal.SIGTERM, signal.SIG_IGN)
            prev_sighup = signal.signal(signal.SIGHUP, signal.SIG_IGN)

            processes = [mock.MagicMock() for _ in range(0, 5)]
            mock_process.side_effect = processes

            standalone.simple_main(server_getter)

            server_getter.assert_called_once_with()
            self.assertFalse(server_getter.return_value.main.called)

            self.assertEqual(5, mock_process.call_count)
            i = 0
            for i, call in enumerate(mock_process.call_args_list):
                self.assertEqual(server_getter.return_value.main,
                                 call[1]['target'])
                self.assertEqual('pysoa-worker-{}'.format(i), call[1]['name'])
                i += 1
            self.assertEqual(5, i)

            for i, process in enumerate(processes):
                self.assertTrue(process.start.called,
                                'Process {} was not started'.format(i))
                self.assertTrue(process.join.called,
                                'Process {} was not joined'.format(i))
                self.assertFalse(
                    process.terminate.called,
                    'Process {} should not have been terminated'.format(i))

            os.kill(os.getpid(), signal.SIGHUP)

            for i, process in enumerate(processes):
                self.assertTrue(process.terminate.called,
                                'Process {} was terminated'.format(i))
        finally:
            if prev_sigint is not False:
                signal.signal(signal.SIGINT, prev_sigint or signal.SIG_IGN)
            if prev_sigterm is not False:
                signal.signal(signal.SIGTERM, prev_sigterm or signal.SIG_IGN)
            if prev_sighup is not False:
                signal.signal(signal.SIGHUP, prev_sighup or signal.SIG_IGN)
    def test_only_forking_not_limited(self, mock_cpu_count, mock_process):
        server_getter = mock.MagicMock()

        mock_cpu_count.return_value = 2

        sys.argv = [
            '/path/to/example_service/standalone.py', '-f', '10',
            '--no-respawn'
        ]

        prev_sigint = prev_sigterm = prev_sighup = None
        try:
            prev_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN)
            prev_sigterm = signal.signal(signal.SIGTERM, signal.SIG_IGN)
            prev_sighup = signal.signal(signal.SIGHUP, signal.SIG_IGN)

            processes = [mock.MagicMock() for _ in range(0, 10)]
            mock_process.side_effect = processes

            standalone.simple_main(server_getter)  # type: ignore

            server_getter.assert_called_once_with()
            self.assertFalse(server_getter.return_value.main.called)

            self.assertEqual(10, mock_process.call_count)
            i = 1
            for call in mock_process.call_args_list:
                self.assertEqual(server_getter.return_value.main,
                                 call[1]['target'])
                self.assertEqual('pysoa-worker-{}'.format(i), call[1]['name'])
                self.assertEqual((i, ), call[1]['args'])
                i += 1

            for i, process in enumerate(processes):
                self.assertTrue(process.start.called,
                                'Process {} was not started'.format(i))
                self.assertTrue(process.join.called,
                                'Process {} was not joined'.format(i))
                self.assertFalse(
                    process.terminate.called,
                    'Process {} should not have been terminated'.format(i))

            for i, process in enumerate(processes):
                assert process.terminate.called is False
        finally:
            if prev_sigint is not None:
                signal.signal(signal.SIGINT, prev_sigint or signal.SIG_IGN)
            if prev_sigterm is not None:
                signal.signal(signal.SIGTERM, prev_sigterm or signal.SIG_IGN)
            if prev_sighup is not None:
                signal.signal(signal.SIGHUP, prev_sighup or signal.SIG_IGN)
Example #5
0
    def test_only_file_watcher_argument_no_values(self, mock_get_reloader):
        server_getter = mock.MagicMock()

        sys.argv = [
            '/path/to/example_service/standalone.py', '--use-file-watcher'
        ]

        standalone.simple_main(server_getter)

        server_getter.assert_called_once_with()
        self.assertFalse(server_getter.return_value.main.called)

        mock_get_reloader.assert_called_once_with('', None, signal_forks=False)
        self.assertEqual(1, mock_get_reloader.return_value.main.call_count)
        self.assertEqual(
            server_getter.return_value,
            mock_get_reloader.return_value.main.call_args_list[0][0][1][1],
        )
Example #6
0
    def test_only_file_watcher_argument_some_values(self, mock_get_reloader):
        server_getter = mock.MagicMock()

        sys.argv = [
            '/path/to/example_service/standalone.py', '--use-file-watcher',
            'example,pysoa,conformity'
        ]

        standalone.simple_main(server_getter)

        server_getter.assert_called_once_with()
        self.assertFalse(server_getter.return_value.main.called)

        mock_get_reloader.assert_called_once_with(
            '', ['example', 'pysoa', 'conformity'], signal_forks=False)
        self.assertEqual(1, mock_get_reloader.return_value.main.call_count)
        self.assertEqual(
            0, mock_get_reloader.return_value.main.call_args_list[0][0][1]
            [0].fork_processes)
        self.assertEqual(
            server_getter.return_value,
            mock_get_reloader.return_value.main.call_args_list[0][0][1][1],
        )
    def test_only_file_watcher_argument_no_values(self, mock_get_reloader):
        server_getter = mock.MagicMock()

        sys.argv = [
            '/path/to/example_service/standalone.py', '--use-file-watcher'
        ]

        standalone.simple_main(server_getter)  # type: ignore

        server_getter.assert_called_once_with()
        self.assertFalse(server_getter.return_value.main.called)

        assert mock_get_reloader.call_count == 1
        assert mock_get_reloader.call_args_list[0][0][0] in ('', 'pytest',
                                                             'coverage')
        assert mock_get_reloader.call_args_list[0][0][1] is None
        assert mock_get_reloader.call_args_list[0][1]['signal_forks'] is False

        self.assertEqual(1, mock_get_reloader.return_value.main.call_count)
        self.assertEqual(
            server_getter.return_value,
            mock_get_reloader.return_value.main.call_args_list[0][0][1][1],
        )
def main():
    from example_service.server import Server
    simple_main(lambda: Server)
    def test_forking_with_default_respawn(self, mock_cpu_count, mock_process):
        server_getter = mock.MagicMock()

        mock_cpu_count.return_value = 2

        sys.argv = ['/path/to/example_service/standalone.py', '-f', '3']

        prev_sigint = prev_sigterm = prev_sighup = None
        try:
            prev_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN)
            prev_sigterm = signal.signal(signal.SIGTERM, signal.SIG_IGN)
            prev_sighup = signal.signal(signal.SIGHUP, signal.SIG_IGN)

            living_processes = []
            quick_dying_processes = []
            slow_dying_processes = []
            bad_processes = []

            def patched_freeze_time():
                # TODO Until https://github.com/spulec/freezegun/issues/307 is fixed
                f = freezegun.freeze_time()
                f.ignore = tuple(set(f.ignore) - {'threading'})
                return f

            with patched_freeze_time() as frozen_time:

                def tick_six_se():
                    frozen_time.tick(datetime.timedelta(seconds=6))

                def tick_twenty_se():
                    frozen_time.tick(datetime.timedelta(seconds=20))

                def signal_se():
                    os.kill(os.getpid(), signal.SIGTERM)
                    time.sleep(0.3)

                def se(target, name, args):
                    process = mock.MagicMock()
                    process.culprit = (target, name, args)
                    if args[0] == 1:
                        # If it's the first process, we want to actually live. This tests normal operation.
                        living_processes.append(process)
                        if len(living_processes) == 6:
                            raise ValueError('Too many, too many!')
                        elif len(living_processes) == 5:
                            process.join.side_effect = signal_se
                        else:
                            process.join.side_effect = tick_twenty_se
                        if len(living_processes) == 1:
                            time.sleep(
                                3
                            )  # sleep 3 seconds so that all of these happen after quick- and slow-dying
                    elif args[0] == 2:
                        # If it's the second process, we want to die quickly. This tests the 15-second respawn limit.
                        quick_dying_processes.append(process)
                        # no sleep so that all of these happen before any ticks, before slow-dying and living
                    elif args[0] == 3:
                        # If it's the third process, we want to die slowly. This tests the 60-second respawn limit.
                        slow_dying_processes.append(process)
                        process.join.side_effect = tick_six_se
                        if len(slow_dying_processes) == 1:
                            time.sleep(
                                1
                            )  # sleep 1 second so that all of these happen after quick-dying
                    else:
                        bad_processes.append((target, name, args))
                        raise ValueError('Nope nope nope')
                    return process

                mock_process.side_effect = se

                standalone.simple_main(server_getter)  # type: ignore

            server_getter.assert_called_once_with()
            assert server_getter.return_value.main.called is False

            assert len(bad_processes) == 0
            assert len(quick_dying_processes) == 4
            assert len(slow_dying_processes) == 9
            assert len(living_processes) == 5

            for i, p in enumerate(living_processes):
                assert p.culprit[0] is server_getter.return_value.main
                assert p.culprit[1] == 'pysoa-worker-1'
                assert p.culprit[2] == (1, )
                if i < 5:
                    p.start.assert_called_once_with()
                    p.join.assert_called_once_with()
            for p in living_processes[:-1]:
                assert p.terminate.called is False
            living_processes[-1].terminate.assert_called_once_with()

            for p in quick_dying_processes:
                assert p.culprit[0] is server_getter.return_value.main
                assert p.culprit[1] == 'pysoa-worker-2'
                assert p.culprit[2] == (2, )
                p.start.assert_called_once_with()
                p.join.assert_called_once_with()
                assert p.terminate.called is False

            for p in slow_dying_processes:
                assert p.culprit[0] is server_getter.return_value.main
                assert p.culprit[1] == 'pysoa-worker-3'
                assert p.culprit[2] == (3, )
                p.start.assert_called_once_with()
                p.join.assert_called_once_with()
                assert p.terminate.called is False
        finally:
            if prev_sigint is not None:
                signal.signal(signal.SIGINT, prev_sigint or signal.SIG_IGN)
            if prev_sigterm is not None:
                signal.signal(signal.SIGTERM, prev_sigterm or signal.SIG_IGN)
            if prev_sighup is not None:
                signal.signal(signal.SIGHUP, prev_sighup or signal.SIG_IGN)