Esempio n. 1
0
    def test_yesterday_general(self):
        today = now()
        first_dt = today - datetime.timedelta(7)
        input_strings = [(first_dt + datetime.timedelta(delta_days)).strftime('%Y-%m-%d')
                         for delta_days in range(7)]

        # the behavior depends on the current datetime relative to registration end,
        # so try it with registration end before and after the current time
        reg_period = RegistrationPeriodFactory(start_time=today - datetime.timedelta(days=5),
                                               end_time=today)
        for fake_registration_end in [today - datetime.timedelta(days=1),
                                      today + datetime.timedelta(days=1)]:
            reg_period.end_time = fake_registration_end
            reg_period.save()
            if registration_in_progress(as_of=today.date()):
                expected_str = input_strings[-2]
            else:
                expected_str = input_strings[-1]
            expected_date = datetime.datetime.strptime(expected_str, '%Y-%m-%d').date()
            date_and_string = calc_yesterday(input_strings)
            self.assertEqual(date_and_string, (expected_date, expected_str))
            # try again, providing the date objects
            input_dates = [datetime.datetime.strptime(s, '%Y-%m-%d').date()
                           for s in input_strings]
            date_and_string = calc_yesterday(input_strings, input_dates)
            self.assertEqual(date_and_string, (expected_date, expected_str))
Esempio n. 2
0
 def setUp(self):
     # lookup_connections takes any identity and creates connections.
     # It's better than create_connection because it uses 'mockbackend'
     # which keeps track of sent messages.
     self.conn = self.lookup_connections(identities=['111'])[0]
     self.good_nid = get_random_number_string(length=constants.NID_LENGTH)
     self.good_center_id = get_random_number_string(
         length=constants.CENTER_ID_LENGTH)
     self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
     self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY,
                                                 end_time=FUTURE_DAY)
     self.election = ElectionFactory(polling_start_time=PAST_DAY,
                                     polling_end_time=FUTURE_DAY)
Esempio n. 3
0
 def setUp(self):
     # Create an existing period.  Then we'll try creating
     # others around it.
     self.reg_period = RegistrationPeriodFactory(
         start_time=now() - datetime.timedelta(days=1),
         end_time=now() + datetime.timedelta(days=1),
     )
Esempio n. 4
0
 def test_query_after_polling(self, mock_lookup):
     # after polling is over, voters can still check their registrations
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     self.election.polling_end_time = PAST_DAY
     self.election.save()
     self.receive(self.msg, self.conn, fields=self.fields)
     self.assertTrue(mock_lookup.called)
Esempio n. 5
0
 def test_two_empty_periods_at_same_time(self):
     # Pathological case - two empty periods do not overlap,
     # even if they start and end at the same time
     RegistrationPeriod.objects.all().delete()
     time = now()
     RegistrationPeriodFactory(start_time=time, end_time=time)
     self.should_work(start_time=time, end_time=time)
Esempio n. 6
0
 def test_query_after_reg_closes(self, mock_lookup):
     # after reg closes but before polling is over
     self.election.polling_start_time = FUTURE_DAY
     self.election.save()
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     mock_lookup.return_value = Result('1', constants.VOTER_QUERY_NOT_FOUND)
     self.receive(self.msg, self.conn, fields=self.fields)
     self.assertTrue(mock_lookup.called)
Esempio n. 7
0
 def setUp(self):
     self.sms = SMSFactory()
     self.citizen = CitizenFactory(national_id=219782058018)
     self.center = RegistrationCenterFactory()
     RegistrationCenterFactory(center_id=self.center.center_id,
                               deleted=True)
     self.mock_response = Mock()
     self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY,
                                                 end_time=FUTURE_DAY)
Esempio n. 8
0
 def setUp(self):
     # lookup_connections takes any identity and creates connections.
     # It's better than create_connection because it uses 'mockbackend'
     # which keeps track of sent messages.
     self.conn = self.lookup_connections(identities=['111'])[0]
     self.good_nid = get_random_number_string(length=constants.NID_LENGTH)
     self.good_center_id = get_random_number_string(length=constants.CENTER_ID_LENGTH)
     self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
     self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY, end_time=FUTURE_DAY)
     self.election = ElectionFactory(polling_start_time=PAST_DAY, polling_end_time=FUTURE_DAY)
Esempio n. 9
0
 def setUp(self):
     self.url = reverse('check_registration')
     self.user = UserFactory(username='******', password='******')
     self.client.login(username='******', password='******')
     # captcha has 2 form fields, _0 is a key, _1 is the text entered by the user
     self.captcha = {'captcha_0': 'dummy', 'captcha_1': 'PASSED'}
     self.registration = RegistrationPeriodFactory(start_time=PAST_DAY,
                                                   end_time=PAST_DAY)
     self.election = ElectionFactory(polling_start_time=FUTURE_DAY,
                                     polling_end_time=FUTURE_DAY)
Esempio n. 10
0
 def test_after_election(self, processor):
     # can still query registration after election
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     ElectionFactory(polling_start_time=PAST_DAY, polling_end_time=PAST_DAY)
     io_table = [
         (self.garbage, constants.REGISTRATION_NOT_OPEN),
         (unicode(self.bad_nid), constants.VOTER_QUERY_NID_WRONG_LENGTH),
         (unicode(self.good_nid), constants.VOTER_QUERY_REGISTERED_AT),
     ]
     result = Mock(message="success",
                   message_code=constants.VOTER_QUERY_REGISTERED_AT)
     processor.return_value = result
     for incoming_message, expected_code in io_table:
         self.receive(incoming_message, self.conn, fields=self.fields)
         self.assertEqual(self.get_last_response_code(), expected_code)
Esempio n. 11
0
 def setUp(self):
     self.number = "919-999-9999"
     self.center = RegistrationCenterFactory()
     self.conn = self.create_connection(data={'identity': self.number})
     self.citizen = CitizenFactory()
     self.good_nid = self.citizen.national_id
     self.bad_nid = get_random_number_string(length=constants.NID_LENGTH)
     self.short_nid = get_random_number_string(length=constants.NID_LENGTH -
                                               1)
     self.good_center_id = self.center.center_id
     self.bad_center_id = get_random_number_string(
         length=constants.CENTER_ID_LENGTH)
     self.long_center_id = get_random_number_string(
         length=constants.CENTER_ID_LENGTH + 1)
     self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=FUTURE_DAY)
Esempio n. 12
0
 def test_query_before_reg_opens(self, mock_lookup):
     RegistrationPeriodFactory(start_time=FUTURE_DAY, end_time=FUTURE_DAY)
     self.receive(self.msg, self.conn, fields=self.fields)
     self.assertTrue(mock_lookup.called)
Esempio n. 13
0
 def setUp(self):
     self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
     self.conn = self.create_connection()
     self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY,
                                                 end_time=FUTURE_DAY)
Esempio n. 14
0
 def test_query_during_reg(self, mock_lookup):
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=FUTURE_DAY)
     mock_lookup.return_value = Result('1', constants.VOTER_QUERY_NOT_FOUND)
     self.receive(self.msg, self.conn, fields=self.fields)
     self.assertTrue(mock_lookup.called)
Esempio n. 15
0
 def setUp(self):
     self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=FUTURE_DAY)
Esempio n. 16
0
 def test_post_polling_reporting_period(self):
     self.election.polling_end_time = FIFTEEN_HOURS_AGO
     self.election.save()
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     self.assertFalse(tool_1_enabled())
     self.assertTrue(polling_reports_enabled())
Esempio n. 17
0
 def test_after_registration_before_polling(self):
     self.election.polling_start_time = FUTURE_DAY
     self.election.save()
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     self.assertFalse(tool_1_enabled())
     self.assertFalse(polling_reports_enabled())
Esempio n. 18
0
 def test_polling_period(self):
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     self.assertFalse(tool_1_enabled())
     self.assertTrue(polling_reports_enabled())
Esempio n. 19
0
class HandlerTest(LibyaRapidTest):
    def setUp(self):
        # lookup_connections takes any identity and creates connections.
        # It's better than create_connection because it uses 'mockbackend'
        # which keeps track of sent messages.
        self.conn = self.lookup_connections(identities=['111'])[0]
        self.good_nid = get_random_number_string(length=constants.NID_LENGTH)
        self.good_center_id = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
        self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY, end_time=FUTURE_DAY)
        self.election = ElectionFactory(polling_start_time=PAST_DAY, polling_end_time=FUTURE_DAY)

    def test_new_logic_rename_me(self):
        phone1 = get_random_number_string(length=10)
        phone2 = get_random_number_string(length=10)
        nid1 = self.good_nid
        ppc1 = self.good_center_id
        ppc2 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc3 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc4 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc5 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        CitizenFactory(national_id=nid1)
        RegistrationCenterFactory(center_id=ppc1)
        RegistrationCenterFactory(center_id=ppc2)
        RegistrationCenterFactory(center_id=ppc3)
        RegistrationCenterFactory(center_id=ppc4)
        RegistrationCenterFactory(center_id=ppc5)
        # Each item in the test_data array is one test.
        # Each test contains one or more steps.
        # Each step contains the phone we receive a message from, the
        # registration center code in that message, the expected response,
        # and the expected registration state after that message.
        # All messages are for the same NID.
        # After each test item, the registrations are reset (deleted).

        # MSG1: you are registered, use same phone to change
        # MSG4: only one more time
        # MSG5: that was your last time

        test_data = [
            # Repeat the same registration from the same phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
            ],
            # Keep trying to change your registration from the same phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc2, constants.MESSAGE_1, ppc2),  # one change is okay
                (phone1, ppc3, constants.MESSAGE_4, ppc3),  # twice is okay but only one left
                (phone1, ppc4, constants.MESSAGE_5, ppc4),  # three is okay but last time
                (phone1, ppc3, constants.MESSAGE_6, ppc4),  # too many, sorry
                (phone1, ppc5, constants.MESSAGE_6, ppc4),  # still too many
            ],
            # Repeat the same registration from a different phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
            ],
            # Try to change registration from a different phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc2, constants.MESSAGE_2, ppc1),  # sorry charlie
                # then from the original phone
                (phone1, ppc2, constants.MESSAGE_1, ppc2),  # that's ok - change 1
                # again from another phone
                (phone2, ppc3, constants.MESSAGE_2, ppc2),
                # back to original phone
                (phone1, ppc3, constants.MESSAGE_4, ppc3),  # change 2 - 1 left
                # try other phone again
                (phone2, ppc4, constants.MESSAGE_2, ppc3),
                # original phone again
                (phone1, ppc2, constants.MESSAGE_5, ppc2),  # 3rd change is the last
                (phone1, ppc4, constants.MESSAGE_6, ppc2),  # too many, sorry
                (phone1, ppc5, constants.MESSAGE_6, ppc2),  # still too many
                # Once you've used up your changes, even sending your current
                # registration results in message 6
                (phone1, ppc2, constants.MESSAGE_6, ppc2),
            ],
            # After changing the registration, the repeat count is reset
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),  # 2nd time - msg 1
                (phone1, ppc1, constants.MESSAGE_1, ppc1),  # 3rd time - msg 1 (enhanced)
                (phone1, ppc2, constants.MESSAGE_1, ppc2),   # change #1 reg - reset counter
                (phone1, ppc2, constants.MESSAGE_1, ppc2),  # 2nd time, same data as #1 change
                (phone1, ppc2, constants.MESSAGE_1, ppc2),  # 3rd time, same data as #1 change
                (phone1, ppc3, constants.MESSAGE_4, ppc3),   # change reg - reset counter
                (phone1, ppc2, constants.MESSAGE_5, ppc2),  # final change
                (phone1, ppc2, constants.MESSAGE_6, ppc2),   # no more changes, always 6
            ],
        ]

        for one_test in test_data:
            # Reset state
            Registration.objects.unfiltered().delete()
            for from_phone, center_id, expected_response, expected_center_id in one_test:
                text = "%s*%s" % (nid1, center_id)
                conn = self.lookup_connections(identities=[from_phone])[0]
                self.receive(text, conn, fields=self.fields)

                # Check the response
                self.assertEqual(expected_response, self.get_last_response_code())
                # Check the state
                reg = Registration.objects.get(citizen__national_id=nid1)
                self.assertEqual(int(expected_center_id), reg.registration_center.center_id)

    def test_input_triggers_proper_response(self):
        short_center_id = u'%s*%s' % (
            self.good_nid, get_random_number_string(length=constants.CENTER_ID_LENGTH - 1))
        long_center_id = u'%s*%s' % (
            self.good_nid, get_random_number_string(length=constants.CENTER_ID_LENGTH + 1))
        short_nid = u"%s*%s" % (
            get_random_number_string(length=constants.NID_LENGTH - 1), self.good_center_id)
        long_nid = u"%s*%s" % (
            get_random_number_string(length=constants.NID_LENGTH + 1), self.good_center_id)
        three_ids = u"%s*%s*123" % (self.good_nid, self.good_center_id)
        io_table = [
            (u"garbage", constants.MESSAGE_INCORRECT),
            (get_random_number_string(), constants.VOTER_QUERY_NID_WRONG_LENGTH),
            (short_center_id, constants.RESPONSE_CENTER_ID_WRONG_LENGTH),
            (long_center_id, constants.RESPONSE_CENTER_ID_WRONG_LENGTH),
            (short_nid, constants.RESPONSE_NID_WRONG_LENGTH),
            (long_nid, constants.RESPONSE_NID_WRONG_LENGTH),
            (three_ids, constants.MESSAGE_INCORRECT),
        ]
        # send the messages
        for (input, _) in io_table:
            self.receive(input, self.conn, fields=self.fields)
        # strip out our split messages
        outputs = [o.fields['message_code'] for o in self.outbound if not o.fields.get('split')]
        for (i, (_, expected_output)) in enumerate(io_table):
            self.assertEqual(outputs[i], expected_output)

    def test_unexpected_error(self):
        with patch.object(PatternHandler, 'dispatch') as dispatch:
            dispatch.side_effect = ValueError
            self.receive("Anything", self.conn, fields=self.fields)
        self.assertEqual(self.outbound[0].fields['message_code'],
                         constants.RESPONSE_SERVER_ERROR)

    @patch('register.handlers.process_registration_request', autospec=True)
    def test_valid_nid(self, mock_prr):
        center_name = u"A Random Center"
        person_name = u"A Random Name"
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        mock_prr.return_value = Result('', constants.RESPONSE_VALID_REGISTRATION,
                                       dict(person=person_name,
                                            centre=center_name,
                                            code=int(self.good_center_id)))
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.outbound[0].fields['message_code'],
                         constants.RESPONSE_VALID_REGISTRATION)
        # message was saved
        sms = SMS.objects.get(message=msg)
        self.assertEqual(SMS.REGISTRATION, sms.msg_type)
        # response was saved
        sms = SMS.objects.filter(to_number=self.conn.identity)
        self.assertNotEqual(sms.count(), 0)

    @patch('register.processors.process_registration_request', autospec=True)
    def test_invalid_center_id(self, mock_prr):
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        mock_prr.return_value = Result('', constants.RESPONSE_CENTER_ID_INVALID)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(), constants.RESPONSE_CENTER_ID_INVALID)

    @patch('register.handlers.registration_allowed')
    def test_outside_registration_period(self, mock_is_open):
        mock_is_open.return_value = False
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(), constants.REGISTRATION_NOT_OPEN)

    def test_not_started(self):
        self.reg_period.start_time = FUTURE_DAY
        self.reg_period.save()
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(), constants.REGISTRATION_NOT_OPEN)

    def test_has_ended(self):
        self.reg_period.end_time = PAST_DAY
        self.reg_period.save()
        self.election.polling_end_time = PAST_DAY
        self.election.save()
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(), constants.REGISTRATION_NOT_OPEN)

    def test_we_only_handle_our_shortcode(self):
        msg = u"garbage"
        not_our_shortcode = '11111'
        self.receive(msg, self.conn, fields={'to_addr': not_our_shortcode})
        # We do send a default response, but we test that more below.
        self.assertEqual(1, len(self.full_outbound()))

    def test_that_we_save_incoming_sms_when_closed(self):
        self.reg_period.start_time = FUTURE_DAY
        self.reg_period.save()
        self.election.polling_start_time = FUTURE_DAY
        self.election.save()
        msg = u"garbage"
        for shortcode in set((settings.REGISTRATION_SHORT_CODE,
                              settings.VOTER_QUERY_SHORT_CODE, settings.REPORTS_SHORT_CODE)):
            self.receive(msg, self.conn, fields={'to_addr': shortcode})
            # test that we save the incoming SMS
            incoming = SMS.objects.filter(to_number=shortcode)
            self.assertEqual(len(incoming), 1)
Esempio n. 20
0
 def test_after_reopened_reg_period(self):
     self.election.polling_end_time = PAST_DAY
     self.election.save()
     RegistrationPeriodFactory(start_time=PAST_DAY, end_time=PAST_DAY)
     self.assertFalse(tool_1_enabled())
     self.assertFalse(polling_reports_enabled())
Esempio n. 21
0
class HandlerTest(LibyaRapidTest):
    def setUp(self):
        # lookup_connections takes any identity and creates connections.
        # It's better than create_connection because it uses 'mockbackend'
        # which keeps track of sent messages.
        self.conn = self.lookup_connections(identities=['111'])[0]
        self.good_nid = get_random_number_string(length=constants.NID_LENGTH)
        self.good_center_id = get_random_number_string(
            length=constants.CENTER_ID_LENGTH)
        self.fields = {'to_addr': settings.REGISTRATION_SHORT_CODE}
        self.reg_period = RegistrationPeriodFactory(start_time=PAST_DAY,
                                                    end_time=FUTURE_DAY)
        self.election = ElectionFactory(polling_start_time=PAST_DAY,
                                        polling_end_time=FUTURE_DAY)

    def test_new_logic_rename_me(self):
        phone1 = get_random_number_string(length=10)
        phone2 = get_random_number_string(length=10)
        nid1 = self.good_nid
        ppc1 = self.good_center_id
        ppc2 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc3 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc4 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        ppc5 = get_random_number_string(length=constants.CENTER_ID_LENGTH)
        CitizenFactory(national_id=nid1)
        RegistrationCenterFactory(center_id=ppc1)
        RegistrationCenterFactory(center_id=ppc2)
        RegistrationCenterFactory(center_id=ppc3)
        RegistrationCenterFactory(center_id=ppc4)
        RegistrationCenterFactory(center_id=ppc5)
        # Each item in the test_data array is one test.
        # Each test contains one or more steps.
        # Each step contains the phone we receive a message from, the
        # registration center code in that message, the expected response,
        # and the expected registration state after that message.
        # All messages are for the same NID.
        # After each test item, the registrations are reset (deleted).

        # MSG1: you are registered, use same phone to change
        # MSG4: only one more time
        # MSG5: that was your last time

        test_data = [
            # Repeat the same registration from the same phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
            ],
            # Keep trying to change your registration from the same phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc2, constants.MESSAGE_1,
                 ppc2),  # one change is okay
                (phone1, ppc3, constants.MESSAGE_4,
                 ppc3),  # twice is okay but only one left
                (phone1, ppc4, constants.MESSAGE_5,
                 ppc4),  # three is okay but last time
                (phone1, ppc3, constants.MESSAGE_6, ppc4),  # too many, sorry
                (phone1, ppc5, constants.MESSAGE_6, ppc4),  # still too many
            ],
            # Repeat the same registration from a different phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc1, constants.MESSAGE_7, ppc1),
            ],
            # Try to change registration from a different phone
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone2, ppc2, constants.MESSAGE_2, ppc1),  # sorry charlie
                # then from the original phone
                (phone1, ppc2, constants.MESSAGE_1, ppc2
                 ),  # that's ok - change 1
                # again from another phone
                (phone2, ppc3, constants.MESSAGE_2, ppc2),
                # back to original phone
                (phone1, ppc3, constants.MESSAGE_4, ppc3),  # change 2 - 1 left
                # try other phone again
                (phone2, ppc4, constants.MESSAGE_2, ppc3),
                # original phone again
                (phone1, ppc2, constants.MESSAGE_5, ppc2
                 ),  # 3rd change is the last
                (phone1, ppc4, constants.MESSAGE_6, ppc2),  # too many, sorry
                (phone1, ppc5, constants.MESSAGE_6, ppc2),  # still too many
                # Once you've used up your changes, even sending your current
                # registration results in message 6
                (phone1, ppc2, constants.MESSAGE_6, ppc2),
            ],
            # After changing the registration, the repeat count is reset
            [
                (phone1, ppc1, constants.MESSAGE_1, ppc1),
                (phone1, ppc1, constants.MESSAGE_1, ppc1),  # 2nd time - msg 1
                (phone1, ppc1, constants.MESSAGE_1,
                 ppc1),  # 3rd time - msg 1 (enhanced)
                (phone1, ppc2, constants.MESSAGE_1,
                 ppc2),  # change #1 reg - reset counter
                (phone1, ppc2, constants.MESSAGE_1,
                 ppc2),  # 2nd time, same data as #1 change
                (phone1, ppc2, constants.MESSAGE_1,
                 ppc2),  # 3rd time, same data as #1 change
                (phone1, ppc3, constants.MESSAGE_4,
                 ppc3),  # change reg - reset counter
                (phone1, ppc2, constants.MESSAGE_5, ppc2),  # final change
                (phone1, ppc2, constants.MESSAGE_6,
                 ppc2),  # no more changes, always 6
            ],
        ]

        for one_test in test_data:
            # Reset state
            Registration.objects.unfiltered().delete()
            for from_phone, center_id, expected_response, expected_center_id in one_test:
                text = "%s*%s" % (nid1, center_id)
                conn = self.lookup_connections(identities=[from_phone])[0]
                self.receive(text, conn, fields=self.fields)

                # Check the response
                self.assertEqual(expected_response,
                                 self.get_last_response_code())
                # Check the state
                reg = Registration.objects.get(citizen__national_id=nid1)
                self.assertEqual(int(expected_center_id),
                                 reg.registration_center.center_id)

    def test_input_triggers_proper_response(self):
        short_center_id = u'%s*%s' % (
            self.good_nid,
            get_random_number_string(length=constants.CENTER_ID_LENGTH - 1))
        long_center_id = u'%s*%s' % (
            self.good_nid,
            get_random_number_string(length=constants.CENTER_ID_LENGTH + 1))
        short_nid = u"%s*%s" % (get_random_number_string(
            length=constants.NID_LENGTH - 1), self.good_center_id)
        long_nid = u"%s*%s" % (get_random_number_string(
            length=constants.NID_LENGTH + 1), self.good_center_id)
        three_ids = u"%s*%s*123" % (self.good_nid, self.good_center_id)
        io_table = [
            (u"garbage", constants.MESSAGE_INCORRECT),
            (get_random_number_string(),
             constants.VOTER_QUERY_NID_WRONG_LENGTH),
            (short_center_id, constants.RESPONSE_CENTER_ID_WRONG_LENGTH),
            (long_center_id, constants.RESPONSE_CENTER_ID_WRONG_LENGTH),
            (short_nid, constants.RESPONSE_NID_WRONG_LENGTH),
            (long_nid, constants.RESPONSE_NID_WRONG_LENGTH),
            (three_ids, constants.MESSAGE_INCORRECT),
        ]
        # send the messages
        for (input, _) in io_table:
            self.receive(input, self.conn, fields=self.fields)
        # strip out our split messages
        outputs = [
            o.fields['message_code'] for o in self.outbound
            if not o.fields.get('split')
        ]
        for (i, (_, expected_output)) in enumerate(io_table):
            self.assertEqual(outputs[i], expected_output)

    def test_unexpected_error(self):
        with patch.object(PatternHandler, 'dispatch') as dispatch:
            dispatch.side_effect = ValueError
            self.receive("Anything", self.conn, fields=self.fields)
        self.assertEqual(self.outbound[0].fields['message_code'],
                         constants.RESPONSE_SERVER_ERROR)

    @patch('register.handlers.process_registration_request', autospec=True)
    def test_valid_nid(self, mock_prr):
        center_name = u"A Random Center"
        person_name = u"A Random Name"
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        mock_prr.return_value = Result(
            '', constants.RESPONSE_VALID_REGISTRATION,
            dict(person=person_name,
                 centre=center_name,
                 code=int(self.good_center_id)))
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.outbound[0].fields['message_code'],
                         constants.RESPONSE_VALID_REGISTRATION)
        # message was saved
        sms = SMS.objects.get(message=msg)
        self.assertEqual(SMS.REGISTRATION, sms.msg_type)
        # response was saved
        sms = SMS.objects.filter(to_number=self.conn.identity)
        self.assertNotEqual(sms.count(), 0)

    @patch('register.processors.process_registration_request', autospec=True)
    def test_invalid_center_id(self, mock_prr):
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        mock_prr.return_value = Result('',
                                       constants.RESPONSE_CENTER_ID_INVALID)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(),
                         constants.RESPONSE_CENTER_ID_INVALID)

    @patch('register.handlers.registration_allowed')
    def test_outside_registration_period(self, mock_is_open):
        mock_is_open.return_value = False
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(),
                         constants.REGISTRATION_NOT_OPEN)

    def test_not_started(self):
        self.reg_period.start_time = FUTURE_DAY
        self.reg_period.save()
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(),
                         constants.REGISTRATION_NOT_OPEN)

    def test_has_ended(self):
        self.reg_period.end_time = PAST_DAY
        self.reg_period.save()
        self.election.polling_end_time = PAST_DAY
        self.election.save()
        RegistrationCenterFactory(center_id=self.good_center_id)
        msg = u"%s*%s" % (self.good_nid, self.good_center_id)
        self.receive(msg, self.conn, fields=self.fields)
        self.assertEqual(self.get_last_response_code(),
                         constants.REGISTRATION_NOT_OPEN)

    def test_we_only_handle_our_shortcode(self):
        msg = u"garbage"
        not_our_shortcode = '11111'
        self.receive(msg, self.conn, fields={'to_addr': not_our_shortcode})
        # We do send a default response, but we test that more below.
        self.assertEqual(1, len(self.full_outbound()))

    def test_that_we_save_incoming_sms_when_closed(self):
        self.reg_period.start_time = FUTURE_DAY
        self.reg_period.save()
        self.election.polling_start_time = FUTURE_DAY
        self.election.save()
        msg = u"garbage"
        for shortcode in set(
            (settings.REGISTRATION_SHORT_CODE, settings.VOTER_QUERY_SHORT_CODE,
             settings.REPORTS_SHORT_CODE)):
            self.receive(msg, self.conn, fields={'to_addr': shortcode})
            # test that we save the incoming SMS
            incoming = SMS.objects.filter(to_number=shortcode)
            self.assertEqual(len(incoming), 1)