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)