def test_with_backtrace(self):
     matcher = HasQueryCount(LessThan(2))
     collector = RequestTimelineCollector()
     collector.count = 2
     collector.queries = [
         (0, 1, "SQL-main-slave", "SELECT 1 FROM Person",
          '  File "example", line 2, in <module>\n'
          '    Store.of(Person).one()\n'),
         (2, 3, "SQL-main-slave", "SELECT 1 FROM Product",
          '  File "example", line 3, in <module>\n'
          '    Store.of(Product).one()\n'),
         ]
     mismatch = matcher.match(collector)
     self.assertThat(mismatch, Not(Is(None)))
     details = mismatch.get_details()
     lines = []
     for name, content in details.items():
         self.assertEqual("queries", name)
         self.assertEqual("text", content.content_type.type)
         lines.append(''.join(content.iter_text()))
     separator = "-" * 70
     backtrace_separator = "." * 70
     expected_lines = [
         '0-1@SQL-main-slave SELECT 1 FROM Person\n' + separator + '\n' +
         '  File "example", line 2, in <module>\n' +
         '    Store.of(Person).one()\n' + backtrace_separator + '\n' +
         '2-3@SQL-main-slave SELECT 1 FROM Product\n' + separator + '\n' +
         '  File "example", line 3, in <module>\n' +
         '    Store.of(Product).one()\n' + backtrace_separator,
         ]
     self.assertEqual(expected_lines, lines)
     self.assertEqual(
         "queries do not match: %s" % (LessThan(2).match(2).describe(),),
         mismatch.describe())
Exemple #2
0
 def test_binary_query_counts(self):
     query_baseline = 40
     # Assess the baseline.
     collector = RequestTimelineCollector()
     collector.register()
     self.addCleanup(collector.unregister)
     ppa = self.factory.makeArchive()
     viewer = self.factory.makePerson()
     browser = self.getUserBrowser(user=viewer)
     with person_logged_in(viewer):
         # The baseline has one package, because otherwise the
         # short-circuit prevents the packages iteration happening at
         # all and we're not actually measuring scaling
         # appropriately.
         pkg = self.factory.makeBinaryPackagePublishingHistory(archive=ppa)
         url = canonical_url(ppa) + "/+packages"
     browser.open(url)
     self.assertThat(collector, HasQueryCount(LessThan(query_baseline)))
     expected_count = collector.count
     # Use all new objects - avoids caching issues invalidating the
     # gathered metrics.
     login(ADMIN_EMAIL)
     ppa = self.factory.makeArchive()
     viewer = self.factory.makePerson()
     browser = self.getUserBrowser(user=viewer)
     with person_logged_in(viewer):
         for i in range(3):
             pkg = self.factory.makeBinaryPackagePublishingHistory(
                 archive=ppa, distroarchseries=pkg.distroarchseries)
         url = canonical_url(ppa) + "/+packages"
     browser.open(url)
     self.assertThat(collector, HasQueryCount(Equals(expected_count)))
 def test_match(self):
     matcher = HasQueryCount(Is(3))
     collector = RequestTimelineCollector()
     collector.count = 3
     # not inspected
     del collector.queries
     self.assertThat(matcher.match(collector), Is(None))
 def test_mismatch(self):
     matcher = HasQueryCount(LessThan(2))
     collector = RequestTimelineCollector()
     collector.count = 2
     collector.queries = [
         (0, 1, "SQL-main-slave", "SELECT 1 FROM Person", None),
         (2, 3, "SQL-main-slave", "SELECT 1 FROM Product", None),
         ]
     mismatch = matcher.match(collector)
     self.assertThat(mismatch, Not(Is(None)))
     details = mismatch.get_details()
     lines = []
     for name, content in details.items():
         self.assertEqual("queries", name)
         self.assertEqual("text", content.content_type.type)
         lines.append(''.join(content.iter_text()))
     separator = "-" * 70
     expected_lines = [
         "0-1@SQL-main-slave SELECT 1 FROM Person\n" + separator + "\n" +
         "2-3@SQL-main-slave SELECT 1 FROM Product\n" + separator,
         ]
     self.assertEqual(expected_lines, lines)
     self.assertEqual(
         "queries do not match: %s" % (LessThan(2).match(2).describe(),),
         mismatch.describe())
 def test_messages_query_counts_constant(self):
     # XXX Robert Collins 2010-09-15 bug=619017
     # This test may be thrown off by the reference bug. To get around the
     # problem, flush and reset are called on the bug storm cache before
     # each call to the webservice. When lp's storm is updated to release
     # the committed fix for this bug, please see about updating this test.
     login(USER_EMAIL)
     bug = self.factory.makeBug()
     store = Store.of(bug)
     self.factory.makeBugComment(bug)
     self.factory.makeBugComment(bug)
     self.factory.makeBugComment(bug)
     webservice = LaunchpadWebServiceCaller('launchpad-library',
                                            'salgado-change-anything')
     collector = RequestTimelineCollector()
     collector.register()
     self.addCleanup(collector.unregister)
     url = '/bugs/%d/messages?ws.size=75' % bug.id
     # First request.
     store.flush()
     store.reset()
     response = webservice.get(url)
     self.assertThat(collector, HasQueryCount(LessThan(24)))
     with_2_count = collector.count
     self.assertEqual(response.status, 200)
     login(USER_EMAIL)
     for i in range(50):
         self.factory.makeBugComment(bug)
     self.factory.makeBugAttachment(bug)
     logout()
     # Second request.
     store.flush()
     store.reset()
     response = webservice.get(url)
     self.assertThat(collector, HasQueryCount(Equals(with_2_count)))
Exemple #6
0
 def test_api_branches_query_count(self):
     webservice = LaunchpadWebServiceCaller()
     collector = RequestTimelineCollector()
     collector.register()
     self.addCleanup(collector.unregister)
     # Get 'all' of the 50 branches this collection is limited to - rather
     # than the default in-test-suite pagination size of 5.
     url = "/branches?ws.size=50"
     logout()
     response = webservice.get(url,
         headers={'User-Agent': 'AnonNeedsThis'})
     self.assertEqual(response.status, 200,
         "Got %d for url %r with response %r" % (
         response.status, url, response.body))
     self.assertThat(collector, HasQueryCount(LessThan(17)))
Exemple #7
0
    def test_permission_check_query_count_for_admin_members(self):
        # The number of administrators a team has doesn't affect the
        # number of queries carried out when checking that one of those
        # administrators can update that team's subscriptions.
        team = self.factory.makeTeam()
        team_2 = self.factory.makeTeam()
        # For this test we'll create two teams, one with one
        # administrator and the other with several.
        with person_logged_in(team.teamowner):
            team.addMember(
                self.subscriber, team.teamowner,
                status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team, team.teamowner)
        with person_logged_in(team_2.teamowner):
            for i in range(25):
                person = self.factory.makePerson()
                team_2.addMember(
                    person, team_2.teamowner,
                    status=TeamMembershipStatus.ADMIN)
            team_2.addMember(
                self.subscriber, team_2.teamowner,
                status=TeamMembershipStatus.ADMIN)
            self.bug.subscribe(team_2, team_2.teamowner)

        collector = RequestTimelineCollector()
        collector.register()
        self.addCleanup(collector.unregister)
        with person_logged_in(self.subscriber):
            self.updateBugNotificationLevelWithWebService(
                self.bug.id, team.name, self.subscriber)
        # 25 is an entirely arbitrary limit for the number of queries
        # this requires, based on the number run when the code was
        # written; it should give us a nice early warning if the number
        # of queries starts to grow.
        self.assertThat(
            collector, HasQueryCount(LessThan(25)))
        # It might seem odd that we don't do this all as one with block,
        # but using the collector and the webservice means our
        # interaction goes away, so we have to set up a new one.
        with person_logged_in(self.subscriber):
            self.updateBugNotificationLevelWithWebService(
                self.bug.id, team_2.name, self.subscriber)
        self.assertThat(
            collector, HasQueryCount(LessThan(25)))
 def test_blueprint_listing_query_count(self):
     """Set a maximum number of queries for sprint blueprint lists."""
     sprint = self.factory.makeSprint()
     for count in range(10):
         blueprint = self.factory.makeSpecification()
         link = blueprint.linkSprint(sprint, blueprint.owner)
         link.acceptBy(sprint.owner)
     with RequestTimelineCollector() as recorder:
         self.getViewBrowser(sprint)
     self.assertThat(recorder, HasQueryCount(Equals(30)))
 def test_proprietary_blueprint_listing_query_count(self):
     """Set a maximum number of queries for sprint blueprint lists."""
     sprint = self.factory.makeSprint()
     for count in range(10):
         blueprint = self.factory.makeSpecification(
             information_type=InformationType.PROPRIETARY)
         owner = removeSecurityProxy(blueprint).owner
         link = removeSecurityProxy(blueprint).linkSprint(sprint, owner)
         link.acceptBy(sprint.owner)
     with RequestTimelineCollector() as recorder:
         self.getViewBrowser(sprint)
     self.assertThat(recorder, HasQueryCount(Equals(22)))
Exemple #10
0
 def test_source_query_counts(self):
     query_baseline = 43
     # Assess the baseline.
     collector = RequestTimelineCollector()
     collector.register()
     self.addCleanup(collector.unregister)
     ppa = self.factory.makeArchive()
     viewer = self.factory.makePerson()
     browser = self.getUserBrowser(user=viewer)
     with person_logged_in(viewer):
         # The baseline has one package, because otherwise the
         # short-circuit prevents the packages iteration happening at
         # all and we're not actually measuring scaling
         # appropriately.
         self.factory.makeSourcePackagePublishingHistory(archive=ppa)
         url = canonical_url(ppa) + "/+packages"
     browser.open(url)
     self.assertThat(collector, HasQueryCount(LessThan(query_baseline)))
     expected_count = collector.count
     # We scale with 1 query per distro series because of
     # getCurrentSourceReleases.
     expected_count += 1
     # We need a fuzz of one because if the test is the first to run a
     # credentials lookup is done as well (and accrued to the collector).
     expected_count += 1
     # Use all new objects - avoids caching issues invalidating the
     # gathered metrics.
     login(ADMIN_EMAIL)
     ppa = self.factory.makeArchive()
     viewer = self.factory.makePerson()
     browser = self.getUserBrowser(user=viewer)
     with person_logged_in(viewer):
         for i in range(2):
             pkg = self.factory.makeSourcePackagePublishingHistory(
                 archive=ppa)
             self.factory.makeSourcePackagePublishingHistory(
                 archive=ppa, distroseries=pkg.distroseries)
         url = canonical_url(ppa) + "/+packages"
     browser.open(url)
     self.assertThat(collector, HasQueryCount(LessThan(expected_count)))
Exemple #11
0
    def check_query_counts_scaling_with_unique_people(self, target,
                                                      targettype):
        """Check that a particular hasSpecifications target scales well.

        :param target: A spec target like a product.
        :param targettype: The parameter to pass to makeSpecification to
            associate the target. e.g. 'product'.
        """
        query_baseline = 40
        people = []
        for _ in range(10):
            people.append(self.factory.makePerson())
        specs = []
        for _ in range(10):
            specs.append(
                self.factory.makeSpecification(**{targettype: target}))
        collector = RequestTimelineCollector()
        collector.register()
        self.addCleanup(collector.unregister)
        url = canonical_url(target) + "/+assignments"
        viewer = self.factory.makePerson()
        browser = self.getUserBrowser(user=viewer)
        # Seed the cookie cache and any other cross-request state we may gain
        # in future.  See lp.services.webapp.serssion: _get_secret.
        browser.open(url)
        self.invalidate_and_render(browser, target, url)
        # Set a baseline
        self.assertThat(collector, HasQueryCount(LessThan(query_baseline)))
        no_assignees_count = collector.count
        # Assign many unique people, which shouldn't change the page queries.
        # Due to storm bug 619017 additional queries can be triggered when
        # revalidating people, so we allow -some- fuzz.
        login(ADMIN_EMAIL)
        for person, spec in zip(people, specs):
            spec.assignee = person
        logout()
        self.invalidate_and_render(browser, target, url)
        self.assertThat(collector,
                        HasQueryCount(LessThan(no_assignees_count + 5)))
 def test_list(self):
     names = ['bob', 'frog']
     for i in range(3):
         builder = self.factory.makeBuilder()
         self.factory.makeBinaryPackageBuild().queueBuild().markAsBuilding(
             builder)
         names.append(builder.name)
     logout()
     with RequestTimelineCollector() as recorder:
         builders = self.webservice.get('/builders',
                                        api_version='devel').jsonBody()
     self.assertContentEqual(names,
                             [b['name'] for b in builders['entries']])
     self.assertThat(recorder, HasQueryCount(Equals(19)))
Exemple #13
0
 def match(self, context):
     # circular dependencies.
     from lp.testing.pages import setupBrowserForUser
     with person_logged_in(self.user):
         context_url = canonical_url(context,
                                     view_name=self.view_name,
                                     **self.options)
     browser = setupBrowserForUser(self.user)
     flush_database_caches()
     with RequestTimelineCollector() as collector:
         browser.open(context_url)
     counter = HasQueryCount(LessThan(self.query_limit))
     # When bug 724691 is fixed, this can become an AnnotateMismatch to
     # describe the object being rendered.
     return counter.match(collector)
 def test_byEquality(self):
     old_collector = RequestTimelineCollector()
     old_collector.count = 2
     old_collector.queries = [
         (0, 1, "SQL-main-slave", "SELECT 1 FROM Person", None),
         (2, 3, "SQL-main-slave", "SELECT 1 FROM Product", None),
         ]
     new_collector = RequestTimelineCollector()
     new_collector.count = 3
     new_collector.queries = [
         (0, 1, "SQL-main-slave", "SELECT 1 FROM Person", None),
         (2, 3, "SQL-main-slave", "SELECT 1 FROM Product", None),
         (4, 5, "SQL-main-slave", "SELECT 1 FROM Distribution", None),
         ]
     matcher = HasQueryCount.byEquality(old_collector)
     mismatch = matcher.match(new_collector)
     self.assertThat(mismatch, Not(Is(None)))
     details = mismatch.get_details()
     old_lines = []
     new_lines = []
     self.assertThat(details, KeysEqual("queries", "other_queries"))
     self.assertEqual("text", details["other_queries"].content_type.type)
     old_lines.append("".join(details["other_queries"].iter_text()))
     self.assertEqual("text", details["queries"].content_type.type)
     new_lines.append("".join(details["queries"].iter_text()))
     separator = "-" * 70
     expected_old_lines = [
         "0-1@SQL-main-slave SELECT 1 FROM Person\n" + separator + "\n" +
         "2-3@SQL-main-slave SELECT 1 FROM Product\n" + separator,
         ]
     expected_new_lines = [
         "0-1@SQL-main-slave SELECT 1 FROM Person\n" + separator + "\n" +
         "2-3@SQL-main-slave SELECT 1 FROM Product\n" + separator + "\n" +
         "4-5@SQL-main-slave SELECT 1 FROM Distribution\n" + separator,
         ]
     self.assertEqual(expected_old_lines, old_lines)
     self.assertEqual(expected_new_lines, new_lines)
     self.assertEqual(
         "queries do not match: %s" % (Equals(2).match(3).describe(),),
         mismatch.describe())
Exemple #15
0
 def test_more_private_bugs_query_count_is_constant(self):
     # This test tests that as we add more private bugs to a milestone
     # index page, the number of queries issued by the page does not
     # change. It also sets a cap on the queries for this page: if the
     # baseline were to increase, the test would fail. As the baseline
     # is very large already, if the test fails due to such a change,
     # please cut some more of the existing fat out of it rather than
     # increasing the cap.
     page_query_limit = 37
     product = self.factory.makeProduct()
     product_owner = product.owner
     login_person(product.owner)
     milestone = self.factory.makeMilestone(
         productseries=product.development_focus)
     bug1 = self.factory.makeBug(target=product,
                                 information_type=InformationType.USERDATA,
                                 owner=product.owner)
     bug1.bugtasks[0].transitionToMilestone(milestone, product.owner)
     # We look at the page as someone who is a member of a team and the
     # team is subscribed to the bugs, so that we don't get trivial
     # shortcuts avoiding queries : test the worst case.
     subscribed_team = self.factory.makeTeam(
         membership_policy=TeamMembershipPolicy.MODERATED)
     viewer = self.factory.makePerson()
     with person_logged_in(subscribed_team.teamowner):
         subscribed_team.addMember(viewer, subscribed_team.teamowner)
     bug1.subscribe(subscribed_team, product.owner)
     bug1_url = canonical_url(bug1)
     milestone_url = canonical_url(milestone)
     browser = self.getUserBrowser(user=viewer)
     # Seed the cookie cache and any other cross-request state we may gain
     # in future.  See lp.services.webapp.serssion: _get_secret.
     browser.open(milestone_url)
     collector = RequestTimelineCollector()
     collector.register()
     self.addCleanup(collector.unregister)
     browser.open(milestone_url)
     # Check that the test found the bug
     self.assertTrue(bug1_url in browser.contents)
     self.assertThat(collector, HasQueryCount(LessThan(page_query_limit)))
     with_1_private_bug = collector.count
     with_1_queries = [
         "%s: %s" % (pos, stmt[3])
         for (pos, stmt) in enumerate(collector.queries)
     ]
     login_person(product_owner)
     bug2 = self.factory.makeBug(target=product,
                                 information_type=InformationType.USERDATA,
                                 owner=product.owner)
     bug2.bugtasks[0].transitionToMilestone(milestone, product.owner)
     bug2.subscribe(subscribed_team, product.owner)
     bug2_url = canonical_url(bug2)
     bug3 = self.factory.makeBug(target=product,
                                 information_type=InformationType.USERDATA,
                                 owner=product.owner)
     bug3.bugtasks[0].transitionToMilestone(milestone, product.owner)
     bug3.subscribe(subscribed_team, product.owner)
     logout()
     browser.open(milestone_url)
     self.assertTrue(bug2_url in browser.contents)
     self.assertThat(collector, HasQueryCount(LessThan(page_query_limit)))
     with_3_private_bugs = collector.count
     with_3_queries = [
         "%s: %s" % (pos, stmt[3])
         for (pos, stmt) in enumerate(collector.queries)
     ]
     self.assertEqual(
         with_1_private_bug, with_3_private_bugs,
         "different query count: \n%s\n******************\n%s\n" %
         ('\n'.join(with_1_queries), '\n'.join(with_3_queries)))