~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/buildmaster/tests/test_buildbase.py

Merge with trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2010 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
 
4
 
from __future__ import with_statement
5
 
 
6
 
"""Tests for `IBuildBase`.
7
 
 
8
 
   XXX 2010-04-26 michael.nelson bug=567922.
9
 
   These tests should be moved into test_packagebuild when buildbase is
10
 
   deleted. For the moment, test_packagebuild inherits these tests to
11
 
   ensure the new classes pass too.
12
 
"""
13
 
__metaclass__ = type
14
 
 
15
 
from datetime import datetime
16
 
import os
17
 
 
18
 
from zope.security.proxy import removeSecurityProxy
19
 
 
20
 
from canonical.config import config
21
 
from canonical.database.constants import UTC_NOW
22
 
from canonical.testing.layers import LaunchpadZopelessLayer
23
 
from lp.buildmaster.interfaces.buildbase import BuildStatus
24
 
from lp.buildmaster.model.buildbase import BuildBase
25
 
from lp.registry.interfaces.pocket import pocketsuffix
26
 
from lp.soyuz.tests.soyuzbuilddhelpers import WaitingSlave
27
 
from lp.testing import TestCase
28
 
from lp.testing.fakemethod import FakeMethod
29
 
 
30
 
 
31
 
class TestBuildBaseMixin:
32
 
    """Tests for `IBuildBase`."""
33
 
 
34
 
    def test_getUploadDirLeaf(self):
35
 
        # getUploadDirLeaf returns the current time, followed by the build
36
 
        # cookie.
37
 
        now = datetime.now()
38
 
        build_cookie = self.factory.getUniqueString()
39
 
        upload_leaf = self.package_build.getUploadDirLeaf(
40
 
            build_cookie, now=now)
41
 
        self.assertEqual(
42
 
            '%s-%s' % (now.strftime("%Y%m%d-%H%M%S"), build_cookie),
43
 
            upload_leaf)
44
 
 
45
 
    def test_getUploadDir(self):
46
 
        # getUploadDir is the absolute path to the directory in which things
47
 
        # are uploaded to.
48
 
        build_cookie = self.factory.getUniqueInteger()
49
 
        upload_leaf = self.package_build.getUploadDirLeaf(build_cookie)
50
 
        upload_dir = self.package_build.getUploadDir(upload_leaf)
51
 
        self.assertEqual(
52
 
            os.path.join(config.builddmaster.root, 'incoming', upload_leaf),
53
 
            upload_dir)
54
 
 
55
 
 
56
 
class TestBuildBase(TestCase, TestBuildBaseMixin):
57
 
 
58
 
    def setUp(self):
59
 
        """Create the package build for testing."""
60
 
        super(TestBuildBase, self).setUp()
61
 
        self.package_build = BuildBase()
62
 
 
63
 
 
64
 
class TestGetUploadMethodsMixin:
65
 
    """Tests for `IBuildBase` that need objects from the rest of Launchpad."""
66
 
 
67
 
    layer = LaunchpadZopelessLayer
68
 
 
69
 
    def makeBuild(self):
70
 
        """Allow classes to override the build with which the test runs.
71
 
 
72
 
        XXX michaeln 2010-06-03 bug=567922
73
 
        Until buildbase is removed, we need to ensure these tests
74
 
        run against new IPackageBuild builds (BinaryPackageBuild)
75
 
        and the IBuildBase builds (SPRecipeBuild). They assume the build
76
 
        is successfully built and check that incorrect upload paths will
77
 
        set the status to FAILEDTOUPLOAD.
78
 
        """
79
 
        raise NotImplemented
80
 
 
81
 
    def setUp(self):
82
 
        super(TestGetUploadMethodsMixin, self).setUp()
83
 
        self.build = self.makeBuild()
84
 
 
85
 
    def test_getUploadLogContent_nolog(self):
86
 
        """If there is no log file there, a string explanation is returned.
87
 
        """
88
 
        self.useTempDir()
89
 
        self.assertEquals('Could not find upload log file',
90
 
            self.build.getUploadLogContent(os.getcwd(), "myleaf"))
91
 
 
92
 
    def test_getUploadLogContent_only_dir(self):
93
 
        """If there is a directory but no log file, expect the error string,
94
 
        not an exception."""
95
 
        self.useTempDir()
96
 
        os.makedirs("accepted/myleaf")
97
 
        self.assertEquals('Could not find upload log file',
98
 
            self.build.getUploadLogContent(os.getcwd(), "myleaf"))
99
 
 
100
 
    def test_getUploadLogContent_readsfile(self):
101
 
        """If there is a log file, return its contents."""
102
 
        self.useTempDir()
103
 
        os.makedirs("accepted/myleaf")
104
 
        with open('accepted/myleaf/uploader.log', 'w') as f:
105
 
            f.write('foo')
106
 
        self.assertEquals('foo',
107
 
            self.build.getUploadLogContent(os.getcwd(), "myleaf"))
108
 
 
109
 
    def test_getUploaderCommand(self):
110
 
        upload_leaf = self.factory.getUniqueString('upload-leaf')
111
 
        config_args = list(config.builddmaster.uploader.split())
112
 
        log_file = self.factory.getUniqueString('logfile')
113
 
        config_args.extend(
114
 
            ['--log-file', log_file,
115
 
             '-d', self.build.distribution.name,
116
 
             '-s', (self.build.distro_series.name
117
 
                    + pocketsuffix[self.build.pocket]),
118
 
             '-b', str(self.build.id),
119
 
             '-J', upload_leaf,
120
 
             '--context=%s' % self.build.policy_name,
121
 
             os.path.abspath(config.builddmaster.root),
122
 
             ])
123
 
        uploader_command = self.build.getUploaderCommand(
124
 
            self.build, upload_leaf, log_file)
125
 
        self.assertEqual(config_args, uploader_command)
126
 
 
127
 
 
128
 
class TestHandleStatusMixin:
129
 
    """Tests for `IBuildBase`s handleStatus method.
130
 
 
131
 
    Note: these tests do *not* test the updating of the build
132
 
    status to FULLYBUILT as this happens during the upload which
133
 
    is stubbed out by a mock function.
134
 
    """
135
 
 
136
 
    layer = LaunchpadZopelessLayer
137
 
 
138
 
    def makeBuild(self):
139
 
        """Allow classes to override the build with which the test runs.
140
 
 
141
 
        XXX michaeln 2010-06-03 bug=567922
142
 
        Until buildbase is removed, we need to ensure these tests
143
 
        run against new IPackageBuild builds (BinaryPackageBuild)
144
 
        and the IBuildBase builds (SPRecipeBuild). They assume the build
145
 
        is successfully built and check that incorrect upload paths will
146
 
        set the status to FAILEDTOUPLOAD.
147
 
        """
148
 
        raise NotImplementedError
149
 
 
150
 
    def setUp(self):
151
 
        super(TestHandleStatusMixin, self).setUp()
152
 
        self.build = self.makeBuild()
153
 
        # For the moment, we require a builder for the build so that
154
 
        # handleStatus_OK can get a reference to the slave.
155
 
        builder = self.factory.makeBuilder()
156
 
        self.build.buildqueue_record.builder = builder
157
 
        self.build.buildqueue_record.setDateStarted(UTC_NOW)
158
 
        self.slave = WaitingSlave('BuildStatus.OK')
159
 
        self.slave.valid_file_hashes.append('test_file_hash')
160
 
        builder.setSlaveForTesting(self.slave)
161
 
 
162
 
        # We overwrite the buildmaster root to use a temp directory.
163
 
        tmp_dir = self.makeTemporaryDirectory()
164
 
        tmp_builddmaster_root = """
165
 
        [builddmaster]
166
 
        root: %s
167
 
        """ % tmp_dir
168
 
        config.push('tmp_builddmaster_root', tmp_builddmaster_root)
169
 
 
170
 
        # We stub out our builds getUploaderCommand() method so
171
 
        # we can check whether it was called as well as
172
 
        # verifySuccessfulUpload().
173
 
        self.fake_getUploaderCommand = FakeMethod(
174
 
            result=['echo', 'noop'])
175
 
        removeSecurityProxy(self.build).getUploaderCommand = (
176
 
            self.fake_getUploaderCommand)
177
 
        removeSecurityProxy(self.build).verifySuccessfulUpload = FakeMethod(
178
 
            result=True)
179
 
 
180
 
    def test_handleStatus_OK_normal_file(self):
181
 
        # A filemap with plain filenames should not cause a problem.
182
 
        # The call to handleStatus will attempt to get the file from
183
 
        # the slave resulting in a URL error in this test case.
184
 
        self.build.handleStatus('OK', None, {
185
 
                'filemap': {'myfile.py': 'test_file_hash'},
186
 
                })
187
 
 
188
 
        self.assertEqual(BuildStatus.FULLYBUILT, self.build.status)
189
 
        self.assertEqual(1, self.fake_getUploaderCommand.call_count)
190
 
 
191
 
    def test_handleStatus_OK_absolute_filepath(self):
192
 
        # A filemap that tries to write to files outside of
193
 
        # the upload directory will result in a failed upload.
194
 
        self.build.handleStatus('OK', None, {
195
 
            'filemap': {'/tmp/myfile.py': 'test_file_hash'},
196
 
            })
197
 
        self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status)
198
 
        self.assertEqual(0, self.fake_getUploaderCommand.call_count)
199
 
 
200
 
    def test_handleStatus_OK_relative_filepath(self):
201
 
        # A filemap that tries to write to files outside of
202
 
        # the upload directory will result in a failed upload.
203
 
        self.build.handleStatus('OK', None, {
204
 
            'filemap': {'../myfile.py': 'test_file_hash'},
205
 
            })
206
 
        self.assertEqual(BuildStatus.FAILEDTOUPLOAD, self.build.status)
207
 
        self.assertEqual(0, self.fake_getUploaderCommand.call_count)
208
 
 
209
 
    def test_handleStatus_OK_sets_build_log(self):
210
 
        # The build log is set during handleStatus.
211
 
        removeSecurityProxy(self.build).log = None
212
 
        self.assertEqual(None, self.build.log)
213
 
        self.build.handleStatus('OK', None, {
214
 
                'filemap': {'myfile.py': 'test_file_hash'},
215
 
                })
216
 
        self.assertNotEqual(None, self.build.log)
217
 
 
218
 
    def test_date_finished_set(self):
219
 
        # The date finished is updated during handleStatus_OK.
220
 
        removeSecurityProxy(self.build).date_finished = None
221
 
        self.assertEqual(None, self.build.date_finished)
222
 
        self.build.handleStatus('OK', None, {
223
 
                'filemap': {'myfile.py': 'test_file_hash'},
224
 
                })
225
 
        self.assertNotEqual(None, self.build.date_finished)