Example #1
0
 def test_def_trigger(self):
     """Test default trigger is :succeed."""
     gp1 = GraphParser()
     gp1.parse_graph("foo => bar")
     gp2 = GraphParser()
     gp2.parse_graph("foo:succeed => bar")
     self.assertEqual(gp1.triggers, gp2.triggers)
def test_family_trigger_equivalence(fam_map, fam_graph, member_graph):
    """Test family trigger semantics."""
    gp1 = GraphParser(fam_map)
    gp1.parse_graph(fam_graph)
    gp2 = GraphParser()
    gp2.parse_graph(member_graph)
    assert gp1.triggers == gp2.triggers
def test_line_continuation():
    """Test syntax-driven line continuation."""
    graph1 = "a => b => c"
    graph2 = """a =>
b => c"""
    graph3 = """a => b
=> c"""
    gp1 = GraphParser()
    gp1.parse_graph(graph1)
    gp2 = GraphParser()
    gp2.parse_graph(graph2)
    gp3 = GraphParser()
    gp3.parse_graph(graph3)
    res = {
        'a': {
            '': ([], False)
        },
        'c': {
            'b:succeeded': (['b:succeeded'], False)
        },
        'b': {
            'a:succeeded': (['a:succeeded'], False)
        }
    }
    assert res == gp1.triggers
    assert gp1.triggers == gp2.triggers
    assert gp1.triggers == gp3.triggers
    graph = """foo => bar
        a => b =>"""
    gp = GraphParser()
    pytest.raises(GraphParseError, gp.parse_graph, graph)
    graph = """ => a => b
        foo => bar"""
    gp = GraphParser()
    pytest.raises(GraphParseError, gp.parse_graph, graph)
Example #4
0
    def test_line_continuation(self):
        """Test syntax-driven line continuation."""
        graph1 = "a => b => c"
        graph2 = """a =>
 b => c"""
        graph3 = """a => b
 => c"""
        gp1 = GraphParser()
        gp1.parse_graph(graph1)
        gp2 = GraphParser()
        gp2.parse_graph(graph2)
        gp3 = GraphParser()
        gp3.parse_graph(graph3)
        res = {
            'a': {
                '': ([], False)
            },
            'c': {
                'b:succeed': (['b:succeed'], False)
            },
            'b': {
                'a:succeed': (['a:succeed'], False)
            }
        }
        self.assertEqual(gp1.triggers, res)
        self.assertEqual(gp1.triggers, gp2.triggers)
        self.assertEqual(gp1.triggers, gp3.triggers)
        graph = """foo => bar
            a => b =>"""
        gp = GraphParser()
        self.assertRaises(GraphParseError, gp.parse_graph, graph)
        graph = """ => a => b
            foo => bar"""
        gp = GraphParser()
        self.assertRaises(GraphParseError, gp.parse_graph, graph)
Example #5
0
 def test_finish_trigger(self):
     """Test finish trigger expansion."""
     gp1 = GraphParser()
     gp1.parse_graph("foo:finish => bar")
     gp2 = GraphParser()
     gp2.parse_graph("(foo:succeed | foo:fail) => bar")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #6
0
 def test_double_oper(self):
     """Test that illegal forms of the logical operators are detected."""
     graph = "foo && bar => baz"
     gp = GraphParser()
     self.assertRaises(GraphParseError, gp.parse_graph, graph)
     graph = "foo || bar => baz"
     gp = GraphParser()
     self.assertRaises(GraphParseError, gp.parse_graph, graph)
Example #7
0
 def test_fam_any_to_one(self):
     """Test family any-to-one semantics."""
     fam_map = {'FAM': ['m1', 'm2']}
     gp1 = GraphParser(fam_map)
     gp1.parse_graph("FAM:succeed-any => post")
     gp2 = GraphParser(fam_map)
     gp2.parse_graph("(m1 | m2) => post")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #8
0
 def test_fam_finish(self):
     """Test family finish semantics."""
     fam_map = {'FAM': ['m1', 'm2']}
     gp1 = GraphParser(fam_map)
     gp1.parse_graph("FAM:finish-all => post")
     gp2 = GraphParser(fam_map)
     gp2.parse_graph("""
         ((m1:succeed | m1:fail) & (m2:succeed | m2:fail)) => post""")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #9
0
 def test_repeat_trigger(self):
     """Test that repeating a trigger has no effect."""
     gp1 = GraphParser()
     gp2 = GraphParser()
     gp1.parse_graph("foo => bar")
     gp2.parse_graph("""
         foo => bar
         foo => bar""")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #10
0
 def test_fam_all_to_all(self):
     """Test family all-to-all semantics."""
     fam_map = {'FAM': ['m1', 'm2'], 'BAM': ['b1', 'b2']}
     gp1 = GraphParser(fam_map)
     gp1.parse_graph("FAM:succeed-all => BAM")
     gp2 = GraphParser(fam_map)
     gp2.parse_graph("""
         (m1 & m2) => b1
         (m1 & m2) => b2""")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #11
0
 def test_chain_stripping(self):
     """Test that trigger type is stripped off right-side nodes."""
     gp1 = GraphParser()
     gp1.parse_graph("""
     bar
     foo => bar:succeed => baz""")
     gp2 = GraphParser()
     gp2.parse_graph("""
         foo => bar
         bar:succeed => baz""")
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #12
0
    def test_fam_any_to_all(self):
        """Test family any-to-all semantics."""
        fam_map = {'FAM': ['m1', 'm2'], 'BAM': ['b1', 'b2']}
        gp1 = GraphParser(fam_map)
        gp1.parse_graph("FAM:fail-any => BAM")

        gp2 = GraphParser(fam_map)
        gp2.parse_graph("""
            (m1:fail | m2:fail) => b1
            (m1:fail | m2:fail) => b2""")
        self.assertEqual(gp1.triggers, gp2.triggers)
Example #13
0
 def test_fam_one_to_all(self):
     """Test family one-to-all semantics."""
     fam_map = {'FAM': ['m1', 'm2']}
     gp1 = GraphParser(fam_map)
     gp1.parse_graph("pre => FAM")
     gp2 = GraphParser(fam_map)
     gp2.parse_graph("""
         pre => m1
         pre => m2
         """)
     self.assertEqual(gp1.triggers, gp2.triggers)
Example #14
0
 def test_parameter_offset(self):
     """Test graph parameter expansion with an offset."""
     params = {'i': ['0', '1'], 'j': ['0', '1', '2']}
     templates = {'i': '_i%(i)s', 'j': '_j%(j)s'}
     gp1 = GraphParser(family_map=None, parameters=(params, templates))
     gp1.parse_graph("bar<i-1,j> => baz<i,j>")
     gp2 = GraphParser()
     gp2.parse_graph("""
        bar_i0_j0 => baz_i1_j0
        bar_i0_j1 => baz_i1_j1
        bar_i0_j2 => baz_i1_j2""")
     self.assertEqual(gp1.triggers, gp2.triggers)
def test_parameter_specific():
    """Test graph parameter expansion with a specific value."""
    params = {'i': ['0', '1'], 'j': ['0', '1', '2']}
    templates = {'i': '_i%(i)s', 'j': '_j%(j)s'}
    gp1 = GraphParser(family_map=None, parameters=(params, templates))
    gp1.parse_graph("bar<i-1,j> => baz<i,j>\nfoo<i=1,j> => qux")
    gp2 = GraphParser()
    gp2.parse_graph("""
       foo_i1_j0 => qux
       foo_i1_j1 => qux
       foo_i1_j2 => qux
       bar_i0_j0 => baz_i1_j0
       bar_i0_j1 => baz_i1_j1
       bar_i0_j2 => baz_i1_j2""")
    assert gp1.triggers == gp2.triggers
def test_graph_syntax_errors_2(seq, graph, expected_err):
    """Test various graph syntax errors."""
    graph = graph.format(seq)
    expected_err = expected_err.format(seq)
    with pytest.raises(GraphParseError) as cm:
        GraphParser().parse_graph(graph)
    assert (expected_err in str(cm.value))
def test_parse_graph_with_parameters():
    """Test parsing graphs with parameters."""
    parameterized_parser = GraphParser(None, ({
        'city': ['la_paz']
    }, {
        'city': '_%(city)s'
    }))
    parameterized_parser.parse_graph('a => b<city>')
    original = parameterized_parser.original
    triggers = parameterized_parser.triggers
    families = parameterized_parser.family_map
    assert (original == {
        'a': {
            '': ''
        },
        'b_la_paz': {
            'a:succeeded': 'a:succeeded'
        }
    })
    assert (triggers == {
        'a': {
            '': ([], False)
        },
        'b_la_paz': {
            'a:succeeded': (['a:succeeded'], False)
        }
    })
    assert not families
def test_spaces_between_tasks_fails():
    """Test that <task> <task> is rejected (i.e. no & or | in between)"""
    gp = GraphParser()
    pytest.raises(GraphParseError, gp.parse_graph, "foo bar=> baz")
    pytest.raises(GraphParseError, gp.parse_graph, "foo&bar=> ba z")
    pytest.raises(GraphParseError, gp.parse_graph, "foo 123=> bar")
    pytest.raises(GraphParseError, gp.parse_graph, "foo - 123 baz=> bar")
Example #19
0
 def test_parse_graph_with_invalid_parameters(self):
     """Test parsing graphs with invalid parameters."""
     parameterized_parser = GraphParser(
         None, ({'city': ['la_paz']}, {'city': '_%(city)s'}))
     with self.assertRaises(ParamExpandError):
         # no state in the parameters list
         parameterized_parser.parse_graph('a => b<state>')
Example #20
0
 def test_parse_graph_with_parameters(self):
     """Test parsing graphs with parameters."""
     parameterized_parser = GraphParser(None, ({
         'city': ['la_paz']
     }, {
         'city': '_%(city)s'
     }))
     parameterized_parser.parse_graph('a => b<city>')
     original = parameterized_parser.original
     triggers = parameterized_parser.triggers
     families = parameterized_parser.family_map
     self.assertEqual(
         {
             'a': {
                 '': ''
             },
             'b_la_paz': {
                 'a:succeed': 'a:succeed'
             }
         }, original)
     self.assertEqual(
         {
             'a': {
                 '': ([], False)
             },
             'b_la_paz': {
                 'a:succeed': (['a:succeed'], False)
             }
         }, triggers)
     self.assertEqual({}, families)
def test_parse_graph_simple_with_break_line_01(graph, expect):
    """Test parsing graphs."""
    parser = GraphParser()
    parser.parse_graph(graph)
    assert parser.original == expect.original
    assert parser.triggers == expect.triggers
    assert not parser.family_map
Example #22
0
    def test_bad_node_syntax(self):
        """Test that badly formatted graph nodes are detected.

        The correct format is:
          NAME(<PARAMS>)([CYCLE-POINT-OFFSET])(:TRIGGER-TYPE)")
        """
        params = {'m': ['0', '1'], 'n': ['0', '1']}
        templates = {'m': '_m%(m)s', 'n': '_n%(n)s'}
        gp = GraphParser(parameters=(params, templates))
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo[-P1Y]<m,n> => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo:fail<m,n> => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo:fail[-P1Y] => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo[-P1Y]:fail<m,n> => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo[-P1Y]<m,n>:fail => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo<m,n>:fail[-P1Y] => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo:fail<m,n>[-P1Y] => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "<m,n>:fail[-P1Y] => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "[-P1Y]<m,n> => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "[-P1Y]<m,n>:fail => bar")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "bar => foo:fail<m,n>[-P1Y]")
        self.assertRaises(GraphParseError, gp.parse_graph,
                          "foo[-P1Y]baz => bar")
Example #23
0
 def test_spaces_between_parameters_fails(self):
     """Test that <param param> are rejected (i.e. no comma)"""
     gp = GraphParser()
     self.assertRaises(GraphParseError, gp.parse_graph, "<foo bar> => baz")
     self.assertRaises(GraphParseError, gp.parse_graph,
                       "<foo=a _bar> => baz")
     self.assertRaises(GraphParseError, gp.parse_graph,
                       "<foo=a_ bar> => baz")
def test_parse_graph_fails_with_continuation_at_last_line(expect):
    """Fails if last line contains a continuation char.
    """
    parser = GraphParser()
    with pytest.raises(GraphParseError) as raised:
        parser.parse_graph(f't1 => t2 {expect}')
    assert isinstance(raised.value, GraphParseError)
    assert f'Dangling {expect}' in raised.value.args[0]
def test_family_trigger_errors(graph, error):
    """Test errors via bad family triggers and member output optionality."""
    fam_map = {'FAM': ['f1', 'f2']}
    gp = GraphParser(fam_map)

    with pytest.raises(GraphParseError) as cm:
        gp.parse_graph(graph)
    assert error in str(cm.value)
Example #26
0
 def test_param_expand_graph_parser(self):
     """Test to validate that the graph parser removes out-of-edge nodes:
     https://github.com/cylc/cylc-flow/pull/3452#issuecomment-677165000"""
     params = {'m': ["cat"]}
     templates = {'m': '_%(m)s'}
     gp = GraphParser(parameters=(params, templates))
     gp.parse_graph("foo => bar<m-1> => baz")
     triggers = {'foo': {'': ([], False)}}
     self.assertEqual(gp.triggers, triggers)
Example #27
0
 def test_spaces_in_trigger_fails(self):
     """Test that 'task:a- b' are rejected"""
     gp = GraphParser()
     self.assertRaises(GraphParseError, gp.parse_graph,
                       "FOO:custom -trigger => baz")
     self.assertRaises(GraphParseError, gp.parse_graph,
                       "FOO:custom- trigger => baz")
     self.assertRaises(GraphParseError, gp.parse_graph,
                       "FOO:custom - trigger => baz")
def test_parse_graph_fails_with_too_many_continuations(before, after):
    """Fails if one line ends with continuation char and the next line
    _also_ starts with one.
    """
    parser = GraphParser()
    with pytest.raises(GraphParseError) as raised:
        parser.parse_graph(f'foo & bar {before}\n{after}baz')
    assert isinstance(raised.value, GraphParseError)
    assert 'Consecutive lines end and start' in raised.value.args[0]
Example #29
0
 def test_spaces_between_parameters_passes(cls):
     """Test that <param-1> works, with spaces around the -+ signs"""
     params = {'m': ['0', '1', '2']}
     templates = {'m': '_m%(m)s'}
     gp = GraphParser(parameters=(params, templates))
     gp.parse_graph("<m- 1> => <m>")
     gp.parse_graph("<m -1> => <m>")
     gp.parse_graph("<m - 1> => <m>")
     gp.parse_graph("<m+ 1> => <m>")
     gp.parse_graph("<m +1> => <m>")
     gp.parse_graph("<m + 1> => <m>")
def test_bad_node_syntax(graph):
    """Test that badly formatted graph nodes are detected.

    The correct format is:
      NAME(<PARAMS>)([CYCLE-POINT-OFFSET])(:TRIGGER-TYPE)")
    """
    params = {'m': ['0', '1'], 'n': ['0', '1']}
    templates = {'m': '_m%(m)s', 'n': '_n%(n)s'}
    gp = GraphParser(parameters=(params, templates))
    with pytest.raises(GraphParseError) as cm:
        gp.parse_graph(graph)
    assert "Bad graph node format" in str(cm.value)