def test_housekeeping_with_xtrigger_satisfied(): """The housekeeping method makes sure only satisfied xtrigger function are kept.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrig = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) xtrigger_mgr.add_trig("get_name", xtrig) xtrig.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xtrig_labels.add("get_name") start_point = ISO8601Point('20000101T0000+05') itask = TaskProxy(tdef=tdef, start_point=start_point) xtrigger_mgr.collate([itask]) # pretend the function has been activated xtrigger_mgr.active.append(xtrig.get_signature()) xtrigger_mgr.callback(xtrig) assert xtrigger_mgr.sat_xtrig xtrigger_mgr.housekeep() # here we still have the same number as before assert xtrigger_mgr.sat_xtrig # however, we have no xclock trigger satisfied assert not xtrigger_mgr.sat_xclock
def test_housekeeping_with_xclock_satisfied(): """The housekeeping method makes sure only satisfied xclock function are kept.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") # the clock xtrigger xtrig = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) xtrig.out = "[\"True\", \"1\"]" xtrigger_mgr.add_clock("wall_clock", xtrig) # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xclock_label = "wall_clock" # cycle point for task proxy # TODO: we need to call init, before we can use ISO8601 points in Cylc, # why? init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xclock = "wall_clock", False # satisfied? # satisfy xclock xtrigger_mgr.satisfy_xclock(itask) # tally xtrigger_mgr.collate([itask]) assert xtrigger_mgr.sat_xclock xtrigger_mgr.housekeep() # here we still have the same number as before assert xtrigger_mgr.sat_xclock
def test_satisfy_xclock_satisfied_xclock(): """Test satisfy_xclock for a satisfied clock trigger.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") # the clock xtrigger xtrig = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) xtrig.out = "[\"True\", \"1\"]" xtrigger_mgr.add_clock("wall_clock", xtrig) # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xclock_label = "wall_clock" # cycle point for task proxy init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xclock = "wall_clock", True # satisfied? # we are defining in the state of the TaskProxy. that its xclock trigger # has been satisfied, without actually adding it to the right dict. assert not xtrigger_mgr.sat_xclock xtrigger_mgr.satisfy_xclock(itask) # as it was already satisfied, the function should return immediately, # without touching sat_xclock, therefore, it must remain empty assert not xtrigger_mgr.sat_xclock
def test_satisfy_xclock_unsatisfied_xclock(): """Test satisfy_xclock for an unsatisfied clock trigger.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") # the clock xtrigger xtrig = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) xtrig.out = "[\"True\", \"1\"]" xtrigger_mgr.add_clock("wall_clock", xtrig) # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xclock_label = "wall_clock" # cycle point for task proxy init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xclock = "wall_clock", False # satisfied? # we are defining in the state of the TaskProxy. that its xclock trigger # has **not** been satisfied. assert not xtrigger_mgr.sat_xclock xtrigger_mgr.satisfy_xclock(itask) # as it was satisfied by the satisfy_clock function, we must have its # signature in the dict. NB the signature is not the same as # get_signature(), as it is actually the signature for that moment # when it was satisfied. assert xtrigger_mgr.sat_xclock
def test_housekeeping_with_xtrigger_satisfied(xtrigger_mgr): """The housekeeping method makes sure only satisfied xtrigger function are kept.""" xtrigger_mgr.validate_xtrigger = lambda *a, **k: True # Ignore validation xtrig = SubFuncContext( label="get_name", func_name="get_name", func_args=[], func_kwargs={} ) xtrigger_mgr.add_trig("get_name", xtrig, 'fdir') xtrig.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, initial_point=1 ) init() sequence = ISO8601Sequence('P1D', '2019') tdef.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask = TaskProxy(tdef, start_point) # pretend the function has been activated xtrigger_mgr.active.append(xtrig.get_signature()) xtrigger_mgr.callback(xtrig) assert xtrigger_mgr.sat_xtrig xtrigger_mgr.housekeep([itask]) # here we still have the same number as before assert xtrigger_mgr.sat_xtrig
def test_callback(xtrigger_mgr): """Test callback.""" get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) get_name.out = "[\"True\", \"1\"]" xtrigger_mgr.active.append(get_name.get_signature()) xtrigger_mgr.callback(get_name) # this means that the xtrigger was satisfied assert xtrigger_mgr.sat_xtrig
def test_callback(): """Test callback.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) get_name.out = "[\"True\", \"1\"]" xtrigger_mgr.active.append(get_name.get_signature()) xtrigger_mgr.callback(get_name) # this means that the xtrigger was satisfied assert xtrigger_mgr.sat_xtrig
def test_callback_invalid_json(xtrigger_mgr): """Test callback with invalid JSON.""" get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) get_name.out = "{no_quotes: \"mom!\"}" xtrigger_mgr.active.append(get_name.get_signature()) xtrigger_mgr.callback(get_name) # this means that the xtrigger was not satisfied # TODO: this means site admins are only aware of this if they # look at the debug log. Is that OK? assert not xtrigger_mgr.sat_xtrig
def _retry_task(self, itask, wallclock_time, submit_retry=False): """Retry a task. Args: itask (cylc.flow.task_proxy.TaskProxy): The task to retry. wallclick_time (float): Unix time to schedule the retry for. submit_retry (bool): False if this is an execution retry. True if this is a submission retry. """ # derive an xtrigger label for this retry label = '_'.join(('cylc', 'submit_retry' if submit_retry else 'retry', itask.identity)) kwargs = {'absolute_as_seconds': wallclock_time} # if this isn't the first retry the xtrigger will already exist if label in itask.state.xtriggers: # retry xtrigger already exists from a previous retry, modify it self.xtrigger_mgr.mutate_trig(label, kwargs) itask.state.xtriggers[label] = False else: # create a new retry xtrigger xtrig = SubFuncContext(label, 'wall_clock', [], kwargs) self.xtrigger_mgr.add_trig(label, xtrig, os.getenv("CYLC_SUITE_RUN_DIR")) itask.state.add_xtrigger(label) itask.state.reset(TASK_STATUS_WAITING)
def coerce_xtrigger(self, value, keys): """Coerce a string into an xtrigger function context object. func_name(*func_args, **func_kwargs) Checks for legal string templates in arg values too. """ label = keys[-1] value = self.strip_and_unquote(keys, value) if not value: raise IllegalValueError("xtrigger", keys, value) fname = None args = [] kwargs = {} match = self._REC_TRIG_FUNC.match(value) if match is None: raise IllegalValueError("xtrigger", keys, value) fname, fargs, intvl = match.groups() if intvl: intvl = self.coerce_interval(intvl, keys) if fargs: # Extract function args and kwargs. for farg in fargs.split(r','): try: key, val = farg.strip().split(r'=', 1) except ValueError: args.append(self._coerce_type(farg.strip())) else: kwargs[key.strip()] = self._coerce_type(val.strip()) return SubFuncContext(label, fname, args, kwargs, intvl)
def test_add_xtrigger(xtrigger_mgr): """Test for adding an xtrigger.""" xtrig = SubFuncContext(label="echo", func_name="echo", func_args=["name", "age"], func_kwargs={"location": "soweto"}) xtrigger_mgr.add_trig("xtrig", xtrig, 'fdir') assert xtrig == xtrigger_mgr.functx_map["xtrig"]
def test_add_xtrigger(): """Test for adding a xtrigger.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrig = SubFuncContext(label="echo", func_name="echo", func_args=["name", "age"], func_kwargs={"location": "soweto"}) xtrigger_mgr.add_trig("xtrig", xtrig) assert xtrig == xtrigger_mgr.functx_map["xtrig"]
def test_add_xtrigger_with_params(xtrigger_mgr): """Test for adding an xtrigger.""" xtrig = SubFuncContext( label="echo", func_name="echo", func_args=["name", "%(point)s"], func_kwargs={"%(location)s": "soweto"} # no problem with the key! ) xtrigger_mgr.add_trig("xtrig", xtrig, 'fdir') assert xtrig == xtrigger_mgr.functx_map["xtrig"]
def test_add_xtrigger_with_params(): """Test for adding a xtrigger.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrig = SubFuncContext( label="echo", func_name="echo", func_args=["name", "%(point)s"], func_kwargs={"%(location)s": "soweto"} # no problem with the key! ) xtrigger_mgr.add_trig("xtrig", xtrig) assert xtrig == xtrigger_mgr.functx_map["xtrig"]
def test_add_clock_xtrigger(): """Test for adding a clock xtrigger. Clock xtriggers go to a different dict than normal xtriggers. This is useful as the execution varies for clock/non-clock xtriggers (e.g. sync vs. async).""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrig = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) xtrigger_mgr.add_clock("xtrig", xtrig) assert xtrig == xtrigger_mgr.clockx_map["xtrig"]
def test_callback_not_active(xtrigger_mgr): """Test callback with no active contexts.""" # calling callback with a SubFuncContext with none active # results in a ValueError get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) with pytest.raises(ValueError): xtrigger_mgr.callback(get_name)
def test_callback_not_active(): """Test callback with no active contexts.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") # calling callback with a SubFuncContext with none active # results in a ValueError get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) with pytest.raises(ValueError): xtrigger_mgr.callback(get_name)
def test_check_xtriggers(xtrigger_mgr_procpool): """Test check_xtriggers call. check_xtriggers does pretty much the same as collate. The difference is that besides tallying on all the xtriggers and clock xtriggers available, it then proceeds to trying to satisfy them.""" # add a xtrigger # that will cause all_xtrig to be populated, but not all_xclock get_name = SubFuncContext( label="get_name", func_name="get_name", func_args=[], func_kwargs={} ) xtrigger_mgr_procpool.add_trig("get_name", get_name, 'fdir') get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef1 = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False ) init() sequence = ISO8601Sequence('P1D', '2019') tdef1.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask1 = TaskProxy(tdef=tdef1, start_point=start_point) itask1.state.xtriggers["get_name"] = False # satisfied? # add a clock xtrigger # that will cause both all_xclock to be populated but not all_xtrig wall_clock = SubFuncContext( label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={} ) wall_clock.out = "[\"True\", \"1\"]" xtrigger_mgr_procpool.add_trig("wall_clock", wall_clock, "fdir") # create a task tdef2 = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False ) tdef2.xtrig_labels[sequence] = ["wall_clock"] init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask2 = TaskProxy(tdef=tdef2, start_point=start_point) xtrigger_mgr_procpool.check_xtriggers([itask1, itask2]) # won't be satisfied, as it is async, we are are not calling callback assert not xtrigger_mgr_procpool.sat_xtrig assert xtrigger_mgr_procpool.all_xtrig
def test__call_xtriggers_async(xtrigger_mgr): """Test _call_xtriggers_async""" xtrigger_mgr.validate_xtrigger = lambda *a, **k: True # Ignore validation # the echo1 xtrig (not satisfied) echo1_xtrig = SubFuncContext(label="echo1", func_name="echo1", func_args=[], func_kwargs={}) echo1_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr.add_trig("echo1", echo1_xtrig, "fdir") # the echo2 xtrig (satisfied through callback later) echo2_xtrig = SubFuncContext(label="echo2", func_name="echo2", func_args=[], func_kwargs={}) echo2_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr.add_trig("echo2", echo2_xtrig, "fdir") # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, initial_point=1) init() sequence = ISO8601Sequence('P1D', '2000') tdef.xtrig_labels[sequence] = ["echo1", "echo2"] # cycle point for task proxy init() start_point = ISO8601Point('2019') # create task proxy itask = TaskProxy(tdef, start_point, FlowLabelMgr().get_new_label()) # we start with no satisfied xtriggers, and nothing active assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 0 # after calling the first time, we get two active xtrigger_mgr.call_xtriggers_async(itask) assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 2 # calling again does not change anything xtrigger_mgr.call_xtriggers_async(itask) assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 2 # now we call callback manually as the proc_pool we passed is a mock # then both should be satisfied xtrigger_mgr.callback(echo1_xtrig) xtrigger_mgr.callback(echo2_xtrig) # so both were satisfied, and nothing is active assert len(xtrigger_mgr.sat_xtrig) == 2 assert len(xtrigger_mgr.active) == 0 # calling satisfy_xtriggers again still does not change anything xtrigger_mgr.call_xtriggers_async(itask) assert len(xtrigger_mgr.sat_xtrig) == 2 assert len(xtrigger_mgr.active) == 0
def test_add_xtrigger_with_deprecated_params(xtrigger_mgr, caplog): """It should flag deprecated template variables.""" xtrig = SubFuncContext( label="echo", func_name="echo", func_args=[1, "name", "%(suite_name)s"], func_kwargs={"location": "soweto"} ) caplog.set_level(logging.WARNING, CYLC_LOG) xtrigger_mgr.add_trig("xtrig", xtrig, 'fdir') assert caplog.messages == [ 'Xtrigger "xtrig" uses deprecated template variables: suite_name' ]
def test_collate(xtrigger_mgr): """Test that collate properly tallies the totals of current xtriggers.""" xtrigger_mgr.collate(itasks=[]) assert not xtrigger_mgr.all_xtrig # add a xtrigger # that will cause all_xtrig to be populated get_name = SubFuncContext( label="get_name", func_name="get_name", func_args=[], func_kwargs={} ) xtrigger_mgr.add_trig("get_name", get_name, 'fdir') get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False ) init() sequence = ISO8601Sequence('P1D', '20190101T00Z') tdef.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xtriggers["get_name"] = get_name xtrigger_mgr.collate([itask]) assert xtrigger_mgr.all_xtrig # add a clock xtrigger # that will cause both all_xclock to be populated but not all_xtrig wall_clock = SubFuncContext( label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={} ) wall_clock.out = "[\"True\", \"1\"]" xtrigger_mgr.add_trig("wall_clock", wall_clock, "fdir") # create a task tdef = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False ) tdef.xtrig_labels[sequence] = ["wall_clock"] start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) xtrigger_mgr.collate([itask]) assert not xtrigger_mgr.all_xtrig
def test_check_xtriggers(): """Test check_xtriggers call. check_xtriggers does pretty much the same as collate. The difference is that besides tallying on all the xtriggers and clock xtriggers available, it then proceeds to trying to satisfy them.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******", proc_pool=MockedProcPool()) # add a xtrigger # that will cause all_xtrig to be populated, but not all_xclock get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) xtrigger_mgr.add_trig("get_name", get_name) get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef1 = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef1.xtrig_labels.add("get_name") start_point = ISO8601Point('20000101T0000+05') itask1 = TaskProxy(tdef=tdef1, start_point=start_point) itask1.state.xtriggers["get_name"] = False # satisfied? # add a clock xtrigger # that will cause both all_xclock to be populated but not all_xtrig wall_clock = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) wall_clock.out = "[\"True\", \"1\"]" xtrigger_mgr.add_clock("wall_clock", wall_clock) # create a task tdef2 = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef2.xclock_label = "wall_clock" init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask2 = TaskProxy(tdef=tdef2, start_point=start_point) itask2.state.xclock = "wall_clock", False # satisfied? xtrigger_mgr.check_xtriggers([itask1, itask2]) assert xtrigger_mgr.sat_xclock assert xtrigger_mgr.all_xclock # won't be satisfied, as it is async, we are are not calling callback assert not xtrigger_mgr.sat_xtrig assert xtrigger_mgr.all_xtrig
def test_collate(): """Test that collate properly tallies the totals of current xtriggers.""" xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrigger_mgr.collate(itasks=[]) assert not xtrigger_mgr.all_xclock assert not xtrigger_mgr.all_xtrig # add a xtrigger # that will cause all_xtrig to be populated, but not all_xclock get_name = SubFuncContext(label="get_name", func_name="get_name", func_args=[], func_kwargs={}) xtrigger_mgr.add_trig("get_name", get_name) get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xtrig_labels.add("get_name") start_point = ISO8601Point('20000101T0000+05') itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xtriggers["get_name"] = get_name xtrigger_mgr.collate([itask]) assert not xtrigger_mgr.all_xclock assert xtrigger_mgr.all_xtrig # add a clock xtrigger # that will cause both all_xclock to be populated but not all_xtrig wall_clock = SubFuncContext(label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={}) wall_clock.out = "[\"True\", \"1\"]" xtrigger_mgr.add_clock("wall_clock", wall_clock) # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xclock_label = "wall_clock" init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) itask.state.xclock = "wall_clock", True xtrigger_mgr.collate([itask]) assert xtrigger_mgr.all_xclock assert not xtrigger_mgr.all_xtrig
def test_check_xtriggers(xtrigger_mgr): """Test process_xtriggers call.""" xtrigger_mgr.validate_xtrigger = lambda *a, **k: True # Ignore validation # add an xtrigger get_name = SubFuncContext( label="get_name", func_name="get_name", func_args=[], func_kwargs={} ) xtrigger_mgr.add_trig("get_name", get_name, 'fdir') get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef1 = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, initial_point=1 ) init() sequence = ISO8601Sequence('P1D', '2019') tdef1.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask1 = TaskProxy(tdef1, start_point) itask1.state.xtriggers["get_name"] = False # satisfied? # add a clock xtrigger wall_clock = SubFuncContext( label="wall_clock", func_name="wall_clock", func_args=[], func_kwargs={} ) wall_clock.out = "[\"True\", \"1\"]" xtrigger_mgr.add_trig("wall_clock", wall_clock, "fdir") # create a task tdef2 = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, initial_point=1 ) tdef2.xtrig_labels[sequence] = ["wall_clock"] init() start_point = ISO8601Point('20000101T0000+05') # create task proxy TaskProxy(tdef2, start_point) xtrigger_mgr.check_xtriggers(itask1, lambda foo: None) # won't be satisfied, as it is async, we are are not calling callback assert not xtrigger_mgr.sat_xtrig
def test_add_xtrigger_with_unknown_params(xtrigger_mgr): """Test for adding an xtrigger with an unknown parameter. The XTriggerManager contains a list of specific parameters that are available in the function template. Values that are not strings raise a TypeError during regex matching, but are ignored, so we should not have any issue with TypeError. If a value in the format %(foo)s appears in the parameters, and 'foo' is not in this list of parameters, then a ValueError is expected. """ xtrig = SubFuncContext(label="echo", func_name="echo", func_args=[1, "name", "%(what_is_this)s"], func_kwargs={"location": "soweto"}) with pytest.raises(ValueError): xtrigger_mgr.add_trig("xtrig", xtrig, 'fdir')
def callback(self, ctx: SubFuncContext): """Callback for asynchronous xtrigger functions. Record satisfaction status and function results dict. Args: ctx (SubFuncContext): function context Raises: ValueError: if the context given is not active """ LOG.debug(ctx) sig = ctx.get_signature() self.active.remove(sig) try: satisfied, results = json.loads(ctx.out) except (ValueError, TypeError): return LOG.debug('%s: returned %s' % (sig, results)) if satisfied: self.pflag = True self.sat_xtrig[sig] = results
def callback(self, ctx: SubFuncContext): """Callback for asynchronous xtrigger functions. Record satisfaction status and function results dict. Args: ctx (SubFuncContext): function context Raises: ValueError: if the context given is not active """ LOG.debug(ctx) sig = ctx.get_signature() self.active.remove(sig) try: satisfied, results = json.loads(ctx.out) except (ValueError, TypeError): return LOG.debug('%s: returned %s', sig, results) if satisfied: self.data_store_mgr.delta_task_xtrigger(sig, True) LOG.info('xtrigger satisfied: %s = %s', ctx.label, sig) self.sat_xtrig[sig] = results
def test_add_xtrigger_with_unkonwn_params(): """Test for adding a xtrigger with an unknown parameter. The XTriggerManager contains a list of specific parameters that are available in the function template. Values that are not strings raise a TypeError during regex matching, but are ignored, so we should not have any issue with TypeError. If a value in the format %(foo)s appears in the parameters, and 'foo' is not in this list of parameters, then a ValueError is expected. """ xtrigger_mgr = XtriggerManager(suite="sample_suite", user="******") xtrig = SubFuncContext(label="echo", func_name="echo", func_args=[1, "name", "%(what_is_this)s"], func_kwargs={"location": "soweto"}) with pytest.raises(ValueError): xtrigger_mgr.add_trig("xtrig", xtrig) # TODO: is it intentional? At the moment when we fail to validate the # function parameters, we add it to the dict anyway. assert xtrigger_mgr.functx_map["xtrig"] == xtrig
def test_satisfy_xtrigger(xtrigger_mgr_procpool_broadcast): """Test satisfy_xtriggers""" # the echo1 xtrig (not satisfied) echo1_xtrig = SubFuncContext( label="echo1", func_name="echo1", func_args=[], func_kwargs={} ) echo1_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr_procpool_broadcast.add_trig("echo1", echo1_xtrig, "fdir") # the echo2 xtrig (satisfied through callback later) echo2_xtrig = SubFuncContext( label="echo2", func_name="echo2", func_args=[], func_kwargs={} ) echo2_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr_procpool_broadcast.add_trig("echo2", echo2_xtrig, "fdir") # create a task tdef = TaskDef( name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False ) init() sequence = ISO8601Sequence('P1D', '2000') tdef.xtrig_labels[sequence] = ["echo1", "echo2"] # cycle point for task proxy init() start_point = ISO8601Point('2019') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) # we start with no satisfied xtriggers, and nothing active assert len(xtrigger_mgr_procpool_broadcast.sat_xtrig) == 0 assert len(xtrigger_mgr_procpool_broadcast.active) == 0 # after calling satisfy_xtriggers the first time, we get two active xtrigger_mgr_procpool_broadcast.satisfy_xtriggers(itask) assert len(xtrigger_mgr_procpool_broadcast.sat_xtrig) == 0 assert len(xtrigger_mgr_procpool_broadcast.active) == 2 # calling satisfy_xtriggers again does not change anything xtrigger_mgr_procpool_broadcast.satisfy_xtriggers(itask) assert len(xtrigger_mgr_procpool_broadcast.sat_xtrig) == 0 assert len(xtrigger_mgr_procpool_broadcast.active) == 2 # now we call callback manually as the proc_pool we passed is a mock # then both should be satisfied xtrigger_mgr_procpool_broadcast.callback(echo1_xtrig) xtrigger_mgr_procpool_broadcast.callback(echo2_xtrig) # so both were satisfied, and nothing is active assert len(xtrigger_mgr_procpool_broadcast.sat_xtrig) == 2 assert len(xtrigger_mgr_procpool_broadcast.active) == 0 # calling satisfy_xtriggers again still does not change anything xtrigger_mgr_procpool_broadcast.satisfy_xtriggers(itask) assert len(xtrigger_mgr_procpool_broadcast.sat_xtrig) == 2 assert len(xtrigger_mgr_procpool_broadcast.active) == 0
def test_satisfy_xtrigger(): """Test satisfy_xtriggers""" # the XtriggerManager instance xtrigger_mgr = XtriggerManager( suite="sample_suite", user="******", proc_pool=MockedProcPool(), broadcast_mgr=MockedBroadcastMgr(suite_db_mgr=None)) # the echo1 xtrig (not satisfied) echo1_xtrig = SubFuncContext(label="echo1", func_name="echo1", func_args=[], func_kwargs={}) echo1_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr.add_trig("echo1", echo1_xtrig) # the echo2 xtrig (satisfied through callback later) echo2_xtrig = SubFuncContext(label="echo2", func_name="echo2", func_args=[], func_kwargs={}) echo2_xtrig.out = "[\"True\", {\"name\": \"herminia\"}]" xtrigger_mgr.add_trig("echo2", echo2_xtrig) # create a task tdef = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1, spawn_ahead=False) tdef.xtrig_labels.add("echo1") tdef.xtrig_labels.add("echo2") # cycle point for task proxy init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef=tdef, start_point=start_point) # we start with no satisfied xtriggers, and nothing active assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 0 # after calling satisfy_xtriggers the first time, we get two active xtrigger_mgr.satisfy_xtriggers(itask) assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 2 # calling satisfy_xtriggers again does not change anything xtrigger_mgr.satisfy_xtriggers(itask) assert len(xtrigger_mgr.sat_xtrig) == 0 assert len(xtrigger_mgr.active) == 2 # now we call callback manually as the proc_pool we passed is a mock # then both should be satisfied xtrigger_mgr.callback(echo1_xtrig) xtrigger_mgr.callback(echo2_xtrig) # so both were satisfied, and nothing is active assert len(xtrigger_mgr.sat_xtrig) == 2 assert len(xtrigger_mgr.active) == 0 # calling satisfy_xtriggers again still does not change anything xtrigger_mgr.satisfy_xtriggers(itask) assert len(xtrigger_mgr.sat_xtrig) == 2 assert len(xtrigger_mgr.active) == 0