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, FlowLabelMgr().get_new_label()) # 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__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_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, FlowLabelMgr().get_new_label()) 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 itask2 = TaskProxy(tdef2, start_point, FlowLabelMgr().get_new_label()) 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_check_xtriggers(xtrigger_mgr): """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.validate_xtrigger = lambda *a, **k: True # Ignore validation # 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, 'fdir') get_name.out = "[\"True\", {\"name\": \"Yossarian\"}]" tdef1 = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1) init() sequence = ISO8601Sequence('P1D', '2019') tdef1.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask1 = TaskProxy(tdef1, start_point, FlowLabelMgr().get_new_label()) 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_trig("wall_clock", wall_clock, "fdir") # create a task tdef2 = TaskDef(name="foo", rtcfg=None, run_mode="live", start_point=1) tdef2.xtrig_labels[sequence] = ["wall_clock"] init() start_point = ISO8601Point('20000101T0000+05') # create task proxy itask2 = TaskProxy(tdef2, start_point, FlowLabelMgr().get_new_label()) xtrigger_mgr.check_xtriggers([itask1, itask2]) # 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(xtrigger_mgr): """Test that collate properly tallies the totals of current xtriggers.""" xtrigger_mgr.validate_xtrigger = lambda *a, **k: True # Ignore validation 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) init() sequence = ISO8601Sequence('P1D', '20190101T00Z') tdef.xtrig_labels[sequence] = ["get_name"] start_point = ISO8601Point('2019') itask = TaskProxy(tdef, start_point, FlowLabelMgr().get_new_label()) 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) tdef.xtrig_labels[sequence] = ["wall_clock"] start_point = ISO8601Point('20000101T0000+05') # create task proxy itask = TaskProxy(tdef, start_point, FlowLabelMgr().get_new_label()) xtrigger_mgr.collate([itask]) assert not xtrigger_mgr.all_xtrig
def main(_, options, reg): """cylc validate CLI.""" profiler = Profiler(None, options.profile_mode) profiler.start() if not cylc.flow.flags.debug: # for readability omit timestamps from logging unless in debug mode for handler in LOG.handlers: if isinstance(handler.formatter, CylcLogFormatter): handler.formatter.configure(timestamp=False) suite, flow_file = parse_suite_arg(options, reg) cfg = SuiteConfig( suite, flow_file, options, load_template_vars(options.templatevars, options.templatevars_file), output_fname=options.output, mem_log_func=profiler.log_memory) # Check bounds of sequences out_of_bounds = [str(seq) for seq in cfg.sequences if seq.get_first_point(cfg.start_point) is None] if out_of_bounds: if len(out_of_bounds) > 1: # avoid spamming users with multiple warnings msg = ('multiple sequences out of bounds for initial cycle point ' '%s:\n%s' % ( cfg.start_point, '\n'.join(textwrap.wrap(', '.join(out_of_bounds), 70)))) else: msg = '%s: sequence out of bounds for initial cycle point %s' % ( out_of_bounds[0], cfg.start_point) if options.strict: LOG.warning(msg) elif cylc.flow.flags.verbose: sys.stderr.write(' + %s\n' % msg) # Instantiate tasks and force evaluation of trigger expressions. # (Taken from config.py to avoid circular import problems.) # TODO - This is not exhaustive, it only uses the initial cycle point. if cylc.flow.flags.verbose: print('Instantiating tasks to check trigger expressions') flow_label = FlowLabelMgr().get_new_label() for name, taskdef in cfg.taskdefs.items(): try: itask = TaskProxy(taskdef, cfg.start_point, flow_label) except TaskProxySequenceBoundsError: # Should already failed above in strict mode. mesg = 'Task out of bounds for %s: %s\n' % (cfg.start_point, name) if cylc.flow.flags.verbose: sys.stderr.write(' + %s\n' % mesg) continue except Exception as exc: raise SuiteConfigError( 'failed to instantiate task %s: %s' % (name, exc)) # force trigger evaluation now try: itask.state.prerequisites_eval_all() except TriggerExpressionError as exc: err = str(exc) if '@' in err: print(f"ERROR, {name}: xtriggers can't be in conditional" f" expressions: {err}", file=sys.stderr) else: print('ERROR, %s: bad trigger: %s' % (name, err), file=sys.stderr) raise SuiteConfigError("ERROR: bad trigger") except Exception as exc: print(str(exc), file=sys.stderr) raise SuiteConfigError( '%s: failed to evaluate triggers.' % name) if cylc.flow.flags.verbose: print(' + %s ok' % itask.identity) print(cparse('<green>Valid for cylc-%s</green>' % CYLC_VERSION)) profiler.stop()