def test_patch_missing_case_with_index(self): self.submit_form(make_test_form("form-1", case_id="case-1")) case = CaseAccessorCouch.get_case("case-1") case.indices = [ CommCareCaseIndex.wrap({ "doc_type": "CommCareCaseIndex", "identifier": "parent", "referenced_type": "household", "referenced_id": "a53346d5", "relationship": "child", }) ] case.save() FormAccessors(self.domain_name).soft_delete_forms(['form-1'], datetime.utcnow(), 'test-deletion') self.do_migration(diffs=IGNORE) self.compare_diffs(changes=[ Diff('case-1', 'missing', ['*'], old='*', new=MISSING, reason="deleted forms"), ]) self.do_case_patch() self.compare_diffs() self.assert_patched_cases(["case-1"])
def _iter_missing_blob_present_forms(statedb, stopper): def get_blob_present_form_ids(diff): if diff.kind == "CommCareCase": case_id = diff.doc_id data = json.loads(diff.old_value)["forms"] form_ids = [ form_id for form_id, status in data.items() if status == "missing, blob present" ] assert form_ids, diff.old_value elif diff.kind == "stock state": case_id = diff.doc_id.split("/", 1)[0] data = json.loads(diff.old_value) assert data["form_state"] == "missing, blob present", data form_ids = [data["ledger"]["last_modified_form_id"]] return form_ids, case_id def iter_blob_metas(form_ids): metas = metadb.get_for_parents(form_ids) parents = set() for meta in metas: if meta.type_code == CODES.form_xml: yield meta, [m for m in metas if m.parent_id == meta.parent_id] assert meta.parent_id not in parents, metas parents.add(meta.parent_id) assert parents == set(form_ids), (form_ids, parents) def xml_to_form(domain, xml_meta, case_id, all_metas): form_id = xml_meta.parent_id with xml_meta.open() as fh: xml = fh.read() form_data = convert_xform_to_json(xml) form = FormProcessorCouch.new_xform(form_data) form.domain = domain form.received_on = get_received_on(case_id, form_id) for meta in all_metas: form.external_blobs[meta.name] = BlobMetaRef( key=meta.key, blobmeta_id=meta.id, content_type=meta.content_type, content_length=meta.content_length, ) return form def get_received_on(case_id, form_id): case = CaseAccessorCouch.get_case(case_id) for action in case.actions: if action.xform_id == form_id: return action.server_date raise ValueError(f"case {case_id} has no actions for form {form_id}")
def get_case(self, case_id): try: return CaseAccessorSQL.get_case(case_id) except CaseNotFound: pass try: return CaseAccessorCouch.get_case(case_id) except ResourceNotFound: pass return None
def get_case(self, case_id): try: return CaseAccessorSQL.get_case(case_id) except CaseNotFound: pass try: return CaseAccessorCouch.get_case(case_id) except ResourceNotFound: pass return None
def test_patch_case_closed_in_couch_missing_sql(self): self.submit_form(make_test_form("form-1", case_id="case-1")) case = CaseAccessorCouch.get_case("case-1") case.closed = True case.closed_by = "3fae4ea4af440efaa53441b5" case.closed_on = datetime(2010, 9, 8, 7, 6, 5) case.user_id = "3fae4ea4af440efaa53441b5" case.save() FormAccessors(self.domain_name).soft_delete_forms(["form-1"], datetime.utcnow(), 'test-deletion') self.do_migration(diffs=IGNORE) self.compare_diffs(changes=[ Diff('case-1', 'missing', ['*'], old='*', new=MISSING, reason="deleted forms"), ]) self.do_case_patch() self.compare_diffs() self.assert_patched_cases(["case-1"])
def test_patch_case_with_deleted_form_and_unexpected_diff(self): self.submit_form(make_test_form("form-1", case_id="case-1")) case = CaseAccessorCouch.get_case("case-1") case.user_id = "unexpected" case.save() FormAccessors(self.domain_name).soft_delete_forms(["form-1"], datetime.utcnow(), 'test-deletion') self.do_migration(diffs=IGNORE) self.compare_diffs(changes=[ Diff('case-1', 'missing', ['*'], old='*', new=MISSING, reason="deleted forms"), ]) # first patch results in unexpected diff self.do_case_patch() self.compare_diffs(diffs=[ Diff('case-1', 'diff', ['opened_by'], old='3fae4ea4af440efaa53441b5', new='unexpected'), Diff('case-1', 'set_mismatch', path=['xform_ids', '[*]'], old='form-1', new=ANY), ]) self.assert_patched_cases(["case-1"]) # second patch resolves unexpected diff self.do_case_patch() self.compare_diffs() self.assert_backend("sql") self.assertFalse(self._get_case("case-1").deleted)
def get_couch_case(case_id): return CaseAccessorCouch.get_case(case_id)
kw.setdefault("diffs", IGNORE) return super().do_migration(*args, **kw) def do_case_diffs(self, cases=None, stop=False): self.migration_success = True # clear migration failure on diff cases migrator = mod.get_migrator(self.domain_name, self.state_dir) return mod.do_case_diffs(migrator, cases, stop=stop, batch_size=100) def do_case_patch(self, cases=None, stop=False): self.migration_success = True # clear migration failure on diff cases migrator = mod.get_migrator(self.domain_name, self.state_dir) return mod.do_case_patch(migrator, cases, stop=stop, batch_size=100) @contextmanager def augmented_couch_case(self, case_id): case = CaseAccessorCouch.get_case(case_id) with self.diff_without_rebuild(): yield case def assert_patched_cases(self, case_ids=None): statedb = open_state_db(self.domain_name, self.state_dir) self.assertEqual(list(statedb.iter_patched_case_ids()), case_ids or []) self.assertFalse(list(statedb.iter_undiffed_case_ids())) THING_FORM = """ <?xml version="1.0" ?> <data name="Thing" uiVersion="1" version="11"