← Back to team overview

launchpad-reviewers team mailing list archive

lp:~allenap/launchpad/series-init-failure-explanations-bug-835024-ui into lp:launchpad

 

Gavin Panella has proposed merging lp:~allenap/launchpad/series-init-failure-explanations-bug-835024-ui into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  Bug #835024 in Launchpad itself: "Unclear why series initialization failed"
  https://bugs.launchpad.net/launchpad/+bug/835024

For more details, see:
https://code.launchpad.net/~allenap/launchpad/series-init-failure-explanations-bug-835024-ui/+merge/74974

Show derivation failure messages in the portlet on DistroSeries:+index.

Needs feature flag soyuz.derived_series_ui.enabled.

-- 
https://code.launchpad.net/~allenap/launchpad/series-init-failure-explanations-bug-835024-ui/+merge/74974
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~allenap/launchpad/series-init-failure-explanations-bug-835024-ui into lp:launchpad.
=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
--- lib/lp/registry/browser/tests/test_distroseries.py	2011-08-19 06:57:33 +0000
+++ lib/lp/registry/browser/tests/test_distroseries.py	2011-09-12 11:42:05 +0000
@@ -28,10 +28,17 @@
     LessThan,
     Not,
     )
+import transaction
 from zope.component import getUtility
-from zope.security.proxy import removeSecurityProxy
+from zope.security.proxy import (
+    ProxyFactory,
+    removeSecurityProxy,
+    )
 
-from canonical.config import config
+from canonical.config import (
+    config,
+    dbconfig,
+    )
 from canonical.database.constants import UTC_NOW
 from canonical.database.sqlbase import flush_database_caches
 from canonical.launchpad.testing.pages import (
@@ -41,13 +48,19 @@
 from canonical.launchpad.webapp.authorization import check_permission
 from canonical.launchpad.webapp.batching import BatchNavigator
 from canonical.launchpad.webapp.interaction import get_current_principal
-from canonical.launchpad.webapp.interfaces import BrowserNotificationLevel
+from canonical.launchpad.webapp.interfaces import (
+    BrowserNotificationLevel,
+    IStoreSelector,
+    MAIN_STORE,
+    MASTER_FLAVOR,
+    )
 from canonical.launchpad.webapp.publisher import canonical_url
 from canonical.launchpad.webapp.url import urlappend
 from canonical.testing.layers import (
     DatabaseFunctionalLayer,
     LaunchpadFunctionalLayer,
     LaunchpadZopelessLayer,
+    reconnect_stores,
     )
 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
 from lp.archivepublisher.debversion import Version
@@ -87,7 +100,9 @@
     )
 from lp.soyuz.model import distroseriesdifferencejob
 from lp.soyuz.model.archivepermission import ArchivePermission
+from lp.soyuz.model.initializedistroseriesjob import InitializeDistroSeriesJob
 from lp.soyuz.model.packagecopyjob import PlainPackageCopyJob
+from lp.soyuz.scripts.initialize_distroseries import InitializationError
 from lp.testing import (
     ANONYMOUS,
     anonymous_logged_in,
@@ -584,6 +599,51 @@
                 "You cannot attempt initialization again, but a "
                 "member of Team Teamy Team Team may be able to help."))
 
+    def load_afresh(self, thing):
+        store = getUtility(IStoreSelector).get(MAIN_STORE, MASTER_FLAVOR)
+        naked_thing = removeSecurityProxy(thing)
+        naked_thing = store.get(naked_thing.__class__, naked_thing.id)
+        return ProxyFactory(naked_thing)
+
+    def fail_job_with_error(self, job, error):
+        # We need to switch to the initializedistroseries user to set the
+        # error_description on the given job. Which is a PITA.
+        distroseries = job.distroseries
+        transaction.commit()
+        starting_database_config_section = dbconfig.getSectionName()
+        reconnect_stores("initializedistroseries")
+        job = self.job_source.get(distroseries)
+        job.start()
+        job.fail()
+        job.notifyUserError(error)
+        transaction.commit()
+        reconnect_stores(starting_database_config_section)
+
+    def test_initialization_failure_explanation_shown(self):
+        # When initialization has failed an explanation of the failure can be
+        # displayed. It depends on the nature of the failure; only some error
+        # types are displayed.
+        set_derived_series_ui_feature_flag(self)
+        series = self.factory.makeDistroSeries()
+        parent = self.factory.makeDistroSeries()
+        job = self.job_source.create(series, [parent.id])
+        self.fail_job_with_error(
+            job, InitializationError(
+                "You cannot be serious. That's really going "
+                "to hurt. Put it away."))
+        # Load series again because the connection was closed in
+        # fail_job_with_error().
+        series = self.load_afresh(series)
+        with person_logged_in(series.owner):
+            view = create_initialized_view(series, '+portlet-derivation')
+            html_content = view()
+        self.assertThat(
+            extract_text(html_content), DocTestMatches(
+                "Series initialization has failed\n"
+                "You cannot be serious. That's really going "
+                "to hurt. Put it away.\n"
+                "You can attempt initialization again."))
+
 
 class TestMilestoneBatchNavigatorAttribute(TestCaseWithFactory):
     """Test the series.milestone_batch_navigator attribute."""

=== modified file 'lib/lp/registry/templates/distroseries-portlet-derivation.pt'
--- lib/lp/registry/templates/distroseries-portlet-derivation.pt	2011-09-02 10:57:52 +0000
+++ lib/lp/registry/templates/distroseries-portlet-derivation.pt	2011-09-12 11:42:05 +0000
@@ -75,6 +75,9 @@
       define="job context/getInitializationJob"
       condition="job/status/enumvalue:FAILED|nothing">
     <h2>Series initialization has failed</h2>
+    <p tal:condition="job/error_description"
+       tal:content="job/error_description">
+    </p>
     <tal:retry
         define="can_retry context/@@+initseries/required:launchpad.Edit ">
       <tal:can_retry condition="can_retry">

=== modified file 'lib/lp/soyuz/interfaces/distributionjob.py'
--- lib/lp/soyuz/interfaces/distributionjob.py	2011-08-26 06:46:43 +0000
+++ lib/lp/soyuz/interfaces/distributionjob.py	2011-09-12 11:42:05 +0000
@@ -25,6 +25,7 @@
 from zope.schema import (
     Int,
     Object,
+    Text,
     )
 
 from canonical.launchpad import _
@@ -117,6 +118,14 @@
 class IInitializeDistroSeriesJob(IRunnableJob):
     """A Job that performs actions on a distribution."""
 
+    error_description = Text(
+        title=_("Error description"),
+        description=_(
+            "A short description of the last error this "
+            "job encountered, if any."),
+        readonly=True,
+        required=False)
+
 
 class IDistroSeriesDifferenceJobSource(IJobSource):
     """An `IJob` for creating `DistroSeriesDifference`s."""