def test_variables(): """Check that an action's variables are properly substituted.""" variable = feature('variable', attributes=incidental) class A(action): var = map(variable, join) command = 'echo $(var)' a = artefact('a', attrs=notfile | always) b = artefact('b', attrs=notfile | always) c = artefact('c', attrs=notfile | always) echo = action('echo', 'echo $(variable)') pye = action('pyecho', pyecho, ['variable']) a = rule(A(), a, features=variable('A')) b = rule(echo, b, a, features=variable('B')) c = rule(pye, c, b, features=variable('C')) with patch('faber.action.action.__status__') as recipe: assert a.update() (_, _, _, _, output, _), kwds = recipe.call_args_list[-1] assert output.strip() == 'A' assert b.update() (_, _, _, _, output, _), kwds = recipe.call_args_list[-1] assert output.strip() == 'B' assert c.update() (_, _, _, _, output, _), kwds = recipe.call_args_list[-1] assert output.strip() == "c <- b (variable=['C'])"
def test_implicit_rule(): a1 = action('a1', 'something') a2 = action('a2', 'something') a3 = action('a3', 'something') c_ = artefact('c', type=c) cc = artefact('cc', type=cxx) o = artefact('o', type=obj) l = artefact('l', type=lib) assembly.implicit_rule(a1, obj, c) assembly.implicit_rule(a2, obj, cxx) assembly.implicit_rule(a3, lib, obj) with patch('faber.assembly.explicit_rule') as rule: assembly.rule(o, c_) assembly.rule(o, cc) assert rule.call_count == 2 assert (rule.call_args_list[0][0][0] is a1 and rule.call_args_list[0][0][1] is o) assert (rule.call_args_list[1][0][0] is a2 and rule.call_args_list[1][0][1] is o) with patch('faber.assembly.explicit_rule') as rule: assembly.rule(l, cc) assert rule.call_count == 2 assert (rule.call_args_list[0][0][0] is a2 and rule.call_args_list[0][1]['attrs'] & intermediate) assert (rule.call_args_list[1][0][0] is a3 and rule.call_args_list[1][0][1] is l)
def test_call(): a = action() b = artefact('b', attrs=notfile) c = artefact('c', attrs=notfile) with pytest.raises(ValueError) as e: a(b, c) assert 'not implemented' in str(e.value) with capture_output() as (out, err): a = action('echo', 'echo $(<)') a([b]) assert out.getvalue().strip() == 'test.b' assert err.getvalue() == ''
def test_outcome(): passing = rule(action('true', 'echo 1'), 'passing', attrs=always | notfile) failing = rule(action('false', 'unknown'), 'failing', attrs=always | notfile) test1 = test('test1', passing) test2 = test('test2', failing) test3 = test('test3', passing, expected=fail) test4 = test('test4', failing, expected=fail) assert not scheduler.update([test1, test2, test3, test4]) assert test1.outcome == pass_ assert test2.outcome == fail assert test3.outcome == xpass assert test4.outcome == xfail
def test_report(): passing = rule(action('true', 'echo 1'), 'passing', attrs=always | notfile) failing = rule(action('false', 'unknown'), 'failing', attrs=always | notfile) test1 = test('t1', passing) test2 = test('t2', failing) test3 = test('t3', passing, expected=fail) test4 = test('t4', failing, expected=fail) test5 = test('t5', failing, condition=False) r = report('report', [test1, test2, test3, test4, test5]) assert scheduler.update(r) assert test1.outcome == pass_ assert test2.outcome == fail assert test3.outcome == xpass assert test4.outcome == xfail assert test5.outcome is None
def test_cycle(): """Test that the scheduler detects dependency cycles.""" echo = action('echo', 'echo $(<) $(>)') a = artefact('a', attrs=notfile | always) b = rule(echo, 'b', a, attrs=notfile) with pytest.raises(scheduler.DependencyError): a = rule(echo, a, b)
def test_fail(): """Check that an artefact won't be updated if a dependent artefact's recipe failed.""" a = artefact('a', attrs=notfile | always) b = artefact('b', attrs=notfile) fail = action('failing', 'fail') a = rule(fail, a) b = rule(pyecho, b, a) with patch('faber.scheduler._report_recipe'): assert not scheduler.update(b)
def test_nocare(): """Check that an artefact will be updated if a dependent artefact's recipe failed but was marked as nocare.""" a = artefact('a', attrs=notfile | always | nocare) b = artefact('b', attrs=notfile) fail = action('failing', 'fail') a = rule(fail, a) b = rule(pyecho, b, a) with patch('faber.scheduler._report_recipe') as recipe: assert scheduler.update(b) (_, _, _, _, _, output, _), kwds = recipe.call_args_list[-1] assert output.strip() == 'b <- a'
def test_late_cycle(): """Test that the scheduler detects dependency cycles created in recipes.""" a = artefact('a', attrs=notfile | always) b = artefact('b', attrs=notfile | always) c = artefact('c', attrs=notfile | always) def generator(targets, sources): depend(b, c) # create cycle ! b = rule(generator, b, a) echo = action('echo', 'echo $(<) $(>)') c = rule(echo, c, b) with pytest.raises(scheduler.DependencyError): assert scheduler.update(c)
def test_dynamic_dependencies(): """Test whether it's possible to add dependencies while the scheduler is already running.""" c = artefact('c', attrs=notfile) def inject_deps(self, *args, **kwds): d = rule(pyecho, 'd', attrs=notfile | always) depend(c, d) print('ddeps.b') a = rule(pyecho, 'a', attrs=notfile | always) b = rule(action('dg', inject_deps), 'b', a, attrs=notfile) c = rule(pyecho, c, b) with patch('faber.scheduler._report_recipe') as recipe: assert scheduler.update(b) (_, _, _, _, _, output, _), kwds = recipe.call_args_list[-1] assert output.strip() == 'ddeps.b' assert scheduler.update(c) # verify that d is actually updated before c output = [i[0][5].strip() for i in recipe.call_args_list] assert 'd <-' in output