launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #00447
[Merge] lp:~lifeless/launchpad/registry into lp:launchpad/devel
Robert Collins has proposed merging lp:~lifeless/launchpad/registry into lp:launchpad/devel.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
Another step along my arc of fixing the /participation API performance. This adds a matcher for query counts and a dependency on a newer testtools to get LessThan.
--
https://code.launchpad.net/~lifeless/launchpad/registry/+merge/31830
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/launchpad/registry into lp:launchpad/devel.
=== modified file 'lib/lp/testing/matchers.py'
--- lib/lp/testing/matchers.py 2010-08-02 20:56:25 +0000
+++ lib/lp/testing/matchers.py 2010-08-05 10:04:46 +0000
@@ -5,6 +5,7 @@
__all__ = [
'DoesNotProvide',
'DoesNotCorrectlyProvide',
+ 'HasQueryCount',
'IsNotProxied',
'IsProxied',
'Provides',
@@ -16,6 +17,8 @@
BrokenImplementation, BrokenMethodImplementation, DoesNotImplement)
from zope.security.proxy import builtin_isinstance, Proxy
+from testtools.content import Content
+from testtools.content_type import ContentType
from testtools.matchers import Matcher, Mismatch
@@ -89,6 +92,45 @@
return None
+class HasQueryCount(Matcher):
+ """Adapt a Binary Matcher to the query count on a QueryCollector.
+
+ If there is a mismatch, the queries from the collector are provided as a
+ test attachment.
+ """
+
+ def __init__(self, count_matcher):
+ """Create a HasQueryCount that will match using count_matcher."""
+ self.count_matcher = count_matcher
+
+ def __str__(self):
+ return "HasQueryCount(%s)" % self.count_matcher
+
+ def match(self, something):
+ mismatch = self.count_matcher.match(something.count)
+ if mismatch is None:
+ return None
+ return _MismatchedQueryCount(mismatch, something)
+
+
+class _MismatchedQueryCount(Mismatch):
+ """The Mismatch for a HasQueryCount matcher."""
+
+ def __init__(self, mismatch, query_collector):
+ self.count_mismatch = mismatch
+ self.query_collector = query_collector
+
+ def describe(self):
+ return "queries do not match: %s" % (self.count_mismatch.describe(),)
+
+ def get_details(self):
+ result = []
+ for query in self.query_collector.queries:
+ result.append(unicode(query).encode('utf8'))
+ return {'queries': Content(ContentType('text', 'plain',
+ {'charset': 'utf8'}), lambda:['\n'.join(result)])}
+
+
class IsNotProxied(Mismatch):
"""An object is not proxied."""
=== modified file 'lib/lp/testing/tests/test_matchers.py'
--- lib/lp/testing/tests/test_matchers.py 2010-08-02 19:52:59 +0000
+++ lib/lp/testing/tests/test_matchers.py 2010-08-05 10:04:46 +0000
@@ -11,8 +11,11 @@
from lp.testing import TestCase
from lp.testing.matchers import (
- DoesNotCorrectlyProvide, DoesNotProvide, IsNotProxied, IsProxied,
- Provides, ProvidesAndIsProxied)
+ DoesNotCorrectlyProvide, DoesNotProvide, HasQueryCount, IsNotProxied,
+ IsProxied, Provides, ProvidesAndIsProxied)
+from lp.testing._webservice import QueryCollector
+
+from testtools.matchers import Is, Not, LessThan
class ITestInterface(Interface):
@@ -169,3 +172,41 @@
obj = ProxyFactory(object(), checker=NamesChecker())
matcher = ProvidesAndIsProxied(ITestInterface)
self.assertIsInstance(matcher.match(obj), DoesNotProvide)
+
+
+class TestQueryMatching(TestCase):
+ """Query matching is a work in progress and can be factored out more.
+
+ For now its pretty hard coded to the initial use case and overlaps some
+ unwritten hypothetical testtools infrastructure - e.g. permitting use of
+ attrgetter and the like.
+ """
+
+ 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_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())
+
+
=== modified file 'versions.cfg'
--- versions.cfg 2010-07-26 16:00:01 +0000
+++ versions.cfg 2010-08-05 10:04:46 +0000
@@ -67,7 +67,8 @@
# This is Storm 0.15 with r342 cherry-picked which fixes a memory leak
# important for message sharing migration script.
storm = 0.15danilo-storm-launchpad-r342
-testtools = 0.9.2
+# Has the LessThan matcher.
+testtools = 0.9.6dev91
transaction = 1.0.0
Twisted = 10.1.0
uuid = 1.30
Follow ups