~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# Copyright 2009 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

__metaclass__ = type

import unittest

import transaction
from zope.component import getUtility
from zope.security.proxy import removeSecurityProxy

from lp.app.interfaces.launchpad import ILaunchpadCelebrities
from lp.registry.interfaces.distribution import IDistributionSet
from lp.registry.interfaces.distributionmirror import (
    IDistributionMirrorSet,
    MirrorContent,
    MirrorFreshness,
    )
from lp.registry.interfaces.pocket import PackagePublishingPocket
from lp.registry.model.distributionmirror import DistributionMirror
from lp.services.database.sqlbase import flush_database_updates
from lp.services.mail import stub
from lp.services.worlddata.interfaces.country import ICountrySet
from lp.testing import (
    login,
    login_as,
    )
from lp.testing.factory import LaunchpadObjectFactory
from lp.testing.layers import LaunchpadFunctionalLayer

# XXX Jan 20, 2010, jcsackett: This test case really needs to be updated to
# TestCaseWithFactory.
class TestDistributionMirror(unittest.TestCase):
    layer = LaunchpadFunctionalLayer

    def setUp(self):
        login('test@canonical.com')
        self.factory = LaunchpadObjectFactory()
        mirrorset = getUtility(IDistributionMirrorSet)
        self.cdimage_mirror = getUtility(IDistributionMirrorSet).getByName(
            'releases-mirror')
        self.archive_mirror = getUtility(IDistributionMirrorSet).getByName(
            'archive-mirror')
        self.hoary = getUtility(IDistributionSet)['ubuntu']['hoary']
        self.hoary_i386 = self.hoary['i386']

    def _create_source_mirror(
            self, distroseries, pocket, component, freshness):
        source_mirror1 = self.archive_mirror.ensureMirrorDistroSeriesSource(
            distroseries, pocket, component)
        removeSecurityProxy(source_mirror1).freshness = freshness

    def _create_bin_mirror(self, archseries, pocket, component, freshness):
        bin_mirror = self.archive_mirror.ensureMirrorDistroArchSeries(
            archseries, pocket, component)
        removeSecurityProxy(bin_mirror).freshness = freshness

    def test_archive_mirror_without_content_should_be_disabled(self):
        self.failUnless(self.archive_mirror.shouldDisable())

    def test_archive_mirror_with_any_content_should_not_be_disabled(self):
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        flush_database_updates()
        self.failIf(self.archive_mirror.shouldDisable())

    def test_cdimage_mirror_not_missing_content_should_not_be_disabled(self):
        expected_file_count = 1
        mirror = self.cdimage_mirror.ensureMirrorCDImageSeries(
            self.hoary, flavour='ubuntu')
        self.failIf(self.cdimage_mirror.shouldDisable(expected_file_count))

    def test_cdimage_mirror_missing_content_should_be_disabled(self):
        expected_file_count = 1
        self.failUnless(
            self.cdimage_mirror.shouldDisable(expected_file_count))

    def test_delete_all_mirror_cdimage_series(self):
        mirror = self.cdimage_mirror.ensureMirrorCDImageSeries(
            self.hoary, flavour='ubuntu')
        mirror = self.cdimage_mirror.ensureMirrorCDImageSeries(
            self.hoary, flavour='edubuntu')
        self.failUnlessEqual(
            self.cdimage_mirror.cdimage_series.count(), 2)
        self.cdimage_mirror.deleteAllMirrorCDImageSeries()
        self.failUnlessEqual(
            self.cdimage_mirror.cdimage_series.count(), 0)

    def test_archive_mirror_without_content_freshness(self):
        self.failIf(self.archive_mirror.source_series or
                    self.archive_mirror.arch_series)
        self.failUnlessEqual(
            self.archive_mirror.getOverallFreshness(),
            MirrorFreshness.UNKNOWN)

    def test_source_mirror_freshness_property(self):
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.TWODAYSBEHIND)
        flush_database_updates()
        self.failUnlessEqual(
            removeSecurityProxy(self.archive_mirror).source_mirror_freshness,
            MirrorFreshness.TWODAYSBEHIND)

    def test_arch_mirror_freshness_property(self):
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.ONEHOURBEHIND)
        flush_database_updates()
        self.failUnlessEqual(
            removeSecurityProxy(self.archive_mirror).arch_mirror_freshness,
            MirrorFreshness.ONEHOURBEHIND)

    def test_archive_mirror_with_source_content_freshness(self):
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.TWODAYSBEHIND)
        flush_database_updates()
        self.failUnlessEqual(
            self.archive_mirror.getOverallFreshness(),
            MirrorFreshness.TWODAYSBEHIND)

    def test_archive_mirror_with_binary_content_freshness(self):
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.ONEHOURBEHIND)
        flush_database_updates()
        self.failUnlessEqual(
            self.archive_mirror.getOverallFreshness(),
            MirrorFreshness.ONEHOURBEHIND)

    def test_archive_mirror_with_binary_and_source_content_freshness(self):
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_bin_mirror(
            self.hoary_i386, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.ONEHOURBEHIND)

        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[0], MirrorFreshness.UP)
        self._create_source_mirror(
            self.hoary, PackagePublishingPocket.RELEASE,
            self.hoary.components[1], MirrorFreshness.TWODAYSBEHIND)
        flush_database_updates()

        self.failUnlessEqual(
            self.archive_mirror.getOverallFreshness(),
            MirrorFreshness.TWODAYSBEHIND)

    def test_disabling_mirror_and_notifying_owner(self):
        login('karl@canonical.com')

        mirror = self.cdimage_mirror
        # If a mirror has been probed only once, the owner will always be
        # notified when it's disabled --it doesn't matter whether it was
        # previously enabled or disabled.
        self.factory.makeMirrorProbeRecord(mirror)
        self.failUnless(mirror.enabled)
        log = 'Got a 404 on http://foo/baz'
        mirror.disable(notify_owner=True, log=log)
        # A notification was sent to the owner and other to the mirror admins.
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 2)
        stub.test_emails = []

        mirror.disable(notify_owner=True, log=log)
        # Again, a notification was sent to the owner and other to the mirror
        # admins.
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 2)
        stub.test_emails = []

        # For mirrors that have been probed more than once, we'll only notify
        # the owner if the mirror was previously enabled.
        self.factory.makeMirrorProbeRecord(mirror)
        mirror.enabled = True
        mirror.disable(notify_owner=True, log=log)
        # A notification was sent to the owner and other to the mirror admins.
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 2)
        stub.test_emails = []

        # We can always disable notifications to the owner by passing
        # notify_owner=False to mirror.disable().
        mirror.enabled = True
        mirror.disable(notify_owner=False, log=log)
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 1)
        stub.test_emails = []

        mirror.enabled = False
        mirror.disable(notify_owner=True, log=log)
        # No notifications were sent this time
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 0)
        stub.test_emails = []

    def test_no_email_sent_to_uncontactable_owner(self):
        # If the owner has no contact address, only the mirror admins are
        # notified.
        mirror = self.cdimage_mirror
        login_as(mirror.owner)
        # Deactivate the mirror owner to remove the contact address.
        mirror.owner.deactivateAccount("I hate mirror spam.")
        login_as(mirror.distribution.mirror_admin)
        # Clear out notifications about the new team member.
        transaction.commit()
        stub.test_emails = []

        # Disabling the mirror results in a single notification to the
        # mirror admins.
        self.factory.makeMirrorProbeRecord(mirror)
        mirror.disable(notify_owner=True, log="It broke.")
        transaction.commit()
        self.failUnlessEqual(len(stub.test_emails), 1)


class TestDistributionMirrorSet(unittest.TestCase):
    layer = LaunchpadFunctionalLayer

    def test_getBestMirrorsForCountry_randomizes_results(self):
        """Make sure getBestMirrorsForCountry() randomizes its results."""
        def my_select(class_, query, *args, **kw):
            """Fake function with the same signature of SQLBase.select().

            This function ensures the orderBy argument given to it contains
            the 'random' string in its first item.
            """
            self.failUnlessEqual(kw['orderBy'][0].name, 'random')
            return [1, 2, 3]

        orig_select = DistributionMirror.select
        DistributionMirror.select = classmethod(my_select)
        try:
            login('foo.bar@canonical.com')
            getUtility(IDistributionMirrorSet).getBestMirrorsForCountry(
                None, MirrorContent.ARCHIVE)
        finally:
            DistributionMirror.select = orig_select

    def test_getBestMirrorsForCountry_appends_main_repo_to_the_end(self):
        """Make sure the main mirror is appended to the list of mirrors for a
        given country.
        """
        login('foo.bar@canonical.com')
        france = getUtility(ICountrySet)['FR']
        main_mirror = getUtility(ILaunchpadCelebrities).ubuntu_archive_mirror
        mirrors = getUtility(IDistributionMirrorSet).getBestMirrorsForCountry(
            france, MirrorContent.ARCHIVE)
        self.failUnless(len(mirrors) > 1, "Not enough mirrors")
        self.failUnlessEqual(main_mirror, mirrors[-1])

        main_mirror = getUtility(ILaunchpadCelebrities).ubuntu_cdimage_mirror
        mirrors = getUtility(IDistributionMirrorSet).getBestMirrorsForCountry(
            france, MirrorContent.RELEASE)
        self.failUnless(len(mirrors) > 1, "Not enough mirrors")
        self.failUnlessEqual(main_mirror, mirrors[-1])