def test_match(self): matcher = HasQueryCount(Is(3)) collector = QueryCollector() collector.count = 3 # not inspected del collector.queries self.assertThat(matcher.match(collector), Is(None))
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 = QueryCollector() 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.failUnlessEqual(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)))
def test_binary_query_counts(self): query_baseline = 40 # Assess the baseline. collector = QueryCollector() 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_binary_query_counts(self): query_baseline = 40 # Assess the baseline. collector = QueryCollector() 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_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 = QueryCollector() 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.failUnlessEqual(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)))
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 = QueryCollector() 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)), )
def test_api_branches_query_count(self): webservice = LaunchpadWebServiceCaller() collector = QueryCollector() 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)))
def test_mismatch(self): matcher = HasQueryCount(LessThan(2)) collector = QueryCollector() collector.count = 2 collector.queries = [("foo", "bar"), ("baaz", "quux")] 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())) self.assertEqual(["('foo', 'bar')\n('baaz', 'quux')"], lines) self.assertEqual( "queries do not match: %s" % (LessThan(2).match(2).describe(),), mismatch.describe())
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 = QueryCollector() 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 QueryCollector() as recorder: self.getViewBrowser(sprint) self.assertThat(recorder, HasQueryCount(Equals(30)))
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 = QueryCollector() 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 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() collector = QueryCollector() collector.register() try: 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) finally: # Unregister now in case this method is called multiple # times in a single test. collector.unregister()
def test_source_query_counts(self): query_baseline = 43 # Assess the baseline. collector = QueryCollector() 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)))
def test_source_query_counts(self): query_baseline = 43 # Assess the baseline. collector = QueryCollector() 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)))
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 = QueryCollector() 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 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 = QueryCollector() 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_binaryFileUrls_include_meta(self): person = self.factory.makePerson() webservice = webservice_for_person( person, permission=OAuthPermission.READ_PUBLIC) bpph, url = self.make_bpph_for(person) query_counts = [] for i in range(3): flush_database_caches() with QueryCollector() as collector: response = webservice.named_get( url, 'binaryFileUrls', include_meta=True, api_version='devel') query_counts.append(collector.count) with person_logged_in(person): self.factory.makeBinaryPackageFile( binarypackagerelease=bpph.binarypackagerelease) self.assertEqual(query_counts[0] - 1, query_counts[-1]) self.assertEqual(200, response.status) urls = response.jsonBody() self.assertEqual(3, len(urls)) self.assertThat(urls[0], IsInstance(dict))
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 = QueryCollector() 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)))