def testAttachInUpdate(self): self.testAttachInCreate() file_path = os.path.join(os.path.dirname(__file__), "data", "attachments", "update_with_attach.xml") with open(file_path, "rb") as f: xml_data = f.read() attach_name = "house.jpg" attachment_path = os.path.join(os.path.dirname(__file__), "data", "attachments", attach_name) with open(attachment_path, "rb") as attachment: uf = UploadedFile(attachment, attach_name) form = post_xform_to_couch(xml_data, {attach_name: uf}) self.assertEqual(1, len(form.attachments)) fileback = form.fetch_attachment(attach_name) # rewind the pointer before comparing attachment.seek(0) self.assertEqual(hashlib.md5(fileback).hexdigest(), hashlib.md5(attachment.read()).hexdigest()) process_cases(sender="testharness", xform=form) case = CommCareCase.get(form.xpath("form/case/case_id")) self.assertEqual(2, len(case.attachments)) self.assertEqual(form.get_id, case.attachments[1][0]) self.assertEqual(attach_name, case.attachments[1][1])
def testDuplicateCasePropertiesBug(self): """ How do we do when submitting multiple values for the same property in an update block """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "duplicate_case_properties.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # before the bug was fixed this call failed process_cases(sender="testharness", xform=form) case = CommCareCase.get(form.xpath("form/case/@case_id")) # make sure the property is there, but empty self.assertEqual("", case.foo) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "duplicate_case_properties_2.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) case = CommCareCase.get(form.xpath("form/case/@case_id")) # make sure the property takes the last defined value self.assertEqual("2", case.bar)
def testOTARestore(self): self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "multicase", "parallel_cases.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) self.assertEqual(4, len(CommCareCase.view("case/by_user", reduce=False).all()))
def _postWithSyncToken(self, filename, token_id): file_path = os.path.join(os.path.dirname(__file__), "data", filename) with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # set last sync token on the form before saving form.last_sync_token = token_id process_cases(sender="testharness", xform=form) return form
def testTopLevelExclusion(self): """ Entire forms tagged as device logs should be excluded """ self.assertEqual(0, len(CommCareCase.view("case/by_user", include_docs=True, reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "exclusion", "device_report.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) self.assertEqual(0, len(CommCareCase.view("case/by_user", include_docs=True, reduce=False).all()))
def testStringFormatProblems(self): """ If two forms share an ID it's a conflict """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "string_formatting.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # before the bug was fixed this call failed process_cases(sender="testharness", xform=form)
def testParseClose(self): self.testParseCreate() file_path = os.path.join(os.path.dirname(__file__), "data", "v2", "basic_close.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) case = CommCareCase.get("foo-case-id") self.assertTrue(case.closed)
def testLotsOfSubcases(self): """ How do we do when submitting a form with multiple blocks for the same case? """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "lots_of_subcases.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # before the bug was fixed this call failed process_cases(sender="testharness", xform=form) self.assertEqual(11, len(CommCareCase.view("case/by_user", reduce=False).all()))
def reprocess_form_cases(form): """ For a given form, reprocess all case elements inside it. This operation should be a no-op if the form was sucessfully processed, but should correctly inject the update into the case history if the form was NOT successfully processed. """ process_cases(None, form, reconcile=True) # mark cleaned up now that we've reprocessed it if form.doc_type != 'XFormInstance': form = XFormInstance.get(form._id) form.doc_type = 'XFormInstance' form.save()
def testDateInCaseNameBug(self): """ How do we do when submitting a case name that looks like a date? """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "date_in_case_name.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # before the bug was fixed this call failed process_cases(sender="testharness", xform=form) case = CommCareCase.get(form.xpath("form/case/case_id")) self.assertEqual("2011-11-16", case.name)
def testParseNamedNamespace(self): file_path = os.path.join(os.path.dirname(__file__), "data", "v2", "named_namespace.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) case = CommCareCase.get("14cc2770-2d1c-49c2-b252-22d6ecce385a") self.assertFalse(case.closed) self.assertEqual("d5ce3a980b5b69e793445ec0e3b2138e", case.user_id) self.assertEqual(datetime(2011, 12, 27), case.modified_on) self.assertEqual("cc_bihar_pregnancy", case.type) self.assertEqual("TEST", case.name) self.assertEqual(2, len(case.actions))
def testEmptyCaseId(self): """ How do we do when submitting an empty case id? """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "empty_id.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) try: process_cases(sender="testharness", xform=form) self.fail("Empty Id should crash") except: pass
def testConflictingIds(self): """ If two forms share an ID it's a conflict """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "id_conflicts.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) try: process_cases(sender="testharness", xform=form) self.fail("Previous statement should have raised an exception") except Exception: pass
def testParseCreate(self): file_path = os.path.join(os.path.dirname(__file__), "data", "v2", "basic_create.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) case = CommCareCase.get("foo-case-id") self.assertFalse(case.closed) self.assertEqual("bar-user-id", case.user_id) self.assertEqual(datetime(2011, 12, 6, 13, 42, 50), case.modified_on) self.assertEqual("v2_case_type", case.type) self.assertEqual("test case name", case.name) self.assertEqual(1, len(case.actions))
def testMultipleCaseBlocks(self): """ How do we do when submitting a form with multiple blocks for the same case? """ self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "bugs", "mutiple_case_blocks.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) # before the bug was fixed this call failed process_cases(sender="testharness", xform=form) case = CommCareCase.get(form.xpath("form/comunidad/case/@case_id")) self.assertEqual('1630005', case.community_code) self.assertEqual('SantaMariaCahabon', case.district_name) self.assertEqual('TAMERLO', case.community_name)
def testUserRestoreWithCase(self): file_path = os.path.join(os.path.dirname(__file__), "data", "create_short.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) user = dummy_user() # implicit length assertion [newcase] = CommCareCase.view("case/by_user", reduce=False, include_docs=True).all() self.assertEqual(1, len(user.get_case_updates(None).actual_cases_to_sync)) expected_case_block = """ <case> <case_id>asdf</case_id> <date_modified>2010-06-29</date_modified> <create> <case_type_id>test_case_type</case_type_id> <user_id>foo</user_id> <case_name>test case name</case_name> <external_id>someexternal</external_id> </create> </case>""" check_xml_line_by_line(self, expected_case_block, xml.get_case_xml(newcase, [case_const.CASE_ACTION_CREATE, case_const.CASE_ACTION_UPDATE])) # check v2 expected_v2_case_block = """ <case case_id="asdf" date_modified="2010-06-29" user_id="foo" xmlns="http://commcarehq.org/case/transaction/v2" > <create> <case_type>test_case_type</case_type> <case_name>test case name</case_name> <owner_id>foo</owner_id> </create> <update> <external_id>someexternal</external_id> </update> </case>""" check_xml_line_by_line(self, expected_v2_case_block, xml.get_case_xml\ (newcase, [case_const.CASE_ACTION_CREATE, case_const.CASE_ACTION_UPDATE], version="2.0")) restore_payload = generate_restore_payload(dummy_user()) # implicit length assertion [sync_log] = SyncLog.view("phone/sync_logs_by_user", include_docs=True, reduce=False).all() check_xml_line_by_line(self, dummy_restore_xml(sync_log.get_id, expected_case_block), restore_payload)
def testParseWithIndices(self): self.testParseCreate() user_id = "bar-user-id" for prereq in ["some_referenced_id", "some_other_referenced_id"]: post_case_blocks([ CaseBlock(create=True, case_id=prereq, user_id=user_id, version=V2).as_xml() ]) file_path = os.path.join(os.path.dirname(__file__), "data", "v2", "index_update.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) case = CommCareCase.get("foo-case-id") self.assertEqual(2, len(case.indices)) self.assertTrue(case.has_index("foo_ref")) self.assertTrue(case.has_index("baz_ref")) self.assertEqual("bar", case.get_index("foo_ref").referenced_type) self.assertEqual("some_referenced_id", case.get_index("foo_ref").referenced_id) self.assertEqual("bop", case.get_index("baz_ref").referenced_type) self.assertEqual("some_other_referenced_id", case.get_index("baz_ref").referenced_id) # check the action self.assertEqual(2, len(case.actions)) [_, index_action] = case.actions self.assertEqual(const.CASE_ACTION_INDEX, index_action.action_type) self.assertEqual(2, len(index_action.indices)) # quick test for ota restore v2response = phone_views.xml_for_case(HttpRequest(), case.get_id, version="2.0") expected_v2_response = """ <case case_id="foo-case-id" date_modified="2011-12-07" user_id="bar-user-id" xmlns="http://commcarehq.org/case/transaction/v2"> <create> <case_type>v2_case_type</case_type> <case_name>test case name</case_name> <owner_id>bar-user-id</owner_id> </create> <index> <baz_ref case_type="bop">some_other_referenced_id</baz_ref> <foo_ref case_type="bar">some_referenced_id</foo_ref> </index> </case>""" check_xml_line_by_line(self, expected_v2_response, v2response.content)
def bootstrap_case_from_xml(test_class, filename, case_id_override=None, referral_id_override=None): starttime = utcnow_sans_milliseconds() file_path = os.path.join(os.path.dirname(__file__), "data", filename) with open(file_path, "rb") as f: xml_data = f.read() doc_id, uid, case_id, ref_id = replace_ids_and_post(xml_data, case_id_override=case_id_override, referral_id_override=referral_id_override) doc = XFormInstance.get(doc_id) process_cases(sender="testharness", xform=doc) case = CommCareCase.get(case_id) test_class.assertTrue(starttime <= case.server_modified_on) test_class.assertTrue(datetime.utcnow() >= case.server_modified_on) test_class.assertEqual(case_id, case.case_id) return case
def testSyncToken(self): """ Tests sync token / sync mode support """ file_path = os.path.join(os.path.dirname(__file__), "data", "create_short.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) time.sleep(1) restore_payload = generate_restore_payload(dummy_user()) # implicit length assertion [sync_log] = SyncLog.view("phone/sync_logs_by_user", include_docs=True, reduce=False).all() check_xml_line_by_line(self, dummy_restore_xml(sync_log.get_id, const.CREATE_SHORT), restore_payload) time.sleep(1) sync_restore_payload = generate_restore_payload(dummy_user(), sync_log.get_id) [latest_log] = [log for log in \ SyncLog.view("phone/sync_logs_by_user", include_docs=True, reduce=False).all() \ if log.get_id != sync_log.get_id] # should no longer have a case block in the restore XML check_xml_line_by_line(self, dummy_restore_xml(latest_log.get_id), sync_restore_payload) # apply an update time.sleep(1) file_path = os.path.join(os.path.dirname(__file__), "data", "update_short.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) time.sleep(1) sync_restore_payload = generate_restore_payload(dummy_user(), latest_log.get_id) [even_latest_log] = [log for log in \ SyncLog.view("phone/sync_logs_by_user", include_docs=True, reduce=False).all() \ if log.get_id != sync_log.get_id and log.get_id != latest_log.get_id] # case block should come back check_xml_line_by_line(self, dummy_restore_xml(even_latest_log.get_id, const.UPDATE_SHORT), sync_restore_payload)
def post_case_blocks(case_blocks, form_extras={}): """ Post case blocks. Extras is used to add runtime attributes to the form before sending it off to the case (current use case is sync-token pairing) """ form = ElementTree.Element("data") form.attrib['xmlns'] = "https://www.commcarehq.org/test/casexml-wrapper" form.attrib['xmlns:jrm'] ="http://openrosa.org/jr/xforms" for block in case_blocks: form.append(block) xform = post_xform_to_couch(ElementTree.tostring(form)) for k, v in form_extras.items(): setattr(xform, k, v) process_cases(sender="testharness", xform=xform) return xform
def testRestoreAttributes(self): file_path = os.path.join(os.path.dirname(__file__), "data", "attributes.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) [newcase] = CommCareCase.view("case/by_user", reduce=False, include_docs=True).all() self.assertTrue(isinstance(newcase.adate, dict)) self.assertEqual(date(2012,02,01), newcase.adate["#text"]) self.assertEqual("i am an attribute", newcase.adate["@someattr"]) self.assertTrue(isinstance(newcase.dateattr, dict)) self.assertEqual("this shouldn't break", newcase.dateattr["#text"]) self.assertEqual(date(2012,01,01), newcase.dateattr["@somedate"]) self.assertTrue(isinstance(newcase.stringattr, dict)) self.assertEqual("neither should this", newcase.stringattr["#text"]) self.assertEqual("i am a string", newcase.stringattr["@somestring"]) restore_payload = generate_restore_payload(dummy_user()) # ghetto self.assertTrue('<dateattr somedate="2012-01-01">' in restore_payload) self.assertTrue('<stringattr somestring="i am a string">' in restore_payload)
def testWithReferrals(self): self.assertEqual(0, len(CommCareCase.view("case/by_user", reduce=False, include_docs=True).all())) file_path = os.path.join(os.path.dirname(__file__), "data", "case_create.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) [newcase] = CommCareCase.view("case/by_user", reduce=False, include_docs=True).all() self.assertEqual(0, len(newcase.referrals)) file_path = os.path.join(os.path.dirname(__file__), "data", "case_refer.xml") with open(file_path, "rb") as f: xml_data = f.read() form = post_xform_to_couch(xml_data) process_cases(sender="testharness", xform=form) [updated_case] = CommCareCase.view("case/by_user", reduce=False, include_docs=True).all() self.assertEqual(1, len(updated_case.referrals)) response = views.xml_for_case(HttpRequest(), updated_case.get_id) expected_response = """<case> <case_id>IKA9G79J4HDSPJLG3ER2OHQUY</case_id> <date_modified>2011-02-19</date_modified> <create> <case_type_id>cc_mobilize_client</case_type_id> <user_id>ae179a62-38af-11e0-b6a3-005056aa7fb5</user_id> <case_name>SIEGEL-ROBERT-5412366523984</case_name> <external_id>5412366523984</external_id> </create> <update> <Problems></Problems> <abdominalpain></abdominalpain> <address></address> <addstaff1></addstaff1> <addstaff2></addstaff2> <allmeds_likert></allmeds_likert> <arv_lasttreatment></arv_lasttreatment> <arv_missedtreatments></arv_missedtreatments> <arv_taking></arv_taking> <assistance></assistance> <confusion></confusion> <contact_age_alt></contact_age_alt> <contact_name_alt></contact_name_alt> <contact_phone_alt></contact_phone_alt> <deafness></deafness> <depression></depression> <diarrhea></diarrhea> <dob>2011-02-11</dob> <gender>male</gender> <given_name>ROBERT</given_name> <imbalance></imbalance> <injectionother></injectionother> <injectiontype></injectiontype> <jaundice></jaundice> <jointpain></jointpain> <legal_name>ROBERT SIEGEL</legal_name> <musclepain></musclepain> <muscleweakness></muscleweakness> <nickname>BOB</nickname> <other></other> <patient_dot>123</patient_dot> <patient_id>5412366523984</patient_id> <phone_number>1</phone_number> <place></place> <psychosis></psychosis> <rash></rash> <request_name>ME</request_name> <request_rank>staff_nurse</request_rank> <request_reason></request_reason> <request_timestamp>2011-02-19 16:46:28</request_timestamp> <ringing></ringing> <seizures></seizures> <short_name>SIEGEL, ROBERT</short_name> <sleeping></sleeping> <staffnumber1></staffnumber1> <staffnumber2></staffnumber2> <staffnumber3></staffnumber3> <surname>SIEGEL</surname> <swelling></swelling> <tb_lasttreatment></tb_lasttreatment> <tb_missedtreatments></tb_missedtreatments> <tbtype></tbtype> <tingling></tingling> <tribal_area></tribal_area> <txoutcome></txoutcome> <txstart>2011-02-11</txstart> <vision></vision> <vomiting></vomiting> </update> <referral> <referral_id>V2RLNE4VQYEMZRGYSOMLYU4PM</referral_id> <followup_date>2011-02-20</followup_date> <open> <referral_types>referral</referral_types> </open> </referral> </case>""" check_xml_line_by_line(self, expected_response, response.content) # this is really ridiculous. TODO, get rid of massive text wall x 2 expected_v2_response = """<case xmlns="http://commcarehq.org/case/transaction/v2" case_id="IKA9G79J4HDSPJLG3ER2OHQUY" date_modified="2011-02-19" user_id="ae179a62-38af-11e0-b6a3-005056aa7fb5"> <create> <case_type>cc_mobilize_client</case_type> <case_name>SIEGEL-ROBERT-5412366523984</case_name> <owner_id>ae179a62-38af-11e0-b6a3-005056aa7fb5</owner_id> </create> <update> <external_id>5412366523984</external_id> <Problems></Problems> <abdominalpain></abdominalpain> <address></address> <addstaff1></addstaff1> <addstaff2></addstaff2> <allmeds_likert></allmeds_likert> <arv_lasttreatment></arv_lasttreatment> <arv_missedtreatments></arv_missedtreatments> <arv_taking></arv_taking> <assistance></assistance> <confusion></confusion> <contact_age_alt></contact_age_alt> <contact_name_alt></contact_name_alt> <contact_phone_alt></contact_phone_alt> <deafness></deafness> <depression></depression> <diarrhea></diarrhea> <dob>2011-02-11</dob> <gender>male</gender> <given_name>ROBERT</given_name> <imbalance></imbalance> <injectionother></injectionother> <injectiontype></injectiontype> <jaundice></jaundice> <jointpain></jointpain> <legal_name>ROBERT SIEGEL</legal_name> <musclepain></musclepain> <muscleweakness></muscleweakness> <nickname>BOB</nickname> <other></other> <patient_dot>123</patient_dot> <patient_id>5412366523984</patient_id> <phone_number>1</phone_number> <place></place> <psychosis></psychosis> <rash></rash> <request_name>ME</request_name> <request_rank>staff_nurse</request_rank> <request_reason></request_reason> <request_timestamp>2011-02-19 16:46:28</request_timestamp> <ringing></ringing> <seizures></seizures> <short_name>SIEGEL, ROBERT</short_name> <sleeping></sleeping> <staffnumber1></staffnumber1> <staffnumber2></staffnumber2> <staffnumber3></staffnumber3> <surname>SIEGEL</surname> <swelling></swelling> <tb_lasttreatment></tb_lasttreatment> <tb_missedtreatments></tb_missedtreatments> <tbtype></tbtype> <tingling></tingling> <tribal_area></tribal_area> <txoutcome></txoutcome> <txstart>2011-02-11</txstart> <vision></vision> <vomiting></vomiting> </update> </case>""" v2response = views.xml_for_case(HttpRequest(), updated_case.get_id, version="2.0") check_xml_line_by_line(self, expected_v2_response, v2response.content)