Example #1
0
class TestCompTestFlow(CompTestTestCase):

    slow = True

    def setUp(self):
        self.duration = 2.0

        prod_pp = ('videotestsrc is-live=true ! '
                   'video/x-raw-rgb,framerate=(fraction)8/1,'
                   'width=32,height=24')
        self.prod = pipeline_src(prod_pp)

        self.cnv1 = pipeline_cnv()
        self.cnv2 = pipeline_cnv()

        self.p = ComponentTestHelper()

    def tearDown(self):
        d = self.p.stop_flow()

        # add cleanup, otherwise components a.t.m. don't cleanup after
        # themselves too well, remove when fixed
        d.addBoth(lambda _: comptest.cleanup_reactor())
        return d

    def testSetupFailGstLinking(self):
        p2 = pipeline_src('fakesink') # this just can't work!
        c2 = pipeline_cnv('fakesink') # and neither can this!

        # we're going to fail in gst - make sure the gst logger is silent
        import gst
        old_debug_level = gst.debug_get_default_threshold()
        gst.debug_set_default_threshold(gst.LEVEL_NONE)

        self.p.set_flow([p2, c2, self.cnv1])
        d = self.p.start_flow()

        if old_debug_level != gst.LEVEL_NONE:

            def _restore_gst_debug_level(rf):
                gst.debug_set_default_threshold(old_debug_level)
                return rf
            d.addBoth(_restore_gst_debug_level)
        # Because component setup errors get swallowed in
        # BaseComponent.setup() we won't get the exact error that will
        # be thrown, i.e. PipelineParseError. Instead, the component
        # will turn sad and we will get a ComponentSad failure from
        # the ComponentWrapper.
        return self.failUnlessFailure(d, ComponentSad)

    def testSetupStartedAndHappy(self):
        flow = [self.prod, self.cnv1, self.cnv2]
        self.p.set_flow(flow)
        d = self.p.start_flow()

        def wait_for_happy(_):
            self.debug('Waiting for happiness')
            d = defer.DeferredList(
                [c.wait_for_mood(moods.happy) for c in flow])
            d.addCallback(check_happy)
            return d

        def check_happy(_):
            self.debug('Checking for happiness')
            for c in flow:
                self.assertEquals(moods.get(c.comp.getMood()), moods.happy)
            return _

        d.addCallback(wait_for_happy)
        return d

    def testRunFailGstLinking(self):
        p2 = pipeline_src('fakesink') # this just can't work!
        c2 = pipeline_cnv('fakesink') # and neither can this!

        # we're going to fail in gst - make sure the gst logger is silent
        import gst
        old_debug_level = gst.debug_get_default_threshold()
        gst.debug_set_default_threshold(gst.LEVEL_NONE)

        self.p.set_flow([p2, c2, self.cnv1])
        d = self.p.run_flow(self.duration)

        if old_debug_level != gst.LEVEL_NONE:

            def _restore_gst_debug_level(rf):
                gst.debug_set_default_threshold(old_debug_level)
                return rf
            d.addBoth(_restore_gst_debug_level)
        # See the comment in test_setup_fail_gst_linking()
        return self.failUnlessFailure(d, ComponentSad)

    def testRunStartTimeout(self):
        start_delay_time = 5.0
        self.p.guard_timeout = 2.0

        class LingeringCompWrapper(ComponentWrapper):

            def instantiate(self, *a, **kw):
                d = ComponentWrapper.instantiate(self, *a, **kw)

                def delay_start(result):
                    dd = defer.Deferred()
                    reactor.callLater(start_delay_time, dd.callback, result)
                    return dd
                d.addCallback(delay_start)
                return d
        c2 = LingeringCompWrapper('pipeline-converter', Converter,
                                  props={'pipeline': 'identity'})
        self.p.set_flow([self.prod, c2])
        d = self.p.run_flow(self.duration)
        return self.failUnlessFailure(d, comptest.StartTimeout)

    def testRunWithDelays(self):
        flow = [self.prod, self.cnv1, self.cnv2]
        self.p.start_delay = 0.5

        self.p.set_flow(flow)
        return self.p.run_flow(self.duration)

    def testRunProvidesClocking(self):
        p2_pp = ('videotestsrc is-live=true ! '
                 'video/x-raw-rgb,framerate=(fraction)8/1,'
                 'width=32,height=24')
        p2 = pipeline_src(p2_pp)

        from flumotion.component.muxers.multipart import Multipart
        mux = ComponentWrapper('multipart-muxer', Multipart, name='mux')

        self.prod.feed(mux)
        p2.feed(mux)
        mux.feed(self.cnv1)

        self.clock_slave = p2

        def check_clocking(_):
            self.warning('check_clocking: %s %r' %
                         (self.clock_slave.name,
                          self.clock_slave.comp.pipeline.get_clock()))
            import gst
            pp = self.clock_slave.comp.pipeline
            # is there a better way to check if that component is
            # using an external clock source?
            self.failUnless(isinstance(pp.get_clock(), gst.NetClientClock),
                            "Didn't receive external clocking info.")
            return _
        task_d = defer.Deferred()
        task_d.addCallback(check_clocking)

        self.p.set_flow([self.prod, p2, mux, self.cnv1], auto_link=False)
        if self.prod is not self.p._master:
            # p2 (of [self.prod, p2]) seems to be the master this time
            self.clock_slave = self.prod
        d = self.p.run_flow(self.duration, tasks=[task_d])
        return d

    def testRunTasksChainedAndFired(self):
        self.tasks_fired = []
        self.tasks = []
        num_tasks = 5

        def tasks_started(result, index):
            self.tasks_fired[index] = True
            return result

        def tasks_check(result):
            self.failIfIn(False, self.tasks_fired)
            self.failIfIn(False, self.tasks_fired)
            return result
        for i in range(num_tasks):
            self.tasks_fired.append(False)
            d = defer.Deferred()
            self.tasks.append(d)
            d.addCallback(tasks_started, i)

        self.p.set_flow([self.prod, self.cnv1, self.cnv2])
        d = self.p.run_flow(self.duration, tasks=self.tasks)
        d.addCallback(tasks_check)

        return d

    def testRunTasksTimeout(self):
        self.p.set_flow([self.prod, self.cnv1, self.cnv2])
        self.p.guard_timeout = 4.0

        def make_eternal_deferred(_):
            # never going to fire this one...
            eternal_d = defer.Deferred()
            return eternal_d
        task_d = defer.Deferred()
        task_d.addCallback(make_eternal_deferred)

        d = self.p.run_flow(self.duration, tasks=[task_d])

        return self.failUnlessFailure(d, comptest.FlowTimeout)

    def testRunStopTimeout(self):
        stop_delay_time = 6.0
        self.p.guard_timeout = 4.0

        class DelayingCompWrapper(ComponentWrapper):
            do_delay = True

            def stop(self, *a, **kw):
                d = ComponentWrapper.stop(self, *a, **kw)

                def delay_stop(result):
                    if self.do_delay:
                        self.do_delay = False
                        dd = defer.Deferred()
                        reactor.callLater(stop_delay_time, dd.callback, result)
                        return dd
                    return result
                d.addCallback(delay_stop)
                return d
        c2 = DelayingCompWrapper('pipeline-converter', Converter,
                                 props={'pipeline': 'identity'})
        self.p.set_flow([self.prod, c2])
        d = self.p.run_flow(self.duration)
        return self.failUnlessFailure(d, comptest.StopTimeout)

    def testRunStartedThenFails(self):
        self.p.set_flow([self.prod, self.cnv1, self.cnv2])
        wrench_timeout = 0.5

        class CustomWrenchException(Exception):
            pass

        def insert_wrenches_into_cogs(_):

            def insert_wrench(c):
                raise CustomWrenchException("Wasn't that loose?")
            d = defer.Deferred()
            d.addCallback(insert_wrench)
            reactor.callLater(wrench_timeout, d.callback, self.cnv1)
            return d
        task_d = defer.Deferred()
        task_d.addCallback(insert_wrenches_into_cogs)

        d = self.p.run_flow(self.duration, tasks=[task_d])
        return self.failUnlessFailure(d, CustomWrenchException)

    def testRunStartedThenFlowAndStopFail(self):
        flow_error_timeout = 0.5

        class CustomFlowException(Exception):
            pass

        class CustomStopException(Exception):
            pass

        class BrokenCompWrapper(ComponentWrapper):
            do_break = True

            def stop(self, *a, **kw):
                d = ComponentWrapper.stop(self, *a, **kw)

                def delay_stop(result):
                    # breaking once should be enough
                    if self.do_break:
                        self.do_break = False
                        raise CustomStopException()
                d.addCallback(delay_stop)
                return d
        c2 = BrokenCompWrapper('pipeline-converter', Converter,
                               props={'pipeline': 'identity'})
        self.p.set_flow([self.prod, c2])

        class CustomFlowException(Exception):
            pass

        def insert_flow_errors(_):

            def insert_error(_ignore):
                raise CustomFlowException("Exception!")
            d = defer.Deferred()
            d.addCallback(insert_error)
            reactor.callLater(flow_error_timeout, d.callback, None)
            return d
        task_d = defer.Deferred()
        task_d.addCallback(insert_flow_errors)
        d = self.p.run_flow(self.duration, tasks=[task_d])
        return self.failUnlessFailure(d, CustomFlowException)