Merge lp:~bac/launchpad/bug-1007111 into lp:launchpad

Proposed by Brad Crittenden on 2012-06-01
Status: Merged
Approved by: Gary Poster on 2012-06-01
Approved revision: no longer in the source branch.
Merged at revision: 15350
Proposed branch: lp:~bac/launchpad/bug-1007111
Merge into: lp:launchpad
Diff against target: 150 lines (+57/-29)
2 files modified
lib/lp/services/testing/customresult.py (+10/-8)
lib/lp/services/testing/tests/test_customresult.py (+47/-21)
To merge this branch: bzr merge lp:~bac/launchpad/bug-1007111
Reviewer Review Type Date Requested Status
Gary Poster (community) 2012-06-01 Approve on 2012-06-01
Review via email: mp+108359@code.launchpad.net

Commit Message

Make --load-list account for duplicate tests across layers.

Description of the Change

= Summary =

--load-list now accounts for multiple tests with the same id to
account for legacy Launchpad testing infrastructure. It was assumed
incorrectly that those repeated tests were all in the same layer.

== Proposed fix ==

Account for repeated tests appearing in multiple layers.

== Tests ==

bin/test -vv lp.services.testing.tests.test_customresult

== Demo and Q/A ==

% echo "lib/lp/bugs/doc/bugmessage.txt" > /tmp/t0
% bin/test --list-tests --load-list /tmp/t0
Listing lp.testing.layers.LaunchpadZopelessLayer tests:
  lib/lp/bugs/doc/bugmessage.txt
  lib/lp/bugs/doc/bugmessage.txt
  lib/lp/bugs/doc/bugmessage.txt
Listing lp.services.mail.tests.test_doc.ProcessMailLayer tests:
  lib/lp/bugs/doc/bugmessage.txt
Listing lp.testing.layers.LaunchpadFunctionalLayer tests:
  lib/lp/bugs/doc/bugmessage.txt

= Launchpad lint =

Checking for conflicts and issues in changed files.

Linting changed files:
  lib/lp/services/testing/customresult.py
  lib/lp/services/testing/tests/test_customresult.py

To post a comment you must log in.
Gary Poster (gary) wrote :

Great, thanks!

We talked on IRC about benji's concern with naming Python file objects after file descriptors, and so possibly changing "fd" to "f" or something else. As I said, your call.

Also as we discussed even earlier, I'd like to see bug 682772 addressed as well (and maybe engage with Robert on ideas he has for a good hook point for bug 682771 if that's not clear) but we have that on our board, and this is a good change.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/services/testing/customresult.py'
2--- lib/lp/services/testing/customresult.py 2012-05-28 16:17:01 +0000
3+++ lib/lp/services/testing/customresult.py 2012-06-01 15:29:18 +0000
4@@ -57,16 +57,18 @@
5 # must be tracked separately.
6 for layer_name, suite in tests_by_layer_name.iteritems():
7 for testcase in suite:
8- layer, testlist = test_lookup.setdefault(
9- testcase.id(), (layer_name, []))
10- testlist.append(testcase)
11+ layer_to_tests = test_lookup.setdefault(
12+ testcase.id(), {})
13+ testcases = layer_to_tests.setdefault(
14+ layer_name, [])
15+ testcases.append(testcase)
16
17 result = {}
18 for testname in tests:
19- layer, testcases = test_lookup.get(testname, (None, None))
20- if testcases is not None:
21- suite = result.setdefault(layer, TestSuite())
22- for testcase in testcases:
23- suite.addTest(testcase)
24+ layer_to_tests = test_lookup.get(testname, {})
25+ for layer_name, testcases in layer_to_tests.items():
26+ if testcases is not None:
27+ suite = result.setdefault(layer_name, TestSuite())
28+ suite.addTests(testcases)
29 return result
30 return do_filter
31
32=== modified file 'lib/lp/services/testing/tests/test_customresult.py'
33--- lib/lp/services/testing/tests/test_customresult.py 2012-05-30 11:41:02 +0000
34+++ lib/lp/services/testing/tests/test_customresult.py 2012-06-01 15:29:18 +0000
35@@ -34,12 +34,13 @@
36
37 layer = BaseLayer
38
39- def writeFile(self, fd, contents):
40+ def writeFile(self, f, contents):
41 for line in contents:
42- fd.write(line + NEWLINE)
43- fd.flush()
44+ f.write(line + NEWLINE)
45+ f.flush()
46
47- def make_suites(self):
48+ @staticmethod
49+ def make_suites():
50 """Make two suites.
51
52 The first has 'a'..'m' and the second 'n'..'z'.
53@@ -54,6 +55,15 @@
54 suite_nz.addTest(FakeTestCase(letter))
55 return suite_am, suite_nz
56
57+ @staticmethod
58+ def make_repeated_suite(testnames):
59+ suite = unittest.TestSuite()
60+ for t in testnames:
61+ # Each test will be repeated equal to the number represented.
62+ for i in range(int(t)):
63+ suite.addTest(FakeTestCase(t))
64+ return suite
65+
66 def test_ordering(self):
67 # Tests should be returned in the order seen in the testfile.
68 layername = 'layer-1'
69@@ -61,9 +71,9 @@
70 suite = unittest.TestSuite()
71 for letter in string.lowercase:
72 suite.addTest(FakeTestCase(letter))
73- with tempfile.NamedTemporaryFile() as fd:
74- self.writeFile(fd, testnames)
75- do_filter = filter_tests(fd.name)
76+ with tempfile.NamedTemporaryFile() as f:
77+ self.writeFile(f, testnames)
78+ do_filter = filter_tests(f.name)
79 results = do_filter({layername: suite})
80 self.assertEqual(1, len(results))
81 self.assertIn(layername, results)
82@@ -74,9 +84,9 @@
83 # Tests must be kept in their layer.
84 suite1, suite2 = self.make_suites()
85 testnames = ['a', 'b', 'c', 'z', 'y', 'x']
86- with tempfile.NamedTemporaryFile() as fd:
87- self.writeFile(fd, testnames)
88- do_filter = filter_tests(fd.name)
89+ with tempfile.NamedTemporaryFile() as f:
90+ self.writeFile(f, testnames)
91+ do_filter = filter_tests(f.name)
92 results = do_filter({'layer1': suite1,
93 'layer2': suite2})
94 self.assertEqual(2, len(results))
95@@ -90,14 +100,10 @@
96 # collapsed and lost.
97 layername = 'layer-1'
98 testnames = ['1', '2', '3']
99- suite = unittest.TestSuite()
100- for t in testnames:
101- # Each test will be repeated equal to the number represented.
102- for i in range(int(t)):
103- suite.addTest(FakeTestCase(t))
104- with tempfile.NamedTemporaryFile() as fd:
105- self.writeFile(fd, testnames)
106- do_filter = filter_tests(fd.name)
107+ suite = self.make_repeated_suite(testnames)
108+ with tempfile.NamedTemporaryFile() as f:
109+ self.writeFile(f, testnames)
110+ do_filter = filter_tests(f.name)
111 results = do_filter({layername: suite})
112 self.assertEqual(1, len(results))
113 self.assertIn(layername, results)
114@@ -105,13 +111,33 @@
115 expected = ['1', '2', '2', '3', '3', '3']
116 self.assertEqual(expected, [t.id() for t in suite])
117
118+ def test_repeated_names_different_layers(self):
119+ # Some doctests are run repeatedly with different scenarios, including
120+ # being included in different layers.
121+ testnames = ['a', 'b', 'c']
122+ suite = self.make_suites()[0]
123+
124+ with tempfile.NamedTemporaryFile() as f:
125+ self.writeFile(f, testnames)
126+ do_filter = filter_tests(f.name)
127+ results = do_filter({'layer1': suite,
128+ 'layer2': suite,
129+ 'layer3': suite})
130+
131+ self.assertEqual(3, len(results))
132+ self.assertEqual(
133+ ['layer1', 'layer2', 'layer3'], sorted(results.keys()))
134+ self.assertEqual(['a', 'b', 'c'], [t.id() for t in results['layer1']])
135+ self.assertEqual(['a', 'b', 'c'], [t.id() for t in results['layer2']])
136+ self.assertEqual(['a', 'b', 'c'], [t.id() for t in results['layer3']])
137+
138 def test_no_layer(self):
139 # If tests have no layer (None) work.
140 testnames = ['a', 'b', 'y', 'z']
141 suite1, suite2 = self.make_suites()
142- with tempfile.NamedTemporaryFile() as fd:
143- self.writeFile(fd, testnames)
144- do_filter = filter_tests(fd.name)
145+ with tempfile.NamedTemporaryFile() as f:
146+ self.writeFile(f, testnames)
147+ do_filter = filter_tests(f.name)
148 results = do_filter({'layer1': suite1,
149 None: suite2})
150 self.assertEqual(2, len(results))