Status: | Merged |
---|---|
Merged at revision: | 733 |
Proposed branch: | lp:~jderose/dmedia/rank |
Merge into: | lp:dmedia |
Diff against target: |
533 lines (+476/-3) 4 files modified
dmedia/metastore.py (+3/-3) dmedia/tests/test_metastore.py (+80/-0) dmedia/tests/test_views.py (+369/-0) dmedia/views.py (+24/-0) |
To merge this branch: | bzr merge lp:~jderose/dmedia/rank |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Raymond | Approve | ||
Review via email: mp+189448@code.launchpad.net |
Commit message
Description of the change
For background, see:
https:/
Changes include:
* Added new file/rank view (map) function, and detailed unit test for the same
* Changed MetaStore.
* Added missing unit test for MetaStore.
To post a comment you must log in.
Revision history for this message
James Raymond (jamesmr) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'dmedia/metastore.py' |
2 | --- dmedia/metastore.py 2013-09-30 04:26:36 +0000 |
3 | +++ dmedia/metastore.py 2013-10-05 03:41:38 +0000 |
4 | @@ -874,13 +874,13 @@ |
5 | """ |
6 | Yield doc for each fragile file. |
7 | """ |
8 | - for copies in range(3): |
9 | - result = self.db.view('file', 'fragile', key=copies, update_seq=True) |
10 | + for rank in range(6): |
11 | + result = self.db.view('file', 'rank', key=rank, update_seq=True) |
12 | update_seq = result.get('update_seq') |
13 | ids = [row['id'] for row in result['rows']] |
14 | del result # result might be quite large, free some memory |
15 | random.shuffle(ids) |
16 | - log.info('%d files with copies=%d', len(ids), copies) |
17 | + log.info('vigilance: %d files at rank=%d', len(ids), rank) |
18 | for _id in ids: |
19 | yield self.db.get(_id) |
20 | if not monitor: |
21 | |
22 | === modified file 'dmedia/tests/test_metastore.py' |
23 | --- dmedia/tests/test_metastore.py 2013-09-24 00:37:23 +0000 |
24 | +++ dmedia/tests/test_metastore.py 2013-10-05 03:41:38 +0000 |
25 | @@ -3116,6 +3116,86 @@ |
26 | fs2.verify(_id) |
27 | fs3.verify(_id) |
28 | |
29 | + def test_iter_fragile(self): |
30 | + db = util.get_db(self.env, True) |
31 | + ms = metastore.MetaStore(db) |
32 | + |
33 | + # Test when no files are in the library: |
34 | + self.assertEqual(list(ms.iter_fragile()), []) |
35 | + |
36 | + # Create rank=(0 through 6) test data: |
37 | + ids = tuple(random_file_id() for i in range(7)) |
38 | + stores = tuple(random_id() for i in range(3)) |
39 | + docs = [ |
40 | + { |
41 | + '_id': ids[0], |
42 | + 'type': 'dmedia/file', |
43 | + 'origin': 'user', |
44 | + 'stored': {}, |
45 | + }, |
46 | + { |
47 | + '_id': ids[1], |
48 | + 'type': 'dmedia/file', |
49 | + 'origin': 'user', |
50 | + 'stored': { |
51 | + stores[0]: {'copies': 0}, |
52 | + }, |
53 | + }, |
54 | + { |
55 | + '_id': ids[2], |
56 | + 'type': 'dmedia/file', |
57 | + 'origin': 'user', |
58 | + 'stored': { |
59 | + stores[0]: {'copies': 1}, |
60 | + }, |
61 | + }, |
62 | + { |
63 | + '_id': ids[3], |
64 | + 'type': 'dmedia/file', |
65 | + 'origin': 'user', |
66 | + 'stored': { |
67 | + stores[0]: {'copies': 1}, |
68 | + stores[1]: {'copies': 0}, |
69 | + }, |
70 | + }, |
71 | + { |
72 | + '_id': ids[4], |
73 | + 'type': 'dmedia/file', |
74 | + 'origin': 'user', |
75 | + 'stored': { |
76 | + stores[0]: {'copies': 1}, |
77 | + stores[1]: {'copies': 1}, |
78 | + }, |
79 | + }, |
80 | + { |
81 | + '_id': ids[5], |
82 | + 'type': 'dmedia/file', |
83 | + 'origin': 'user', |
84 | + 'stored': { |
85 | + stores[0]: {'copies': 1}, |
86 | + stores[1]: {'copies': 1}, |
87 | + stores[2]: {'copies': 0}, |
88 | + }, |
89 | + }, |
90 | + { |
91 | + '_id': ids[6], |
92 | + 'type': 'dmedia/file', |
93 | + 'origin': 'user', |
94 | + 'stored': { |
95 | + stores[0]: {'copies': 1}, |
96 | + stores[1]: {'copies': 1}, |
97 | + stores[2]: {'copies': 1}, |
98 | + }, |
99 | + }, |
100 | + ] |
101 | + db.save_many(docs) |
102 | + |
103 | + # We should get docs[0:6]: |
104 | + self.assertEqual(list(ms.iter_fragile()), docs[0:-1]) |
105 | + |
106 | + # Docs should not be changed: |
107 | + self.assertEqual(db.get_many(ids), docs) |
108 | + |
109 | def test_iter_actionable_fragile(self): |
110 | db = util.get_db(self.env, True) |
111 | ms = metastore.MetaStore(db) |
112 | |
113 | === modified file 'dmedia/tests/test_views.py' |
114 | --- dmedia/tests/test_views.py 2013-07-02 07:34:11 +0000 |
115 | +++ dmedia/tests/test_views.py 2013-10-05 03:41:38 +0000 |
116 | @@ -884,6 +884,375 @@ |
117 | {'rows': [], 'offset': 0, 'total_rows': 1}, |
118 | ) |
119 | |
120 | + def test_rank(self): |
121 | + #################################################################### |
122 | + # 1st, test sort order and other properties on a collection of docs: |
123 | + db = Database('foo', self.env) |
124 | + db.put(None) |
125 | + design = self.build_view('rank') |
126 | + db.save(design) |
127 | + |
128 | + # Test when empty |
129 | + self.assertEqual( |
130 | + db.view('file', 'rank'), |
131 | + {'rows': [], 'offset': 0, 'total_rows': 0}, |
132 | + ) |
133 | + |
134 | + # Create rank=(0 through 6) test data: |
135 | + ids = tuple(random_file_id() for i in range(7)) |
136 | + stores = tuple(random_id() for i in range(3)) |
137 | + docs = [ |
138 | + { |
139 | + '_id': ids[0], |
140 | + 'type': 'dmedia/file', |
141 | + 'origin': 'user', |
142 | + 'stored': {}, |
143 | + }, |
144 | + { |
145 | + '_id': ids[1], |
146 | + 'type': 'dmedia/file', |
147 | + 'origin': 'user', |
148 | + 'stored': { |
149 | + stores[0]: {'copies': 0}, |
150 | + }, |
151 | + }, |
152 | + { |
153 | + '_id': ids[2], |
154 | + 'type': 'dmedia/file', |
155 | + 'origin': 'user', |
156 | + 'stored': { |
157 | + stores[0]: {'copies': 1}, |
158 | + }, |
159 | + }, |
160 | + { |
161 | + '_id': ids[3], |
162 | + 'type': 'dmedia/file', |
163 | + 'origin': 'user', |
164 | + 'stored': { |
165 | + stores[0]: {'copies': 1}, |
166 | + stores[1]: {'copies': 0}, |
167 | + }, |
168 | + }, |
169 | + { |
170 | + '_id': ids[4], |
171 | + 'type': 'dmedia/file', |
172 | + 'origin': 'user', |
173 | + 'stored': { |
174 | + stores[0]: {'copies': 1}, |
175 | + stores[1]: {'copies': 1}, |
176 | + }, |
177 | + }, |
178 | + { |
179 | + '_id': ids[5], |
180 | + 'type': 'dmedia/file', |
181 | + 'origin': 'user', |
182 | + 'stored': { |
183 | + stores[0]: {'copies': 1}, |
184 | + stores[1]: {'copies': 1}, |
185 | + stores[2]: {'copies': 0}, |
186 | + }, |
187 | + }, |
188 | + { |
189 | + '_id': ids[6], |
190 | + 'type': 'dmedia/file', |
191 | + 'origin': 'user', |
192 | + 'stored': { |
193 | + stores[0]: {'copies': 1}, |
194 | + stores[1]: {'copies': 1}, |
195 | + stores[2]: {'copies': 1}, |
196 | + }, |
197 | + }, |
198 | + ] |
199 | + db.save_many(docs) |
200 | + |
201 | + # Test sorting, overall properties: |
202 | + self.assertEqual( |
203 | + db.view('file', 'rank'), |
204 | + { |
205 | + 'offset': 0, |
206 | + 'total_rows': 7, |
207 | + 'rows': [ |
208 | + {'key': 0, 'id': ids[0], 'value': None}, |
209 | + {'key': 1, 'id': ids[1], 'value': None}, |
210 | + {'key': 2, 'id': ids[2], 'value': None}, |
211 | + {'key': 3, 'id': ids[3], 'value': None}, |
212 | + {'key': 4, 'id': ids[4], 'value': None}, |
213 | + {'key': 5, 'id': ids[5], 'value': None}, |
214 | + {'key': 6, 'id': ids[6], 'value': None}, |
215 | + ], |
216 | + }, |
217 | + ) |
218 | + self.assertEqual( |
219 | + db.view('file', 'rank', descending=True), |
220 | + { |
221 | + 'offset': 0, |
222 | + 'total_rows': 7, |
223 | + 'rows': [ |
224 | + {'key': 6, 'id': ids[6], 'value': None}, |
225 | + {'key': 5, 'id': ids[5], 'value': None}, |
226 | + {'key': 4, 'id': ids[4], 'value': None}, |
227 | + {'key': 3, 'id': ids[3], 'value': None}, |
228 | + {'key': 2, 'id': ids[2], 'value': None}, |
229 | + {'key': 1, 'id': ids[1], 'value': None}, |
230 | + {'key': 0, 'id': ids[0], 'value': None}, |
231 | + ], |
232 | + }, |
233 | + ) |
234 | + |
235 | + ################################################### |
236 | + # 2nd, drill down on the minutia with a single doc: |
237 | + db = Database('bar', self.env) |
238 | + db.put(None) |
239 | + design = self.build_view('rank') |
240 | + db.save(design) |
241 | + |
242 | + # Test when empty |
243 | + self.assertEqual( |
244 | + db.view('file', 'rank'), |
245 | + {'rows': [], 'offset': 0, 'total_rows': 0}, |
246 | + ) |
247 | + |
248 | + # rank should be 0 when doc['stored'] is missing, empty, or wrong type: |
249 | + _id = random_file_id() |
250 | + store_id = random_id() |
251 | + doc = { |
252 | + '_id': _id, |
253 | + 'type': 'dmedia/file', |
254 | + 'origin': 'user', |
255 | + } |
256 | + db.save(doc) |
257 | + self.assertEqual( |
258 | + db.view('file', 'rank'), |
259 | + { |
260 | + 'offset': 0, |
261 | + 'total_rows': 1, |
262 | + 'rows': [ |
263 | + {'key': 0, 'id': _id, 'value': None}, |
264 | + ], |
265 | + }, |
266 | + ) |
267 | + doc['stored'] = {} |
268 | + db.save(doc) |
269 | + self.assertEqual( |
270 | + db.view('file', 'rank'), |
271 | + { |
272 | + 'offset': 0, |
273 | + 'total_rows': 1, |
274 | + 'rows': [ |
275 | + {'key': 0, 'id': _id, 'value': None}, |
276 | + ], |
277 | + }, |
278 | + ) |
279 | + doc['stored'] = ['hello', 'world'] |
280 | + db.save(doc) |
281 | + self.assertEqual( |
282 | + db.view('file', 'rank'), |
283 | + { |
284 | + 'offset': 0, |
285 | + 'total_rows': 1, |
286 | + 'rows': [ |
287 | + {'key': 0, 'id': _id, 'value': None}, |
288 | + ], |
289 | + }, |
290 | + ) |
291 | + doc['stored'] = 'helloworld' |
292 | + db.save(doc) |
293 | + self.assertEqual( |
294 | + db.view('file', 'rank'), |
295 | + { |
296 | + 'offset': 0, |
297 | + 'total_rows': 1, |
298 | + 'rows': [ |
299 | + {'key': 0, 'id': _id, 'value': None}, |
300 | + ], |
301 | + }, |
302 | + ) |
303 | + doc['stored'] = None |
304 | + db.save(doc) |
305 | + self.assertEqual( |
306 | + db.view('file', 'rank'), |
307 | + { |
308 | + 'offset': 0, |
309 | + 'total_rows': 1, |
310 | + 'rows': [ |
311 | + {'key': 0, 'id': _id, 'value': None}, |
312 | + ], |
313 | + }, |
314 | + ) |
315 | + doc['stored'] = 17 |
316 | + db.save(doc) |
317 | + self.assertEqual( |
318 | + db.view('file', 'rank'), |
319 | + { |
320 | + 'offset': 0, |
321 | + 'total_rows': 1, |
322 | + 'rows': [ |
323 | + {'key': 0, 'id': _id, 'value': None}, |
324 | + ], |
325 | + }, |
326 | + ) |
327 | + |
328 | + # Test with one location, broken doc['stored'][STORE_id]: |
329 | + doc['stored'] = {random_id(): 'blah blah broken'} |
330 | + db.save(doc) |
331 | + self.assertEqual( |
332 | + db.view('file', 'rank'), |
333 | + { |
334 | + 'offset': 0, |
335 | + 'total_rows': 1, |
336 | + 'rows': [ |
337 | + {'key': 1, 'id': _id, 'value': None}, |
338 | + ], |
339 | + }, |
340 | + ) |
341 | + |
342 | + # Test with one location, broken doc['stored'][STORE_id]['copies']: |
343 | + doc['stored'] = {random_id(): {'copies': '2'}} |
344 | + db.save(doc) |
345 | + self.assertEqual( |
346 | + db.view('file', 'rank'), |
347 | + { |
348 | + 'offset': 0, |
349 | + 'total_rows': 1, |
350 | + 'rows': [ |
351 | + {'key': 1, 'id': _id, 'value': None}, |
352 | + ], |
353 | + }, |
354 | + ) |
355 | + doc['stored'] = {random_id(): {'copies': 'foo bar'}} |
356 | + db.save(doc) |
357 | + self.assertEqual( |
358 | + db.view('file', 'rank'), |
359 | + { |
360 | + 'offset': 0, |
361 | + 'total_rows': 1, |
362 | + 'rows': [ |
363 | + {'key': 1, 'id': _id, 'value': None}, |
364 | + ], |
365 | + }, |
366 | + ) |
367 | + doc['stored'] = {random_id(): {'copies': -3}} |
368 | + db.save(doc) |
369 | + self.assertEqual( |
370 | + db.view('file', 'rank'), |
371 | + { |
372 | + 'offset': 0, |
373 | + 'total_rows': 1, |
374 | + 'rows': [ |
375 | + {'key': 1, 'id': _id, 'value': None}, |
376 | + ], |
377 | + }, |
378 | + ) |
379 | + |
380 | + # Test with locations=1, durability=2: |
381 | + doc['stored'] = {random_id(): {'copies': 2}} |
382 | + db.save(doc) |
383 | + self.assertEqual( |
384 | + db.view('file', 'rank'), |
385 | + { |
386 | + 'offset': 0, |
387 | + 'total_rows': 1, |
388 | + 'rows': [ |
389 | + {'key': 3, 'id': _id, 'value': None}, |
390 | + ], |
391 | + }, |
392 | + ) |
393 | + |
394 | + # Test with locations=2, durability=0: |
395 | + doc['stored'] = { |
396 | + random_id(): {'copies': 0}, |
397 | + random_id(): {'copies': 0}, |
398 | + } |
399 | + db.save(doc) |
400 | + self.assertEqual( |
401 | + db.view('file', 'rank'), |
402 | + { |
403 | + 'offset': 0, |
404 | + 'total_rows': 1, |
405 | + 'rows': [ |
406 | + {'key': 2, 'id': _id, 'value': None}, |
407 | + ], |
408 | + }, |
409 | + ) |
410 | + |
411 | + # Test with locations=2, durability=1: |
412 | + doc['stored'] = { |
413 | + random_id(): {'copies': 1}, |
414 | + random_id(): {'copies': 0}, |
415 | + } |
416 | + db.save(doc) |
417 | + self.assertEqual( |
418 | + db.view('file', 'rank'), |
419 | + { |
420 | + 'offset': 0, |
421 | + 'total_rows': 1, |
422 | + 'rows': [ |
423 | + {'key': 3, 'id': _id, 'value': None}, |
424 | + ], |
425 | + }, |
426 | + ) |
427 | + |
428 | + # Test that locations is clamped at 3: |
429 | + doc['stored'] = { |
430 | + random_id(): {'copies': 0}, |
431 | + random_id(): {'copies': 0}, |
432 | + random_id(): {'copies': 0}, |
433 | + random_id(): {'copies': 0}, |
434 | + } |
435 | + db.save(doc) |
436 | + self.assertEqual( |
437 | + db.view('file', 'rank'), |
438 | + { |
439 | + 'offset': 0, |
440 | + 'total_rows': 1, |
441 | + 'rows': [ |
442 | + {'key': 3, 'id': _id, 'value': None}, |
443 | + ], |
444 | + }, |
445 | + ) |
446 | + |
447 | + # Test that durability is clamped at 3: |
448 | + doc['stored'] = {random_id(): {'copies': 17}} |
449 | + db.save(doc) |
450 | + self.assertEqual( |
451 | + db.view('file', 'rank'), |
452 | + { |
453 | + 'offset': 0, |
454 | + 'total_rows': 1, |
455 | + 'rows': [ |
456 | + {'key': 4, 'id': _id, 'value': None}, |
457 | + ], |
458 | + }, |
459 | + ) |
460 | + |
461 | + # Make sure doc['type'] is checked: |
462 | + doc['type'] = 'dmedia/guile' |
463 | + db.save(doc) |
464 | + self.assertEqual( |
465 | + db.view('file', 'rank'), |
466 | + {'rows': [], 'offset': 0, 'total_rows': 0}, |
467 | + ) |
468 | + |
469 | + # Make sure doc['orign'] is checked: |
470 | + doc['type'] = 'dmedia/file' |
471 | + db.save(doc) |
472 | + self.assertEqual( |
473 | + db.view('file', 'rank'), |
474 | + { |
475 | + 'offset': 0, |
476 | + 'total_rows': 1, |
477 | + 'rows': [ |
478 | + {'key': 4, 'id': _id, 'value': None}, |
479 | + ], |
480 | + }, |
481 | + ) |
482 | + doc['origin'] = 'render' |
483 | + db.save(doc) |
484 | + self.assertEqual( |
485 | + db.view('file', 'rank'), |
486 | + {'rows': [], 'offset': 0, 'total_rows': 0}, |
487 | + ) |
488 | + |
489 | def test_fragile(self): |
490 | db = Database('foo', self.env) |
491 | db.put(None) |
492 | |
493 | === modified file 'dmedia/views.py' |
494 | --- dmedia/views.py 2013-07-29 00:22:01 +0000 |
495 | +++ dmedia/views.py 2013-10-05 03:41:38 +0000 |
496 | @@ -123,6 +123,29 @@ |
497 | } |
498 | """ |
499 | |
500 | +file_rank = """ |
501 | +function(doc) { |
502 | + if (doc.type == 'dmedia/file' && doc.origin == 'user') { |
503 | + if (typeof doc.stored != 'object' || isArray(doc.stored)) { |
504 | + emit(0, null); |
505 | + return; |
506 | + } |
507 | + var locations = 0; |
508 | + var durability = 0; |
509 | + var key, copies; |
510 | + for (key in doc.stored) { |
511 | + locations += 1; |
512 | + copies = doc.stored[key].copies; |
513 | + if (typeof copies == 'number' && copies > 0) { |
514 | + durability += copies; |
515 | + } |
516 | + } |
517 | + var rank = Math.min(3, locations) + Math.min(3, durability); |
518 | + emit(rank, null); |
519 | + } |
520 | +} |
521 | +""" |
522 | + |
523 | file_fragile = """ |
524 | function(doc) { |
525 | if (doc.type == 'dmedia/file' && doc.origin == 'user') { |
526 | @@ -279,6 +302,7 @@ |
527 | 'stored': {'map': file_stored, 'reduce': _stats}, |
528 | 'nonzero': {'map': file_nonzero}, |
529 | 'copies': {'map': file_copies}, |
530 | + 'rank': {'map': file_rank}, |
531 | 'fragile': {'map': file_fragile}, |
532 | 'never-verified': {'map': file_never_verified}, |
533 | 'last-verified': {'map': file_last_verified}, |