~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/plugins/launchpad/test_lp_api_lite.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-07-18 18:33:35 UTC
  • mfrom: (6024.3.7 2.5-up-to-date-609187)
  • Revision ID: pqm@pqm.ubuntu.com-20110718183335-rall83p4yxjdd900
(jameinel) Bug #609187: warn the user if a package-import branch doesn't
 have the most recent source package. (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tools for dealing with the Launchpad API without using launchpadlib.
 
18
"""
 
19
 
 
20
import socket
 
21
 
 
22
from bzrlib import tests
 
23
from bzrlib.plugins import launchpad
 
24
from bzrlib.plugins.launchpad import lp_api_lite
 
25
 
 
26
class _JSONParserFeature(tests.Feature):
 
27
 
 
28
    def _probe(self):
 
29
        return lp_api_lite.json is not None
 
30
 
 
31
    def feature_name(self):
 
32
        return 'simplejson or json'
 
33
 
 
34
JSONParserFeature = _JSONParserFeature()
 
35
 
 
36
_example_response = r"""
 
37
{
 
38
    "total_size": 2,
 
39
    "start": 0,
 
40
    "next_collection_link": "https://api.launchpad.net/1.0/ubuntu/+archive/primary?distro_series=%2Fubuntu%2Flucid&exact_match=true&source_name=%22bzr%22&status=Published&ws.op=getPublishedSources&ws.start=1&ws.size=1",
 
41
    "entries": [
 
42
        {
 
43
            "package_creator_link": "https://api.launchpad.net/1.0/~maxb",
 
44
            "package_signer_link": "https://api.launchpad.net/1.0/~jelmer",
 
45
            "source_package_name": "bzr",
 
46
            "removal_comment": null,
 
47
            "display_name": "bzr 2.1.4-0ubuntu1 in lucid",
 
48
            "date_made_pending": null,
 
49
            "source_package_version": "2.1.4-0ubuntu1",
 
50
            "date_superseded": null,
 
51
            "http_etag": "\"9ba966152dec474dc0fe1629d0bbce2452efaf3b-5f4c3fbb3eaf26d502db4089777a9b6a0537ffab\"",
 
52
            "self_link": "https://api.launchpad.net/1.0/ubuntu/+archive/primary/+sourcepub/1750327",
 
53
            "distro_series_link": "https://api.launchpad.net/1.0/ubuntu/lucid",
 
54
            "component_name": "main",
 
55
            "status": "Published",
 
56
            "date_removed": null,
 
57
            "pocket": "Updates",
 
58
            "date_published": "2011-05-30T06:09:58.653984+00:00",
 
59
            "removed_by_link": null,
 
60
            "section_name": "devel",
 
61
            "resource_type_link": "https://api.launchpad.net/1.0/#source_package_publishing_history",
 
62
            "archive_link": "https://api.launchpad.net/1.0/ubuntu/+archive/primary",
 
63
            "package_maintainer_link": "https://api.launchpad.net/1.0/~ubuntu-devel-discuss-lists",
 
64
            "date_created": "2011-05-30T05:19:12.233621+00:00",
 
65
            "scheduled_deletion_date": null
 
66
        }
 
67
    ]
 
68
}"""
 
69
 
 
70
_no_versions_response = '{"total_size": 0, "start": 0, "entries": []}'
 
71
 
 
72
 
 
73
class TestLatestPublication(tests.TestCase):
 
74
 
 
75
    def make_latest_publication(self, archive='ubuntu', series='natty',
 
76
                                project='bzr'):
 
77
        return lp_api_lite.LatestPublication(archive, series, project)
 
78
 
 
79
    def test_init(self):
 
80
        latest_pub = self.make_latest_publication()
 
81
        self.assertEqual('ubuntu', latest_pub._archive)
 
82
        self.assertEqual('natty', latest_pub._series)
 
83
        self.assertEqual('bzr', latest_pub._project)
 
84
        self.assertEqual('Release', latest_pub._pocket)
 
85
 
 
86
    def test__archive_URL(self):
 
87
        latest_pub = self.make_latest_publication()
 
88
        self.assertEqual(
 
89
            'https://api.launchpad.net/1.0/ubuntu/+archive/primary',
 
90
            latest_pub._archive_URL())
 
91
 
 
92
    def test__publication_status_for_ubuntu(self):
 
93
        latest_pub = self.make_latest_publication()
 
94
        self.assertEqual('Published', latest_pub._publication_status())
 
95
 
 
96
    def test__publication_status_for_debian(self):
 
97
        latest_pub = self.make_latest_publication(archive='debian')
 
98
        self.assertEqual('Pending', latest_pub._publication_status())
 
99
 
 
100
    def test_pocket(self):
 
101
        latest_pub = self.make_latest_publication(series='natty-proposed')
 
102
        self.assertEqual('natty', latest_pub._series)
 
103
        self.assertEqual('Proposed', latest_pub._pocket)
 
104
 
 
105
    def test_series_None(self):
 
106
        latest_pub = self.make_latest_publication(series=None)
 
107
        self.assertEqual('ubuntu', latest_pub._archive)
 
108
        self.assertEqual(None, latest_pub._series)
 
109
        self.assertEqual('bzr', latest_pub._project)
 
110
        self.assertEqual('Release', latest_pub._pocket)
 
111
 
 
112
    def test__query_params(self):
 
113
        latest_pub = self.make_latest_publication()
 
114
        self.assertEqual({'ws.op': 'getPublishedSources',
 
115
                          'exact_match': 'true',
 
116
                          'source_name': '"bzr"',
 
117
                          'status': 'Published',
 
118
                          'ws.size': '1',
 
119
                          'distro_series': '/ubuntu/natty',
 
120
                          'pocket': 'Release',
 
121
                         }, latest_pub._query_params())
 
122
 
 
123
    def test__query_params_no_series(self):
 
124
        latest_pub = self.make_latest_publication(series=None)
 
125
        self.assertEqual({'ws.op': 'getPublishedSources',
 
126
                          'exact_match': 'true',
 
127
                          'source_name': '"bzr"',
 
128
                          'status': 'Published',
 
129
                          'ws.size': '1',
 
130
                          'pocket': 'Release',
 
131
                         }, latest_pub._query_params())
 
132
 
 
133
    def test__query_params_pocket(self):
 
134
        latest_pub = self.make_latest_publication(series='natty-proposed')
 
135
        self.assertEqual({'ws.op': 'getPublishedSources',
 
136
                          'exact_match': 'true',
 
137
                          'source_name': '"bzr"',
 
138
                          'status': 'Published',
 
139
                          'ws.size': '1',
 
140
                          'distro_series': '/ubuntu/natty',
 
141
                          'pocket': 'Proposed',
 
142
                         }, latest_pub._query_params())
 
143
 
 
144
    def test__query_URL(self):
 
145
        latest_pub = self.make_latest_publication()
 
146
        # we explicitly sort params, so we can be sure this URL matches exactly
 
147
        self.assertEqual(
 
148
            'https://api.launchpad.net/1.0/ubuntu/+archive/primary'
 
149
            '?distro_series=%2Fubuntu%2Fnatty&exact_match=true'
 
150
            '&pocket=Release&source_name=%22bzr%22&status=Published'
 
151
            '&ws.op=getPublishedSources&ws.size=1',
 
152
            latest_pub._query_URL())
 
153
 
 
154
    def DONT_test__gracefully_handle_failed_rpc_connection(self):
 
155
        # TODO: This test kind of sucks. We intentionally create an arbitrary
 
156
        #       port and don't listen to it, because we want the request to fail.
 
157
        #       However, it seems to take 1s for it to timeout. Is there a way
 
158
        #       to make it fail faster?
 
159
        latest_pub = self.make_latest_publication()
 
160
        s = socket.socket()
 
161
        s.bind(('127.0.0.1', 0))
 
162
        addr, port = s.getsockname()
 
163
        latest_pub.LP_API_ROOT = 'http://%s:%s/' % (addr, port)
 
164
        s.close()
 
165
        self.assertIs(None, latest_pub._get_lp_info())
 
166
 
 
167
    def DONT_test__query_launchpad(self):
 
168
        # TODO: This is a test that we are making a valid request against
 
169
        #       launchpad. This seems important, but it is slow, requires net
 
170
        #       access, and requires launchpad to be up and running. So for
 
171
        #       now, it is commented out for production tests.
 
172
        latest_pub = self.make_latest_publication()
 
173
        json_txt = latest_pub._get_lp_info()
 
174
        self.assertIsNot(None, json_txt)
 
175
        if lp_api_lite.json is None:
 
176
            # We don't have a way to parse the text
 
177
            return
 
178
        # The content should be a valid json result
 
179
        content = lp_api_lite.json.loads(json_txt)
 
180
        entries = content['entries'] # It should have an 'entries' field.
 
181
        # ws.size should mean we get 0 or 1, and there should be something
 
182
        self.assertEqual(1, len(entries))
 
183
        entry = entries[0]
 
184
        self.assertEqual('bzr', entry['source_package_name'])
 
185
        version = entry['source_package_version']
 
186
        self.assertIsNot(None, version)
 
187
 
 
188
    def test__get_lp_info_no_json(self):
 
189
        # If we can't parse the json, we don't make the query.
 
190
        self.overrideAttr(lp_api_lite, 'json', None)
 
191
        latest_pub = self.make_latest_publication()
 
192
        self.assertIs(None, latest_pub._get_lp_info())
 
193
 
 
194
    def test__parse_json_info_no_module(self):
 
195
        # If a json parsing module isn't available, we just return None here.
 
196
        self.overrideAttr(lp_api_lite, 'json', None)
 
197
        latest_pub = self.make_latest_publication()
 
198
        self.assertIs(None, latest_pub._parse_json_info(_example_response))
 
199
 
 
200
    def test__parse_json_example_response(self):
 
201
        self.requireFeature(JSONParserFeature)
 
202
        latest_pub = self.make_latest_publication()
 
203
        content = latest_pub._parse_json_info(_example_response)
 
204
        self.assertIsNot(None, content)
 
205
        self.assertEqual(2, content['total_size'])
 
206
        entries = content['entries']
 
207
        self.assertEqual(1, len(entries))
 
208
        entry = entries[0]
 
209
        self.assertEqual('bzr', entry['source_package_name'])
 
210
        self.assertEqual("2.1.4-0ubuntu1", entry["source_package_version"])
 
211
 
 
212
    def test__parse_json_not_json(self):
 
213
        self.requireFeature(JSONParserFeature)
 
214
        latest_pub = self.make_latest_publication()
 
215
        self.assertIs(None, latest_pub._parse_json_info('Not_valid_json'))
 
216
 
 
217
    def test_get_latest_version_no_response(self):
 
218
        latest_pub = self.make_latest_publication()
 
219
        latest_pub._get_lp_info = lambda: None
 
220
        self.assertEqual(None, latest_pub.get_latest_version())
 
221
 
 
222
    def test_get_latest_version_no_json(self):
 
223
        self.overrideAttr(lp_api_lite, 'json', None)
 
224
        latest_pub = self.make_latest_publication()
 
225
        self.assertEqual(None, latest_pub.get_latest_version())
 
226
 
 
227
    def test_get_latest_version_invalid_json(self):
 
228
        self.requireFeature(JSONParserFeature)
 
229
        latest_pub = self.make_latest_publication()
 
230
        latest_pub._get_lp_info = lambda: "not json"
 
231
        self.assertEqual(None, latest_pub.get_latest_version())
 
232
 
 
233
    def test_get_latest_version_no_versions(self):
 
234
        self.requireFeature(JSONParserFeature)
 
235
        latest_pub = self.make_latest_publication()
 
236
        latest_pub._get_lp_info = lambda: _no_versions_response
 
237
        self.assertEqual(None, latest_pub.get_latest_version())
 
238
 
 
239
    def test_get_latest_version_missing_entries(self):
 
240
        # Launchpad's no-entries response does have an empty entries value.
 
241
        # However, lets test that we handle other failures without tracebacks
 
242
        self.requireFeature(JSONParserFeature)
 
243
        latest_pub = self.make_latest_publication()
 
244
        latest_pub._get_lp_info = lambda: '{}'
 
245
        self.assertEqual(None, latest_pub.get_latest_version())
 
246
 
 
247
    def test_get_latest_version_invalid_entries(self):
 
248
        # Make sure we sanely handle a json response we don't understand
 
249
        self.requireFeature(JSONParserFeature)
 
250
        latest_pub = self.make_latest_publication()
 
251
        latest_pub._get_lp_info = lambda: '{"entries": {"a": 1}}'
 
252
        self.assertEqual(None, latest_pub.get_latest_version())
 
253
 
 
254
    def test_get_latest_version_example(self):
 
255
        self.requireFeature(JSONParserFeature)
 
256
        latest_pub = self.make_latest_publication()
 
257
        latest_pub._get_lp_info = lambda: _example_response
 
258
        self.assertEqual("2.1.4-0ubuntu1", latest_pub.get_latest_version())
 
259
 
 
260
    def DONT_test_get_latest_version_from_launchpad(self):
 
261
        self.requireFeature(JSONParserFeature)
 
262
        latest_pub = self.make_latest_publication()
 
263
        self.assertIsNot(None, latest_pub.get_latest_version())
 
264
 
 
265
 
 
266
class TestIsUpToDate(tests.TestCase):
 
267
 
 
268
    def assertPackageBranchRe(self, url, user, archive, series, project):
 
269
        m = launchpad._package_branch.search(url)
 
270
        if m is None:
 
271
            self.fail('package_branch regex did not match url: %s' % (url,))
 
272
        self.assertEqual(
 
273
            (user, archive, series, project),
 
274
            m.group('user', 'archive', 'series', 'project'))
 
275
 
 
276
    def assertNotPackageBranch(self, url):
 
277
        self.assertIs(None, launchpad._get_package_branch_info(url))
 
278
 
 
279
    def assertBranchInfo(self, url, archive, series, project):
 
280
        self.assertEqual((archive, series, project),
 
281
            launchpad._get_package_branch_info(url))
 
282
 
 
283
    def test_package_branch_regex(self):
 
284
        self.assertPackageBranchRe(
 
285
            'http://bazaar.launchpad.net/+branch/ubuntu/foo',
 
286
            None, 'ubuntu', None, 'foo')
 
287
        self.assertPackageBranchRe(
 
288
            'bzr+ssh://bazaar.launchpad.net/+branch/ubuntu/natty/foo',
 
289
            None, 'ubuntu', 'natty/', 'foo')
 
290
        self.assertPackageBranchRe(
 
291
            'sftp://bazaar.launchpad.net/+branch/debian/foo',
 
292
            None, 'debian', None, 'foo')
 
293
        self.assertPackageBranchRe(
 
294
            'http://bazaar.launchpad.net/+branch/debian/sid/foo',
 
295
            None, 'debian', 'sid/', 'foo')
 
296
        self.assertPackageBranchRe(
 
297
            'http://bazaar.launchpad.net/+branch'
 
298
            '/~ubuntu-branches/ubuntu/natty/foo/natty',
 
299
            '~ubuntu-branches/', 'ubuntu', 'natty/', 'foo')
 
300
        self.assertPackageBranchRe(
 
301
            'http://bazaar.launchpad.net/+branch'
 
302
            '/~user/ubuntu/natty/foo/test',
 
303
            '~user/', 'ubuntu', 'natty/', 'foo')
 
304
 
 
305
    def test_package_branch_doesnt_match(self):
 
306
        self.assertNotPackageBranch('http://example.com/ubuntu/foo')
 
307
        self.assertNotPackageBranch(
 
308
            'http://bazaar.launchpad.net/+branch/bzr')
 
309
        self.assertNotPackageBranch(
 
310
            'http://bazaar.launchpad.net/+branch/~bzr-pqm/bzr/bzr.dev')
 
311
        # Not a packaging branch because ~user isn't ~ubuntu-branches
 
312
        self.assertNotPackageBranch(
 
313
            'http://bazaar.launchpad.net/+branch'
 
314
            '/~user/ubuntu/natty/foo/natty')
 
315
 
 
316
    def test__get_package_branch_info(self):
 
317
        self.assertBranchInfo(
 
318
            'bzr+ssh://bazaar.launchpad.net/+branch/ubuntu/natty/foo',
 
319
            'ubuntu', 'natty', 'foo')
 
320
        self.assertBranchInfo(
 
321
            'bzr+ssh://bazaar.launchpad.net/+branch'
 
322
            '/~ubuntu-branches/ubuntu/natty/foo/natty',
 
323
            'ubuntu', 'natty', 'foo')
 
324
        self.assertBranchInfo(
 
325
            'http://bazaar.launchpad.net/+branch'
 
326
            '/~ubuntu-branches/debian/sid/foo/sid',
 
327
            'debian', 'sid', 'foo')
 
328
 
 
329
 
 
330
class TestGetMostRecentTag(tests.TestCaseWithMemoryTransport):
 
331
 
 
332
    def make_simple_builder(self):
 
333
        builder = self.make_branch_builder('tip')
 
334
        builder.build_snapshot('A', [], [
 
335
            ('add', ('', 'root-id', 'directory', None))])
 
336
        b = builder.get_branch()
 
337
        b.tags.set_tag('tip-1.0', 'A')
 
338
        return builder, b, b.tags.get_tag_dict()
 
339
 
 
340
    def test_get_most_recent_tag_tip(self):
 
341
        builder, b, tag_dict = self.make_simple_builder()
 
342
        self.assertEqual('tip-1.0',
 
343
                         lp_api_lite.get_most_recent_tag(tag_dict, b))
 
344
 
 
345
    def test_get_most_recent_tag_older(self):
 
346
        builder, b, tag_dict = self.make_simple_builder()
 
347
        builder.build_snapshot('B', ['A'], [])
 
348
        self.assertEqual('B', b.last_revision())
 
349
        self.assertEqual('tip-1.0',
 
350
                         lp_api_lite.get_most_recent_tag(tag_dict, b))