예제 #1
0
 def test_rendering(self):
     self.assertThat(
         self.makeView("+new-webhook")(),
         soupmatchers.HTMLContains(
             soupmatchers.Within(breadcrumbs_tag,
                                 webhooks_collection_crumb_tag),
             soupmatchers.Within(
                 breadcrumbs_tag,
                 soupmatchers.Tag('add webhook breadcrumb',
                                  'li',
                                  text=re.compile('Add webhook'))),
             soupmatchers.Tag('cancel link',
                              'a',
                              text='Cancel',
                              attrs={'href': re.compile(r'/\+webhooks$')})))
예제 #2
0
 def test_rendering(self):
     self.assertThat(
         self.makeView("+index")(),
         soupmatchers.HTMLContains(
             soupmatchers.Within(breadcrumbs_tag,
                                 webhooks_collection_crumb_tag),
             soupmatchers.Within(
                 breadcrumbs_tag,
                 soupmatchers.Tag('webhook breadcrumb',
                                  'li',
                                  text=re.compile(
                                      re.escape(
                                          self.webhook.delivery_url)))),
             soupmatchers.Tag('delete link',
                              'a',
                              text='Delete webhook',
                              attrs={'href': re.compile(r'/\+delete$')})))
예제 #3
0
 def test_store_upload_status_failed_with_extended_error_message(self):
     build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT)
     job = getUtility(ISnapStoreUploadJobSource).create(build)
     naked_job = removeSecurityProxy(job)
     naked_job.job._status = JobStatus.FAILED
     naked_job.error_message = "This should not be shown."
     naked_job.error_messages = [
         {"message": (
             "The new version submitted for 'name' does not match the "
             "upload ('other-name').")},
         {"message": "Scan failed.", "link": "link1"},
         {"message": "Classic not allowed.", "link": "link2"}]
     build_view = create_initialized_view(build, "+index")
     built_view = build_view()
     self.assertThat(built_view, Not(soupmatchers.HTMLContains(
         soupmatchers.Tag(
             "store upload status", "li",
             attrs={"id": "store-upload-status"},
             text=re.compile('.*This should not be shown.*')))))
     self.assertThat(built_view, soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload status", "li",
                 attrs={"id": "store-upload-status"}),
             soupmatchers.Tag(
                 "store upload error messages", "ul",
                 attrs={"id": "store-upload-error-messages"}))))
     self.assertThat(built_view, soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload error messages", "ul",
                 attrs={"id": "store-upload-error-messages"}),
             soupmatchers.Tag(
                 "store upload error message", "li",
                 text=re.compile(".*The new version.*")))))
     self.assertThat(built_view, soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload error messages", "ul",
                 attrs={"id": "store-upload-error-messages"}),
             soupmatchers.Within(
                 soupmatchers.Tag(
                     "store upload error message", "li",
                     text=re.compile(".*Scan failed\..*")),
                 soupmatchers.Tag(
                     "store upload error link", "a",
                     attrs={"href": "link1"}, text="(?)")))))
     self.assertThat(built_view, soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload error messages", "ul",
                 attrs={"id": "store-upload-error-messages"}),
             soupmatchers.Within(
                 soupmatchers.Tag(
                     "store upload error message", "li",
                     text=re.compile(".*Classic not allowed\..*")),
                 soupmatchers.Tag(
                     "store upload error link", "a",
                     attrs={"href": "link2"}, text="(?)")))))
예제 #4
0
 def test_store_upload_status_completed(self):
     build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT)
     job = getUtility(ISnapStoreUploadJobSource).create(build)
     naked_job = removeSecurityProxy(job)
     naked_job.job._status = JobStatus.COMPLETED
     naked_job.store_url = "http://sca.example/dev/click-apps/1/rev/1/"
     build_view = create_initialized_view(build, "+index")
     self.assertThat(build_view(), soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload status", "li",
                 attrs={"id": "store-upload-status"}),
             soupmatchers.Tag(
                 "store link", "a", attrs={"href": job.store_url},
                 text=re.compile(
                     r"^\s*Manage this package in the store\s*$")))))
예제 #5
0
 def test_store_upload_status_release_failed(self):
     build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT)
     job = getUtility(ISnapStoreUploadJobSource).create(build)
     naked_job = removeSecurityProxy(job)
     naked_job.job._status = JobStatus.FAILED
     naked_job.store_url = "http://sca.example/dev/click-apps/1/rev/1/"
     naked_job.error_message = "Failed to publish"
     build_view = create_initialized_view(build, "+index")
     self.assertThat(build_view(), soupmatchers.HTMLContains(
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload status", "li",
                 attrs={"id": "store-upload-status"},
                 text=re.compile(
                     r"^\s*Releasing package to channels failed:\s+"
                     r"Failed to publish\s*$")),
             soupmatchers.Tag(
                 "store link", "a", attrs={"href": job.store_url}))))
예제 #6
0
 def test_store_upload_status_failed(self):
     build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT)
     job = getUtility(ISnapStoreUploadJobSource).create(build)
     naked_job = removeSecurityProxy(job)
     naked_job.job._status = JobStatus.FAILED
     naked_job.error_message = "Scan failed."
     build_view = create_initialized_view(build, "+index")
     self.assertThat(build_view(), soupmatchers.HTMLContains(
         soupmatchers.Tag(
             "store upload status", "li",
             attrs={"id": "store-upload-status"}),
         soupmatchers.Within(
             soupmatchers.Tag(
                 "store upload error messages", "ul",
                 attrs={"id": "store-upload-error-messages"}),
             soupmatchers.Tag(
                 "store upload error message", "li",
                 text=re.compile(r"^\s*Scan failed.\s*$")))))
class DistroSeriesDifferenceTemplateTestCase(TestCaseWithFactory):

    layer = LaunchpadFunctionalLayer

    def number_of_request_diff_texts(self, html_or_soup):
        """Returns the number of request diff text."""
        if not (isinstance(html_or_soup, BeautifulSoup)):
            soup = BeautifulSoup(html_or_soup)
        else:
            soup = html_or_soup
        class_dict = {'class': re.compile('request-derived-diff')}
        return len(soup.findAll('span', class_dict))

    def contains_one_link_to_diff(self, html_or_soup, package_diff):
        """Return whether the html contains a link to the diff content."""
        if not (isinstance(html_or_soup, BeautifulSoup)):
            soup = BeautifulSoup(html_or_soup)
        else:
            soup = html_or_soup
        return 1 == len(
            soup.findAll('a', href=package_diff.diff_content.http_url))

    def test_both_request_diff_texts_rendered(self):
        # An unlinked description of a potential diff is displayed when
        # no diff is present.
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)

        with person_logged_in(self.factory.makePerson()):
            view = create_initialized_view(
                ds_diff, '+listing-distroseries-extra')  # , principal=user)
            soup = BeautifulSoup(view())
        # Both diffs present simple text repr. of proposed diff.
        self.assertEqual(2, self.number_of_request_diff_texts(soup))

    def test_source_diff_rendering_diff(self):
        # A linked description of the diff is displayed when
        # it is present.
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)

        with person_logged_in(self.factory.makePerson()):
            ds_diff.package_diff = self.factory.makePackageDiff()

        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        html = view()
        # The text for the parent diff remains, but the source package
        # diff is now a link.
        self.assertEqual(1, self.number_of_request_diff_texts(html))
        self.assertTrue(
            self.contains_one_link_to_diff(html, ds_diff.package_diff))

    def test_source_diff_rendering_diff_no_link(self):
        # The status of the package is shown if the package diff is in a
        # PENDING or FAILED state.
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)

        statuses_and_classes = [(PackageDiffStatus.PENDING, 'PENDING'),
                                (PackageDiffStatus.FAILED, 'FAILED')]
        for status, css_class in statuses_and_classes:
            with person_logged_in(self.factory.makePerson()):
                ds_diff.package_diff = self.factory.makePackageDiff(
                    status=status)

            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            soup = BeautifulSoup(view())
            # Only one link since the other package diff is not COMPLETED.
            self.assertEqual(1, self.number_of_request_diff_texts(soup))
            # The diff has a css_class class.
            self.assertEqual(
                1, len(soup.findAll('span', {'class': re.compile(css_class)})))

    def test_parent_source_diff_rendering_diff_no_link(self):
        # The status of the package is shown if the parent package diff is
        # in a PENDING or FAILED state.
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)

        statuses_and_classes = [(PackageDiffStatus.PENDING, 'PENDING'),
                                (PackageDiffStatus.FAILED, 'FAILED')]
        for status, css_class in statuses_and_classes:
            with person_logged_in(self.factory.makePerson()):
                ds_diff.parent_package_diff = self.factory.makePackageDiff(
                    status=status)

            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            soup = BeautifulSoup(view())
            # Only one link since the other package diff is not COMPLETED.
            self.assertEqual(1, self.number_of_request_diff_texts(soup))
            # The diff has a css_class class.
            self.assertEqual(
                1, len(soup.findAll('span', {'class': re.compile(css_class)})))

    def test_source_diff_rendering_no_source(self):
        # If there is no source pub for this difference, then we don't
        # display even the request for a diff.
        missing_type = DistroSeriesDifferenceType.MISSING_FROM_DERIVED_SERIES
        ds_diff = self.factory.makeDistroSeriesDifference(
            difference_type=missing_type)

        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        self.assertEqual(0, self.number_of_request_diff_texts(view()))

    def test_parent_source_diff_rendering_diff(self):
        # A linked description of the diff is displayed when
        # it is present.
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)

        with person_logged_in(self.factory.makePerson()):
            ds_diff.parent_package_diff = self.factory.makePackageDiff()

        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        # The text for the source diff remains, but the parent package
        # diff is now a link.
        html = view()
        self.assertEqual(1, self.number_of_request_diff_texts(html))
        self.assertTrue(
            self.contains_one_link_to_diff(html, ds_diff.parent_package_diff))

    def test_parent_source_diff_rendering_no_source(self):
        # If there is no source pub for this difference, then we don't
        # display even the request for a diff.
        unique_type = DistroSeriesDifferenceType.UNIQUE_TO_DERIVED_SERIES
        ds_diff = self.factory.makeDistroSeriesDifference(
            difference_type=unique_type)

        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        self.assertEqual(0, self.number_of_request_diff_texts(view()))

    def test_comments_rendered(self):
        # If there are comments on the difference, they are rendered.
        ds_diff = self.factory.makeDistroSeriesDifference()
        person = self.factory.makePerson()
        with person_logged_in(person):
            ds_diff.addComment(person, "I'm working on this.")
            ds_diff.addComment(person, "Here's another comment.")

        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        soup = BeautifulSoup(view())

        self.assertEqual(
            1, len(soup.findAll('pre', text="I'm working on this.")))
        self.assertEqual(
            1, len(soup.findAll('pre', text="Here's another comment.")))

    def test_last_common_version_is_linked(self):
        # The "Last Common Version" version text should link to the
        # parent distro sourcepackagerelease page.
        ds_diff = removeSecurityProxy(
            self.factory.makeDistroSeriesDifference(set_base_version=True))
        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')
        page = view()

        distro = ds_diff.parent_series.distribution
        sourcepackagerelease = ds_diff.parent_source_package_release
        url = canonical_url(DistributionSourcePackageRelease(
            distro, sourcepackagerelease),
                            force_local_path=True)
        anchor_matcher = soupmatchers.HTMLContains(
            soupmatchers.Tag("VERSION LINK", 'a', attrs=dict(href=url)))

        self.assertThat(page, anchor_matcher)

    def getViewContentXmlHttpRequest(self, context, view_name, person):
        # Helper method to request a view via an XMLHttpRequest.
        with person_logged_in(person):
            request = LaunchpadTestRequest(
                HTTP_X_REQUESTED_WITH='XMLHttpRequest')
            view = create_initialized_view(context, view_name, request=request)
            return view()

    def test_blacklist_options(self):
        # Blacklist options are presented to the users who are archive
        # admins.
        ds_diff = self.factory.makeDistroSeriesDifference()
        archive_admin = self.factory.makeArchiveAdmin(
            archive=ds_diff.derived_series.main_archive)
        view_content = self.getViewContentXmlHttpRequest(
            ds_diff, '+listing-distroseries-extra', archive_admin)
        soup = BeautifulSoup(view_content)

        self.assertEqual(
            1, len(soup.findAll('div', {'class': 'blacklist-options'})))

    def test_blacklist_options_disabled(self):
        # Blacklist options are disabled to the users who are *not* archive
        # admins.
        ds_diff = self.factory.makeDistroSeriesDifference()
        person = self.factory.makePerson()
        view_content = self.getViewContentXmlHttpRequest(
            ds_diff, '+listing-distroseries-extra', person)
        soup = BeautifulSoup(view_content)

        self.assertEqual(
            1, len(soup.findAll('div',
                                {'class': 'blacklist-options-disabled'})))

    def test_blacklist_options_initial_values_none(self):
        ds_diff = self.factory.makeDistroSeriesDifference()
        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')

        # If the difference is not currently blacklisted, 'NONE' is set
        # as the default value for the field.
        self.assertEqual('NONE', view.initial_values.get('blacklist_options'))

    def test_blacklist_options_initial_values_current(self):
        ds_diff = self.factory.makeDistroSeriesDifference(
            status=DistroSeriesDifferenceStatus.BLACKLISTED_CURRENT)
        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')

        self.assertEqual(DistroSeriesDifferenceStatus.BLACKLISTED_CURRENT,
                         view.initial_values.get('blacklist_options'))

    def test_blacklist_options_initial_values_always(self):
        ds_diff = self.factory.makeDistroSeriesDifference(
            status=DistroSeriesDifferenceStatus.BLACKLISTED_ALWAYS)
        view = create_initialized_view(ds_diff, '+listing-distroseries-extra')

        self.assertEqual(DistroSeriesDifferenceStatus.BLACKLISTED_ALWAYS,
                         view.initial_values.get('blacklist_options'))

    def test_package_diff_request_link(self):
        # The link to compute package diffs is only shown to
        # a user with lp.Edit permission (i.e. lp.View on the
        # distribution).
        ds_diff = self.factory.makeDistroSeriesDifference(
            set_base_version=True)
        package_diff_request_matcher = soupmatchers.HTMLContains(
            soupmatchers.Tag(
                'Request link',
                'a',
                text=re.compile(
                    '\s*Compute differences from last common version\s*')))

        with person_logged_in(self.factory.makePerson()):
            self.assertTrue(check_permission('launchpad.Edit', ds_diff))
            self.assertTrue(
                check_permission('launchpad.View',
                                 ds_diff.derived_series.parent))
            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            self.assertThat(view(), package_diff_request_matcher)
            self.assertTrue(view.show_package_diffs_request_link)

    package_diff_header_matcher = soupmatchers.HTMLContains(
        soupmatchers.Tag(
            'Package diffs header',
            'dt',
            text=re.compile('\s*Differences from last common version:')))

    package_diff_info_matcher = soupmatchers.HTMLContains(
        soupmatchers.Within(
            soupmatchers.Tag('Package diff container', 'dd'),
            soupmatchers.Tag('Package diffs info',
                             'ul',
                             attrs={'class': 'package-diff-status'})))

    def test_package_diff_label(self):
        # If base_version is not None the label for the section is
        # there.
        changelog_lfa = self.factory.makeChangelog('foo', ['0.30-1'])
        parent_changelog_lfa = self.factory.makeChangelog(
            'foo', ['0.32-1', '0.30-1'])
        transaction.commit()  # Yay, librarian.
        ds_diff = self.factory.makeDistroSeriesDifference(
            versions={
                'derived': '0.30-1',
                'parent': '0.32-1',
            },
            changelogs={
                'derived': changelog_lfa,
                'parent': parent_changelog_lfa
            })

        with celebrity_logged_in('admin'):
            ds_diff.parent_package_diff = self.factory.makePackageDiff()
            ds_diff.package_diff = self.factory.makePackageDiff()
            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            html = view()
            self.assertThat(html, self.package_diff_header_matcher)

    def test_package_diff_no_base_version(self):
        # If diff's base_version is None packages diffs are not displayed
        # and neither is the link to compute them.
        versions = {
            'base': None,  # No base version.
            'derived': '0.1-1derived1',
            'parent': '0.1-2'
        }
        ds_diff = self.factory.makeDistroSeriesDifference(versions=versions)
        package_diff_request_matcher = soupmatchers.HTMLContains(
            soupmatchers.Tag(
                'Request link',
                'a',
                text=re.compile(
                    '\s*Compute differences from last common version\s*')))

        pending_package_diff_matcher = soupmatchers.HTMLContains(
            soupmatchers.Tag('Pending package diff',
                             'span',
                             attrs={'class': 'PENDING'}))

        unknown_base_version = soupmatchers.HTMLContains(
            soupmatchers.Tag(
                'Unknown base version',
                'dd',
                text=re.compile('\s*Unknown, so no diffs are available')))

        with celebrity_logged_in('admin'):
            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            html = view()
            self.assertFalse(view.show_package_diffs_request_link)
            self.assertThat(html, unknown_base_version)
            self.assertThat(
                html,
                Not(
                    MatchesAny(package_diff_request_matcher,
                               pending_package_diff_matcher,
                               self.package_diff_header_matcher)))

    def test_package_diffs_hidden_to_unprivileged_user_if_not_available(self):
        # No diff information is shown if pacakge diffs are not available and
        # the user does not have permission to request their creation.
        ds_diff = self.factory.makeDistroSeriesDifference(
            versions={
                'base': '0.1',
                'derived': '0.1-1derived1',
                'parent': '0.1-2'
            },
            set_base_version=True)
        with anonymous_logged_in():
            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            html = view()
            self.assertThat(html, Not(self.package_diff_header_matcher))
            self.assertThat(html, Not(self.package_diff_info_matcher))
예제 #8
0
                                   attrs={'class': 'breadcrumbs'})
webhooks_page_crumb_tag = soupmatchers.Tag('webhooks page breadcrumb',
                                           'li',
                                           text=re.compile('Webhooks'))
webhooks_collection_crumb_tag = soupmatchers.Tag(
    'webhooks page breadcrumb',
    'a',
    text=re.compile('Webhooks'),
    attrs={'href': re.compile(r'/\+webhooks$')})
add_webhook_tag = soupmatchers.Tag(
    'add webhook',
    'a',
    text='Add webhook',
    attrs={'href': re.compile(r'/\+new-webhook$')})
webhook_listing_constants = soupmatchers.HTMLContains(
    soupmatchers.Within(breadcrumbs_tag, webhooks_page_crumb_tag),
    add_webhook_tag)

webhook_listing_tag = soupmatchers.Tag('webhook listing',
                                       'table',
                                       attrs={'class': 'listing'})
batch_nav_tag = soupmatchers.Tag('batch nav links',
                                 'td',
                                 attrs={'class': 'batch-navigation-links'})


class GitRepositoryTestHelpers:

    event_type = "git:push:0.1"
    expected_event_types = [
        ("git:push:0.1", "Git push"),