Merge lp:~jml/pkgme/index-error into lp:pkgme

Proposed by Jonathan Lange
Status: Merged
Approved by: James Westby
Approved revision: 148
Merged at revision: 143
Proposed branch: lp:~jml/pkgme/index-error
Merge into: lp:pkgme
Diff against target: 133 lines (+69/-4)
3 files modified
NEWS.txt (+3/-0)
pkgme/backend.py (+10/-4)
pkgme/tests/test_backend.py (+56/-0)
To merge this branch: bzr merge lp:~jml/pkgme/index-error
Reviewer Review Type Date Requested Status
James Westby Approve
Review via email: mp+123843@code.launchpad.net

Commit message

Properly handle no eligible backends.

Description of the change

Fixes a bug where we get IndexErrors when there's no eligible backend.

There are now some tests. Yay.

To post a comment you must log in.
Revision history for this message
James Westby (james-w) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS.txt'
2--- NEWS.txt 2012-09-06 16:24:31 +0000
3+++ NEWS.txt 2012-09-12 09:06:20 +0000
4@@ -9,6 +9,9 @@
5 Changes
6 -------
7
8+ * ``query_backends`` raises a ``NoEligibleBackend`` error if there are no
9+ eligible backends. (Jonathan Lange).
10+
11 Improvements
12 ------------
13
14
15=== modified file 'pkgme/backend.py'
16--- pkgme/backend.py 2012-08-31 11:42:33 +0000
17+++ pkgme/backend.py 2012-09-12 09:06:20 +0000
18@@ -308,7 +308,12 @@
19
20
21 def choose_backend(eligible_backends):
22- return eligible_backends[0]['backend']
23+ """Choose the most eligible backend.
24+
25+ If ``eligible_backends`` is empty, then raises an IndexError.
26+ """
27+ bs = sorted(eligible_backends, key=itemgetter('score'), reverse=True)
28+ return bs[0]['backend']
29
30
31 def query_backends(path, backends, allowed_backend_names=None):
32@@ -321,6 +326,10 @@
33 lambda b: b.name in allowed_backend_names, backends)
34 results = _query_backends(path, allowed)
35 ineligible, eligible = dichotomy(_is_eligible, results)
36+ if not eligible:
37+ raise NoEligibleBackend(
38+ path, ineligible, disallowed_backends=disallowed)
39+ # XXX: Can maybe get rid of this.
40 eligible.sort(key=itemgetter('score'), reverse=True)
41 return disallowed, ineligible, eligible
42
43@@ -350,9 +359,6 @@
44 """
45 disallowed, ineligible, eligible = query_backends(
46 path, self.backends, self.allowed_backend_names)
47- if not eligible:
48- raise NoEligibleBackend(
49- path, ineligible, disallowed_backends=disallowed)
50 return eligible
51
52 def get_info(self, path):
53
54=== modified file 'pkgme/tests/test_backend.py'
55--- pkgme/tests/test_backend.py 2012-09-03 16:14:08 +0000
56+++ pkgme/tests/test_backend.py 2012-09-12 09:06:20 +0000
57@@ -11,6 +11,7 @@
58 from ..backend import (
59 Backend,
60 BackendSelector,
61+ choose_backend,
62 EXTERNAL_BACKEND_PATHS,
63 ExternalHelpersBackend,
64 ExternalHelpersBackendLoader,
65@@ -19,6 +20,7 @@
66 get_info_for,
67 NoBackend,
68 NoEligibleBackend,
69+ query_backends,
70 StaticBackend,
71 StaticLoader,
72 WantError,
73@@ -489,6 +491,60 @@
74 self.assertEqual(EXTERNAL_BACKEND_PATHS, loader.paths)
75
76
77+class ChooseBackendTests(TestCase):
78+
79+ def test_first_backend(self):
80+ b1 = object()
81+ b2 = object()
82+ backends = [{'score': 10, 'backend': b1}, {'score': 20, 'backend': b2}]
83+ self.assertIs(b2, choose_backend(backends))
84+
85+ def test_no_backends(self):
86+ self.assertRaises(IndexError, choose_backend, [])
87+
88+
89+class QueryBackendsTests(TestCase):
90+
91+ def make_backend(self, name=None, score=0, info=None, reason=None):
92+ if name is None:
93+ name = self.getUniqueString('name')
94+ if info is None:
95+ info = {}
96+ if reason is None:
97+ reason = self.getUniqueString('reason')
98+ return StaticBackend(name, score, info, reason=reason)
99+
100+ def to_query(self, backends):
101+ return sorted(
102+ [{'score': b.score, 'reason': b.reason, 'backend': b}
103+ for b in backends])
104+
105+ def test_no_backends(self):
106+ self.assertRaises(NoBackend, query_backends, '.', [])
107+
108+ def test_no_eligible_backends(self):
109+ backends = [self.make_backend(score=0), self.make_backend(score=0)]
110+ self.assertRaises(NoEligibleBackend, query_backends, '.', backends)
111+
112+ def test_eligible_backends_only(self):
113+ eligible = [self.make_backend(score=10), self.make_backend(score=20)]
114+ expected_eligible = self.to_query(eligible)
115+ result = query_backends('.', eligible)
116+ self.assertEqual(
117+ ([], [], expected_eligible),
118+ (result[0], result[1], sorted(result[2])))
119+
120+ def test_ineligible_backends(self):
121+ eligible = [self.make_backend(score=10), self.make_backend(score=20)]
122+ expected_eligible = self.to_query(eligible)
123+ ineligible = [self.make_backend() for i in range(3)]
124+ expected_ineligible = self.to_query(ineligible)
125+ result = query_backends('.', eligible + ineligible)
126+ self.assertEqual(
127+ ([], expected_ineligible, expected_eligible),
128+ (result[0], sorted(result[1]), sorted(result[2])))
129+
130+
131 class TestSelector(BackendSelector):
132
133 def get_info(self, path):

Subscribers

People subscribed via source and target branches