Merge ~pappacena/launchpad:fix-oci-upload-job-config into launchpad:master

Proposed by Thiago F. Pappacena
Status: Merged
Approved by: Thiago F. Pappacena
Approved revision: c8fa04d0fc840c5c9a947fccb4d157fefebf6ad2
Merge reported by: Otto Co-Pilot
Merged at revision: not available
Proposed branch: ~pappacena/launchpad:fix-oci-upload-job-config
Merge into: launchpad:master
Diff against target: 239 lines (+127/-41)
2 files modified
lib/lp/oci/model/ocirecipebuildjob.py (+16/-5)
lib/lp/oci/tests/test_ocirecipebuildjob.py (+111/-36)
Reviewer Review Type Date Requested Status
Colin Watson (community) Approve
Review via email: mp+392545@code.launchpad.net

Commit message

Fixing OCIRegistryUploadJob.config and avoiding crash logging it

To post a comment you must log in.
Revision history for this message
Colin Watson (cjwatson) :
review: Approve
Revision history for this message
Thiago F. Pappacena (pappacena) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/lib/lp/oci/model/ocirecipebuildjob.py b/lib/lp/oci/model/ocirecipebuildjob.py
index 991b9a4..0db2514 100644
--- a/lib/lp/oci/model/ocirecipebuildjob.py
+++ b/lib/lp/oci/model/ocirecipebuildjob.py
@@ -42,6 +42,7 @@ from lp.oci.interfaces.ociregistryclient import (
42 IOCIRegistryClient,42 IOCIRegistryClient,
43 OCIRegistryError,43 OCIRegistryError,
44 )44 )
45from lp.services.config import config
45from lp.services.database.enumcol import DBEnum46from lp.services.database.enumcol import DBEnum
46from lp.services.database.interfaces import (47from lp.services.database.interfaces import (
47 IMasterStore,48 IMasterStore,
@@ -114,11 +115,19 @@ class OCIRecipeBuildJobDerived(
114115
115 def __repr__(self):116 def __repr__(self):
116 """An informative representation of the job."""117 """An informative representation of the job."""
117 build = self.build118 try:
118 return "<%s for ~%s/%s/+oci/%s/+recipe/%s/+build/%d>" % (119 build = self.build
119 self.__class__.__name__, build.recipe.owner.name,120 return "<%s for ~%s/%s/+oci/%s/+recipe/%s/+build/%d>" % (
120 build.recipe.oci_project.pillar.name,121 self.__class__.__name__, build.recipe.owner.name,
121 build.recipe.oci_project.name, build.recipe.name, build.id)122 build.recipe.oci_project.pillar.name,
123 build.recipe.oci_project.name, build.recipe.name, build.id)
124 except Exception:
125 # There might be errors while trying to do the full
126 # representation of this object (database transaction errors,
127 # for example). There has been some issues in the past trying to
128 # log this object, so let's not crash everything in case we
129 # cannot provide a full description of self.
130 return "<%s ID#%s>" % (self.__class__.__name__, self.job_id)
122131
123 @classmethod132 @classmethod
124 def get(cls, job_id):133 def get(cls, job_id):
@@ -180,6 +189,8 @@ class OCIRegistryUploadJob(OCIRecipeBuildJobDerived):
180 retry_error_types = (ManifestListUploadError, )189 retry_error_types = (ManifestListUploadError, )
181 max_retries = 5190 max_retries = 5
182191
192 config = config.IOCIRegistryUploadJobSource
193
183 @classmethod194 @classmethod
184 def create(cls, build):195 def create(cls, build):
185 """See `IOCIRegistryUploadJobSource`"""196 """See `IOCIRegistryUploadJobSource`"""
diff --git a/lib/lp/oci/tests/test_ocirecipebuildjob.py b/lib/lp/oci/tests/test_ocirecipebuildjob.py
index 7b66c1d..2b39f4e 100644
--- a/lib/lp/oci/tests/test_ocirecipebuildjob.py
+++ b/lib/lp/oci/tests/test_ocirecipebuildjob.py
@@ -17,11 +17,9 @@ import time
17from fixtures import FakeLogger17from fixtures import FakeLogger
18from testtools.matchers import (18from testtools.matchers import (
19 Equals,19 Equals,
20 Is,
21 MatchesDict,20 MatchesDict,
22 MatchesListwise,21 MatchesListwise,
23 MatchesStructure,22 MatchesStructure,
24 Not,
25 )23 )
26import transaction24import transaction
27from zope.component import getUtility25from zope.component import getUtility
@@ -54,6 +52,10 @@ from lp.services.config import config
54from lp.services.features.testing import FeatureFixture52from lp.services.features.testing import FeatureFixture
55from lp.services.job.interfaces.job import JobStatus53from lp.services.job.interfaces.job import JobStatus
56from lp.services.job.runner import JobRunner54from lp.services.job.runner import JobRunner
55from lp.services.job.tests import (
56 block_on_job,
57 pop_remote_notifications,
58 )
57from lp.services.webapp import canonical_url59from lp.services.webapp import canonical_url
58from lp.services.webhooks.testing import LogsScheduledWebhooks60from lp.services.webhooks.testing import LogsScheduledWebhooks
59from lp.testing import (61from lp.testing import (
@@ -64,6 +66,7 @@ from lp.testing.dbuser import dbuser
64from lp.testing.fakemethod import FakeMethod66from lp.testing.fakemethod import FakeMethod
65from lp.testing.fixture import ZopeUtilityFixture67from lp.testing.fixture import ZopeUtilityFixture
66from lp.testing.layers import (68from lp.testing.layers import (
69 CeleryJobLayer,
67 DatabaseFunctionalLayer,70 DatabaseFunctionalLayer,
68 LaunchpadZopelessLayer,71 LaunchpadZopelessLayer,
69 )72 )
@@ -124,7 +127,79 @@ class TestOCIRecipeBuildJob(TestCaseWithFactory):
124 self.assertEqual(expected, oops)127 self.assertEqual(expected, oops)
125128
126129
127class TestOCIRegistryUploadJob(TestCaseWithFactory):130class TestOCIRecipeBuildJobDerived(TestCaseWithFactory):
131
132 layer = DatabaseFunctionalLayer
133
134 def setUp(self):
135 super(TestOCIRecipeBuildJobDerived, self).setUp()
136 self.useFixture(FeatureFixture({OCI_RECIPE_ALLOW_CREATE: 'on'}))
137
138 def test_repr(self):
139 build = self.factory.makeOCIRecipeBuild()
140 job = OCIRecipeBuildJob(
141 build, OCIRecipeBuildJobType.REGISTRY_UPLOAD, {})
142 derived_job = OCIRecipeBuildJobDerived(job)
143 expected_repr = (
144 "<OCIRecipeBuildJobDerived for "
145 "~%s/%s/+oci/%s/+recipe/%s/+build/%d>" % (
146 build.recipe.owner.name,
147 build.recipe.oci_project.pillar.name,
148 build.recipe.oci_project.name, build.recipe.name, build.id))
149 self.assertEqual(expected_repr, repr(derived_job))
150
151 def test_repr_fails_to_get_an_attribute(self):
152 class ErrorOCIRecipeBuildJobDerived(OCIRecipeBuildJobDerived):
153 def __getattribute__(self, item):
154 if item == 'build':
155 raise AttributeError("Somethng is wrong with build")
156 return super(
157 ErrorOCIRecipeBuildJobDerived, self).__getattribute__(item)
158 oci_build = self.factory.makeOCIRecipeBuild()
159 job = OCIRecipeBuildJob(
160 oci_build, OCIRecipeBuildJobType.REGISTRY_UPLOAD, {})
161 derived_job = ErrorOCIRecipeBuildJobDerived(job)
162 self.assertEqual(
163 "<ErrorOCIRecipeBuildJobDerived ID#%s>" % derived_job.job_id,
164 repr(derived_job))
165
166
167class MultiArchRecipeMixin:
168 def makeRecipe(self, include_i386=True, include_amd64=True):
169 i386 = getUtility(IProcessorSet).getByName("386")
170 amd64 = getUtility(IProcessorSet).getByName("amd64")
171 recipe = self.factory.makeOCIRecipe()
172 distroseries = self.factory.makeDistroSeries(
173 distribution=recipe.oci_project.distribution)
174 distro_i386 = self.factory.makeDistroArchSeries(
175 distroseries=distroseries, architecturetag="i386",
176 processor=i386)
177 distro_i386.addOrUpdateChroot(self.factory.makeLibraryFileAlias())
178 distro_amd64 = self.factory.makeDistroArchSeries(
179 distroseries=distroseries, architecturetag="amd64",
180 processor=amd64)
181 distro_amd64.addOrUpdateChroot(self.factory.makeLibraryFileAlias())
182
183 archs = []
184 if include_i386:
185 archs.append(i386)
186 if include_amd64:
187 archs.append(amd64)
188 recipe.setProcessors(archs)
189 return recipe
190
191 def makeBuildRequest(self, include_i386=True, include_amd64=True):
192 recipe = self.makeRecipe(include_i386, include_amd64)
193 # Creates a build request with a build in it.
194 build_request = recipe.requestBuilds(recipe.owner)
195 with admin_logged_in():
196 jobs = getUtility(IOCIRecipeRequestBuildsJobSource).iterReady()
197 with dbuser(config.IOCIRecipeRequestBuildsJobSource.dbuser):
198 JobRunner(jobs).runAll()
199 return build_request
200
201
202class TestOCIRegistryUploadJob(TestCaseWithFactory, MultiArchRecipeMixin):
128203
129 layer = LaunchpadZopelessLayer204 layer = LaunchpadZopelessLayer
130205
@@ -189,39 +264,6 @@ class TestOCIRegistryUploadJob(TestCaseWithFactory):
189 job = OCIRegistryUploadJob.create(ocibuild)264 job = OCIRegistryUploadJob.create(ocibuild)
190 self.assertProvides(job, IOCIRegistryUploadJob)265 self.assertProvides(job, IOCIRegistryUploadJob)
191266
192 def makeRecipe(self, include_i386=True, include_amd64=True):
193 i386 = getUtility(IProcessorSet).getByName("386")
194 amd64 = getUtility(IProcessorSet).getByName("amd64")
195 recipe = self.factory.makeOCIRecipe()
196 distroseries = self.factory.makeDistroSeries(
197 distribution=recipe.oci_project.distribution)
198 distro_i386 = self.factory.makeDistroArchSeries(
199 distroseries=distroseries, architecturetag="i386",
200 processor=i386)
201 distro_i386.addOrUpdateChroot(self.factory.makeLibraryFileAlias())
202 distro_amd64 = self.factory.makeDistroArchSeries(
203 distroseries=distroseries, architecturetag="amd64",
204 processor=amd64)
205 distro_amd64.addOrUpdateChroot(self.factory.makeLibraryFileAlias())
206
207 archs = []
208 if include_i386:
209 archs.append(i386)
210 if include_amd64:
211 archs.append(amd64)
212 recipe.setProcessors(archs)
213 return recipe
214
215 def makeBuildRequest(self, include_i386=True, include_amd64=True):
216 recipe = self.makeRecipe(include_i386, include_amd64)
217 # Creates a build request with a build in it.
218 build_request = recipe.requestBuilds(recipe.owner)
219 with admin_logged_in():
220 jobs = getUtility(IOCIRecipeRequestBuildsJobSource).iterReady()
221 with dbuser(config.IOCIRecipeRequestBuildsJobSource.dbuser):
222 JobRunner(jobs).runAll()
223 return build_request
224
225 def test_run(self):267 def test_run(self):
226 logger = self.useFixture(FakeLogger())268 logger = self.useFixture(FakeLogger())
227 build_request = self.makeBuildRequest(include_i386=False)269 build_request = self.makeBuildRequest(include_i386=False)
@@ -485,3 +527,36 @@ class TestOCIRegistryUploadJob(TestCaseWithFactory):
485 self.assertEqual([], pop_notifications())527 self.assertEqual([], pop_notifications())
486 self.assertWebhookDeliveries(528 self.assertWebhookDeliveries(
487 ocibuild, ["Pending", "Failed to upload"], logger)529 ocibuild, ["Pending", "Failed to upload"], logger)
530
531
532class TestOCIRegistryUploadJobViaCelery(TestCaseWithFactory,
533 MultiArchRecipeMixin):
534 """Runs OCIRegistryUploadJob via Celery, to make sure the machinery
535 around it works.
536
537 It's important to have this test specially because this job does some
538 dodgy things with its own status and the database transaction,
539 so we should make sure we are not breaking anything in the interaction
540 with the job lifecycle via celery.
541 """
542 layer = CeleryJobLayer
543
544 def setUp(self):
545 super(TestOCIRegistryUploadJobViaCelery, self).setUp()
546 self.useFixture(FeatureFixture({
547 'webhooks.new.enabled': 'true',
548 OCI_RECIPE_WEBHOOKS_FEATURE_FLAG: 'on',
549 OCI_RECIPE_ALLOW_CREATE: 'on',
550 'jobs.celery.enabled_classes': 'OCIRegistryUploadJob',
551 }))
552
553 def test_run_upload(self):
554 build_request = self.makeBuildRequest()
555 builds = build_request.builds
556 self.assertEqual(2, builds.count())
557
558 with block_on_job():
559 for build in builds:
560 OCIRegistryUploadJob.create(build)
561 transaction.commit()
562 self.assertEqual(0, len(pop_remote_notifications()))