~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/canonical/buildd/tests/test_buildd_slave.py

  • Committer: mbp at canonical
  • Date: 2011-11-20 23:37:23 UTC
  • mto: This revision was merged to the branch mainline in revision 14344.
  • Revision ID: mbp@canonical.com-20111120233723-370p96db2crru5tm
Delete canonical.buildd again

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2009 Canonical Ltd.  This software is licensed under the
2
 
# GNU Affero General Public License version 3 (see the file LICENSE).
3
 
 
4
 
"""Buildd Slave tests.
5
 
 
6
 
This file contains the follwoing tests:
7
 
 
8
 
 * Basic authentication handling (used to download private sources);
9
 
 * Build log sanitization (removal of passwords from private buildlog);
10
 
 * Build log(tail) mechanisms (limited output from the end of the buildlog).
11
 
 
12
 
"""
13
 
 
14
 
__metaclass__ = type
15
 
 
16
 
__all__ = ['LaunchpadBuilddSlaveTests']
17
 
 
18
 
import difflib
19
 
import os
20
 
import shutil
21
 
import urllib2
22
 
import unittest
23
 
import xmlrpclib
24
 
 
25
 
from canonical.buildd.tests.harness import (
26
 
    BuilddSlaveTestSetup, BuilddTestCase)
27
 
 
28
 
 
29
 
def read_file(path):
30
 
    """Helper for reading the contents of a file."""
31
 
    file_object = open(path)
32
 
    try:
33
 
        return file_object.read()
34
 
    finally:
35
 
        file_object.close()
36
 
 
37
 
 
38
 
class LaunchpadBuilddSlaveTests(BuilddTestCase):
39
 
    """Unit tests for scrubbing (removal of passwords) of buildlog files."""
40
 
 
41
 
    def testBasicAuth(self):
42
 
        """Test that the auth handler is installed with the right details."""
43
 
        url = "http://fakeurl/"
44
 
        user = "myuser"
45
 
        password = "fakepassword"
46
 
 
47
 
        opener = self.slave.setupAuthHandler(url, user, password)
48
 
 
49
 
        # Inspect the openers and ensure the wanted handler is installed.
50
 
        basic_auth_handler = None
51
 
        for handler in opener.handlers:
52
 
            if isinstance(handler, urllib2.HTTPBasicAuthHandler):
53
 
                basic_auth_handler = handler
54
 
                break
55
 
        self.assertTrue(
56
 
            basic_auth_handler is not None,
57
 
            "No basic auth handler installed.")
58
 
 
59
 
        password_mgr = basic_auth_handler.passwd
60
 
        stored_user, stored_pass = password_mgr.find_user_password(None, url)
61
 
        self.assertEqual(user, stored_user)
62
 
        self.assertEqual(password, stored_pass)
63
 
 
64
 
    def testBuildlogScrubbing(self):
65
 
        """Tests the buildlog scrubbing (removal of passwords from URLs)."""
66
 
        # This is where the buildlog file lives.
67
 
        log_path = self.slave.cachePath('buildlog')
68
 
 
69
 
        # This is where the slave leaves the original/unsanitized
70
 
        # buildlog file after scrubbing.
71
 
        unsanitized_path = self.slave.cachePath('buildlog.unsanitized')
72
 
 
73
 
        # Copy the fake buildlog file to the cache path.
74
 
        shutil.copy(os.path.join(self.here, 'buildlog'), log_path)
75
 
 
76
 
        # Invoke the slave's buildlog scrubbing method.
77
 
        self.slave.sanitizeBuildlog(log_path)
78
 
 
79
 
        # Read the unsanitized original content.
80
 
        unsanitized = read_file(unsanitized_path).splitlines()
81
 
        # Read the new, sanitized content.
82
 
        clean = read_file(log_path).splitlines()
83
 
 
84
 
        # Compare the scrubbed content with the unsanitized one.
85
 
        differences = '\n'.join(difflib.unified_diff(unsanitized, clean))
86
 
 
87
 
        # Read the expected differences from the prepared disk file.
88
 
        expected = read_file(os.path.join(self.here, 'test_1.diff'))
89
 
 
90
 
        # Make sure they match.
91
 
        self.assertEqual(differences, expected)
92
 
 
93
 
    def testLogtailScrubbing(self):
94
 
        """Test the scrubbing of the slave's getLogTail() output."""
95
 
 
96
 
        # This is where the buildlog file lives.
97
 
        log_path = self.slave.cachePath('buildlog')
98
 
 
99
 
        # Copy the prepared, longer buildlog file so we can test lines
100
 
        # that are chopped off in the middle.
101
 
        shutil.copy(os.path.join(self.here, 'buildlog.long'), log_path)
102
 
 
103
 
        # First get the unfiltered log tail output (which is the default
104
 
        # behaviour because the BuildManager's 'is_archive_private'
105
 
        # property is initialized to False).
106
 
        self.slave.manager.is_archive_private = False
107
 
        unsanitized = self.slave.getLogTail().splitlines()
108
 
 
109
 
        # Make the slave believe we are building in a private archive to
110
 
        # obtain the scrubbed log tail output.
111
 
        self.slave.manager.is_archive_private = True
112
 
        clean = self.slave.getLogTail().splitlines()
113
 
 
114
 
        # Get the differences ..
115
 
        differences = '\n'.join(difflib.unified_diff(unsanitized, clean))
116
 
 
117
 
        # .. and the expected differences.
118
 
        expected = read_file(os.path.join(self.here, 'test_2.diff'))
119
 
 
120
 
        # Finally make sure what we got is what we expected.
121
 
        self.assertEqual(differences, expected)
122
 
 
123
 
    def testLogtail(self):
124
 
        """Tests the logtail mechanisms.
125
 
 
126
 
        'getLogTail' return up to 2 KiB text from the current 'buildlog' file.
127
 
        """
128
 
        self.makeLog(0)
129
 
        log_tail = self.slave.getLogTail()
130
 
        self.assertEqual(len(log_tail), 0)
131
 
 
132
 
        self.makeLog(1)
133
 
        log_tail = self.slave.getLogTail()
134
 
        self.assertEqual(len(log_tail), 1)
135
 
 
136
 
        self.makeLog(2048)
137
 
        log_tail = self.slave.getLogTail()
138
 
        self.assertEqual(len(log_tail), 2048)
139
 
 
140
 
        self.makeLog(2049)
141
 
        log_tail = self.slave.getLogTail()
142
 
        self.assertEqual(len(log_tail), 2048)
143
 
 
144
 
        self.makeLog(4096)
145
 
        log_tail = self.slave.getLogTail()
146
 
        self.assertEqual(len(log_tail), 2048)
147
 
 
148
 
    def testLogtailWhenLogFileVanishes(self):
149
 
        """Slave.getLogTail doesn't get hurt if the logfile has vanished.
150
 
 
151
 
        This is a common race-condition in our slaves, since they get
152
 
        pooled all the time when they are building.
153
 
 
154
 
        Sometimes the getLogTail calls coincides with the job
155
 
        cleanup/sanitization, so there is no buildlog to inspect and thus
156
 
        we expect an empty string to be returned instead of a explosion.
157
 
        """
158
 
        # Create some log content and read it.
159
 
        self.makeLog(2048)
160
 
        log_tail = self.slave.getLogTail()
161
 
        self.assertEqual(len(log_tail), 2048)
162
 
 
163
 
        # Read it again for luck.
164
 
        log_tail = self.slave.getLogTail()
165
 
        self.assertEqual(len(log_tail), 2048)
166
 
 
167
 
        # Remove the buildlog file
168
 
        os.remove(self.slave.cachePath('buildlog'))
169
 
 
170
 
        # Instead of shocking the getLogTail call, return an empty string.
171
 
        log_tail = self.slave.getLogTail()
172
 
        self.assertEqual(len(log_tail), 0)
173
 
 
174
 
 
175
 
class XMLRPCBuildDSlaveTests(unittest.TestCase):
176
 
 
177
 
    def setUp(self):
178
 
        super(XMLRPCBuildDSlaveTests, self).setUp()
179
 
        self.slave = BuilddSlaveTestSetup()
180
 
        self.slave.setUp()
181
 
        self.server = xmlrpclib.Server('http://localhost:8221/rpc/')
182
 
 
183
 
    def tearDown(self):
184
 
        self.slave.tearDown()
185
 
        super(XMLRPCBuildDSlaveTests, self).tearDown()
186
 
 
187
 
    def test_build_unknown_builder(self):
188
 
        # If a bogus builder name is passed into build, it returns an
189
 
        # appropriate error message and not just 'None'.
190
 
        buildername = 'nonexistentbuilder'
191
 
        status, info = self.server.build('foo', buildername, 'sha1', {}, {})
192
 
 
193
 
        self.assertEqual('BuilderStatus.UNKNOWNBUILDER', status)
194
 
        self.assertTrue(
195
 
            info is not None, "UNKNOWNBUILDER returns 'None' info.")
196
 
        self.assertTrue(
197
 
            info.startswith("%s not in [" % buildername),
198
 
            'UNKNOWNBUILDER info is "%s"' % info)