summaryrefslogtreecommitdiff
path: root/tests/integration/pullbuildtrees.py
blob: 0f939725114e56a1eee14455e104004db852f123 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import os
import shutil
import pytest

from tests.testutils import cli_integration as cli, create_artifact_share
from tests.testutils.integration import assert_contains
from tests.testutils.site import HAVE_BWRAP, IS_LINUX
from buildstream._exceptions import ErrorDomain, LoadErrorReason


DATA_DIR = os.path.join(
    os.path.dirname(os.path.realpath(__file__)),
    "project"
)


# Remove artifact cache & set cli.config value of pull-buildtrees
# to false, which is the default user context. The cache has to be
# cleared as just forcefully removing the refpath leaves dangling objects.
def default_state(cli, tmpdir, share):
    shutil.rmtree(os.path.join(str(tmpdir), 'artifacts'))
    cli.configure({
        'artifacts': {'url': share.repo, 'push': False},
        'artifactdir': os.path.join(str(tmpdir), 'artifacts'),
        'cache': {'pull-buildtrees': False},
    })


# A test to capture the integration of the pullbuildtrees
# behaviour, which by default is to not include the buildtree
# directory of an element.
@pytest.mark.integration
@pytest.mark.datafiles(DATA_DIR)
@pytest.mark.skipif(IS_LINUX and not HAVE_BWRAP, reason='Only available with bubblewrap on Linux')
def test_pullbuildtrees(cli, tmpdir, datafiles, integration_cache):
    project = os.path.join(datafiles.dirname, datafiles.basename)
    element_name = 'autotools/amhello.bst'

    # Create artifact shares for pull & push testing
    with create_artifact_share(os.path.join(str(tmpdir), 'share1')) as share1,\
        create_artifact_share(os.path.join(str(tmpdir), 'share2')) as share2:
        cli.configure({
            'artifacts': {'url': share1.repo, 'push': True},
            'artifactdir': os.path.join(str(tmpdir), 'artifacts')
        })

        # Build autotools element, checked pushed, delete local
        result = cli.run(project=project, args=['build', element_name])
        assert result.exit_code == 0
        assert cli.get_element_state(project, element_name) == 'cached'
        assert share1.has_artifact('test', element_name, cli.get_element_key(project, element_name))
        default_state(cli, tmpdir, share1)

        # Pull artifact with default config, assert that pulling again
        # doesn't create a pull job, then assert with buildtrees user
        # config set creates a pull job.
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name in result.get_pulled_elements()
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name not in result.get_pulled_elements()
        cli.configure({'cache': {'pull-buildtrees': True}})
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name in result.get_pulled_elements()
        default_state(cli, tmpdir, share1)

        # Pull artifact with default config, then assert that pulling
        # with buildtrees cli flag set creates a pull job.
        # Also assert that the buildtree is added to the artifact's
        # extract dir
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name in result.get_pulled_elements()
        elementdigest = share1.has_artifact('test', element_name, cli.get_element_key(project, element_name))
        buildtreedir = os.path.join(str(tmpdir), 'artifacts', 'extract', 'test', 'autotools-amhello',
                                    elementdigest.hash, 'buildtree')
        assert not os.path.isdir(buildtreedir)
        result = cli.run(project=project, args=['--pull-buildtrees', 'pull', element_name])
        assert element_name in result.get_pulled_elements()
        assert os.path.isdir(buildtreedir)
        default_state(cli, tmpdir, share1)

        # Pull artifact with pullbuildtrees set in user config, then assert
        # that pulling with the same user config doesn't creates a pull job,
        # or when buildtrees cli flag is set.
        cli.configure({'cache': {'pull-buildtrees': True}})
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name in result.get_pulled_elements()
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name not in result.get_pulled_elements()
        result = cli.run(project=project, args=['--pull-buildtrees', 'pull', element_name])
        assert element_name not in result.get_pulled_elements()
        default_state(cli, tmpdir, share1)

        # Pull artifact with default config and buildtrees cli flag set, then assert
        # that pulling with pullbuildtrees set in user config doesn't create a pull
        # job.
        result = cli.run(project=project, args=['--pull-buildtrees', 'pull', element_name])
        assert element_name in result.get_pulled_elements()
        cli.configure({'cache': {'pull-buildtrees': True}})
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name not in result.get_pulled_elements()
        default_state(cli, tmpdir, share1)

        # Assert that a partial build element (not containing a populated buildtree dir)
        # can't be pushed to an artifact share, then assert that a complete build element
        # can be. This will attempt a partial pull from share1 and then a partial push
        # to share2
        result = cli.run(project=project, args=['pull', element_name])
        assert element_name in result.get_pulled_elements()
        cli.configure({'artifacts': {'url': share2.repo, 'push': True}})
        result = cli.run(project=project, args=['push', element_name])
        assert element_name not in result.get_pushed_elements()
        assert not share2.has_artifact('test', element_name, cli.get_element_key(project, element_name))

        # Assert that after pulling the missing buildtree the element artifact can be
        # successfully pushed to the remote. This will attempt to pull the buildtree
        # from share1 and then a 'complete' push to share2
        cli.configure({'artifacts': {'url': share1.repo, 'push': False}})
        result = cli.run(project=project, args=['--pull-buildtrees', 'pull', element_name])
        assert element_name in result.get_pulled_elements()
        cli.configure({'artifacts': {'url': share2.repo, 'push': True}})
        result = cli.run(project=project, args=['push', element_name])
        assert element_name in result.get_pushed_elements()
        assert share2.has_artifact('test', element_name, cli.get_element_key(project, element_name))
        default_state(cli, tmpdir, share1)


# Ensure that only valid pull-buildtrees boolean options make it through the loading
# process.
@pytest.mark.parametrize("value,success", [
    (True, True),
    (False, True),
    ("pony", False),
    ("1", False)
])
@pytest.mark.datafiles(DATA_DIR)
def test_invalid_cache_pullbuildtrees(cli, datafiles, tmpdir, value, success):
    project = os.path.join(datafiles.dirname, datafiles.basename)

    cli.configure({
        'cache': {
            'pull-buildtrees': value,
        }
    })

    res = cli.run(project=project, args=['workspace', 'list'])
    if success:
        res.assert_success()
    else:
        res.assert_main_error(ErrorDomain.LOAD, LoadErrorReason.ILLEGAL_COMPOSITE)