~canonical-launchpad-branches/launchpad-buildd/trunk

« back to all changes in this revision

Viewing changes to lpbuildd/tests/test_sourcepackagerecipe.py

  • Committer: Colin Watson
  • Date: 2017-05-11 08:34:07 UTC
  • mfrom: (215.1.1 extended-snap-status)
  • Revision ID: cjwatson@canonical.com-20170511083407-2jvw6phrd50strdk
[r=wgrant] Record the branch revision used to build a snap and return it along with other XML-RPC status information (LP: #1679157).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2013-2018 Canonical Ltd.  This software is licensed under the
 
1
# Copyright 2013 Canonical Ltd.  This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
3
 
4
4
__metaclass__ = type
9
9
from textwrap import dedent
10
10
 
11
11
from testtools import TestCase
12
 
from testtools.deferredruntest import AsynchronousDeferredRunTest
13
 
from twisted.internet import defer
14
12
 
 
13
from lpbuildd.tests.fakeslave import FakeSlave
15
14
from lpbuildd.sourcepackagerecipe import (
16
15
    RETCODE_FAILURE_INSTALL_BUILD_DEPS,
17
16
    SourcePackageRecipeBuildManager,
18
17
    SourcePackageRecipeBuildState,
19
18
    )
20
 
from lpbuildd.tests.fakebuilder import FakeBuilder
21
 
from lpbuildd.tests.matchers import HasWaitingFiles
22
19
 
23
20
 
24
21
class MockBuildManager(SourcePackageRecipeBuildManager):
37
34
 
38
35
class TestSourcePackageRecipeBuildManagerIteration(TestCase):
39
36
    """Run SourcePackageRecipeBuildManager through its iteration steps."""
40
 
 
41
 
    run_tests_with = AsynchronousDeferredRunTest.make_factory(timeout=5)
42
 
 
43
37
    def setUp(self):
44
38
        super(TestSourcePackageRecipeBuildManagerIteration, self).setUp()
45
39
        self.working_dir = tempfile.mkdtemp()
46
40
        self.addCleanup(lambda: shutil.rmtree(self.working_dir))
47
 
        builder_dir = os.path.join(self.working_dir, 'builder')
 
41
        slave_dir = os.path.join(self.working_dir, 'slave')
48
42
        home_dir = os.path.join(self.working_dir, 'home')
49
 
        for dir in (builder_dir, home_dir):
 
43
        for dir in (slave_dir, home_dir):
50
44
            os.mkdir(dir)
51
 
        self.builder = FakeBuilder(builder_dir)
 
45
        self.slave = FakeSlave(slave_dir)
52
46
        self.buildid = '123'
53
 
        self.buildmanager = MockBuildManager(self.builder, self.buildid)
 
47
        self.buildmanager = MockBuildManager(self.slave, self.buildid)
54
48
        self.buildmanager.home = home_dir
55
 
        self.buildmanager._cachepath = self.builder._cachepath
 
49
        self.buildmanager._cachepath = self.slave._cachepath
56
50
        self.chrootdir = os.path.join(
57
51
            home_dir, 'build-%s' % self.buildid, 'chroot-autobuild')
58
52
 
60
54
        """Retrieve build manager's state."""
61
55
        return self.buildmanager._state
62
56
 
63
 
    @defer.inlineCallbacks
64
57
    def startBuild(self, git=False):
65
58
        # The build manager's iterate() kicks off the consecutive states
66
59
        # after INIT.
68
61
            'recipe_text': dedent("""\
69
62
                # bzr-builder format 0.2 deb-version {debupstream}-0~{revno}
70
63
                http://bazaar.launchpad.dev/~ppa-user/+junk/wakeonlan"""),
71
 
            'series': 'maverick',
72
64
            'suite': 'maverick',
73
65
            'ogrecomponent': 'universe',
74
66
            'author_name': 'Steve\u1234',
89
81
        # directly before BUILD_RECIPE.
90
82
        self.buildmanager._state = SourcePackageRecipeBuildState.UPDATE
91
83
 
92
 
        # BUILD_RECIPE: Run the builder's payload to build the source package.
93
 
        yield self.buildmanager.iterate(0)
 
84
        # BUILD_RECIPE: Run the slave's payload to build the source package.
 
85
        self.buildmanager.iterate(0)
94
86
        self.assertEqual(
95
87
            SourcePackageRecipeBuildState.BUILD_RECIPE, self.getState())
96
 
        expected_command = ['sharepath/bin/buildrecipe', 'buildrecipe']
 
88
        expected_command = [
 
89
            'sharepath/slavebin/buildrecipe', 'buildrecipe']
97
90
        if git:
98
91
            expected_command.append('--git')
99
92
        expected_command.extend([
104
97
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
105
98
        self.assertEqual(
106
99
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
107
 
        self.assertFalse(self.builder.wasCalled('chrootFail'))
 
100
        self.assertFalse(self.slave.wasCalled('chrootFail'))
108
101
 
109
 
    @defer.inlineCallbacks
110
102
    def test_iterate(self):
111
103
        # The build manager iterates a normal build from start to finish.
112
 
        yield self.startBuild()
 
104
        self.startBuild()
113
105
 
114
106
        log_path = os.path.join(self.buildmanager._cachepath, 'buildlog')
115
 
        with open(log_path, 'w') as log:
116
 
            log.write("I am a build log.")
 
107
        log = open(log_path, 'w')
 
108
        log.write("I am a build log.")
 
109
        log.close()
117
110
 
118
111
        changes_path = os.path.join(
119
112
            self.buildmanager.home, 'build-%s' % self.buildid,
120
113
            'foo_1_source.changes')
121
 
        with open(changes_path, 'w') as changes:
122
 
            changes.write("I am a changes file.")
 
114
        changes = open(changes_path, 'w')
 
115
        changes.write("I am a changes file.")
 
116
        changes.close()
123
117
 
124
118
        manifest_path = os.path.join(
125
119
            self.buildmanager.home, 'build-%s' % self.buildid, 'manifest')
126
 
        with open(manifest_path, 'w') as manifest:
127
 
            manifest.write("I am a manifest file.")
 
120
        manifest = open(manifest_path, 'w')
 
121
        manifest.write("I am a manifest file.")
 
122
        manifest.close()
128
123
 
129
124
        # After building the package, reap processes.
130
 
        yield self.buildmanager.iterate(0)
 
125
        self.buildmanager.iterate(0)
131
126
        expected_command = [
132
 
            'sharepath/bin/in-target', 'in-target', 'scan-for-processes',
133
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
 
127
            'sharepath/slavebin/scan-for-processes', 'scan-for-processes',
134
128
            self.buildid,
135
129
            ]
136
130
        self.assertEqual(
138
132
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
139
133
        self.assertNotEqual(
140
134
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
141
 
        self.assertFalse(self.builder.wasCalled('buildFail'))
142
 
        self.assertThat(self.builder, HasWaitingFiles.byEquality({
143
 
            'foo_1_source.changes': b'I am a changes file.',
144
 
            'manifest': b'I am a manifest file.',
145
 
            }))
 
135
        self.assertFalse(self.slave.wasCalled('buildFail'))
 
136
        self.assertEqual(
 
137
            [((changes_path,), {}), ((manifest_path,), {})],
 
138
            self.slave.addWaitingFile.calls)
146
139
 
147
140
        # Control returns to the DebianBuildManager in the UMOUNT state.
148
141
        self.buildmanager.iterateReap(self.getState(), 0)
149
142
        expected_command = [
150
 
            'sharepath/bin/in-target', 'in-target', 'umount-chroot',
151
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
152
 
            self.buildid,
 
143
            'sharepath/slavebin/umount-chroot', 'umount-chroot', self.buildid
153
144
            ]
154
145
        self.assertEqual(SourcePackageRecipeBuildState.UMOUNT, self.getState())
155
146
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
156
147
        self.assertEqual(
157
148
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
158
 
        self.assertFalse(self.builder.wasCalled('buildFail'))
 
149
        self.assertFalse(self.slave.wasCalled('buildFail'))
159
150
 
160
 
    @defer.inlineCallbacks
161
151
    def test_iterate_BUILD_RECIPE_install_build_deps_depfail(self):
162
152
        # The build manager can detect dependency wait states.
163
 
        yield self.startBuild()
 
153
        self.startBuild()
164
154
 
165
155
        log_path = os.path.join(self.buildmanager._cachepath, 'buildlog')
166
 
        with open(log_path, 'w') as log:
167
 
            log.write(
168
 
                "The following packages have unmet dependencies:\n"
169
 
                " pbuilder-satisfydepends-dummy :"
170
 
                " Depends: base-files (>= 1000)"
171
 
                " but it is not going to be installed.\n")
 
156
        log = open(log_path, 'w')
 
157
        log.write(
 
158
            "The following packages have unmet dependencies:\n"
 
159
            " pbuilder-satisfydepends-dummy : Depends: base-files (>= 1000)"
 
160
            " but it is not going to be installed.\n")
 
161
        log.close()
172
162
 
173
163
        # The buildmanager calls depFail correctly and reaps processes.
174
 
        yield self.buildmanager.iterate(RETCODE_FAILURE_INSTALL_BUILD_DEPS)
 
164
        self.buildmanager.iterate(RETCODE_FAILURE_INSTALL_BUILD_DEPS)
175
165
        expected_command = [
176
 
            'sharepath/bin/in-target', 'in-target', 'scan-for-processes',
177
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
 
166
            'sharepath/slavebin/scan-for-processes', 'scan-for-processes',
178
167
            self.buildid,
179
168
            ]
180
169
        self.assertEqual(
182
171
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
183
172
        self.assertNotEqual(
184
173
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
185
 
        self.assertFalse(self.builder.wasCalled('buildFail'))
 
174
        self.assertFalse(self.slave.wasCalled('buildFail'))
186
175
        self.assertEqual(
187
 
            [(("base-files (>= 1000)",), {})], self.builder.depFail.calls)
 
176
            [(("base-files (>= 1000)",), {})], self.slave.depFail.calls)
188
177
 
189
178
        # Control returns to the DebianBuildManager in the UMOUNT state.
190
179
        self.buildmanager.iterateReap(self.getState(), 0)
191
180
        expected_command = [
192
 
            'sharepath/bin/in-target', 'in-target', 'umount-chroot',
193
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
194
 
            self.buildid,
 
181
            'sharepath/slavebin/umount-chroot', 'umount-chroot', self.buildid,
195
182
            ]
196
183
        self.assertEqual(SourcePackageRecipeBuildState.UMOUNT, self.getState())
197
184
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
198
185
        self.assertEqual(
199
186
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
200
 
        self.assertFalse(self.builder.wasCalled('buildFail'))
 
187
        self.assertFalse(self.slave.wasCalled('buildFail'))
201
188
 
202
 
    @defer.inlineCallbacks
203
189
    def test_iterate_BUILD_RECIPE_install_build_deps_buildfail(self):
204
190
        # If the build manager cannot detect a dependency wait from a
205
191
        # build-dependency installation failure, it fails the build.
206
 
        yield self.startBuild()
 
192
        self.startBuild()
207
193
 
208
194
        log_path = os.path.join(self.buildmanager._cachepath, 'buildlog')
209
 
        with open(log_path, 'w') as log:
210
 
            log.write("I am a failing build log.")
 
195
        log = open(log_path, 'w')
 
196
        log.write("I am a failing build log.")
 
197
        log.close()
211
198
 
212
199
        # The buildmanager calls buildFail correctly and reaps processes.
213
 
        yield self.buildmanager.iterate(RETCODE_FAILURE_INSTALL_BUILD_DEPS)
 
200
        self.buildmanager.iterate(RETCODE_FAILURE_INSTALL_BUILD_DEPS)
214
201
        expected_command = [
215
 
            'sharepath/bin/in-target', 'in-target', 'scan-for-processes',
216
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
 
202
            'sharepath/slavebin/scan-for-processes', 'scan-for-processes',
217
203
            self.buildid,
218
204
            ]
219
205
        self.assertEqual(
221
207
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
222
208
        self.assertNotEqual(
223
209
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
224
 
        self.assertTrue(self.builder.wasCalled('buildFail'))
225
 
        self.assertFalse(self.builder.wasCalled('depFail'))
 
210
        self.assertTrue(self.slave.wasCalled('buildFail'))
 
211
        self.assertFalse(self.slave.wasCalled('depFail'))
226
212
 
227
213
        # Control returns to the DebianBuildManager in the UMOUNT state.
228
214
        self.buildmanager.iterateReap(self.getState(), 0)
229
215
        expected_command = [
230
 
            'sharepath/bin/in-target', 'in-target', 'umount-chroot',
231
 
            '--backend=chroot', '--series=maverick', '--arch=i386',
232
 
            self.buildid,
 
216
            'sharepath/slavebin/umount-chroot', 'umount-chroot', self.buildid,
233
217
            ]
234
218
        self.assertEqual(SourcePackageRecipeBuildState.UMOUNT, self.getState())
235
219
        self.assertEqual(expected_command, self.buildmanager.commands[-1])
236
220
        self.assertEqual(
237
221
            self.buildmanager.iterate, self.buildmanager.iterators[-1])
238
222
 
239
 
    @defer.inlineCallbacks
240
223
    def test_iterate_git(self):
241
224
        # Starting a git-based recipe build passes the correct option.  (The
242
225
        # rest of the build is identical to bzr-based recipe builds from the
243
226
        # build manager's point of view.)
244
 
        yield self.startBuild(git=True)
 
227
        self.startBuild(git=True)