コード例 #1
0
ファイル: test_Carousel.py プロジェクト: thangduong/kamaelia
    def setup_test(self, **args):
        self.children = []

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:

            def defaultFactory(arg, parent=self):
                child = MockChild(self.children, arg)
                return child

            args["componentFactory"] = defaultFactory

        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc, "outbox"), (self.carousel, "inbox"))
        self.inSrc.link((self.inSrc, "signal"), (self.carousel, "control"))

        self.outDest = Dummy()
        self.outDest.link((self.carousel, "outbox"), (self.outDest, "inbox"))
        self.outDest.link((self.carousel, "signal"), (self.outDest, "control"))

        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel, "requestNext"),
                          (self.nextFbk, "inbox"))
        self.nextFbk.link((self.nextFbk, "outbox"), (self.carousel, "next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()
コード例 #2
0
ファイル: test_Carousel.py プロジェクト: casibbald/kamaelia
    def setup_test(self, **args):
        self.children=[]

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:
            def defaultFactory(arg,parent=self):
                child = MockChild(self.children, arg)
                return child
        
            args["componentFactory"]=defaultFactory
            
        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc,"outbox"), (self.carousel,"inbox"))
        self.inSrc.link((self.inSrc,"signal"), (self.carousel,"control"))
        
        self.outDest = Dummy()
        self.outDest.link((self.carousel,"outbox"), (self.outDest,"inbox"))
        self.outDest.link((self.carousel,"signal"), (self.outDest,"control"))
        
        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel,"requestNext"), (self.nextFbk,"inbox"))
        self.nextFbk.link((self.nextFbk,"outbox"), (self.carousel,"next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()
コード例 #3
0
ファイル: test_Carousel.py プロジェクト: casibbald/kamaelia
class Test_Carousel(unittest.TestCase):

    def setup_test(self, **args):
        self.children=[]

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:
            def defaultFactory(arg,parent=self):
                child = MockChild(self.children, arg)
                return child
        
            args["componentFactory"]=defaultFactory
            
        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc,"outbox"), (self.carousel,"inbox"))
        self.inSrc.link((self.inSrc,"signal"), (self.carousel,"control"))
        
        self.outDest = Dummy()
        self.outDest.link((self.carousel,"outbox"), (self.outDest,"inbox"))
        self.outDest.link((self.carousel,"signal"), (self.outDest,"control"))
        
        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel,"requestNext"), (self.nextFbk,"inbox"))
        self.nextFbk.link((self.nextFbk,"outbox"), (self.carousel,"next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()

    def sendToInbox(self,data):
        self.inSrc.send(data,"outbox")

    def sendToControl(self,data):
        self.inSrc.send(data,"signal")

    def sendToNext(self,data):
        self.nextFbk.send(data,"outbox")

    def dataReadyOutbox(self):
        return self.outDest.dataReady("inbox")

    def dataReadySignal(self):
        return self.outDest.dataReady("control")

    def dataReadyRequestNext(self):
        return self.nextFbk.dataReady("inbox")

    def recvOutbox(self):
        return self.outDest.recv("inbox")

    def recvSignal(self):
        return self.outDest.recv("control")

    def recvRequestNext(self):
        return self.nextFbk.recv("inbox")

    def collectOutbox(self):
        out=[]
        while self.dataReadyOutbox():
            out.append(self.recvOutbox())
        return out

    def collectSignal(self):
        out=[]
        while self.dataReadySignal():
            out.append(self.recvSignal())
        return out

    def collectRequestNext(self):
        out=[]
        while self.dataReadyRequestNext():
            out.append(self.recvRequestNext())
        return out

    def runFor(self, cycles):
        numcycles=cycles*5    # approx this many components in the system
        for i in range(0,numcycles): self.run.next()



    def test_byDefaultDoesNothing(self):
        """Carousel initialises. By default it does nothing."""
        self.setup_test()

        self.runFor(cycles=100)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(not self.dataReadyRequestNext(), "Carousel should have sent nothing to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")
        
    def test_canAskToMake1stRequest(self):
        """If the make1stRequest argument is set to True at initialisation, Carousel sends a "NEXT" message out of its "requestNext" outbox after it has started up."""
        self.setup_test(make1stRequest=True)

        self.runFor(cycles=5)

        self.assert_(self.children==[], "Carousel should create no children")
        self.assert_(not self.dataReadyOutbox(), "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(not self.dataReadySignal(), "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(), "Carousel should still be running")

    def test_shutsDownWhenToldToAndIdle(self):
        """When idle, with no child; a shutdownMicroprocess or producerFinished message will cause Carousel to terminate."""
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()
    
            self.runFor(cycles=100)
            self.sendToControl(IPC())
            self.assert_(not self.carousel._isStopped(), "Carousel should still be running")
            self.runFor(cycles=100)
    
            got=self.collectSignal()
            self.assert_(len(got)==1 and isinstance(got[0],IPC), "Carousel should send a "+IPC.__class__.__name__+" message out its 'signal' outbox")
            self.assert_(self.carousel._isStopped(), "Carousel should have terminated")

    def test_messageToNextRunsFactoryFunction(self):
        """When a message is sent to the "next" inbox, the supplied factory function is run with that argument."""
        self.factoryRun=None
        def factory(arg):
            self.factoryRun=arg
            return Dummy()
        
        self.setup_test(componentFactory=factory)

        self.runFor(cycles=5)
        self.assert_(self.factoryRun==None)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)
        self.assert_(self.factoryRun=="BLAH")
        
            
    def test_messageToNextSpawnsChild(self):
        """Messages sent to the "next" inbox trigger the factory function, leading to the creation and activation of a child component."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.assert_(len(self.children)==1, "Carousel should have spawned a child in response to the 'next' request")
        self.assert_(self.children[-1].arg=="BLAH", "Carousel should have spawned child with the 'next' message as the argument")
        self.assert_(self.children[-1].wasActivated, "The child should have been activated")

    def test_childTerminationTriggersRequestNext(self):
        """When a child terminates; the Carousel sends a "NEXT" message out of its "requestNext" outbox."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.children[-1].stopNow=True
        self.runFor(cycles=5)

        self.assert_(self.collectRequestNext()==["NEXT"], "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox")
        
    def test_childShutdownSignalDoesntTriggerRequest(self):
        """If the child sends out a producerFinished or shutdownMicroprocess message out of its "signal" outbox; the Carousel does not send out a message from its "requestNext" outbox in response."""
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)
    
            self.children[-1].send(IPC(),"signal")
            self.runFor(cycles=50)
    
            self.assert_(self.collectRequestNext()==[], "Carousel should have not sent anything 'requestNext' outbox")
        
    def test_ChildReceivesShutdownSignal(self):
        """A shutdownMicroprocess or producerFinished message sent to the "control" inbox of the Carousel gets passed onto the "control" inbox of the child."""
        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)
    
            self.sendToControl(IPC())
            self.runFor(cycles=50)
    
            self.assert_(self.children[-1].dataReady("control"), "Child should have received something on its 'control' inbox")
            msg=self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should have received a "+IPC.__class__.__name__+" message out its 'control' inbox")
        
    def test_nextRequestStartsNewchildOnceCurrentHasTerminated(self):
        """A message sent to the "next" inbox starts a new child; but only once the current child has terminated."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        for i in range(0,5):
            self.sendToNext("BLAH")
            self.runFor(cycles=50)
    
            self.assert_(len(self.children)==i+1, "The new child should not be created until the previous has terminated")
            self.children[-1].stopNow=True
            self.runFor(cycles=5)
            
            self.assert_(len(self.children)==i+2, "The 'next' message should have resulted in a new child")
            self.assert_(self.children[-2]._isStopped(), "The older child should by now be terminated")
            self.assert_(self.children[-1].wasActivated and not self.children[-1]._isStopped(), "The new child should be active and running")

    def test_dataReachesChildInbox(self):
        """Any messages sent to the "inbox" inbox of the Carousel gets sent on tot the "inbox" inbox of the child component."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=1)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.sendToInbox(MSG)
            self.runFor(cycles=1)

            self.assert_(self.children[-1].dataReady("inbox"), "Something should have arrived at the inbox")
            self.assert_(self.children[-1].recv("inbox")==MSG, "The message sent to the Carousel's 'inbox' inbox should have reached the child's 'inbox' inbox")
        
            self.runFor(cycles=10)


    def test_dataReachesCarouselOutbox(self):
        """Any mesasges sent out of the "outbox" outbox of a child emerges from the "outbox" outbox of the Carousel."""
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for i in range(0,5):
            MSG = "HELLO"+str(i)
            self.children[-1].send(MSG,"outbox")
            self.runFor(cycles=1)

            self.assert_(self.collectOutbox()==[MSG], "The message sent to the child's 'outbox' outbox should have reached the Carousel's 'outbox' outbox")
        
            self.runFor(cycles=10)

    def test_childSignalIgnored(self):
        """Messages coming out of the child's "signal" outbox are ignored. They do not emerge from the "signal" outbox of the Carousel."""
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for MSG in (producerFinished,shutdownMicroprocess,"HELLO!"):
            self.children[-1].send(MSG,"signal")
            self.runFor(cycles=1)

            self.assert_(self.collectSignal()==[], "Any message sent to the child's 'signal' outbox should not have reached the Carousel's 'signal' outbox")
        
            self.runFor(cycles=10)

    def test_terminatingCarouselWithChildPassesSignalToChildToo(self):
        """If a producerFinshed or shutdownMicroprocess is sent to a Carousel's "control" inbox, it is passed onto the child's "control" inbox."""

        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            
            # create new child
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            # send shutdown to Carousel
            self.sendToControl(IPC())
            self.runFor(cycles=5)

            # did the child get it
            msg = self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should also receive a "+IPC.__class__.__name__+" request")
            self.children[-1].stopNow=True
            self.runFor(cycles=5)
                
    def test_carouselDoesntTerminateUntilChildHas(self):
        """Carousel doesn't terminate (in response to producerFinished or shutdownMicroprocess) until the child has terminated."""

        for IPC in (producerFinished,shutdownMicroprocess):
            self.setup_test()
            
            # create new child
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            # send shutdown to Carousel
            self.sendToControl(IPC())
            self.runFor(cycles=50)

            # did the child get it
            msg = self.children[-1].recv("control")
            self.assert_(isinstance(msg,IPC), "Child should also receive a "+IPC.__class__.__name__+" request")

            # carousel and child should still be running
            self.assert_(not self.carousel._isStopped())
            self.assert_(not self.children[-1]._isStopped())
            
            self.children[-1].stopNow=True
            self.runFor(cycles=5)
            
            self.assert_(self.carousel._isStopped())
            self.assert_(self.children[-1]._isStopped())
                
    def test_queuedNextsFinishedIfProducerFinished(self):
        """If a producerFinished() is received, but there are still messages queued on the 'next' inbox, those messages are processed (and children created) first. *Then* the Carousel terminates."""
        
        self.setup_test()
        
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=50)
        
        self.sendToControl(producerFinished())
        for i in range(1,10):
            self.sendToNext("BLAH")
            
        self.runFor(cycles=1000)
        self.assert_(len(self.children)==1)
        self.assert_(not self.carousel._isStopped())
        
        for i in range(0,9):
            self.assert_(self.children[i].wasActivated)
            self.assert_(not self.children[i]._isStopped())
            msg=self.children[i].recv("control")
            self.assert_(isinstance(msg,(shutdownMicroprocess,producerFinished)))
            self.children[i].stopNow=True
            
            while len(self.children)<=i+1:
                self.runFor(cycles=1)
                
            while not self.children[-1].wasActivated:
                self.runFor(cycles=1)
                
    def test_queuedNextsAbortedIfShutdownMicroprocess(self):
        """If a shutdownMicroprocess() is received, any messages queued on the 'next' inbox are discarded; and Carousel shuts down as soon as any current child has terminated."""
            
        self.setup_test()
        
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=50)
        
        self.sendToControl(shutdownMicroprocess())
        for i in range(1,10):
            self.sendToNext("BLAH")
            
        self.runFor(cycles=50)
        self.assert_(len(self.children)==1, "Should only be the one child")
        self.assert_(not self.carousel._isStopped(), "Carousel shouldn't have stopped until the child has")
        msg=self.children[-1].recv("control")
        self.assert_(isinstance(msg,(shutdownMicroprocess,producerFinished)))

        self.children[-1].stopNow=True
        self.runFor(cycles=2)
        
        self.assert_(len(self.children)==1, "Should only be the one child")
        self.assert_(self.carousel._isStopped(), "Carousel should have terminated")
        self.assert_(self.children[0]._isStopped(), "Child should have terminated")
コード例 #4
0
ファイル: test_Carousel.py プロジェクト: thangduong/kamaelia
class Test_Carousel(unittest.TestCase):
    def setup_test(self, **args):
        self.children = []

        self.scheduler = scheduler()
        scheduler.run = self.scheduler

        if "componentFactory" not in args:

            def defaultFactory(arg, parent=self):
                child = MockChild(self.children, arg)
                return child

            args["componentFactory"] = defaultFactory

        self.carousel = Carousel(**args)

        self.inSrc = Dummy()
        self.inSrc.link((self.inSrc, "outbox"), (self.carousel, "inbox"))
        self.inSrc.link((self.inSrc, "signal"), (self.carousel, "control"))

        self.outDest = Dummy()
        self.outDest.link((self.carousel, "outbox"), (self.outDest, "inbox"))
        self.outDest.link((self.carousel, "signal"), (self.outDest, "control"))

        self.nextFbk = Dummy()
        self.nextFbk.link((self.carousel, "requestNext"),
                          (self.nextFbk, "inbox"))
        self.nextFbk.link((self.nextFbk, "outbox"), (self.carousel, "next"))

        self.carousel.activate(Scheduler=self.scheduler)
        self.inSrc.activate(Scheduler=self.scheduler)
        self.outDest.activate(Scheduler=self.scheduler)
        self.nextFbk.activate(Scheduler=self.scheduler)

        self.run = self.scheduler.main()

    def sendToInbox(self, data):
        self.inSrc.send(data, "outbox")

    def sendToControl(self, data):
        self.inSrc.send(data, "signal")

    def sendToNext(self, data):
        self.nextFbk.send(data, "outbox")

    def dataReadyOutbox(self):
        return self.outDest.dataReady("inbox")

    def dataReadySignal(self):
        return self.outDest.dataReady("control")

    def dataReadyRequestNext(self):
        return self.nextFbk.dataReady("inbox")

    def recvOutbox(self):
        return self.outDest.recv("inbox")

    def recvSignal(self):
        return self.outDest.recv("control")

    def recvRequestNext(self):
        return self.nextFbk.recv("inbox")

    def collectOutbox(self):
        out = []
        while self.dataReadyOutbox():
            out.append(self.recvOutbox())
        return out

    def collectSignal(self):
        out = []
        while self.dataReadySignal():
            out.append(self.recvSignal())
        return out

    def collectRequestNext(self):
        out = []
        while self.dataReadyRequestNext():
            out.append(self.recvRequestNext())
        return out

    def runFor(self, cycles):
        numcycles = cycles * 5  # approx this many components in the system
        for i in range(0, numcycles):
            self.run.next()

    def test_byDefaultDoesNothing(self):
        """Carousel initialises. By default it does nothing."""
        self.setup_test()

        self.runFor(cycles=100)

        self.assert_(self.children == [], "Carousel should create no children")
        self.assert_(
            not self.dataReadyOutbox(),
            "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(
            not self.dataReadySignal(),
            "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(
            not self.dataReadyRequestNext(),
            "Carousel should have sent nothing to its 'requestNext' outbox")
        self.assert_(not self.carousel._isStopped(),
                     "Carousel should still be running")

    def test_canAskToMake1stRequest(self):
        """If the make1stRequest argument is set to True at initialisation, Carousel sends a "NEXT" message out of its "requestNext" outbox after it has started up."""
        self.setup_test(make1stRequest=True)

        self.runFor(cycles=5)

        self.assert_(self.children == [], "Carousel should create no children")
        self.assert_(
            not self.dataReadyOutbox(),
            "Carousel should have sent nothing to its 'outbox' outbox")
        self.assert_(
            not self.dataReadySignal(),
            "Carousel should have sent nothing to its 'signal' outbox")
        self.assert_(
            self.collectRequestNext() == ["NEXT"],
            "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox"
        )
        self.assert_(not self.carousel._isStopped(),
                     "Carousel should still be running")

    def test_shutsDownWhenToldToAndIdle(self):
        """When idle, with no child; a shutdownMicroprocess or producerFinished message will cause Carousel to terminate."""
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()

            self.runFor(cycles=100)
            self.sendToControl(IPC())
            self.assert_(not self.carousel._isStopped(),
                         "Carousel should still be running")
            self.runFor(cycles=100)

            got = self.collectSignal()
            self.assert_(
                len(got) == 1 and isinstance(got[0], IPC),
                "Carousel should send a " + IPC.__class__.__name__ +
                " message out its 'signal' outbox")
            self.assert_(self.carousel._isStopped(),
                         "Carousel should have terminated")

    def test_messageToNextRunsFactoryFunction(self):
        """When a message is sent to the "next" inbox, the supplied factory function is run with that argument."""
        self.factoryRun = None

        def factory(arg):
            self.factoryRun = arg
            return Dummy()

        self.setup_test(componentFactory=factory)

        self.runFor(cycles=5)
        self.assert_(self.factoryRun == None)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)
        self.assert_(self.factoryRun == "BLAH")

    def test_messageToNextSpawnsChild(self):
        """Messages sent to the "next" inbox trigger the factory function, leading to the creation and activation of a child component."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.assert_(
            len(self.children) == 1,
            "Carousel should have spawned a child in response to the 'next' request"
        )
        self.assert_(
            self.children[-1].arg == "BLAH",
            "Carousel should have spawned child with the 'next' message as the argument"
        )
        self.assert_(self.children[-1].wasActivated,
                     "The child should have been activated")

    def test_childTerminationTriggersRequestNext(self):
        """When a child terminates; the Carousel sends a "NEXT" message out of its "requestNext" outbox."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        self.children[-1].stopNow = True
        self.runFor(cycles=5)

        self.assert_(
            self.collectRequestNext() == ["NEXT"],
            "Carousel should have sent a single 'NEXT' to its 'requestNext' outbox"
        )

    def test_childShutdownSignalDoesntTriggerRequest(self):
        """If the child sends out a producerFinished or shutdownMicroprocess message out of its "signal" outbox; the Carousel does not send out a message from its "requestNext" outbox in response."""
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.children[-1].send(IPC(), "signal")
            self.runFor(cycles=50)

            self.assert_(
                self.collectRequestNext() == [],
                "Carousel should have not sent anything 'requestNext' outbox")

    def test_ChildReceivesShutdownSignal(self):
        """A shutdownMicroprocess or producerFinished message sent to the "control" inbox of the Carousel gets passed onto the "control" inbox of the child."""
        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=5)

            self.sendToControl(IPC())
            self.runFor(cycles=50)

            self.assert_(
                self.children[-1].dataReady("control"),
                "Child should have received something on its 'control' inbox")
            msg = self.children[-1].recv("control")
            self.assert_(
                isinstance(msg, IPC), "Child should have received a " +
                IPC.__class__.__name__ + " message out its 'control' inbox")

    def test_nextRequestStartsNewchildOnceCurrentHasTerminated(self):
        """A message sent to the "next" inbox starts a new child; but only once the current child has terminated."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=5)

        for i in range(0, 5):
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            self.assert_(
                len(self.children) == i + 1,
                "The new child should not be created until the previous has terminated"
            )
            self.children[-1].stopNow = True
            self.runFor(cycles=5)

            self.assert_(
                len(self.children) == i + 2,
                "The 'next' message should have resulted in a new child")
            self.assert_(self.children[-2]._isStopped(),
                         "The older child should by now be terminated")
            self.assert_(
                self.children[-1].wasActivated
                and not self.children[-1]._isStopped(),
                "The new child should be active and running")

    def test_dataReachesChildInbox(self):
        """Any messages sent to the "inbox" inbox of the Carousel gets sent on tot the "inbox" inbox of the child component."""
        self.setup_test()
        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=1)

        for i in range(0, 5):
            MSG = "HELLO" + str(i)
            self.sendToInbox(MSG)
            self.runFor(cycles=1)

            self.assert_(self.children[-1].dataReady("inbox"),
                         "Something should have arrived at the inbox")
            self.assert_(
                self.children[-1].recv("inbox") == MSG,
                "The message sent to the Carousel's 'inbox' inbox should have reached the child's 'inbox' inbox"
            )

            self.runFor(cycles=10)

    def test_dataReachesCarouselOutbox(self):
        """Any mesasges sent out of the "outbox" outbox of a child emerges from the "outbox" outbox of the Carousel."""
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for i in range(0, 5):
            MSG = "HELLO" + str(i)
            self.children[-1].send(MSG, "outbox")
            self.runFor(cycles=1)

            self.assert_(
                self.collectOutbox() == [MSG],
                "The message sent to the child's 'outbox' outbox should have reached the Carousel's 'outbox' outbox"
            )

            self.runFor(cycles=10)

    def test_childSignalIgnored(self):
        """Messages coming out of the child's "signal" outbox are ignored. They do not emerge from the "signal" outbox of the Carousel."""
        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=2)

        for MSG in (producerFinished, shutdownMicroprocess, "HELLO!"):
            self.children[-1].send(MSG, "signal")
            self.runFor(cycles=1)

            self.assert_(
                self.collectSignal() == [],
                "Any message sent to the child's 'signal' outbox should not have reached the Carousel's 'signal' outbox"
            )

            self.runFor(cycles=10)

    def test_terminatingCarouselWithChildPassesSignalToChildToo(self):
        """If a producerFinshed or shutdownMicroprocess is sent to a Carousel's "control" inbox, it is passed onto the child's "control" inbox."""

        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()

            # create new child
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            # send shutdown to Carousel
            self.sendToControl(IPC())
            self.runFor(cycles=5)

            # did the child get it
            msg = self.children[-1].recv("control")
            self.assert_(
                isinstance(msg, IPC), "Child should also receive a " +
                IPC.__class__.__name__ + " request")
            self.children[-1].stopNow = True
            self.runFor(cycles=5)

    def test_carouselDoesntTerminateUntilChildHas(self):
        """Carousel doesn't terminate (in response to producerFinished or shutdownMicroprocess) until the child has terminated."""

        for IPC in (producerFinished, shutdownMicroprocess):
            self.setup_test()

            # create new child
            self.runFor(cycles=5)
            self.sendToNext("BLAH")
            self.runFor(cycles=50)

            # send shutdown to Carousel
            self.sendToControl(IPC())
            self.runFor(cycles=50)

            # did the child get it
            msg = self.children[-1].recv("control")
            self.assert_(
                isinstance(msg, IPC), "Child should also receive a " +
                IPC.__class__.__name__ + " request")

            # carousel and child should still be running
            self.assert_(not self.carousel._isStopped())
            self.assert_(not self.children[-1]._isStopped())

            self.children[-1].stopNow = True
            self.runFor(cycles=5)

            self.assert_(self.carousel._isStopped())
            self.assert_(self.children[-1]._isStopped())

    def test_queuedNextsFinishedIfProducerFinished(self):
        """If a producerFinished() is received, but there are still messages queued on the 'next' inbox, those messages are processed (and children created) first. *Then* the Carousel terminates."""

        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=50)

        self.sendToControl(producerFinished())
        for i in range(1, 10):
            self.sendToNext("BLAH")

        self.runFor(cycles=1000)
        self.assert_(len(self.children) == 1)
        self.assert_(not self.carousel._isStopped())

        for i in range(0, 9):
            self.assert_(self.children[i].wasActivated)
            self.assert_(not self.children[i]._isStopped())
            msg = self.children[i].recv("control")
            self.assert_(
                isinstance(msg, (shutdownMicroprocess, producerFinished)))
            self.children[i].stopNow = True

            while len(self.children) <= i + 1:
                self.runFor(cycles=1)

            while not self.children[-1].wasActivated:
                self.runFor(cycles=1)

    def test_queuedNextsAbortedIfShutdownMicroprocess(self):
        """If a shutdownMicroprocess() is received, any messages queued on the 'next' inbox are discarded; and Carousel shuts down as soon as any current child has terminated."""

        self.setup_test()

        self.runFor(cycles=5)
        self.sendToNext("BLAH")
        self.runFor(cycles=50)

        self.sendToControl(shutdownMicroprocess())
        for i in range(1, 10):
            self.sendToNext("BLAH")

        self.runFor(cycles=50)
        self.assert_(len(self.children) == 1, "Should only be the one child")
        self.assert_(not self.carousel._isStopped(),
                     "Carousel shouldn't have stopped until the child has")
        msg = self.children[-1].recv("control")
        self.assert_(isinstance(msg, (shutdownMicroprocess, producerFinished)))

        self.children[-1].stopNow = True
        self.runFor(cycles=2)

        self.assert_(len(self.children) == 1, "Should only be the one child")
        self.assert_(self.carousel._isStopped(),
                     "Carousel should have terminated")
        self.assert_(self.children[0]._isStopped(),
                     "Child should have terminated")