Exemple #1
0
    def test_rendering(self):
        some_repo = self.factory.makeGitRepository(
            owner=self.owner, target=self.target, name="foo")
        self.factory.makeGitRefs(
            some_repo,
            paths=["refs/heads/master", "refs/heads/bug-1234"])

        other_repo = self.factory.makeGitRepository(
            owner=self.owner, target=self.target, name="bar")
        self.factory.makeGitRefs(other_repo, paths=["refs/heads/bug-2468"])

        view = create_initialized_view(self.context, '+git')
        self.assertIs(None, view.default_git_repository)

        content = view()
        soup = BeautifulSoup(content)

        # No details about the default repo are shown, as a person
        # without a target doesn't have a default repo
        self.assertNotIn('Branches', content)
        self.assertNotIn('Browse the code', content)
        self.assertNotIn('git clone', content)
        self.assertNotIn('bug-1234', content)

        # All owned repos are listed.
        table = soup.find(
            'div', id='gitrepositories-table-listing').find('table')
        self.assertContentEqual(
            [some_repo.git_identity, other_repo.git_identity],
            [link.find(text=True) for link in table.findAll('a')])
 def test_remove_link_not_shown_if_no_duplicate(self):
     with person_logged_in(self.bug_owner):
         view = create_initialized_view(self.bug.default_bugtask,
                                        name="+duplicate",
                                        principal=self.bug_owner)
         soup = BeautifulSoup(view.render())
     self.assertIsNone(soup.find(attrs={'id': 'field.actions.remove'}))
    def test_ajax_remove_duplicate(self):
        # An ajax request to remove a duplicate returns the new bugtask table.
        with person_logged_in(self.bug_owner):
            self.bug.markAsDuplicate(self.duplicate_bug)
            extra = {
                'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest',
            }
            form = {
                'field.actions.remove': u'Remove Duplicate',
            }

            view = create_initialized_view(self.bug.default_bugtask,
                                           name="+duplicate",
                                           principal=self.bug_owner,
                                           form=form,
                                           **extra)
            result_html = view.render()

        self.assertIsNone(self.bug.duplicateof)
        self.assertEqual(view.request.response.getHeader('content-type'),
                         'text/html')
        soup = BeautifulSoup(result_html)
        table = soup.find('table', {
            'id': 'affected-software',
            'class': 'listing'
        })
        self.assertIsNotNone(table)
Exemple #4
0
    def getRemoteBug(self, bug_id):
        """See `ExternalBugTracker`."""
        # Only parse tables to save time and memory. If we didn't have
        # to check for application errors in the page (using
        # _checkForApplicationError) then we could be much more
        # specific than this.
        bug_page = BeautifulSoup(self._getPage('view.php?id=%s' %
                                               bug_id).content,
                                 convertEntities=BeautifulSoup.HTML_ENTITIES,
                                 parseOnlyThese=SoupStrainer('table'))

        app_error = self._checkForApplicationError(bug_page)
        if app_error:
            app_error_code, app_error_message = app_error
            # 1100 is ERROR_BUG_NOT_FOUND in Mantis (see
            # mantisbt/core/constant_inc.php).
            if app_error_code == '1100':
                return None, None
            else:
                raise BugWatchUpdateError("Mantis APPLICATION ERROR #%s: %s" %
                                          (app_error_code, app_error_message))

        bug = {
            'id': bug_id,
            'status': self._findValueRightOfKey(bug_page, 'Status'),
            'resolution': self._findValueRightOfKey(bug_page, 'Resolution')
        }

        return int(bug_id), bug
Exemple #5
0
 def test_job_notifications_display_multiple(self):
     job1 = self.makeJob('package_1')
     job2 = self.makeJob('package_2', failed=True)
     job3 = self.makeJob('package_3')
     with person_logged_in(self.archive.owner):
         view = create_initialized_view(self.archive,
                                        "+packages",
                                        principal=self.archive.owner)
         html = view.render()
     packages_matches = soupmatchers.HTMLContains(
         soupmatchers.Tag('job1',
                          'div',
                          attrs={
                              'class': 'pending-job',
                              'job_id': job1.id
                          }),
         soupmatchers.Tag('job2',
                          'div',
                          attrs={
                              'class': 'pending-job',
                              'job_id': job2.id
                          }),
         soupmatchers.Tag('job3',
                          'div',
                          attrs={
                              'class': 'pending-job',
                              'job_id': job3.id
                          }),
     )
     self.assertThat(html, packages_matches)
     self.assertEqual([],
                      BeautifulSoup(html).findAll(
                          'span', text=re.compile('Showing 5 of .')))
 def test_user_without_launchpad_view(self):
     # When the user does not have launchpad.View on the context,
     # base-layout does not render the main slot and side slot.
     owner = self.factory.makePerson()
     with person_logged_in(owner):
         team = self.factory.makeTeam(displayname='Waffles',
                                      owner=owner,
                                      visibility=PersonVisibility.PRIVATE)
         archive = self.factory.makeArchive(private=True, owner=team)
         archive.newSubscription(self.user, registrant=owner)
     with person_logged_in(self.user):
         view = self.makeTemplateView('main_side', context=team)
         content = BeautifulSoup(view())
     self.assertIs(None, content.find(text=' Extra head content '))
     self.verify_base_layout_html_element(content)
     self.verify_base_layout_head_parts(view, content)
     document = find_tag_by_id(content, 'document')
     self.verify_base_layout_body_parts(document)
     self.verify_watermark(document)
     # These parts are unique to the case without launchpad.View.
     self.assertIsNone(document.find(True, id='side-portlets'))
     self.assertIsNone(document.find(True, id='registration'))
     self.assertEndsWith(
         extract_text(document.find(True, id='maincontent')),
         'The information in this page is not shared with you.')
    def test_does_display_child_diff(self):
        # If the child's latest published version is not the same as the base
        # version, we display two links to two diffs.
        changelog_lfa = self.factory.makeChangelog('foo',
                                                   ['0.1-1derived1', '0.1-1'])
        parent_changelog_lfa = self.factory.makeChangelog(
            'foo', ['0.1-2', '0.1-1'])
        transaction.commit()  # Yay, librarian.
        ds_diff = self.factory.makeDistroSeriesDifference(
            versions={
                'derived': '0.1-1derived1',
                'parent': '0.1-2',
            },
            changelogs={
                'derived': changelog_lfa,
                'parent': parent_changelog_lfa
            })

        self.assertEqual('0.1-1', ds_diff.base_version)
        with person_logged_in(self.factory.makePerson()):
            view = create_initialized_view(ds_diff,
                                           '+listing-distroseries-extra')
            soup = BeautifulSoup(view())
        tags = soup.find('ul', 'package-diff-status').findAll('span')
        self.assertEqual(2, len(tags))
Exemple #8
0
def print_upstream_linking_form(browser):
    """Print the upstream linking form found via +choose-affected-product.

    The resulting output will look something like:
    (*) A checked option
        [A related text field]
    ( ) An unchecked option
    """
    soup = BeautifulSoup(browser.contents)

    link_upstream_how_radio_control = browser.getControl(
        name='field.link_upstream_how')
    link_upstream_how_buttons = soup.findAll(
        'input', {'name': 'field.link_upstream_how'})

    wrapper = textwrap.TextWrapper(width=65, subsequent_indent='    ')
    for button in link_upstream_how_buttons:
        # Print the radio button.
        label = button.findParent('label')
        if label is None:
            label = soup.find('label', {'for': button['id']})
        if button.get('value') in link_upstream_how_radio_control.value:
            print wrapper.fill('(*) %s' % extract_text(label))
        else:
            print wrapper.fill('( ) %s' % extract_text(label))
        # Print related text field, if found. Assumes that the text
        # field is in the same table row as the radio button.
        text_field = button.findParent('tr').find('input', {'type': 'text'})
        if text_field is not None:
            text_control = browser.getControl(name=text_field.get('name'))
            print '    [%s]' % text_control.value.ljust(10)
    def test_blog_posts(self):
        """Posts from the launchpad blog are shown when feature is enabled"""
        self.useFixture(FeatureFixture({'app.root_blog.enabled': True}))
        posts = [
            self._make_blog_post(1, "A post", "Post contents.", "2002"),
            self._make_blog_post(2, "Another post", "More contents.", "2003"),
        ]
        calls = []

        def _get_blog_posts():
            calls.append('called')
            return posts

        root = getUtility(ILaunchpadRoot)
        with anonymous_logged_in():
            view = create_initialized_view(root, 'index.html')
            view.getRecentBlogPosts = _get_blog_posts
            result = view()
        markup = BeautifulSoup(
            result, parse_only=SoupStrainer(id='homepage-blogposts'))
        self.assertEqual(['called'], calls)
        items = markup.findAll('li', 'news')
        # Notice about launchpad being opened is always added at the end
        self.assertEqual(3, len(items))
        a = items[-1].find("a")
        self.assertEqual("Launchpad now open source", a.string.strip())
        for post, item in zip(posts, items):
            a = item.find("a")
            self.assertEqual(post['link'], a["href"])
            self.assertEqual(post['title'], a.string)
 def test_bug_description_in_meta_description_anonymous(self):
     browser = self.getBrowserForBugWithEmail(no_login=True)
     soup = BeautifulSoup(browser.contents)
     meat = soup.find('meta', dict(name='description'))
     self.assertThat(meat['content'],
                     MatchesAll(
                         Contains('Description with'), Not(Contains('@')),
                         Contains('...')))  # Ellipsis from hidden address.
 def test_contact_support_anonymous(self):
     # The support link points to /feedback when the user is anonymous.
     view = self.makeTemplateView('main_only')
     view._user = None
     content = BeautifulSoup(view())
     footer = find_tag_by_id(content, 'footer')
     link = footer.find('a', text='Contact Launchpad Support')
     self.assertEqual('/feedback', link['href'])
 def test_contact_support_logged_in(self):
     # The support link points to /support when the user is logged in.
     view = self.makeTemplateView('main_only')
     view._user = self.user
     content = BeautifulSoup(view())
     footer = find_tag_by_id(content, 'footer')
     link = footer.find('a', text='Contact Launchpad Support')
     self.assertEqual('/support', link['href'])
 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))
Exemple #14
0
 def test_sharing_menu(self):
     url = canonical_url(self.pillar)
     sharing_url = canonical_url(self.pillar, view_name='+sharing')
     browser = setupBrowserForUser(user=self.driver)
     browser.open(url)
     soup = BeautifulSoup(browser.contents)
     sharing_menu = soup.find('a', {'href': sharing_url})
     self.assertIsNotNone(sharing_menu)
 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))
Exemple #16
0
 def test_product_with_edit_permission(self):
     login_person(self.product.owner)
     self.view = create_initialized_view(
         self.product, '+questions', principal=self.product.owner)
     content = BeautifulSoup(self.view())
     self.assertCommonPageElements(content)
     self.assertTrue(
         content.find(True, id='configure-support') is not None)
Exemple #17
0
def get_feedback_messages(content):
    """Find and return the feedback messages of the page."""
    message_classes = [
        'message', 'informational message', 'error message', 'warning message'
    ]
    soup = BeautifulSoup(content,
                         parseOnlyThese=SoupStrainer(
                             ['div', 'p'], {'class': message_classes}))
    return [extract_text(tag) for tag in soup]
Exemple #18
0
 def test_call(self):
     # The __call__ method sets up the widgets and the options.
     markup = self.widget()
     self.assertIsNotNone(self.widget.person_widget)
     self.assertIn("repository_owner", self.widget.options)
     self.assertIn("person", self.widget.options)
     soup = BeautifulSoup(markup)
     fields = soup.findAll(["input", "select"], {"id": re.compile(".*")})
     ids = [field["id"] for field in fields]
     self.assertContentEqual(self.expected_ids, ids)
 def test_information_type_vocabulary(self):
     # Test that the view creates the vocabulary correctly.
     bug = self.factory.makeBug()
     with person_logged_in(bug.owner):
         view = create_initialized_view(bug.default_bugtask,
                                        name='+secrecy',
                                        principal=bug.owner)
         html = view.render()
         soup = BeautifulSoup(html)
     self.assertEqual(u'Private', soup.find('label', text="Private").string)
 def test_bug_description_in_meta_description_not_anonymous(self):
     browser = self.getBrowserForBugWithEmail(no_login=False)
     soup = BeautifulSoup(browser.contents)
     meat = soup.find('meta', dict(name='description'))
     # Even logged in users get email stripped from the metadata, in case
     # they use a tool that copies it out.
     self.assertThat(meat['content'],
                     MatchesAll(
                         Contains('Description with'), Not(Contains('@')),
                         Contains('...')))  # Ellipsis from hidden address.
Exemple #21
0
def print_radio_button_field(content, name):
    """Find the input called field.name, and print a friendly representation.

    The resulting output will look something like:
    (*) A checked option
    ( ) An unchecked option
    """
    main = BeautifulSoup(content)
    for field in get_radio_button_text_for_field(main, name):
        print field
 def test_call(self):
     # The __call__ method sets up the widgets.
     markup = self.widget()
     self.assertIsNotNone(self.widget.repository_widget)
     self.assertIsNotNone(self.widget.path_widget)
     soup = BeautifulSoup(markup)
     fields = soup.findAll("input", id=True)
     ids = [field["id"] for field in fields]
     self.assertContentEqual(
         ["field.git_ref.repository", "field.git_ref.path"], ids)
 def test_filebug_information_type_public_policy(self):
     # The vocabulary for information_type when filing a bug is created
     # correctly for non commercial projects.
     product = self.factory.makeProduct(official_malone=True)
     with person_logged_in(product.owner):
         view = create_initialized_view(product,
                                        '+filebug',
                                        principal=product.owner)
         html = view.render()
         soup = BeautifulSoup(html)
     self.assertIsNone(soup.find('label', text="Proprietary"))
Exemple #24
0
 def test_view_contents(self):
     # Distributions are rendered with the correct text.
     url = canonical_url(self.pillar, view_name='+sharing')
     browser = setupBrowserForUser(user=self.driver)
     browser.open(url)
     soup = BeautifulSoup(browser.contents)
     commercial_text = soup.find('p', {'id': 'commercial-project-text'})
     non_commercial_text = soup.find(
         'p', {'id': 'non-commercial-project-text'})
     self.assertIsNone(commercial_text)
     self.assertIsNone(non_commercial_text)
Exemple #25
0
    def test_rendering(self):
        default_repo = self.factory.makeGitRepository(
            owner=self.owner, target=self.target, name="foo")
        self.factory.makeGitRefs(
            default_repo,
            paths=["refs/heads/master", "refs/heads/bug-1234"])

        other_repo = self.factory.makeGitRepository(
            owner=self.owner, target=self.target, name="bar")
        self.factory.makeGitRefs(other_repo, paths=["refs/heads/bug-2468"])

        with admin_logged_in():
            getUtility(IGitRepositorySet).setDefaultRepositoryForOwner(
                owner=self.owner, target=self.target, repository=default_repo,
                user=self.owner)

        view = create_initialized_view(self.owner_target, '+git')
        self.assertEqual(default_repo, view.default_git_repository)

        content = view()
        soup = BeautifulSoup(content)

        # Clone instructions for the default repo are present.
        self.assertEqual(
            'https://git.launchpad.dev/~dev/%s' % self.target_path,
            soup.find(attrs={'class': 'https-url'}).find(text=True))
        self.assertEqual(
            'https://git.launchpad.dev/~dev/%s' % self.target_path,
            soup.find(text='Browse the code').parent['href'])

        # The default repo's branches are shown.
        table = soup.find(
            'div', id='default-repository-branches').find('table')
        self.assertContentEqual(
            ['master', 'bug-1234'],
            [link.find(text=True) for link in table.findAll('a')])
        self.assertEndsWith(
            table.find(text="bug-1234").parent['href'],
            "/~dev/%s/+git/foo/+ref/bug-1234" % self.target_path)

        # Other repos are listed.
        table = soup.find(
            'div', id='gitrepositories-table-listing').find('table')
        self.assertContentEqual(
            ['lp:~dev/%s' % self.target_path,
             'lp:~dev/%s/+git/bar' % self.target_path],
            [link.find(text=True) for link in table.findAll('a')])
        self.assertEndsWith(
            table.find(
                text="lp:~dev/%s/+git/bar" % self.target_path).parent['href'],
            "/~dev/%s/+git/bar" % self.target_path)

        # But not their branches.
        self.assertNotIn('bug-2468', content)
Exemple #26
0
    def get_text_values(self, bug):
        """Returns the text of status and substatus for the given bug.

        This is done by downloading the HTML bug page and scraping it.
        """
        url = '%s%s' % (self.base_url, bug['id'])
        page = self.fetch(url).read()
        soup = BeautifulSoup(page)
        return tuple(
            node.string for node in
            soup.find('th', text='Status').findNext('td').findAll('span'))
    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(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_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_featured_projects_manage_link_requires_edit(self):
     self.setUpRegistryExpert()
     view = create_initialized_view(self.root,
                                    'index.html',
                                    principal=self.expert)
     # Stub out the getRecentBlogPosts which fetches a blog feed using
     # urlfetch.
     view.getRecentBlogPosts = lambda: []
     content = BeautifulSoup(view(), parse_only=SoupStrainer('a'))
     self.assertTrue(
         content.find('a', href='+featuredprojects'),
         "Cannot find the +featuredprojects link on the first page")