verify-expanded-review-intake.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. """Rebuild the transferred source packages and compare every review field."""
  2. import json
  3. from pathlib import Path
  4. import sqlite3
  5. import sys
  6. import tempfile
  7. import zipfile
  8. ROOT = Path(__file__).resolve().parents[1]
  9. sys.path.insert(0, str(ROOT / 'server/voc-library'))
  10. import agent_batch
  11. import board_library
  12. import structured_batch
  13. import update_library
  14. import voc_db
  15. def main():
  16. root = ROOT / 'work/product-reviews/round2/intake'
  17. report = json.loads((root / 'verification.json').read_text(encoding='utf-8'))
  18. verified = 0
  19. products = set()
  20. packages = []
  21. fields = 'id,product_id,content,append_content_json,rating_raw,rating_scale,review_date_raw,purchased_sku_text,is_default,identity_state,source_time_raw'
  22. for ordinal, batch in enumerate(report['batches'], 1):
  23. folder = root / ('batch-' + str(ordinal).zfill(2))
  24. archive = folder / 'channel-source.zip'
  25. assert agent_batch.digest(archive) == batch['channelArchiveSha256']
  26. before = {p.name: agent_batch.digest(p) for p in [archive, folder / 'staging.sqlite', folder / 'batch.json']}
  27. with tempfile.TemporaryDirectory(prefix='review-r2-source-check-', dir=ROOT / 'work/product-reviews/round2') as td:
  28. target = Path(td)
  29. with zipfile.ZipFile(archive) as z:
  30. assert z.testzip() is None
  31. for info in z.infolist():
  32. p = target / info.filename
  33. assert p.resolve().is_relative_to(target.resolve())
  34. p.parent.mkdir(parents=True, exist_ok=True)
  35. p.write_bytes(z.read(info))
  36. dry = structured_batch.build(target / 'batch.json', target / 'rebuilt.sqlite')
  37. structured_batch.build(target / 'batch.json', target / 'rebuilt.sqlite', True)
  38. update_library.verified(target / 'rebuilt.sqlite')
  39. with voc_db.readonly(folder / 'staging.sqlite') as old, voc_db.readonly(target / 'rebuilt.sqlite') as new:
  40. prior = [tuple(r) for r in old.execute('SELECT ' + fields + ' FROM reviews ORDER BY id')]
  41. rebuilt = [tuple(r) for r in new.execute('SELECT ' + fields + ' FROM reviews ORDER BY id')]
  42. assert prior == rebuilt and len(rebuilt) == batch['reviews']
  43. assert all(row[8] is None and row[9] == 'matched' for row in rebuilt)
  44. for pid, n in batch['reviewCounts'].items():
  45. data = board_library.run({'db': str(target / 'rebuilt.sqlite')}, {'op': 'browse',
  46. 'entity': 'reviews', 'quality': 'audit', 'filters': {'productId': pid}, 'limit': 100})
  47. assert data['totalMatched'] == n and len(data['records']) == n
  48. assert all(r['product_id'] == pid for r in data['records'])
  49. products.add(pid)
  50. verified += len(rebuilt)
  51. packages.append({'batchId': batch['batchId'], 'reviews': len(rebuilt),
  52. 'sourceFilesVerified': dry['sourceFilesVerified'], 'channelArchiveSha256': batch['channelArchiveSha256']})
  53. assert before == {p.name: agent_batch.digest(p) for p in [archive, folder / 'staging.sqlite', folder / 'batch.json']}
  54. assert verified == report['selectedReviews'] and len(products) == report['sourceVerifiedProducts']
  55. result = {'ok': True, 'verifiedReviews': verified, 'verifiedProducts': len(products),
  56. 'allTransferSourcesRebuilt': True, 'allReviewFieldsMatched': True, 'sourceFilesUnchanged': True,
  57. 'exactProductBrowseVerified': True, 'unknownDefaultStatesPreserved': True,
  58. 'productionWrites': 0, 'packages': packages}
  59. with (root / 'source-rebuild-verification.json').open('x', encoding='utf-8', newline='\n') as f:
  60. json.dump(result, f, ensure_ascii=False, indent=2)
  61. f.write('\n')
  62. print(json.dumps(result, ensure_ascii=False, indent=2))
  63. if __name__ == '__main__':
  64. main()