def test_sync_from_creation(self):
        properties = _arbitrary_session_properties()
        couch_session = XFormsSession(**properties)
        couch_session.save()
        sql_session = SQLXFormsSession.objects.get(couch_id=couch_session._id)
        for prop, value in properties.items():
            self.assertEqual(getattr(sql_session, prop), value)

        # make sure we didn't do any excess saves
        self.assertTrue(XFormsSession.get_db().get_rev(couch_session._id).startswith('1-'))
    def handle(self, *args, **options):
        db = XFormsSession.get_db()
        session_ids = [row['id'] for row in db.view("smsforms/sessions_by_touchforms_id")]
        errors = []
        for session_doc in iter_docs(db, session_ids):
            try:
                # Handle the old touchforms session id convention where it was
                # always an int
                session_id = session_doc.get("session_id", None)
                if isinstance(session_id, int):
                    session_doc["session_id"] = str(session_id)

                couch_session = XFormsSession.wrap(session_doc)
                sync_sql_session_from_couch_session(couch_session)
            except Exception as e:
                logging.exception('problem migrating session {}: {}'.format(session_doc['_id'], e))
                errors.append(session_doc['_id'])

        print 'migrated {} couch sessions. there are now {} in sql'.format(
            len(session_ids) - len(errors), SQLXFormsSession.objects.count()
        )
        if errors:
            print 'errors: {}'.format(', '.join(errors))
    def test_all_inbound(self):
        # Mobile worker creates a case
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1234")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1234")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1234")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # now take the case away from the user
        self.update_case_owner(case, self.user3)
        case = self.get_case("pid1234")

        # then they should no longer have access
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))

        # now add access back via parent connection
        self.add_parent_access(self.user1, case)
        incoming("999123", "mod pid1234", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1234")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        form = self.get_last_form_submission()

        # Bad external id
        incoming("999123", "mod pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # Test validation on all fields
        incoming("999123", "Validation_Test", "TEST")
        session = self.get_open_session(self.user1)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "text")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "ab", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "abc", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "single select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertTrue(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s single select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_CHOICE_OUT_OF_RANGE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2", "TEST")
        self.assertFalse(sms.invalid_survey_response)
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "multi select 1:a, 2:b, 3:c, 4:d.")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_FIELD_REQUIRED))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2 x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 5", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s multi select 1:a, 2:b, 3:c, 4:d." % get_message(MSG_INVALID_CHOICE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "1 c", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "int")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s int" % get_message(MSG_INVALID_INT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "50", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "float")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s float" % get_message(MSG_INVALID_FLOAT))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "21.3", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)
        
        sms = self.assertLastOutboundSMSEquals(self.user1, "long")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s long" % get_message(MSG_INVALID_LONG))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "-100", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "date")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s date" % get_message(MSG_INVALID_DATE))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "20140101", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "time")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "x", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2500", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = self.assertLastOutboundSMSEquals(self.user1, "%s time" % get_message(MSG_INVALID_TIME))
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        sms = incoming("999123", "2345", "TEST")
        self.assertMetadataEqual(sms, session._id, WORKFLOW_KEYWORD)

        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Mobile worker creates a case via structured sms
        incoming("999123", "reg_ss pid1235 1", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your registration submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1235")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1235")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1235")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "mod_ss pid1235 b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "mod_ss pid1236", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "mod_ss", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        def get_field_and_message(field_name, msg_id):
            msg1 = get_message(MSG_FIELD_DESCRIPTOR,
                context=(field_name,))
            msg2 = get_message(msg_id)
            return "%s%s" % (msg1, msg2)

        # Test validation on all fields from structured sms: positional args
        incoming("999123", "validation_test_ss_1 ab 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc x c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 5 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 x 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 5 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c x 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 x -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 x 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 x 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_date", MSG_INVALID_DATE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_1 abc 2 c 50 21.3 -100 20140101 2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: positional args with custom delimiter
        incoming("999123", "validation_test_ss_2,ab,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,x,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,5,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_single_select", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 x,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 5,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_multi_select", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,x,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_int", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,x,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_float", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,x,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_long", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,x,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_date", MSG_INVALID_DATE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("q_time", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_2,abc,2,1 c,50,21.3,-100,20140101,2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter
        incoming("999123", "validation_test_ss_3,arg1ab,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg2x,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg25,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 x,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 5,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg3,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg4x,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg5x,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6x,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg7x,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG7", MSG_INVALID_DATE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg8x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_3,arg1abc,arg22,arg31 c,arg450,arg521.3,arg6-100,arg720140101,arg82345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test validation on all fields from structured sms: named args with custom delimiter and joining character
        incoming("999123", "validation_test_ss_4,arg1=ab,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, 'Expected "abc"')
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=x,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=5,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG2", MSG_CHOICE_OUT_OF_RANGE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 x,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 5,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_INVALID_CHOICE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG3", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=x,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG4", MSG_INVALID_INT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=x,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG5", MSG_INVALID_FLOAT))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=x,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG6", MSG_INVALID_LONG))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=x,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG7", MSG_INVALID_DATE))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=x", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2500", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARG8", MSG_INVALID_TIME))
        self.assertNoNewSubmission(form)
        incoming("999123", "validation_test_ss_4,arg1=abc,arg2=2,arg3=1 c,arg4=50,arg5=21.3,arg6=-100,arg7=20140101,arg8=2345", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", 50, cast=int)
        self.assertFormQuestionEquals(form, "q_float", 21.3, cast=float)
        self.assertFormQuestionEquals(form, "q_long", -100, cast=long)
        self.assertFormQuestionEquals(form, "q_date", date(2014, 1, 1))
        self.assertFormQuestionEquals(form, "q_time", time(23, 45), cast=time_parser)

        # Test leaving fields blank via structured sms
        incoming("999123", "validation_test_ss_4,arg1=abc,arg3=1 c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "")
        self.assertFormQuestionEquals(form, "q_multi_select", "a c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "validation_test_ss_1 abc b c", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "q_text", "abc")
        self.assertFormQuestionEquals(form, "q_single_select", "b")
        self.assertFormQuestionEquals(form, "q_multi_select", "c")
        self.assertFormQuestionEquals(form, "q_int", "")
        self.assertFormQuestionEquals(form, "q_float", "")
        self.assertFormQuestionEquals(form, "q_long", "")
        self.assertFormQuestionEquals(form, "q_date", "")
        self.assertFormQuestionEquals(form, "q_time", "")

        incoming("999123", "mod_ss_2,pid1235", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_2,pid1235,", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("arm", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_field_and_message("ARM", MSG_FIELD_REQUIRED))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_EXPECTED_NAMED_ARGS_SEPARATOR, context=("=",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3,pid1235,arm=a,arm=b", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MULTIPLE_ANSWERS_FOUND, context=("ARM",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "mod_ss_3 ,  pid1235  ,  arm = a", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1235")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test global keywords
        incoming("999123", "#start unknownkeyword", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_KEYWORD_NOT_FOUND, context=("UNKNOWNKEYWORD",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#start", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_START_KEYWORD_USAGE, context=("#START",)))
        self.assertNoNewSubmission(form)

        incoming("999123", "#unknown", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_UNKNOWN_GLOBAL_KEYWORD, context=("#UNKNOWN",)))
        self.assertNoNewSubmission(form)

        # Mobile worker creates a case
        incoming("999123", "#start reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "participant_id", "pid1237")
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        self.assertFormQuestionEquals(form, "external_id", "pid1237")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "name", "pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Mobile worker modifies a case
        incoming("999123", "#start mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Bad external id
        incoming("999123", "#start mod pid1240", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_CASE_NOT_FOUND))
        self.assertNoNewSubmission(form)

        # No external id
        incoming("999123", "#start mod", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, get_message(MSG_MISSING_EXTERNAL_ID))
        self.assertNoNewSubmission(form)

        # CURRENT keyword
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "#CURRENT", "TEST")
        sms2 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        self.assertNotEqual(sms1._id, sms2._id)

        # STOP keyword
        session = self.get_open_session(self.user1)
        self.assertIsNotNone(session)
        incoming("999123", "#STOP", "TEST")
        session = self.get_open_session(self.user1)
        self.assertIsNone(session)
        self.assertNoNewSubmission(form)

        # One keyword overrides another
        incoming("999123", "reg", "TEST")
        sms1 = self.assertLastOutboundSMSEquals(self.user1, "Enter Participant ID")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        self.assertNoNewSubmission(form)
        incoming("999123", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "%s Enter Study Arm 1:a, 2:b." % get_message(MSG_INVALID_CHOICE))
        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertIsNotNone(case)
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test initator filters
        case = self.get_case("pid1237")
        case.set_case_property("contact_phone_number", "999124")
        case.set_case_property("contact_phone_number_is_verified", "1")
        case.save()

        incoming("999123", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for users")
        incoming("999123", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Default SMS Response")

        incoming("999124", "for_case", "TEST")
        self.assertLastOutboundSMSEquals(case, "This message is for cases")
        incoming("999124", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(case, "Default SMS Response")

        # Test form over sms for case
        incoming("999124", "mod", "TEST")
        self.assertLastOutboundSMSEquals(case, "Enter Study Arm 1:a, 2:b.")
        incoming("999123", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "Enter Study Arm 1:a, 2:b.")
        incoming("999124", "b", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        incoming("999123", "a", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test structured sms for case
        incoming("999124", "mod_ss 2", "TEST")
        self.assertLastOutboundSMSEquals(case, "Thank you for your modification submission.")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_b")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_b")

        # Test Auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, get_message(MSG_CASE_NOT_FOUND))

        # Test notifying others
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")

        incoming("999124", "for_group", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the group")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the group")

        case = self.get_case("pid1237")
        case.owner_id = self.group1._id
        case.save()
        incoming("999124", "for_owner", "TEST")
        self.assertLastOutboundSMSEquals(self.user1, "This message is for the case owner")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for the case owner")

        # Test case sharing auth
        incoming("999122", "mod pid1237", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Study Arm 1:a, 2:b.")
        incoming("999122", "1", "TEST")
        form = self.get_last_form_submission()
        self.assertFormQuestionEquals(form, "arm", "arm_a")
        case = self.get_case("pid1237")
        self.assertCasePropertyEquals(case, "arm", "arm_a")

        # Test closing open sessions on an sms reply
        incoming("999122", "reg", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Enter Participant ID")
        incoming("999122", "for_user", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "This message is for users")
        incoming("999122", "null", "TEST")
        self.assertLastOutboundSMSEquals(self.user2, "Default SMS Response")

        # make sure the same number of sessions were made
        couch_number = XFormsSession.get_db().view('smsforms/sessions_by_touchforms_id', limit=0).total_rows
        sql_number = SQLXFormsSession.objects.count()
        self.assertEqual(couch_number, sql_number)