def test_idle_to_exit(self):
        b = ProcessBus()
        self.log(b, level=20)

        self.responses = []
        num = 3
        for index in range(num):
            b.subscribe('EXIT', self.get_listener('EXIT', index))
            b.subscribe('EXITED', self.get_listener('EXITED', index))

        b.transition('EXITED')

        # The bus MUST call all 'EXIT' listeners,
        # and then all 'EXITED' listeners.
        assert (set(self.responses) ==
                set([msg % (i, 'EXIT', None) for i in range(num)] +
                    [msg % (i, 'EXITED', None) for i in range(num)]))
        # The bus MUST move the state to EXITED
        assert b.state == 'EXITED'

        # The bus MUST log its states.
        self.assertLog([
            'Bus state: ENTER', 'Bus state: IDLE', 'Bus state: EXIT',
            'Waiting for child threads to terminate...', 'Bus state: EXITED'
        ])
    def test_builtin_channels(self):
        b = ProcessBus()
        listeners = [
            l for l in b.listeners if l != 'log' and not l.endswith('_ERROR')
        ]

        self.responses, expected = [], []

        for channel in listeners:
            if channel != 'log':
                for index, priority in enumerate([100, 50, 0, 51]):
                    b.subscribe(channel, self.get_listener(channel, index),
                                priority)

        try:
            for channel in listeners:
                if channel != 'log':
                    b.publish(channel)
                    expected.extend(
                        [msg % (i, channel, ()) for i in (2, 1, 3, 0)])

            assert self.responses == expected
        finally:
            # Exit so the atexit handler doesn't complain.
            b.transition('EXITED')
Example #3
0
    def test_idle_to_exit(self):
        b = ProcessBus()
        self.log(b, level=20)

        self.responses = []
        num = 3
        for index in range(num):
            b.subscribe('EXIT', self.get_listener('EXIT', index))
            b.subscribe('EXITED', self.get_listener('EXITED', index))

        b.transition('EXITED')

        # The bus MUST call all 'EXIT' listeners,
        # and then all 'EXITED' listeners.
        self.assertEqual(
            set(self.responses),
            set([msg % (i, 'EXIT', None) for i in range(num)] +
                [msg % (i, 'EXITED', None) for i in range(num)])
        )
        # The bus MUST move the state to EXITED
        self.assertEqual(b.state, 'EXITED')

        # The bus MUST log its states.
        self.assertLog([
            'Bus state: ENTER',
            'Bus state: IDLE',
            'Bus state: EXIT',
            'Waiting for child threads to terminate...',
            'Bus state: EXITED'
        ])
    def test_idle_to_run(self):
        b = ProcessBus()
        self.log(b, level=20)

        self.responses = []
        num = 3
        for index in range(num):
            b.subscribe('START', self.get_listener('START', index))

        b.transition('RUN')
        try:
            # The start method MUST call all 'start' listeners.
            assert (set(self.responses) == set(
                [msg % (i, 'START', None) for i in range(num)]))
            # The transition method MUST move the state to RUN
            # (or START_ERROR, if errors occur)
            assert b.state == 'RUN'

            # The start method MUST log its states.
            self.assertLog([
                'Bus state: ENTER', 'Bus state: IDLE', 'Bus state: START',
                'Bus state: RUN'
            ])
        finally:
            # Exit so the atexit handler doesn't complain.
            b.transition('EXITED')
Example #5
0
    def test_run_to_idle(self):
        b = ProcessBus()
        b.transition('RUN')
        self.log(b, level=20)

        try:
            self.responses = []
            num = 3
            for index in range(num):
                b.subscribe('STOP', self.get_listener('STOP', index))

            b.transition('IDLE')

            # The idle transition MUST call all 'stop' listeners.
            self.assertEqual(
                set(self.responses),
                set(msg % (i, 'STOP', None) for i in range(num))
            )
            # The idle method MUST move the state to IDLE
            self.assertEqual(b.state, 'IDLE')
            # The idle method MUST log its states.
            self.assertLog([
                'Bus state: STOP',
                'Bus state: IDLE'
            ])
        finally:
            # Exit so the atexit handler doesn't complain.
            b.transition('EXITED')
Example #6
0
    def test_idle_to_run(self):
        b = ProcessBus()
        self.log(b, level=20)

        self.responses = []
        num = 3
        for index in range(num):
            b.subscribe('START', self.get_listener('START', index))

        b.transition('RUN')
        try:
            # The start method MUST call all 'start' listeners.
            self.assertEqual(
                set(self.responses),
                set([msg % (i, 'START', None) for i in range(num)])
            )
            # The transition method MUST move the state to RUN
            # (or START_ERROR, if errors occur)
            self.assertEqual(b.state, 'RUN')

            # The start method MUST log its states.
            self.assertLog([
                'Bus state: ENTER',
                'Bus state: IDLE',
                'Bus state: START',
                'Bus state: RUN'
            ])
        finally:
            # Exit so the atexit handler doesn't complain.
            b.transition('EXITED')
Example #7
0
    def test_block(self):
        b = ProcessBus()
        self.log(b)

        def f():
            time.sleep(0.2)
            b.transition('EXITED')

        def g():
            time.sleep(0.4)

        def main_listener():
            main_calls.append(1)
        main_calls = []
        b.subscribe("main", main_listener)

        f_thread = threading.Thread(target=f, name='f')
        f_thread.start()
        threading.Thread(target=g, name='g').start()
        threads = [t for t in threading.enumerate() if not t.daemon]
        self.assertEqual(len(threads), 3)

        b.block()
        f_thread.join()

        # The block method MUST wait for the EXITED state.
        self.assertEqual(b.state, 'EXITED')
        # The block method MUST wait for ALL non-main, non-daemon threads to
        # finish.
        threads = [t for t in threading.enumerate() if not t.daemon]
        self.assertEqual(len(threads), 1)
        # The last message will mention an indeterminable thread name; ignore
        # it
        self.assertEqual(
            [entry for entry in self._log_entries
             if not entry.startswith('Publishing')
             and not entry.startswith('Waiting')],
            [
                'Bus state: ENTER',
                'Bus state: IDLE',
                'Bus state: EXIT',
                'Bus state: EXITED'
            ]
        )

        # While the bus was blocked, it should have published periodically
        # to the "main" channel.
        self.assertGreater(len(main_calls), 0)
    def test_start_with_callback(self):
        b = ProcessBus()
        self.log(b)
        try:
            events = []

            def f(*args, **kwargs):
                events.append(('f', args, kwargs))

            def g():
                events.append('g')

            b.subscribe('RUN', g)
            b.start_with_callback(f, (1, 3, 5), {'foo': 'bar'})
            # Give wait() time to run f()
            time.sleep(0.2)

            # The callback method MUST wait for the STARTED state.
            assert b.state == 'RUN'
            # The callback method MUST run after all start methods.
            assert events == ['g', ('f', (1, 3, 5), {'foo': 'bar'})]
        finally:
            b.transition('EXITED')
Example #9
0
    def test_start_with_callback(self):
        b = ProcessBus()
        self.log(b)
        try:
            events = []

            def f(*args, **kwargs):
                events.append(('f', args, kwargs))

            def g():
                events.append('g')

            b.subscribe('RUN', g)
            b.start_with_callback(f, (1, 3, 5), {'foo': 'bar'})
            # Give wait() time to run f()
            time.sleep(0.2)

            # The callback method MUST wait for the STARTED state.
            self.assertEqual(b.state, 'RUN')
            # The callback method MUST run after all start methods.
            self.assertEqual(events, ['g', ('f', (1, 3, 5), {'foo': 'bar'})])
        finally:
            b.transition('EXITED')
Example #10
0
    def test_builtin_channels(self):
        b = ProcessBus()
        listeners = [l for l in b.listeners
                     if l != 'log' and not l.endswith('_ERROR')]

        self.responses, expected = [], []

        for channel in listeners:
            if channel != 'log':
                for index, priority in enumerate([100, 50, 0, 51]):
                    b.subscribe(channel,
                                self.get_listener(channel, index), priority)

        try:
            for channel in listeners:
                if channel != 'log':
                    b.publish(channel)
                    expected.extend([msg % (i, channel, ()) for i in (2, 1, 3, 0)])

            self.assertEqual(self.responses, expected)
        finally:
            # Exit so the atexit handler doesn't complain.
            b.transition('EXITED')