~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2011-08-20 09:28:27 UTC
  • mfrom: (5050.78.2 2.2)
  • mto: (5609.48.8 2.3)
  • mto: This revision was merged to the branch mainline in revision 6090.
  • Revision ID: v.ladeuil+lp@free.fr-20110820092827-9dyakfslp0r3hb1k
Merge 2.2 into 2.3 (including fix for #614713, #609187 and #812928)

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 doctest
 
21
import socket
 
22
 
 
23
from bzrlib import tests
 
24
from bzrlib.plugins import launchpad
 
25
from bzrlib.plugins.launchpad import lp_api_lite
 
26
 
 
27
from testtools.matchers import DocTestMatches
 
28
 
 
29
 
 
30
class _JSONParserFeature(tests.Feature):
 
31
 
 
32
    def _probe(self):
 
33
        return lp_api_lite.json is not None
 
34
 
 
35
    def feature_name(self):
 
36
        return 'simplejson or json'
 
37
 
 
38
JSONParserFeature = _JSONParserFeature()
 
39
 
 
40
_example_response = r"""
 
41
{
 
42
    "total_size": 2,
 
43
    "start": 0,
 
44
    "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",
 
45
    "entries": [
 
46
        {
 
47
            "package_creator_link": "https://api.launchpad.net/1.0/~maxb",
 
48
            "package_signer_link": "https://api.launchpad.net/1.0/~jelmer",
 
49
            "source_package_name": "bzr",
 
50
            "removal_comment": null,
 
51
            "display_name": "bzr 2.1.4-0ubuntu1 in lucid",
 
52
            "date_made_pending": null,
 
53
            "source_package_version": "2.1.4-0ubuntu1",
 
54
            "date_superseded": null,
 
55
            "http_etag": "\"9ba966152dec474dc0fe1629d0bbce2452efaf3b-5f4c3fbb3eaf26d502db4089777a9b6a0537ffab\"",
 
56
            "self_link": "https://api.launchpad.net/1.0/ubuntu/+archive/primary/+sourcepub/1750327",
 
57
            "distro_series_link": "https://api.launchpad.net/1.0/ubuntu/lucid",
 
58
            "component_name": "main",
 
59
            "status": "Published",
 
60
            "date_removed": null,
 
61
            "pocket": "Updates",
 
62
            "date_published": "2011-05-30T06:09:58.653984+00:00",
 
63
            "removed_by_link": null,
 
64
            "section_name": "devel",
 
65
            "resource_type_link": "https://api.launchpad.net/1.0/#source_package_publishing_history",
 
66
            "archive_link": "https://api.launchpad.net/1.0/ubuntu/+archive/primary",
 
67
            "package_maintainer_link": "https://api.launchpad.net/1.0/~ubuntu-devel-discuss-lists",
 
68
            "date_created": "2011-05-30T05:19:12.233621+00:00",
 
69
            "scheduled_deletion_date": null
 
70
        }
 
71
    ]
 
72
}"""
 
73
 
 
74
_no_versions_response = '{"total_size": 0, "start": 0, "entries": []}'
 
75
 
 
76
 
 
77
class TestLatestPublication(tests.TestCase):
 
78
 
 
79
    def make_latest_publication(self, archive='ubuntu', series='natty',
 
80
                                project='bzr'):
 
81
        return lp_api_lite.LatestPublication(archive, series, project)
 
82
 
 
83
    def assertPlace(self, place, archive, series, project):
 
84
        lp = lp_api_lite.LatestPublication(archive, series, project)
 
85
        self.assertEqual(place, lp.place())
 
86
 
 
87
    def test_init(self):
 
88
        latest_pub = self.make_latest_publication()
 
89
        self.assertEqual('ubuntu', latest_pub._archive)
 
90
        self.assertEqual('natty', latest_pub._series)
 
91
        self.assertEqual('bzr', latest_pub._project)
 
92
        self.assertEqual('Release', latest_pub._pocket)
 
93
 
 
94
    def test__archive_URL(self):
 
95
        latest_pub = self.make_latest_publication()
 
96
        self.assertEqual(
 
97
            'https://api.launchpad.net/1.0/ubuntu/+archive/primary',
 
98
            latest_pub._archive_URL())
 
99
 
 
100
    def test__publication_status_for_ubuntu(self):
 
101
        latest_pub = self.make_latest_publication()
 
102
        self.assertEqual('Published', latest_pub._publication_status())
 
103
 
 
104
    def test__publication_status_for_debian(self):
 
105
        latest_pub = self.make_latest_publication(archive='debian')
 
106
        self.assertEqual('Pending', latest_pub._publication_status())
 
107
 
 
108
    def test_pocket(self):
 
109
        latest_pub = self.make_latest_publication(series='natty-proposed')
 
110
        self.assertEqual('natty', latest_pub._series)
 
111
        self.assertEqual('Proposed', latest_pub._pocket)
 
112
 
 
113
    def test_series_None(self):
 
114
        latest_pub = self.make_latest_publication(series=None)
 
115
        self.assertEqual('ubuntu', latest_pub._archive)
 
116
        self.assertEqual(None, latest_pub._series)
 
117
        self.assertEqual('bzr', latest_pub._project)
 
118
        self.assertEqual('Release', latest_pub._pocket)
 
119
 
 
120
    def test__query_params(self):
 
121
        latest_pub = self.make_latest_publication()
 
122
        self.assertEqual({'ws.op': 'getPublishedSources',
 
123
                          'exact_match': 'true',
 
124
                          'source_name': '"bzr"',
 
125
                          'status': 'Published',
 
126
                          'ws.size': '1',
 
127
                          'distro_series': '/ubuntu/natty',
 
128
                          'pocket': 'Release',
 
129
                         }, latest_pub._query_params())
 
130
 
 
131
    def test__query_params_no_series(self):
 
132
        latest_pub = self.make_latest_publication(series=None)
 
133
        self.assertEqual({'ws.op': 'getPublishedSources',
 
134
                          'exact_match': 'true',
 
135
                          'source_name': '"bzr"',
 
136
                          'status': 'Published',
 
137
                          'ws.size': '1',
 
138
                          'pocket': 'Release',
 
139
                         }, latest_pub._query_params())
 
140
 
 
141
    def test__query_params_pocket(self):
 
142
        latest_pub = self.make_latest_publication(series='natty-proposed')
 
143
        self.assertEqual({'ws.op': 'getPublishedSources',
 
144
                          'exact_match': 'true',
 
145
                          'source_name': '"bzr"',
 
146
                          'status': 'Published',
 
147
                          'ws.size': '1',
 
148
                          'distro_series': '/ubuntu/natty',
 
149
                          'pocket': 'Proposed',
 
150
                         }, latest_pub._query_params())
 
151
 
 
152
    def test__query_URL(self):
 
153
        latest_pub = self.make_latest_publication()
 
154
        # we explicitly sort params, so we can be sure this URL matches exactly
 
155
        self.assertEqual(
 
156
            'https://api.launchpad.net/1.0/ubuntu/+archive/primary'
 
157
            '?distro_series=%2Fubuntu%2Fnatty&exact_match=true'
 
158
            '&pocket=Release&source_name=%22bzr%22&status=Published'
 
159
            '&ws.op=getPublishedSources&ws.size=1',
 
160
            latest_pub._query_URL())
 
161
 
 
162
    def DONT_test__gracefully_handle_failed_rpc_connection(self):
 
163
        # TODO: This test kind of sucks. We intentionally create an arbitrary
 
164
        #       port and don't listen to it, because we want the request to fail.
 
165
        #       However, it seems to take 1s for it to timeout. Is there a way
 
166
        #       to make it fail faster?
 
167
        latest_pub = self.make_latest_publication()
 
168
        s = socket.socket()
 
169
        s.bind(('127.0.0.1', 0))
 
170
        addr, port = s.getsockname()
 
171
        latest_pub.LP_API_ROOT = 'http://%s:%s/' % (addr, port)
 
172
        s.close()
 
173
        self.assertIs(None, latest_pub._get_lp_info())
 
174
 
 
175
    def DONT_test__query_launchpad(self):
 
176
        # TODO: This is a test that we are making a valid request against
 
177
        #       launchpad. This seems important, but it is slow, requires net
 
178
        #       access, and requires launchpad to be up and running. So for
 
179
        #       now, it is commented out for production tests.
 
180
        latest_pub = self.make_latest_publication()
 
181
        json_txt = latest_pub._get_lp_info()
 
182
        self.assertIsNot(None, json_txt)
 
183
        if lp_api_lite.json is None:
 
184
            # We don't have a way to parse the text
 
185
            return
 
186
        # The content should be a valid json result
 
187
        content = lp_api_lite.json.loads(json_txt)
 
188
        entries = content['entries'] # It should have an 'entries' field.
 
189
        # ws.size should mean we get 0 or 1, and there should be something
 
190
        self.assertEqual(1, len(entries))
 
191
        entry = entries[0]
 
192
        self.assertEqual('bzr', entry['source_package_name'])
 
193
        version = entry['source_package_version']
 
194
        self.assertIsNot(None, version)
 
195
 
 
196
    def disableJSON(self):
 
197
        orig = lp_api_lite.json
 
198
        def cleanup():
 
199
            lp_api_lite.json = orig
 
200
        self.addCleanup(cleanup)
 
201
        lp_api_lite.json = None
 
202
 
 
203
    def test__get_lp_info_no_json(self):
 
204
        # If we can't parse the json, we don't make the query.
 
205
        self.disableJSON()
 
206
        latest_pub = self.make_latest_publication()
 
207
        self.assertIs(None, latest_pub._get_lp_info())
 
208
 
 
209
    def test__parse_json_info_no_module(self):
 
210
        # If a json parsing module isn't available, we just return None here.
 
211
        self.disableJSON()
 
212
        latest_pub = self.make_latest_publication()
 
213
        self.assertIs(None, latest_pub._parse_json_info(_example_response))
 
214
 
 
215
    def test__parse_json_example_response(self):
 
216
        self.requireFeature(JSONParserFeature)
 
217
        latest_pub = self.make_latest_publication()
 
218
        content = latest_pub._parse_json_info(_example_response)
 
219
        self.assertIsNot(None, content)
 
220
        self.assertEqual(2, content['total_size'])
 
221
        entries = content['entries']
 
222
        self.assertEqual(1, len(entries))
 
223
        entry = entries[0]
 
224
        self.assertEqual('bzr', entry['source_package_name'])
 
225
        self.assertEqual("2.1.4-0ubuntu1", entry["source_package_version"])
 
226
 
 
227
    def test__parse_json_not_json(self):
 
228
        self.requireFeature(JSONParserFeature)
 
229
        latest_pub = self.make_latest_publication()
 
230
        self.assertIs(None, latest_pub._parse_json_info('Not_valid_json'))
 
231
 
 
232
    def test_get_latest_version_no_response(self):
 
233
        latest_pub = self.make_latest_publication()
 
234
        latest_pub._get_lp_info = lambda: None
 
235
        self.assertEqual(None, latest_pub.get_latest_version())
 
236
 
 
237
    def test_get_latest_version_no_json(self):
 
238
        self.disableJSON()
 
239
        latest_pub = self.make_latest_publication()
 
240
        self.assertEqual(None, latest_pub.get_latest_version())
 
241
 
 
242
    def test_get_latest_version_invalid_json(self):
 
243
        self.requireFeature(JSONParserFeature)
 
244
        latest_pub = self.make_latest_publication()
 
245
        latest_pub._get_lp_info = lambda: "not json"
 
246
        self.assertEqual(None, latest_pub.get_latest_version())
 
247
 
 
248
    def test_get_latest_version_no_versions(self):
 
249
        self.requireFeature(JSONParserFeature)
 
250
        latest_pub = self.make_latest_publication()
 
251
        latest_pub._get_lp_info = lambda: _no_versions_response
 
252
        self.assertEqual(None, latest_pub.get_latest_version())
 
253
 
 
254
    def test_get_latest_version_missing_entries(self):
 
255
        # Launchpad's no-entries response does have an empty entries value.
 
256
        # However, lets test that we handle other failures without tracebacks
 
257
        self.requireFeature(JSONParserFeature)
 
258
        latest_pub = self.make_latest_publication()
 
259
        latest_pub._get_lp_info = lambda: '{}'
 
260
        self.assertEqual(None, latest_pub.get_latest_version())
 
261
 
 
262
    def test_get_latest_version_invalid_entries(self):
 
263
        # Make sure we sanely handle a json response we don't understand
 
264
        self.requireFeature(JSONParserFeature)
 
265
        latest_pub = self.make_latest_publication()
 
266
        latest_pub._get_lp_info = lambda: '{"entries": {"a": 1}}'
 
267
        self.assertEqual(None, latest_pub.get_latest_version())
 
268
 
 
269
    def test_get_latest_version_example(self):
 
270
        self.requireFeature(JSONParserFeature)
 
271
        latest_pub = self.make_latest_publication()
 
272
        latest_pub._get_lp_info = lambda: _example_response
 
273
        self.assertEqual("2.1.4-0ubuntu1", latest_pub.get_latest_version())
 
274
 
 
275
    def DONT_test_get_latest_version_from_launchpad(self):
 
276
        self.requireFeature(JSONParserFeature)
 
277
        latest_pub = self.make_latest_publication()
 
278
        self.assertIsNot(None, latest_pub.get_latest_version())
 
279
 
 
280
    def test_place(self):
 
281
        self.assertPlace('Ubuntu', 'ubuntu', None, 'bzr')
 
282
        self.assertPlace('Ubuntu Natty', 'ubuntu', 'natty', 'bzr')
 
283
        self.assertPlace('Ubuntu Natty Proposed', 'ubuntu', 'natty-proposed',
 
284
                         'bzr')
 
285
        self.assertPlace('Debian', 'debian', None, 'bzr')
 
286
        self.assertPlace('Debian Sid', 'debian', 'sid', 'bzr')
 
287
 
 
288
 
 
289
class TestIsUpToDate(tests.TestCase):
 
290
 
 
291
    def assertPackageBranchRe(self, url, user, archive, series, project):
 
292
        m = launchpad._package_branch.search(url)
 
293
        if m is None:
 
294
            self.fail('package_branch regex did not match url: %s' % (url,))
 
295
        self.assertEqual(
 
296
            (user, archive, series, project),
 
297
            m.group('user', 'archive', 'series', 'project'))
 
298
 
 
299
    def assertNotPackageBranch(self, url):
 
300
        self.assertIs(None, launchpad._get_package_branch_info(url))
 
301
 
 
302
    def assertBranchInfo(self, url, archive, series, project):
 
303
        self.assertEqual((archive, series, project),
 
304
            launchpad._get_package_branch_info(url))
 
305
 
 
306
    def test_package_branch_regex(self):
 
307
        self.assertPackageBranchRe(
 
308
            'http://bazaar.launchpad.net/+branch/ubuntu/foo',
 
309
            None, 'ubuntu', None, 'foo')
 
310
        self.assertPackageBranchRe(
 
311
            'bzr+ssh://bazaar.launchpad.net/+branch/ubuntu/natty/foo',
 
312
            None, 'ubuntu', 'natty/', 'foo')
 
313
        self.assertPackageBranchRe(
 
314
            'sftp://bazaar.launchpad.net/+branch/debian/foo',
 
315
            None, 'debian', None, 'foo')
 
316
        self.assertPackageBranchRe(
 
317
            'http://bazaar.launchpad.net/+branch/debian/sid/foo',
 
318
            None, 'debian', 'sid/', 'foo')
 
319
        self.assertPackageBranchRe(
 
320
            'http://bazaar.launchpad.net/+branch'
 
321
            '/~ubuntu-branches/ubuntu/natty/foo/natty',
 
322
            '~ubuntu-branches/', 'ubuntu', 'natty/', 'foo')
 
323
        self.assertPackageBranchRe(
 
324
            'http://bazaar.launchpad.net/+branch'
 
325
            '/~user/ubuntu/natty/foo/test',
 
326
            '~user/', 'ubuntu', 'natty/', 'foo')
 
327
 
 
328
    def test_package_branch_doesnt_match(self):
 
329
        self.assertNotPackageBranch('http://example.com/ubuntu/foo')
 
330
        self.assertNotPackageBranch(
 
331
            'http://bazaar.launchpad.net/+branch/bzr')
 
332
        self.assertNotPackageBranch(
 
333
            'http://bazaar.launchpad.net/+branch/~bzr-pqm/bzr/bzr.dev')
 
334
        # Not a packaging branch because ~user isn't ~ubuntu-branches
 
335
        self.assertNotPackageBranch(
 
336
            'http://bazaar.launchpad.net/+branch'
 
337
            '/~user/ubuntu/natty/foo/natty')
 
338
        # Older versions of bzr-svn/hg/git did not set Branch.base until after
 
339
        # they called Branch.__init__().
 
340
        self.assertNotPackageBranch(None)
 
341
 
 
342
    def test__get_package_branch_info(self):
 
343
        self.assertBranchInfo(
 
344
            'bzr+ssh://bazaar.launchpad.net/+branch/ubuntu/natty/foo',
 
345
            'ubuntu', 'natty', 'foo')
 
346
        self.assertBranchInfo(
 
347
            'bzr+ssh://bazaar.launchpad.net/+branch'
 
348
            '/~ubuntu-branches/ubuntu/natty/foo/natty',
 
349
            'ubuntu', 'natty', 'foo')
 
350
        self.assertBranchInfo(
 
351
            'http://bazaar.launchpad.net/+branch'
 
352
            '/~ubuntu-branches/debian/sid/foo/sid',
 
353
            'debian', 'sid', 'foo')
 
354
 
 
355
 
 
356
class TestGetMostRecentTag(tests.TestCaseWithMemoryTransport):
 
357
 
 
358
    def make_simple_builder(self):
 
359
        builder = self.make_branch_builder('tip')
 
360
        builder.build_snapshot('A', None, [
 
361
            ('add', ('', 'root-id', 'directory', None))])
 
362
        b = builder.get_branch()
 
363
        b.tags.set_tag('tip-1.0', 'A')
 
364
        return builder, b, b.tags.get_tag_dict()
 
365
 
 
366
    def test_get_most_recent_tag_tip(self):
 
367
        builder, b, tag_dict = self.make_simple_builder()
 
368
        self.assertEqual('tip-1.0',
 
369
                         lp_api_lite.get_most_recent_tag(tag_dict, b))
 
370
 
 
371
    def test_get_most_recent_tag_older(self):
 
372
        builder, b, tag_dict = self.make_simple_builder()
 
373
        builder.build_snapshot('B', ['A'], [])
 
374
        self.assertEqual('B', b.last_revision())
 
375
        self.assertEqual('tip-1.0',
 
376
                         lp_api_lite.get_most_recent_tag(tag_dict, b))
 
377
 
 
378
 
 
379
class StubLatestPublication(object):
 
380
 
 
381
    def __init__(self, latest):
 
382
        self.called = False
 
383
        self.latest = latest
 
384
 
 
385
    def get_latest_version(self):
 
386
        self.called = True
 
387
        return self.latest
 
388
 
 
389
    def place(self):
 
390
        return 'Ubuntu Natty'
 
391
 
 
392
 
 
393
class TestReportFreshness(tests.TestCaseWithMemoryTransport):
 
394
 
 
395
    def setUp(self):
 
396
        super(TestReportFreshness, self).setUp()
 
397
        builder = self.make_branch_builder('tip')
 
398
        builder.build_snapshot('A', None, [
 
399
            ('add', ('', 'root-id', 'directory', None))])
 
400
        self.branch = builder.get_branch()
 
401
 
 
402
    def assertFreshnessReports(self, verbosity, latest_version, content):
 
403
        """Assert that lp_api_lite.report_freshness reports the given content.
 
404
 
 
405
        :param verbosity: The reporting level
 
406
        :param latest_version: The version reported by StubLatestPublication
 
407
        :param content: The expected content. This should be in DocTest form.
 
408
        """
 
409
        orig_log_len = len(self.get_log())
 
410
        lp_api_lite.report_freshness(self.branch, verbosity,
 
411
            StubLatestPublication(latest_version))
 
412
        new_content = self.get_log()[orig_log_len:]
 
413
        # Strip out lines that have LatestPublication.get_* because those are
 
414
        # timing related lines. While interesting to log for now, they aren't
 
415
        # something we want to be testing
 
416
        new_content = new_content.split('\n')
 
417
        for i in range(2):
 
418
            if (len(new_content) > 0
 
419
                and 'LatestPublication.get_' in new_content[0]):
 
420
                new_content = new_content[1:]
 
421
        new_content = '\n'.join(new_content)
 
422
        self.assertThat(new_content,
 
423
            DocTestMatches(content,
 
424
                doctest.ELLIPSIS | doctest.REPORT_UDIFF))
 
425
 
 
426
    def test_verbosity_off_skips_check(self):
 
427
        # We force _get_package_branch_info so that we know it would otherwise
 
428
        # try to connect to launcphad
 
429
        orig_gpbi = launchpad._get_package_branch_info
 
430
        orig_lp = lp_api_lite.LatestPublication
 
431
        def cleanup():
 
432
            launchpad._get_package_branch_info = orig_gpbi
 
433
            lp_api_lite.LatestPublication = orig_lp
 
434
        self.addCleanup(cleanup)
 
435
        launchpad._get_package_branch_info = lambda x: ('ubuntu', 'natty', 'bzr')
 
436
        lp_api_lite.LatestPublication = lambda *args: self.fail('Tried to query launchpad')
 
437
        c = self.branch.get_config()
 
438
        c.set_user_option('launchpad.packaging_verbosity', 'off')
 
439
        orig_log_len = len(self.get_log())
 
440
        launchpad._check_is_up_to_date(self.branch)
 
441
        new_content = self.get_log()[orig_log_len:]
 
442
        self.assertContainsRe(new_content,
 
443
            'not checking memory.*/tip/ because verbosity is turned off')
 
444
 
 
445
    def test_verbosity_off(self):
 
446
        latest_pub = StubLatestPublication('1.0-1ubuntu2')
 
447
        lp_api_lite.report_freshness(self.branch, 'off', latest_pub)
 
448
        self.assertFalse(latest_pub.called)
 
449
 
 
450
    def test_verbosity_all_out_of_date_smoke(self):
 
451
        self.branch.tags.set_tag('1.0-1ubuntu1', 'A')
 
452
        self.assertFreshnessReports('all', '1.0-1ubuntu2',
 
453
             '    INFO  Most recent Ubuntu Natty version: 1.0-1ubuntu2\n'
 
454
             'Packaging branch version: 1.0-1ubuntu1\n'
 
455
             'Packaging branch status: OUT-OF-DATE\n')
 
456
 
 
457
 
 
458
class Test_GetNewestVersions(tests.TestCaseWithMemoryTransport):
 
459
 
 
460
    def setUp(self):
 
461
        super(Test_GetNewestVersions, self).setUp()
 
462
        builder = self.make_branch_builder('tip')
 
463
        builder.build_snapshot('A', None, [
 
464
            ('add', ('', 'root-id', 'directory', None))])
 
465
        self.branch = builder.get_branch()
 
466
 
 
467
    def assertLatestVersions(self, latest_branch_version, pub_version):
 
468
        if latest_branch_version is not None:
 
469
            self.branch.tags.set_tag(latest_branch_version, 'A')
 
470
        latest_pub = StubLatestPublication(pub_version)
 
471
        self.assertEqual((pub_version, latest_branch_version),
 
472
            lp_api_lite._get_newest_versions(self.branch, latest_pub))
 
473
 
 
474
    def test_no_tags(self):
 
475
        self.assertLatestVersions(None, '1.0-1ubuntu2')
 
476
 
 
477
    def test_out_of_date(self):
 
478
        self.assertLatestVersions('1.0-1ubuntu1', '1.0-1ubuntu2')
 
479
 
 
480
    def test_up_to_date(self):
 
481
        self.assertLatestVersions('1.0-1ubuntu2', '1.0-1ubuntu2')
 
482
 
 
483
    def test_missing(self):
 
484
        self.assertLatestVersions(None, None)
 
485
 
 
486
 
 
487
class Test_ReportFreshness(tests.TestCase):
 
488
 
 
489
    def assertReportedFreshness(self, verbosity, latest_ver, branch_latest_ver,
 
490
                               content, place='Ubuntu Natty'):
 
491
        """Assert that lp_api_lite.report_freshness reports the given content.
 
492
        """
 
493
        reported = []
 
494
        def report_func(value):
 
495
            reported.append(value)
 
496
        lp_api_lite._report_freshness(latest_ver, branch_latest_ver, place,
 
497
                                      verbosity, report_func)
 
498
        new_content = '\n'.join(reported)
 
499
        self.assertThat(new_content,
 
500
            DocTestMatches(content,
 
501
                doctest.ELLIPSIS | doctest.REPORT_UDIFF))
 
502
 
 
503
    def test_verbosity_minimal_no_tags(self):
 
504
        self.assertReportedFreshness('minimal', '1.0-1ubuntu2', None,
 
505
            'Branch is OUT-OF-DATE, Ubuntu Natty has 1.0-1ubuntu2\n')
 
506
 
 
507
    def test_verbosity_minimal_out_of_date(self):
 
508
        self.assertReportedFreshness('minimal', '1.0-1ubuntu2', '1.0-1ubuntu1',
 
509
            '1.0-1ubuntu1 is OUT-OF-DATE,'
 
510
            ' Ubuntu Natty has 1.0-1ubuntu2\n')
 
511
 
 
512
    def test_verbosity_minimal_up_to_date(self):
 
513
        self.assertReportedFreshness('minimal', '1.0-1ubuntu2', '1.0-1ubuntu2',
 
514
             '')
 
515
 
 
516
    def test_verbosity_minimal_missing(self):
 
517
        self.assertReportedFreshness('minimal', None, None,
 
518
             '')
 
519
 
 
520
    def test_verbosity_short_out_of_date(self):
 
521
        self.assertReportedFreshness('short', '1.0-1ubuntu2', '1.0-1ubuntu1',
 
522
            '1.0-1ubuntu1 is OUT-OF-DATE,'
 
523
            ' Ubuntu Natty has 1.0-1ubuntu2\n')
 
524
 
 
525
    def test_verbosity_short_up_to_date(self):
 
526
        self.assertReportedFreshness('short', '1.0-1ubuntu2', '1.0-1ubuntu2',
 
527
             '1.0-1ubuntu2 is CURRENT in Ubuntu Natty')
 
528
 
 
529
    def test_verbosity_short_missing(self):
 
530
        self.assertReportedFreshness('short', None, None,
 
531
             'Ubuntu Natty is MISSING a version')
 
532
 
 
533
    def test_verbosity_all_no_tags(self):
 
534
        self.assertReportedFreshness('all', '1.0-1ubuntu2', None,
 
535
             'Most recent Ubuntu Natty version: 1.0-1ubuntu2\n'
 
536
             'Packaging branch version: None\n'
 
537
             'Packaging branch status: OUT-OF-DATE\n')
 
538
 
 
539
    def test_verbosity_all_out_of_date(self):
 
540
        self.assertReportedFreshness('all', '1.0-1ubuntu2', '1.0-1ubuntu1',
 
541
             'Most recent Ubuntu Natty version: 1.0-1ubuntu2\n'
 
542
             'Packaging branch version: 1.0-1ubuntu1\n'
 
543
             'Packaging branch status: OUT-OF-DATE\n')
 
544
 
 
545
    def test_verbosity_all_up_to_date(self):
 
546
        self.assertReportedFreshness('all', '1.0-1ubuntu2', '1.0-1ubuntu2',
 
547
             'Most recent Ubuntu Natty version: 1.0-1ubuntu2\n'
 
548
             'Packaging branch status: CURRENT\n')
 
549
 
 
550
    def test_verbosity_all_missing(self):
 
551
        self.assertReportedFreshness('all', None, None,
 
552
             'Most recent Ubuntu Natty version: MISSING\n')
 
553
 
 
554
    def test_verbosity_None_is_all(self):
 
555
        self.assertReportedFreshness(None, '1.0-1ubuntu2', '1.0-1ubuntu2',
 
556
             'Most recent Ubuntu Natty version: 1.0-1ubuntu2\n'
 
557
             'Packaging branch status: CURRENT\n')