summaryrefslogtreecommitdiff
path: root/tests/frontend/overlaps.py
blob: 77e9a82c9c71745f6456bcccf8cdfe3b381216af (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Pylint doesn't play well with fixtures and dependency injection from pytest
# pylint: disable=redefined-outer-name

import os
import pytest
from buildstream.testing.runcli import cli  # pylint: disable=unused-import
from buildstream.exceptions import ErrorDomain, LoadErrorReason
from buildstream import _yaml
from buildstream.plugin import CoreWarnings
from tests.testutils import generate_junction

# Project directory
DATA_DIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "overlaps")


def gen_project(project_dir, fatal_warnings, *, project_name="test"):
    template = {"name": project_name, "min-version": "2.0"}
    template["fatal-warnings"] = [CoreWarnings.OVERLAPS, CoreWarnings.UNSTAGED_FILES] if fatal_warnings else []
    projectfile = os.path.join(project_dir, "project.conf")
    _yaml.roundtrip_dump(template, projectfile)


@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("error", [False, True], ids=["warning", "error"])
def test_unstaged_files(cli, datafiles, error):
    project_dir = str(datafiles)
    gen_project(project_dir, error)
    result = cli.run(project=project_dir, silent=True, args=["build", "unstaged.bst"])
    if error:
        result.assert_main_error(ErrorDomain.STREAM, None)
        result.assert_task_error(ErrorDomain.PLUGIN, CoreWarnings.UNSTAGED_FILES)
    else:
        result.assert_success()
        assert "WARNING [unstaged-files]" in result.stderr


@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("error", [False, True], ids=["warning", "error"])
def test_overlaps(cli, datafiles, error):
    project_dir = str(datafiles)
    gen_project(project_dir, error)
    result = cli.run(project=project_dir, silent=True, args=["build", "collect.bst"])
    if error:
        result.assert_main_error(ErrorDomain.STREAM, None)
        result.assert_task_error(ErrorDomain.PLUGIN, CoreWarnings.OVERLAPS)
    else:
        result.assert_success()
        assert "WARNING [overlaps]" in result.stderr


#
# When the overlap is whitelisted, there is no warning or error.
#
# Still test this in fatal/nonfatal warning modes
#
@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("error", [False, True], ids=["warning", "error"])
def test_overlaps_whitelisted(cli, datafiles, error):
    project_dir = str(datafiles)
    gen_project(project_dir, error)
    result = cli.run(project=project_dir, silent=True, args=["build", "collect-whitelisted.bst"])
    result.assert_success()
    assert "WARNING [overlaps]" not in result.stderr


@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("error", [False, True], ids=["warning", "error"])
def test_overlaps_whitelist_on_overlapper(cli, datafiles, error):
    # Tests that the overlapping element is responsible for whitelisting,
    # i.e. that if A overlaps B overlaps C, and the B->C overlap is permitted,
    # it'll still fail because A doesn't permit overlaps.
    project_dir = str(datafiles)
    gen_project(project_dir, error)
    result = cli.run(project=project_dir, silent=True, args=["build", "collect-partially-whitelisted.bst"])
    if error:
        result.assert_main_error(ErrorDomain.STREAM, None)
        result.assert_task_error(ErrorDomain.PLUGIN, CoreWarnings.OVERLAPS)
    else:
        result.assert_success()
        assert "WARNING [overlaps]" in result.stderr


@pytest.mark.datafiles(DATA_DIR)
def test_overlaps_whitelist_undefined_variable(cli, datafiles):
    project_dir = str(datafiles)
    gen_project(project_dir, False)
    result = cli.run(project=project_dir, silent=True, args=["show", "whitelist-undefined.bst"])

    # Assert that we get the expected undefined variable error,
    # and that it has the provenance we expect from whitelist-undefined.bst
    #
    result.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.UNRESOLVED_VARIABLE)
    assert "whitelist-undefined.bst [line 13 column 6]" in result.stderr


@pytest.mark.datafiles(DATA_DIR)
def test_overlaps_script(cli, datafiles):
    # Test overlaps with script element to test
    # Element.stage_dependency_artifacts() with Scope.RUN
    project_dir = str(datafiles)
    gen_project(project_dir, False)
    result = cli.run(project=project_dir, silent=True, args=["build", "script.bst"])
    result.assert_success()


@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.parametrize("project_policy", [("fail"), ("warn")])
@pytest.mark.parametrize("subproject_policy", [("fail"), ("warn")])
def test_overlap_subproject(cli, tmpdir, datafiles, project_policy, subproject_policy):
    project_dir = str(datafiles)
    subproject_dir = os.path.join(project_dir, "sub-project")
    junction_path = os.path.join(project_dir, "sub-project.bst")

    gen_project(project_dir, bool(project_policy == "fail"), project_name="test")
    gen_project(subproject_dir, bool(subproject_policy == "fail"), project_name="subtest")
    generate_junction(tmpdir, subproject_dir, junction_path)

    # Here we have a dependency chain where the project element
    # always overlaps with the subproject element.
    #
    # Test that overlap error vs warning policy for this overlap
    # is always controlled by the project and not the subproject.
    #
    result = cli.run(project=project_dir, silent=True, args=["build", "sub-collect.bst"])
    if project_policy == "fail":
        result.assert_main_error(ErrorDomain.STREAM, None)
        result.assert_task_error(ErrorDomain.PLUGIN, CoreWarnings.OVERLAPS)
    else:
        result.assert_success()
        assert "WARNING [overlaps]" in result.stderr