Merge lp:~jcsackett/charmworld/multiple-appflowers into lp:charmworld

Proposed by j.c.sackett
Status: Merged
Approved by: j.c.sackett
Approved revision: 454
Merged at revision: 451
Proposed branch: lp:~jcsackett/charmworld/multiple-appflowers
Merge into: lp:charmworld
Diff against target: 165 lines (+43/-46)
4 files modified
charmworld/models.py (+12/-5)
charmworld/tests/test_models.py (+29/-10)
charmworld/views/tests/test_tools.py (+0/-27)
charmworld/views/tools.py (+2/-4)
To merge this branch: bzr merge lp:~jcsackett/charmworld/multiple-appflowers
Reviewer Review Type Date Requested Status
Juju Gui Bot continuous-integration Approve
Curtis Hovey (community) code Approve
Review via email: mp+194241@code.launchpad.net

Commit message

Removes old-revision proof error charms from the review queue.

Description of the change

The linked bug reports a situation wherein a charm (appflower) is shown to have
proof errors but the actual charm page shows no errors. This is because we have
introduced versioned charms. The charm page uses the tip revision of any charm,
but CharmSource isn't actually really revision aware. This results in
find_proof_error_charms returning all charms with proof errors, even those where
a subsequent version has fixed the proof error.

One solution that was investigated was using the elastic search index to search
for proof charms, as it's only aware of the tip version of charms. However, the
only way to query for the existence of data, without trying to match on it, is
the "exists" filter, which cannot be used as proof is a json object, which
"exists" can't use. Equally, testing for the existence of proof.e fails, because
that is a list object--again a type that exists fails on.

We can however attempt to find the charm_id of a charm to test if it's in the
index; if it is, we can reliably say that is the tip.

charmworld/models.py
--------------------
* _is_latest is added to CharmSource, which uses the index to test for the charm
  id.
* find_proof_error_charms is updated to use _is_latest to filter out the old
  charms.
* As a drive by, the undocumented "sub" feature is removed, making the code
  simpler. This feature isn't used.

charmworld/views/tools.py
-------------------------
* The "sub" feature, accessible only by url mangling, is removed. Addiitonally,
  this entire view will be removed soon.

charmworld/tests/test_models.py
-------------------------------
A test for the new find_proof_error_charms behavior is added.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you.

review: Approve (code)
Revision history for this message
Juju Gui Bot (juju-gui-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://162.213.35.27:8080/job/charmworld-autoland-lxc/70/
Executed test runs:

review: Needs Fixing (continuous-integration)
Revision history for this message
Juju Gui Bot (juju-gui-bot) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://162.213.35.27:8080/job/charmworld-autoland-lxc/71/
Executed test runs:

review: Needs Fixing (continuous-integration)
454. By j.c.sackett

Shut up, lint.

Revision history for this message
Juju Gui Bot (juju-gui-bot) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmworld/models.py'
--- charmworld/models.py 2013-11-06 02:32:43 +0000
+++ charmworld/models.py 2013-11-08 14:33:22 +0000
@@ -1262,16 +1262,23 @@
1262 {"store_data.errors": {"$exists": True}})1262 {"store_data.errors": {"$exists": True}})
1263 return (Charm(data) for data in self.collection.find(query))1263 return (Charm(data) for data in self.collection.find(query))
12641264
1265 def find_proof_error_charms(self, sub_only):1265 def find_proof_error_charms(self):
1266 query = {"proof.e": {"$exists": True}, "promulgated": True}1266 query = {"proof.e": {"$exists": True}, "promulgated": True}
1267 if sub_only:
1268 query['subordinate'] = True
1269 query = self.exclude_obsolete(query)1267 query = self.exclude_obsolete(query)
1270 sort = [("series", pymongo.DESCENDING), ("name", pymongo.ASCENDING)]1268 sort = [("series", pymongo.DESCENDING), ("name", pymongo.ASCENDING)]
1271 return (Charm(data) for data in self.collection.find(query, sort=sort))1269 return (Charm(data) for data in self.collection.find(query, sort=sort)
1270 if self._is_latest(data))
1271
1272 def _is_latest(self, charm_data):
1273 """Determine whether or not the data is for the latest store_revision
1274 of this charm.
1275 """
1276 # Only the latest version of a charm is in elasticsearch.
1277 latest = self.index_client.get(charm_data['_id'])
1278 return latest is not None
12721279
1273 def _get_all(self, charm_id):1280 def _get_all(self, charm_id):
1274 """"Return all stored values for a given charm."""1281 """Return all stored values for a given charm."""
1275 yield self.collection.find_one({'_id': charm_id})1282 yield self.collection.find_one({'_id': charm_id})
1276 yield self.index_client.get(charm_id)1283 yield self.index_client.get(charm_id)
12771284
12781285
=== modified file 'charmworld/tests/test_models.py'
--- charmworld/tests/test_models.py 2013-11-06 02:32:43 +0000
+++ charmworld/tests/test_models.py 2013-11-08 14:33:22 +0000
@@ -1482,30 +1482,49 @@
1482 self.assertEqual(foo, bar)1482 self.assertEqual(foo, bar)
14831483
1484 def test_find_proof_error_charms(self):1484 def test_find_proof_error_charms(self):
1485 self.use_index_client()1485 client = self.use_index_client()
1486 proof_with_errors = {'e': ['error 1']}1486 proof_with_errors = {'e': ['error 1']}
1487 proof_with_warnings = {'w': ['warning 1']}1487 proof_with_warnings = {'w': ['warning 1']}
1488 # The view retrieves promulgated charms with proof errors.
1489 ignore, charm_1 = factory.makeCharm(1488 ignore, charm_1 = factory.makeCharm(
1490 self.db, owner='joe', promulgated=True, proof=proof_with_errors)1489 self.db, owner='joe', promulgated=True, proof=proof_with_errors)
1491 # The view ignores promulgated charms with proof warning.1490 client.index_charm(charm_1)
1492 factory.makeCharm(self.db, promulgated=True, proof=proof_with_warnings)1491 ignore, charm_2 = factory.makeCharm(
1493 # The view ignored unpromulgated charms with proof errors.1492 self.db, promulgated=True, proof=proof_with_warnings)
1494 factory.makeCharm(self.db, promulgated=False, proof=proof_with_errors)1493 client.index_charm(charm_2)
1494 ignore, charm_3 = factory.makeCharm(
1495 self.db, promulgated=False, proof=proof_with_errors)
1496 client.index_charm(charm_3)
1495 charm_source = CharmSource.from_request(self)1497 charm_source = CharmSource.from_request(self)
1496 errors = list(charm_source.find_proof_error_charms(False))1498 errors = list(charm_source.find_proof_error_charms())
1497 self.assertEqual(1, len(errors))1499 self.assertEqual(1, len(errors))
1498 self.assertEqual(charm_1['name'], errors[0].name)1500 self.assertEqual(charm_1['name'], errors[0].name)
14991501
1500 def test_obsolete_charms_ignored_by_find_proof_error_charms(self):1502 def test_obsolete_charms_ignored_by_find_proof_error_charms(self):
1501 self.use_index_client()1503 client = self.use_index_client()
1502 proof_with_errors = {'e': ['error 1']}1504 proof_with_errors = {'e': ['error 1']}
1503 # The view retrieves promulgated charms with proof errors.1505 # The view retrieves promulgated charms with proof errors.
1504 ignore, charm_1 = factory.makeCharm(1506 ignore, charm_1 = factory.makeCharm(
1505 self.db, owner='joe', promulgated=True, proof=proof_with_errors,1507 self.db, owner='joe', promulgated=True, proof=proof_with_errors,
1506 series='oneiric')1508 series='oneiric')
1507 charm_source = CharmSource.from_request(self)1509 client.index_charm(charm_1)
1508 errors = list(charm_source.find_proof_error_charms(False))1510 charm_source = CharmSource.from_request(self)
1511 errors = list(charm_source.find_proof_error_charms())
1512 self.assertEqual([], errors)
1513
1514 def test_find_proof_error_charms_ignores_old_revisions(self):
1515 client = self.use_index_client()
1516 proof_with_errors = {'e': ['error 1']}
1517 # The view retrieves promulgated charms with proof errors.
1518 ignore, charm_1 = factory.makeCharm(
1519 self.db, name='foo', owner='joe', promulgated=True,
1520 proof=proof_with_errors, store_revision=1, series='precise')
1521 client.index_charm(charm_1)
1522 ignore, charm_2 = factory.makeCharm(
1523 self.db, name='foo', owner='joe', promulgated=True,
1524 series='precise', store_revision=2)
1525 client.index_charm(charm_2)
1526 charm_source = CharmSource.from_request(self)
1527 errors = list(charm_source.find_proof_error_charms())
1509 self.assertEqual([], errors)1528 self.assertEqual([], errors)
15101529
1511 def test_store_errors_in_queue(self):1530 def test_store_errors_in_queue(self):
15121531
=== modified file 'charmworld/views/tests/test_tools.py'
--- charmworld/views/tests/test_tools.py 2013-10-10 15:42:33 +0000
+++ charmworld/views/tests/test_tools.py 2013-11-08 14:33:22 +0000
@@ -17,7 +17,6 @@
17 format_items_for_queue,17 format_items_for_queue,
18 get_missing_qa_items,18 get_missing_qa_items,
19 get_sparklines,19 get_sparklines,
20 proof_errors,
21)20)
22from charmworld.testing import factory21from charmworld.testing import factory
23from charmworld.testing import ViewTestBase22from charmworld.testing import ViewTestBase
@@ -181,29 +180,3 @@
181 series='oneiric')180 series='oneiric')
182 response = charm_store_missing(self.getRequest())181 response = charm_store_missing(self.getRequest())
183 self.assertEqual([], response['queue'])182 self.assertEqual([], response['queue'])
184
185
186class ProofErrorsTestCase(ViewTestBase):
187
188 def test_promulgated_charms_with_errors(self):
189 proof_with_errors = {'e': ['error 1']}
190 proof_with_warnings = {'w': ['warning 1']}
191 # The view retrieves promulgated charms with proof errors.
192 ignore, charm_1 = factory.makeCharm(
193 self.db, owner='joe', promulgated=True, proof=proof_with_errors)
194 # The view ignores promulgated charms with proof warning.
195 factory.makeCharm(self.db, promulgated=True, proof=proof_with_warnings)
196 # The view ignored unpromulgated charms with proof errors.
197 factory.makeCharm(self.db, promulgated=False, proof=proof_with_errors)
198 response = proof_errors(self.getRequest())
199 charm = Charm(charm_1)
200 self.assertEqual([charm], response['charms'])
201
202 def test_obsolete_charms_ignored(self):
203 proof_with_errors = {'e': ['error 1']}
204 # The view retrieves promulgated charms with proof errors.
205 ignore, charm_1 = factory.makeCharm(
206 self.db, owner='joe', promulgated=True, proof=proof_with_errors,
207 series='oneiric')
208 response = proof_errors(self.getRequest())
209 self.assertEqual([], response['charms'])
210183
=== modified file 'charmworld/views/tools.py'
--- charmworld/views/tools.py 2013-10-10 16:22:17 +0000
+++ charmworld/views/tools.py 2013-11-08 14:33:22 +0000
@@ -65,7 +65,7 @@
6565
66def build_review_queue(request):66def build_review_queue(request):
67 source = CharmSource.from_request(request)67 source = CharmSource.from_request(request)
68 proof_items = source.find_proof_error_charms(False)68 proof_items = source.find_proof_error_charms()
69 store_items = source.find_mia_charms()69 store_items = source.find_mia_charms()
70 qa_items = get_missing_qa_items(source, request.db)70 qa_items = get_missing_qa_items(source, request.db)
7171
@@ -163,12 +163,10 @@
163 http_cache=REPORT_CACHE,163 http_cache=REPORT_CACHE,
164 renderer="charmworld:templates/charm-proof-errors.pt")164 renderer="charmworld:templates/charm-proof-errors.pt")
165def proof_errors(request):165def proof_errors(request):
166 sub_only = bool(request.GET.get('sub'))
167 source = CharmSource.from_request(request)166 source = CharmSource.from_request(request)
168 charms = list(source.find_proof_error_charms(sub_only))167 charms = list(source.find_proof_error_charms())
169168
170 return {169 return {
171 'charms': charms,170 'charms': charms,
172 'format_proof': format_proof,171 'format_proof': format_proof,
173 'sub_only': sub_only,
174 }172 }

Subscribers

People subscribed via source and target branches

to all changes: