~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/tests/test_packagecopyjob.py

Merge db-devel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2010 Canonical Ltd.  This software is licensed under the
 
1
# Copyright 2010-2011 Canonical Ltd.  This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
3
 
4
4
"""Tests for sync package jobs."""
10
10
 
11
11
from canonical.testing import LaunchpadZopelessLayer
12
12
from lp.registry.interfaces.pocket import PackagePublishingPocket
 
13
from lp.services.features.testing import FeatureFixture
 
14
from lp.services.job.interfaces.job import JobStatus
 
15
from lp.soyuz.enums import (
 
16
    ArchivePurpose,
 
17
    SourcePackageFormat,
 
18
    )
 
19
from lp.soyuz.model.distroseriesdifferencejob import (
 
20
    FEATURE_FLAG_ENABLE_MODULE,
 
21
    )
13
22
from lp.soyuz.interfaces.archive import CannotCopy
14
 
from lp.soyuz.interfaces.distributionjob import (
 
23
from lp.soyuz.interfaces.packagecopyjob import (
15
24
    IPackageCopyJob,
16
 
    IPackageCopyJobSource,
 
25
    IPlainPackageCopyJobSource,
17
26
    )
18
27
from lp.soyuz.interfaces.publishing import PackagePublishingStatus
 
28
from lp.soyuz.interfaces.sourcepackageformat import (
 
29
    ISourcePackageFormatSelectionSet,
 
30
    )
 
31
from lp.soyuz.model.packagecopyjob import specify_dsd_package
19
32
from lp.soyuz.tests.test_publishing import SoyuzTestPublisher
20
33
from lp.testing import (
21
34
    run_script,
23
36
    )
24
37
 
25
38
 
26
 
class PackageCopyJobTests(TestCaseWithFactory):
27
 
    """Test case for PackageCopyJob."""
 
39
class PlainPackageCopyJobTests(TestCaseWithFactory):
 
40
    """Test case for PlainPackageCopyJob."""
28
41
 
29
42
    layer = LaunchpadZopelessLayer
30
43
 
 
44
    def makeJob(self, dsd):
 
45
        """Create a `PlainPackageCopyJob` that would resolve `dsd`."""
 
46
        source_packages = [specify_dsd_package(dsd)]
 
47
        source_archive = dsd.parent_series.main_archive
 
48
        target_archive = dsd.derived_series.main_archive
 
49
        target_distroseries = dsd.derived_series
 
50
        target_pocket = self.factory.getAnyPocket()
 
51
        return getUtility(IPlainPackageCopyJobSource).create(
 
52
            source_packages, source_archive, target_archive,
 
53
            target_distroseries, target_pocket)
 
54
 
 
55
    def runJob(self, job):
 
56
        """Helper to switch to the right DB user and run the job."""
 
57
        self.layer.txn.commit()
 
58
        self.layer.switchDbUser('sync_packages')
 
59
        job.run()
 
60
 
31
61
    def test_create(self):
32
62
        # A PackageCopyJob can be created and stores its arguments.
33
63
        distroseries = self.factory.makeDistroSeries()
34
64
        archive1 = self.factory.makeArchive(distroseries.distribution)
35
65
        archive2 = self.factory.makeArchive(distroseries.distribution)
36
 
        source = getUtility(IPackageCopyJobSource)
 
66
        source = getUtility(IPlainPackageCopyJobSource)
37
67
        job = source.create(
38
68
            source_packages=[("foo", "1.0-1"), ("bar", "2.4")],
39
69
            source_archive=archive1, target_archive=archive2,
41
71
            target_pocket=PackagePublishingPocket.RELEASE,
42
72
            include_binaries=False)
43
73
        self.assertProvides(job, IPackageCopyJob)
44
 
        self.assertEquals(distroseries, job.distroseries)
45
74
        self.assertEquals(archive1.id, job.source_archive_id)
46
75
        self.assertEquals(archive1, job.source_archive)
47
76
        self.assertEquals(archive2.id, job.target_archive_id)
58
87
        distroseries = self.factory.makeDistroSeries()
59
88
        archive1 = self.factory.makeArchive(distroseries.distribution)
60
89
        archive2 = self.factory.makeArchive(distroseries.distribution)
61
 
        source = getUtility(IPackageCopyJobSource)
 
90
        source = getUtility(IPlainPackageCopyJobSource)
62
91
        job = source.create(
63
92
            source_packages=[("foo", "1.0-1")], source_archive=archive1,
64
93
            target_archive=archive2, target_distroseries=distroseries,
66
95
            include_binaries=False)
67
96
        self.assertContentEqual([job], source.getActiveJobs(archive2))
68
97
 
 
98
    def test_getActiveJobs_gets_oldest_first(self):
 
99
        # getActiveJobs returns the oldest available job first.
 
100
        dsd = self.factory.makeDistroSeriesDifference()
 
101
        target_archive = dsd.derived_series.main_archive
 
102
        jobs = [self.makeJob(dsd) for counter in xrange(2)]
 
103
        source = getUtility(IPlainPackageCopyJobSource)
 
104
        self.assertEqual(jobs[0], source.getActiveJobs(target_archive)[0])
 
105
 
 
106
    def test_getActiveJobs_only_returns_waiting_jobs(self):
 
107
        # getActiveJobs ignores jobs that aren't in the WAITING state.
 
108
        job = self.makeJob(self.factory.makeDistroSeriesDifference())
 
109
        removeSecurityProxy(job).job._status = JobStatus.RUNNING
 
110
        source = getUtility(IPlainPackageCopyJobSource)
 
111
        self.assertContentEqual([], source.getActiveJobs(job.target_archive))
 
112
 
69
113
    def test_run_unknown_package(self):
70
114
        # A job properly records failure.
71
115
        distroseries = self.factory.makeDistroSeries()
72
116
        archive1 = self.factory.makeArchive(distroseries.distribution)
73
117
        archive2 = self.factory.makeArchive(distroseries.distribution)
74
 
        source = getUtility(IPackageCopyJobSource)
 
118
        source = getUtility(IPlainPackageCopyJobSource)
75
119
        job = source.create(
76
120
            source_packages=[("foo", "1.0-1")], source_archive=archive1,
77
121
            target_archive=archive2, target_distroseries=distroseries,
78
122
            target_pocket=PackagePublishingPocket.RELEASE,
79
123
            include_binaries=False)
80
 
        self.assertRaises(CannotCopy, job.run)
 
124
        self.assertRaises(CannotCopy, self.runJob, job)
81
125
 
82
126
    def test_target_ppa_non_release_pocket(self):
83
127
        # When copying to a PPA archive the target must be the release pocket.
84
128
        distroseries = self.factory.makeDistroSeries()
85
129
        archive1 = self.factory.makeArchive(distroseries.distribution)
86
130
        archive2 = self.factory.makeArchive(distroseries.distribution)
87
 
        source = getUtility(IPackageCopyJobSource)
 
131
        source = getUtility(IPlainPackageCopyJobSource)
88
132
        job = source.create(
89
133
            source_packages=[], source_archive=archive1,
90
134
            target_archive=archive2, target_distroseries=distroseries,
91
135
            target_pocket=PackagePublishingPocket.UPDATES,
92
136
            include_binaries=False)
93
 
        self.assertRaises(CannotCopy, job.run)
 
137
        self.assertRaises(CannotCopy, self.runJob, job)
94
138
 
95
139
    def test_run(self):
96
140
        # A proper test run synchronizes packages.
 
141
 
 
142
        # Turn on DSD jobs.
 
143
        self.useFixture(FeatureFixture({FEATURE_FLAG_ENABLE_MODULE: 'on'}))
 
144
 
97
145
        publisher = SoyuzTestPublisher()
98
146
        publisher.prepareBreezyAutotest()
99
147
        distroseries = publisher.breezy_autotest
100
148
 
101
 
        archive1 = self.factory.makeArchive(distroseries.distribution)
102
 
        archive2 = self.factory.makeArchive(distroseries.distribution)
 
149
        # Synchronise from breezy-autotest to a brand new distro derived
 
150
        # from breezy.
 
151
        breezy_archive = self.factory.makeArchive(
 
152
            distroseries.distribution, purpose=ArchivePurpose.PRIMARY)
 
153
        dsp = self.factory.makeDistroSeriesParent(parent_series=distroseries)
 
154
        target_series = dsp.derived_series
 
155
        target_archive = self.factory.makeArchive(
 
156
            target_series.distribution, purpose=ArchivePurpose.PRIMARY)
 
157
        getUtility(ISourcePackageFormatSelectionSet).add(
 
158
            target_series, SourcePackageFormat.FORMAT_1_0)
103
159
 
104
160
        source_package = publisher.getPubSource(
105
161
            distroseries=distroseries, sourcename="libc",
106
162
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
107
 
            archive=archive1)
 
163
            archive=breezy_archive)
108
164
 
109
 
        source = getUtility(IPackageCopyJobSource)
 
165
        source = getUtility(IPlainPackageCopyJobSource)
110
166
        job = source.create(
111
 
            source_packages=[("libc", "2.8-1")], source_archive=archive1,
112
 
            target_archive=archive2, target_distroseries=distroseries,
 
167
            source_packages=[("libc", "2.8-1")], source_archive=breezy_archive,
 
168
            target_archive=target_archive, target_distroseries=target_series,
113
169
            target_pocket=PackagePublishingPocket.RELEASE,
114
170
            include_binaries=False)
115
171
        self.assertContentEqual(
123
179
        self.layer.switchDbUser('sync_packages')
124
180
        job.run()
125
181
 
126
 
        published_sources = archive2.getPublishedSources()
 
182
        published_sources = target_archive.getPublishedSources()
127
183
        spr = published_sources.one().sourcepackagerelease
128
184
        self.assertEquals("libc", spr.name)
129
185
        self.assertEquals("2.8-1", spr.version)
130
186
 
 
187
        # Switch back to a db user that has permission to clean up
 
188
        # featureflag.
 
189
        self.layer.switchDbUser('launchpad_main')
 
190
 
131
191
    def test_getOopsVars(self):
132
192
        distroseries = self.factory.makeDistroSeries()
133
193
        archive1 = self.factory.makeArchive(distroseries.distribution)
134
194
        archive2 = self.factory.makeArchive(distroseries.distribution)
135
 
        source = getUtility(IPackageCopyJobSource)
 
195
        source = getUtility(IPlainPackageCopyJobSource)
136
196
        job = source.create(
137
197
            source_packages=[("foo", "1.0-1")], source_archive=archive1,
138
198
            target_archive=archive2, target_distroseries=distroseries,
141
201
        oops_vars = job.getOopsVars()
142
202
        naked_job = removeSecurityProxy(job)
143
203
        self.assertIn(
144
 
            ('distribution_id', distroseries.distribution.id), oops_vars)
145
 
        self.assertIn(('distroseries_id', distroseries.id), oops_vars)
146
 
        self.assertIn(
147
 
            ('distribution_job_id', naked_job.context.id), oops_vars)
 
204
            ('source_archive_id', archive1.id), oops_vars)
 
205
        self.assertIn(
 
206
            ('target_archive_id', archive2.id), oops_vars)
 
207
        self.assertIn(
 
208
            ('target_distroseries_id', distroseries.id), oops_vars)
 
209
        self.assertIn(
 
210
            ('package_copy_job_id', naked_job.context.id), oops_vars)
 
211
        self.assertIn(
 
212
            ('package_copy_job_type', naked_job.context.job_type.title),
 
213
            oops_vars)
148
214
 
149
215
    def test_smoke(self):
150
216
        publisher = SoyuzTestPublisher()
156
222
            distroseries=distroseries, sourcename="libc",
157
223
            version="2.8-1", status=PackagePublishingStatus.PUBLISHED,
158
224
            archive=archive1)
159
 
        getUtility(IPackageCopyJobSource).create(
 
225
        getUtility(IPlainPackageCopyJobSource).create(
160
226
            source_packages=[("libc", "2.8-1")], source_archive=archive1,
161
227
            target_archive=archive2, target_distroseries=distroseries,
162
228
            target_pocket=PackagePublishingPocket.RELEASE,
165
231
 
166
232
        out, err, exit_code = run_script(
167
233
            "LP_DEBUG_SQL=1 cronscripts/process-job-source.py -vv %s" % (
168
 
                IPackageCopyJobSource.getName()))
 
234
                IPlainPackageCopyJobSource.getName()))
169
235
 
170
236
        self.addDetail("stdout", text_content(out))
171
237
        self.addDetail("stderr", text_content(err))
174
240
        copied_source_package = archive2.getPublishedSources(
175
241
            name="libc", version="2.8-1", exact_match=True).first()
176
242
        self.assertIsNot(copied_source_package, None)
 
243
 
 
244
    def test___repr__(self):
 
245
        distroseries = self.factory.makeDistroSeries()
 
246
        archive1 = self.factory.makeArchive(distroseries.distribution)
 
247
        archive2 = self.factory.makeArchive(distroseries.distribution)
 
248
        source = getUtility(IPlainPackageCopyJobSource)
 
249
        job = source.create(
 
250
            source_packages=[("foo", "1.0-1"), ("bar", "2.4")],
 
251
            source_archive=archive1, target_archive=archive2,
 
252
            target_distroseries=distroseries,
 
253
            target_pocket=PackagePublishingPocket.RELEASE,
 
254
            include_binaries=True)
 
255
        self.assertEqual(
 
256
            ("<PlainPackageCopyJob to copy 2 package(s) from "
 
257
             "{distroseries.distribution.name}/{archive1.name} to "
 
258
             "{distroseries.distribution.name}/{archive2.name}, "
 
259
             "RELEASE pocket, in {distroseries.distribution.name} "
 
260
             "{distroseries.name}, including binaries>").format(
 
261
                distroseries=distroseries, archive1=archive1,
 
262
                archive2=archive2),
 
263
            repr(job))
 
264
 
 
265
    def test_getPendingJobsPerPackage_finds_jobs(self):
 
266
        # getPendingJobsPerPackage finds jobs, and the packages they
 
267
        # belong to.
 
268
        dsd = self.factory.makeDistroSeriesDifference()
 
269
        job = self.makeJob(dsd)
 
270
        job_source = getUtility(IPlainPackageCopyJobSource)
 
271
        self.assertEqual(
 
272
            {specify_dsd_package(dsd): job},
 
273
            job_source.getPendingJobsPerPackage(dsd.derived_series))
 
274
 
 
275
    def test_getPendingJobsPerPackage_ignores_other_distroseries(self):
 
276
        # getPendingJobsPerPackage only looks for jobs on the indicated
 
277
        # distroseries.
 
278
        dsd = self.factory.makeDistroSeriesDifference()
 
279
        self.makeJob(dsd)
 
280
        other_series = self.factory.makeDistroSeries()
 
281
        job_source = getUtility(IPlainPackageCopyJobSource)
 
282
        self.assertEqual(
 
283
            {}, job_source.getPendingJobsPerPackage(other_series))
 
284
 
 
285
    def test_getPendingJobsPerPackage_only_returns_pending_jobs(self):
 
286
        # getPendingJobsPerPackage ignores jobs that have already been
 
287
        # run.
 
288
        dsd = self.factory.makeDistroSeriesDifference()
 
289
        package = specify_dsd_package(dsd)
 
290
        job = self.makeJob(dsd)
 
291
        job_source = getUtility(IPlainPackageCopyJobSource)
 
292
        found_by_state = {}
 
293
        for status in JobStatus.items:
 
294
            removeSecurityProxy(job).job._status = status
 
295
            result = job_source.getPendingJobsPerPackage(dsd.derived_series)
 
296
            if len(result) > 0:
 
297
                found_by_state[status] = result[package]
 
298
        expected = {
 
299
            JobStatus.WAITING: job,
 
300
            JobStatus.RUNNING: job,
 
301
            JobStatus.SUSPENDED: job,
 
302
        }
 
303
        self.assertEqual(expected, found_by_state)
 
304
 
 
305
    def test_getPendingJobsPerPackage_distinguishes_jobs(self):
 
306
        # getPendingJobsPerPackage associates the right job with the
 
307
        # right package.
 
308
        derived_series = self.factory.makeDistroSeries()
 
309
        dsds = [
 
310
            self.factory.makeDistroSeriesDifference(
 
311
                derived_series=derived_series)
 
312
            for counter in xrange(2)]
 
313
        jobs = map(self.makeJob, dsds)
 
314
        job_source = getUtility(IPlainPackageCopyJobSource)
 
315
        self.assertEqual(
 
316
            dict(zip(map(specify_dsd_package, dsds), jobs)),
 
317
            job_source.getPendingJobsPerPackage(derived_series))
 
318
 
 
319
    def test_getPendingJobsPerPackage_picks_oldest_job_for_dsd(self):
 
320
        # If there are multiple jobs for one package,
 
321
        # getPendingJobsPerPackage picks the oldest.
 
322
        dsd = self.factory.makeDistroSeriesDifference()
 
323
        jobs = [self.makeJob(dsd) for counter in xrange(2)]
 
324
        job_source = getUtility(IPlainPackageCopyJobSource)
 
325
        self.assertEqual(
 
326
            {specify_dsd_package(dsd): jobs[0]},
 
327
            job_source.getPendingJobsPerPackage(dsd.derived_series))
 
328
 
 
329
    def test_getPendingJobsPerPackage_ignores_dsds_without_jobs(self):
 
330
        # getPendingJobsPerPackage produces no dict entry for packages
 
331
        # that have no pending jobs, even if they do have DSDs.
 
332
        dsd = self.factory.makeDistroSeriesDifference()
 
333
        job_source = getUtility(IPlainPackageCopyJobSource)
 
334
        self.assertEqual(
 
335
            {}, job_source.getPendingJobsPerPackage(dsd.derived_series))