Ejemplo n.º 1
0
    def test_trigger_when_paused(self):
        # not paused
        with patch.object(RepeatRecord, 'fire') as mock_fire:
            with patch.object(RepeatRecord, 'postpone_by') as mock_postpone_fire:
                process_repeat_record(self.repeat_record)
                self.assertEqual(mock_fire.call_count, 1)
                self.assertEqual(mock_postpone_fire.call_count, 0)

                # paused
                self.repeater.pause()
                # re fetch repeat record
                repeat_record_id = self.repeat_record.get_id
                self.repeat_record = RepeatRecord.get(repeat_record_id)
                process_repeat_record(self.repeat_record)
                self.assertEqual(mock_fire.call_count, 1)
                self.assertEqual(mock_postpone_fire.call_count, 1)

                # resumed
                self.repeater.resume()
                # re fetch repeat record
                repeat_record_id = self.repeat_record.get_id
                self.repeat_record = RepeatRecord.get(repeat_record_id)
                process_repeat_record(self.repeat_record)
                self.assertEqual(mock_fire.call_count, 2)
                self.assertEqual(mock_postpone_fire.call_count, 1)
Ejemplo n.º 2
0
    def test_trigger_when_paused(self):
        # not paused
        with patch.object(RepeatRecord, 'fire') as mock_fire:
            with patch.object(RepeatRecord, 'postpone_by') as mock_postpone_fire:
                # calls process_repeat_record():
                self.repeat_record = self.repeater.register(CaseAccessors(self.domain).get_case(CASE_ID))
                self.assertEqual(mock_fire.call_count, 1)
                self.assertEqual(mock_postpone_fire.call_count, 0)

                # paused
                self.repeater.pause()
                # re fetch repeat record
                repeat_record_id = self.repeat_record.get_id
                self.repeat_record = RepeatRecord.get(repeat_record_id)
                process_repeat_record(self.repeat_record)
                self.assertEqual(mock_fire.call_count, 1)
                self.assertEqual(mock_postpone_fire.call_count, 1)

                # resumed
                self.repeater.resume()
                # re fetch repeat record
                repeat_record_id = self.repeat_record.get_id
                self.repeat_record = RepeatRecord.get(repeat_record_id)
                process_repeat_record(self.repeat_record)
                self.assertEqual(mock_fire.call_count, 2)
                self.assertEqual(mock_postpone_fire.call_count, 1)
Ejemplo n.º 3
0
    def test_repeat_record_status_check(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        # Do not trigger cancelled records
        for repeat_record in RepeatRecord.all():
            repeat_record.cancelled = True
            repeat_record.save()
        with patch('corehq.motech.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)

        # trigger force send records if not cancelled and tries not exhausted
        for repeat_record in RepeatRecord.all():
            with patch('corehq.motech.repeaters.models.simple_post',
                       return_value=MockResponse(status_code=200, reason='')
                       ) as mock_fire:
                repeat_record.fire(force_send=True)
                self.assertEqual(mock_fire.call_count, 1)

        # all records should be in SUCCESS state after force try
        for repeat_record in RepeatRecord.all():
                self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)
                self.assertEqual(repeat_record.overall_tries, 1)

        # not trigger records succeeded triggered after cancellation
        with patch('corehq.motech.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
            for repeat_record in RepeatRecord.all():
                self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)
Ejemplo n.º 4
0
    def test_repeater_failed_sends(self):
        """
        This tests records that fail are requeued later
        """
        def now():
            return datetime.utcnow()

        repeat_records = self.repeat_records()
        self.assertEqual(len(repeat_records), 2)

        for repeat_record in repeat_records:
            with patch(
                    'corehq.motech.repeaters.models.simple_post',
                    return_value=MockResponse(status_code=404, reason='Not Found')) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 1)

        # Enqueued repeat records have next_check incremented by 48 hours
        next_check_time = now() + timedelta(minutes=60) + timedelta(hours=48)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=now() + timedelta(minutes=15),
        )
        self.assertEqual(len(repeat_records), 0)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time,
        )
        self.assertEqual(len(repeat_records), 2)
Ejemplo n.º 5
0
    def test_get_all_repeat_records_by_domain_since(self):
        new_records = [
            # FAIL
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 24, 0, 0, 0),
                failure_reason='some error',
            ),
            # CANCELLED
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 10, 0, 0, 0),
                cancelled=True,
            ),
            # CANCELLED
            RepeatRecord(
                domain=self.domain,
                repeater_id=self.repeater_id,
                last_checked=datetime(2017, 5, 24, 0, 0, 0),
                cancelled=True,
            ),
        ]
        RepeatRecord.bulk_save(new_records)
        self.addCleanup(RepeatRecord.bulk_delete, new_records)

        records = list(iter_repeat_records_by_domain(self.domain, state=RECORD_CANCELLED_STATE,
                                                     since=datetime(2017, 5, 20)))
        self.assertEqual(len(records), 1)
        record, = records
        self.assertEqual(record.to_json(), new_records[-1].to_json())
Ejemplo n.º 6
0
 def setUpClass(cls):
     super(TestOtherDBAccessors, cls).setUpClass()
     cls.records = [
         RepeatRecord(domain='a'),
         RepeatRecord(domain='b'),
         RepeatRecord(domain='c'),
     ]
     RepeatRecord.bulk_save(cls.records)
Ejemplo n.º 7
0
 def test_skip_duplicates(self):
     """
     Ensure that submitting a duplicate form does not create extra RepeatRecords
     """
     self.assertEqual(len(RepeatRecord.all()), 2)
     # this form is already submitted during setUp so a second submission should be a duplicate
     form = self.post_xml(self.xform_xml, self.domain).xform
     self.assertTrue(form.is_duplicate)
     self.assertEqual(len(RepeatRecord.all()), 2)
Ejemplo n.º 8
0
    def test_update_failure_next_check(self):
        now = datetime.utcnow()
        record = RepeatRecord(domain=self.domain, next_check=now)
        self.assertIsNone(record.last_checked)

        attempt = record.make_set_next_try_attempt(None)
        record.add_attempt(attempt)
        self.assertTrue(record.last_checked > now)
        self.assertEqual(record.next_check, record.last_checked + MIN_RETRY_WAIT)
    def handle(self, *args, **options):
        domain = options.get('domain')
        repeater_id = options.get('repeater_id')
        state = options.get('state')
        records_file_path = options.get('records_file_path')

        if records_file_path:
            self._load_record_ids_from_file(records_file_path)
            records = self.record_ids
            record_count = len(records)
        elif domain and repeater_id:
            records = iter_repeat_records_by_domain(domain, repeater_id=repeater_id, state=state)
            record_count = get_repeat_record_count(domain, repeater_id=repeater_id, state=state)
        else:
            raise CommandError("Insufficient Arguments")

        for record in with_progress_bar(records, length=record_count):
            if isinstance(record, str):
                record_id = record
                try:
                    record = RepeatRecord.get(record_id)
                except ResourceNotFound:
                    self.ws.append([record_id, '', 'Not Found'])
                    continue
            self._add_row(record)

        file_name = self._save_file(repeater_id, state)
        print("Report saved in file:{filename}".format(filename=file_name))
 def delete_already_successful_records(self, redundant_records):
     log = []
     with IterDB(RepeatRecord.get_db()) as iter_db:
         for record in redundant_records:
             iter_db.delete(record)
             log.append((record._id, record.payload_id, record.failure_reason, 'Yes', 'Already Sent'))
     return log
Ejemplo n.º 11
0
def openmrs_test_fire(request, domain, repeater_id, record_id):
    repeater = OpenmrsRepeater.get(repeater_id)
    record = RepeatRecord.get(record_id)
    assert repeater.domain == domain
    assert record.domain == domain
    assert record.repeater_id == repeater.get_id

    attempt = repeater.fire_for_record(record)
    return JsonResponse(attempt.to_json())
Ejemplo n.º 12
0
def requeue_repeat_record(request, domain):
    try:
        record = RepeatRecord.get(request.POST.get('record_id'))
    except ResourceNotFound:
        return HttpResponse(status=404)
    record.requeue()
    record.save()
    if record.cancelled:
        return HttpResponse(status=400)
    return HttpResponse('OK')
Ejemplo n.º 13
0
    def get_record_or_404(request, domain, record_id):
        try:
            record = RepeatRecord.get(record_id)
        except ResourceNotFound:
            raise Http404()

        if record.domain != domain:
            raise Http404()

        return record
 def resolve_duplicates(self, records_by_payload_id):
     log = []
     with IterDB(RepeatRecord.get_db()) as iter_db:
         for payload_id, records in records_by_payload_id.items():
             log.append((records[0]._id, payload_id, records[0].failure_reason, 'No', ''))
             if len(records) > 1:
                 for record in records[1:]:
                     iter_db.delete(record)
                     log.append((record._id, payload_id, record.failure_reason, 'Yes', 'Duplicate'))
     return log
Ejemplo n.º 15
0
    def test_check_repeat_records(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.motech.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 2)

        with patch('corehq.motech.repeaters.models.simple_post') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
Ejemplo n.º 16
0
    def test_process_repeat_record_locking(self):
        self.assertEqual(len(RepeatRecord.all()), 2)

        with patch('corehq.motech.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)

        with patch('corehq.motech.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 0)

        records = RepeatRecord.all()
        # Saving should unlock them again by changing the rev
        for record in records:
            record.save()

        with patch('corehq.motech.repeaters.tasks.process_repeat_record') as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)
Ejemplo n.º 17
0
    def _run_test(self, event_type, expected_records_after_create, expected_records_after_update,
                  case_type=ZAPIER_CASE_TYPE):
        ZapierSubscription.objects.create(
            domain=self.domain,
            user_id=str(self.web_user._id),
            event_name=event_type,
            url='http://example.com/lets-make-some-cases/',
            case_type=ZAPIER_CASE_TYPE,
        )

        # create case and run checks
        case_id = uuid.uuid4().hex
        post_case_blocks(
            [
                CaseBlock(
                    create=True,
                    case_id=case_id,
                    case_type=case_type,
                ).as_xml()
            ], domain=self.domain
        )
        # Enqueued repeat records have next_check set 48 hours in the future.
        later = datetime.utcnow() + timedelta(hours=48 + 1)
        repeat_records = list(RepeatRecord.all(domain=self.domain, due_before=later))
        self.assertEqual(expected_records_after_create, len(repeat_records))
        for record in repeat_records:
            self.assertEqual(case_id, record.payload_id)

        # update case and run checks
        post_case_blocks(
            [
                CaseBlock(
                    create=False,
                    case_id=case_id,
                ).as_xml()
            ], domain=self.domain
        )
        repeat_records = list(RepeatRecord.all(domain=self.domain, due_before=later))
        self.assertEqual(expected_records_after_update, len(repeat_records))
        for record in repeat_records:
            self.assertEqual(case_id, record.payload_id)
Ejemplo n.º 18
0
 def page_context(self):
     return {
         'repeaters': self.repeaters,
         'pending_record_count': RepeatRecord.count(self.domain),
         'gefingerpoken': (
             # Set gefingerpoken_ to whether the user should be allowed to change MOTECH configuration.
             # .. _gefingerpoken: https://en.wikipedia.org/wiki/Blinkenlights
             self.request.couch_user.is_superuser or
             self.request.couch_user.can_edit_motech() or
             toggles.IS_CONTRACTOR.enabled(self.request.couch_user.username)
         )
     }
Ejemplo n.º 19
0
    def test_ignore_document(self):
        """
        When get_payload raises IgnoreDocument, fire should call update_success
        """
        repeat_records = RepeatRecord.all(
            domain=self.domain,
        )
        for repeat_record_ in repeat_records:
            repeat_record_.fire()

            self.assertIsNone(repeat_record_.next_check)
            self.assertTrue(repeat_record_.succeeded)
Ejemplo n.º 20
0
    def _run_test(self, event_type, expected_records_after_create, expected_records_after_update,
                  case_type=ZAPIER_CASE_TYPE):
        ZapierSubscription.objects.create(
            domain=self.domain,
            user_id=str(self.web_user._id),
            event_name=event_type,
            url='http://example.com/lets-make-some-cases/',
            case_type=ZAPIER_CASE_TYPE,
        )

        # create case and run checks
        case_id = uuid.uuid4().hex
        post_case_blocks(
            [
                CaseBlock(
                    create=True,
                    case_id=case_id,
                    case_type=case_type,
                ).as_xml()
            ], domain=self.domain
        )
        repeat_records = list(RepeatRecord.all(domain=self.domain))
        self.assertEqual(expected_records_after_create, len(repeat_records))
        for record in repeat_records:
            self.assertEqual(case_id, record.payload_id)

        # update case and run checks
        post_case_blocks(
            [
                CaseBlock(
                    create=False,
                    case_id=case_id,
                ).as_xml()
            ], domain=self.domain
        )
        repeat_records = list(RepeatRecord.all(domain=self.domain))
        self.assertEqual(expected_records_after_update, len(repeat_records))
        for record in repeat_records:
            self.assertEqual(case_id, record.payload_id)
Ejemplo n.º 21
0
    def test_repeater_successful_send(self):

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())

        for repeat_record in repeat_records:
            with patch(
                    'corehq.motech.repeaters.models.simple_post',
                    return_value=MockResponse(status_code=200, reason='No Reason')) as mock_post:
                repeat_record.fire()
                self.assertEqual(mock_post.call_count, 1)
                mock_post.assert_any_call(
                    repeat_record.get_payload(),
                    repeat_record.repeater.get_url(repeat_record),
                    headers=repeat_record.repeater.get_headers(repeat_record),
                    timeout=POST_TIMEOUT,
                    auth=repeat_record.repeater.get_auth(),
                    verify=repeat_record.repeater.verify,
                )

        # The following is pretty fickle and depends on which of
        #   - corehq.motech.repeaters.signals
        #   - casexml.apps.case.signals
        # gets loaded first.
        # This is deterministic but easily affected by minor code changes
        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=datetime.utcnow(),
        )
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.succeeded, True)
            self.assertEqual(repeat_record.next_check, None)

        self.assertEqual(len(self.repeat_records(self.domain)), 0)

        self.post_xml(self.update_xform_xml, self.domain)
        self.assertEqual(len(self.repeat_records(self.domain)), 2)
Ejemplo n.º 22
0
    def test_repeat_record_created(self):
        '''
        Tests that whenever an application with a repeater is saved that a repeat record is created.
        '''
        application = Application(domain=self.domain)
        application.save()

        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())
        self.assertEqual(len(repeat_records), 0)

        app_structure_repeater = AppStructureRepeater(domain=self.domain, url=self.forwarding_url)
        app_structure_repeater.save()

        application.save()
        repeat_records = RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())

        self.assertEqual(len(repeat_records), 1)
        for repeat_record in repeat_records:
                self.assertEqual(repeat_record.repeater.get_url(repeat_record), self.forwarding_url)
                self.assertEqual(repeat_record.get_payload(), application.get_id)
                repeat_record.delete()

        application.delete()
        app_structure_repeater.delete()
Ejemplo n.º 23
0
 def repeat_records(self):
     return RepeatRecord.all(domain=self.domain,
                             due_before=datetime.utcnow())
Ejemplo n.º 24
0
 def repeat_records(self):
     # Enqueued repeat records have next_check set 48 hours in the future.
     later = datetime.utcnow() + timedelta(hours=48 + 1)
     return RepeatRecord.all(domain=self.domain, due_before=later)
Ejemplo n.º 25
0
 def repeat_records(self):
     return RepeatRecord.all(domain=self.domain, due_before=datetime.utcnow())
Ejemplo n.º 26
0
 def repeat_records(cls, domain_name):
     return RepeatRecord.all(domain=domain_name, due_before=datetime.utcnow())
Ejemplo n.º 27
0
        with patch('corehq.motech.repeaters.models.simple_request',
                   side_effect=RequestException('Boom!')):
            rr = self.repeater.register(case)  # calls repeat_record.fire()

        # Fetch the repeat_record revision that was updated
        repeat_record = RepeatRecord.get(rr.record_id)
        self.assertEqual(repeat_record.failure_reason, 'Boom!')
        self.assertFalse(repeat_record.succeeded)

    def test_unexpected_failure(self):
        case = CommCareCase.objects.get_case(CASE_ID, self.domain)
        with patch('corehq.motech.repeaters.models.simple_request',
                   side_effect=Exception('Boom!')):
            rr = self.repeater.register(case)

        repeat_record = RepeatRecord.get(rr.record_id)
        self.assertEqual(repeat_record.failure_reason, 'Internal Server Error')
        self.assertFalse(repeat_record.succeeded)

    def test_success(self):
        case = CommCareCase.objects.get_case(CASE_ID, self.domain)
        # Should be marked as successful after a successful run
        with patch('corehq.motech.repeaters.models.simple_request'
                   ) as mock_simple_post:
            mock_simple_post.return_value.status_code = 200
            rr = self.repeater.register(case)

        repeat_record = RepeatRecord.get(rr.record_id)
        self.assertTrue(repeat_record.succeeded)

Ejemplo n.º 28
0
 def test_content_is_None(self):
     response = Response(500, 'The core is exposed')
     formatted = RepeatRecord._format_response(response)
     self.assertEqual(formatted, '500: The core is exposed.\n')
Ejemplo n.º 29
0
def cleanup_repeat_records_for_domain(domain):
    for repeat_record in RepeatRecord.all(domain=domain):
        repeat_record.delete()
Ejemplo n.º 30
0
class RepeaterTest(BaseRepeaterTest):
    domain = "repeater-test"

    def setUp(self):
        super(RepeaterTest, self).setUp()
        self.case_connx = ConnectionSettings.objects.create(
            domain=self.domain,
            url='case-repeater-url',
        )
        self.case_repeater = CaseRepeater(
            domain=self.domain,
            connection_settings_id=self.case_connx.id,
            format='case_json',
        )
        self.case_repeater.save()

        self.form_connx = ConnectionSettings.objects.create(
            domain=self.domain,
            url='form-repeater-url',
        )
        self.form_repeater = FormRepeater(
            domain=self.domain,
            connection_settings_id=self.form_connx.id,
            format='form_json')
        self.form_repeater.save()
        self.log = []

        with patch('corehq.motech.repeaters.models.simple_request',
                   return_value=MockResponse(status_code=500,
                                             reason="Borked")) as mock_fire:
            self.post_xml(self.xform_xml, self.domain)
            self.initial_fire_call_count = mock_fire.call_count

    def tearDown(self):
        self.case_repeater.delete()
        self.case_connx.delete()
        self.form_repeater.delete()
        self.form_connx.delete()
        FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain)
        delete_all_repeat_records()
        super(RepeaterTest, self).tearDown()

    def repeat_records(self):
        return super(RepeaterTest, self).repeat_records(self.domain)

    # whatever value specified will be doubled since both case and form repeater are active
    def _create_additional_repeat_records(self, count):
        for _ in range(count):
            instance_id = uuid.uuid4().hex
            xform_xml = XFORM_XML_TEMPLATE.format(
                "https://www.commcarehq.org/test/repeater/", USER_ID,
                instance_id, self.case_block)
            with patch('corehq.motech.repeaters.models.simple_request',
                       return_value=MockResponse(status_code=500,
                                                 reason="Borked")):
                self.post_xml(xform_xml, self.domain)

    def test_skip_device_logs(self):
        devicelog_xml = XFORM_XML_TEMPLATE.format(DEVICE_LOG_XMLNS, USER_ID,
                                                  '1234', '')
        self.post_xml(devicelog_xml, self.domain)
        for repeat_record in self.repeat_records():
            self.assertNotEqual(repeat_record.payload_id, '1234')

    def test_skip_duplicates(self):
        """
        Ensure that submitting a duplicate form does not create extra RepeatRecords
        """
        self.assertEqual(len(self.repeat_records()), 2)
        # this form is already submitted during setUp so a second submission should be a duplicate
        form = self.post_xml(self.xform_xml, self.domain).xform
        self.assertTrue(form.is_duplicate)
        self.assertEqual(len(self.repeat_records()), 2)

    def test_repeater_failed_sends(self):
        """
        This tests records that fail are requeued later
        """
        def now():
            return datetime.utcnow()

        repeat_records = self.repeat_records()
        self.assertEqual(len(repeat_records), 2)

        for repeat_record in repeat_records:
            with patch('corehq.motech.repeaters.models.simple_request',
                       return_value=MockResponse(
                           status_code=404,
                           reason='Not Found')) as mock_request:
                repeat_record.fire()
                self.assertEqual(mock_request.call_count, 1)

        # Enqueued repeat records have next_check incremented by 48 hours
        next_check_time = now() + timedelta(minutes=60) + timedelta(hours=48)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=now() + timedelta(minutes=15),
        )
        self.assertEqual(len(repeat_records), 0)

        repeat_records = RepeatRecord.all(
            domain=self.domain,
            due_before=next_check_time,
        )
        self.assertEqual(len(repeat_records), 2)

    def test_update_failure_next_check(self):
        now = datetime.utcnow()
        record = RepeatRecord(
            domain=self.domain,
            repeater_id=self.case_repeater.get_id,
            next_check=now,
        )
        self.assertIsNone(record.last_checked)

        attempt = record.make_set_next_try_attempt(None)
        record.add_attempt(attempt)
        self.assertTrue(record.last_checked > now)
        self.assertEqual(record.next_check,
                         record.last_checked + MIN_RETRY_WAIT)

    def test_repeater_successful_send(self):

        repeat_records = self.repeat_records()

        for repeat_record in repeat_records:
            with patch('corehq.motech.repeaters.models.simple_request') as mock_request, \
                    patch.object(ConnectionSettings, 'get_auth_manager') as mock_manager:
                mock_request.return_value.status_code = 200
                mock_manager.return_value = 'MockAuthManager'
                repeat_record.fire()
                self.assertEqual(mock_request.call_count, 1)
                mock_request.assert_called_with(
                    self.domain,
                    repeat_record.repeater.get_url(repeat_record),
                    repeat_record.get_payload(),
                    headers=repeat_record.repeater.get_headers(repeat_record),
                    auth_manager='MockAuthManager',
                    verify=repeat_record.repeater.verify,
                    notify_addresses=[],
                    payload_id=repeat_record.payload_id,
                    method="POST",
                )

        # The following is pretty fickle and depends on which of
        #   - corehq.motech.repeaters.signals
        #   - casexml.apps.case.signals
        # gets loaded first.
        # This is deterministic but easily affected by minor code changes
        repeat_records = self.repeat_records()
        for repeat_record in repeat_records:
            self.assertEqual(repeat_record.succeeded, True)
            self.assertEqual(repeat_record.next_check, None)

        self.assertEqual(len(self.repeat_records()), 0)

        self.post_xml(self.update_xform_xml, self.domain)
        self.assertEqual(len(self.repeat_records()), 2)

    def test_check_repeat_records(self):
        self.assertEqual(len(self.repeat_records()), 2)
        self.assertEqual(self.initial_fire_call_count, 2)

        with patch(
                'corehq.motech.repeaters.models.simple_request') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)

    def test_repeat_record_status_check(self):
        self.assertEqual(len(self.repeat_records()), 2)

        # Do not trigger cancelled records
        for repeat_record in self.repeat_records():
            repeat_record.cancelled = True
            repeat_record.save()
        with patch(
                'corehq.motech.repeaters.models.simple_request') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)

        # trigger force send records if not cancelled and tries not exhausted
        for repeat_record in self.repeat_records():
            with patch('corehq.motech.repeaters.models.simple_request',
                       return_value=MockResponse(status_code=200,
                                                 reason='')) as mock_fire:
                repeat_record.fire(force_send=True)
                self.assertEqual(mock_fire.call_count, 1)

        # all records should be in SUCCESS state after force try
        for repeat_record in self.repeat_records():
            self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)
            self.assertEqual(repeat_record.overall_tries, 1)

        # not trigger records succeeded triggered after cancellation
        with patch(
                'corehq.motech.repeaters.models.simple_request') as mock_fire:
            check_repeaters()
            self.assertEqual(mock_fire.call_count, 0)
            for repeat_record in self.repeat_records():
                self.assertEqual(repeat_record.state, RECORD_SUCCESS_STATE)

    def test_retry_process_repeat_record_locking(self):
        self.assertEqual(len(self.repeat_records()), 2)

        with patch('corehq.motech.repeaters.tasks.retry_process_repeat_record'
                   ) as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 0)

        for record in self.repeat_records():
            # Resetting next_check should allow them to be requeued
            record.next_check = datetime.utcnow()
            record.save()

        with patch('corehq.motech.repeaters.tasks.retry_process_repeat_record'
                   ) as mock_process:
            check_repeaters()
            self.assertEqual(mock_process.delay.call_count, 2)

    def test_automatic_cancel_repeat_record(self):
        case = CommCareCase.objects.get_case(CASE_ID, self.domain)
        rr = self.case_repeater.register(case)
        # Fetch the revision that was updated:
        repeat_record = RepeatRecord.get(rr.record_id)
        self.assertEqual(1, repeat_record.overall_tries)
        with patch('corehq.motech.repeaters.models.simple_request',
                   side_effect=Exception('Boom!')):
            for __ in range(repeat_record.max_possible_tries -
                            repeat_record.overall_tries):
                repeat_record.fire()
        self.assertEqual(True, repeat_record.cancelled)
        repeat_record.requeue()
        self.assertEqual(0, repeat_record.overall_tries)
        self.assertNotEqual(None, repeat_record.next_check)
Ejemplo n.º 31
0
class TestRepeaterFormat(BaseRepeaterTest):
    domain = 'test-fmt'

    @classmethod
    def setUpClass(cls):
        super(TestRepeaterFormat, cls).setUpClass()
        cls.payload = 'some random case'

        class NewCaseGenerator(BasePayloadGenerator):
            format_name = 'new_format'
            format_label = 'XML'
            deprecated_format_names = ('new_format_alias', )

            def get_payload(self, repeat_record, payload_doc):
                return cls.payload

        RegisterGenerator.get_collection(CaseRepeater).add_new_format(
            NewCaseGenerator)
        cls.new_generator = NewCaseGenerator

    def setUp(self):
        super().setUp()
        self.post_xml(self.xform_xml, self.domain)
        self.connx = ConnectionSettings.objects.create(
            domain=self.domain,
            url='case-repeater-url',
        )
        self.repeater = CaseRepeater(
            domain=self.domain,
            connection_settings_id=self.connx.id,
            format='new_format',
        )
        # SQL Repeater Model restricts format and would raise error on unexpected values
        self.repeater.save(sync_to_sql=False)

    def tearDown(self):
        self.repeater.delete(sync_to_sql=False)
        self.connx.delete()
        FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain)
        delete_all_repeat_records()
        super().tearDown()

    def test_new_format_same_name(self):
        class NewCaseGenerator(BasePayloadGenerator):
            format_name = 'case_xml'
            format_label = 'XML'

            def get_payload(self, repeat_record, payload_doc):
                return self.payload

        with self.assertRaises(DuplicateFormatException):
            RegisterGenerator.get_collection(CaseRepeater).add_new_format(
                NewCaseGenerator)

    def test_new_format_second_default(self):
        class NewCaseGenerator(BasePayloadGenerator):
            format_name = 'rubbish'
            format_label = 'XML'

            def get_payload(self, repeat_record, payload_doc):
                return self.payload

        with self.assertRaises(DuplicateFormatException):
            RegisterGenerator.get_collection(CaseRepeater).add_new_format(
                NewCaseGenerator, is_default=True)

    def test_new_format_payload(self):
        case = CommCareCase.objects.get_case(CASE_ID, self.domain)
        with patch('corehq.motech.repeaters.models.simple_request') as mock_request, \
                patch.object(ConnectionSettings, 'get_auth_manager') as mock_manager:
            mock_request.return_value.status_code = 200
            mock_manager.return_value = 'MockAuthManager'
            rr = self.repeater.register(case)

            repeat_record = RepeatRecord.get(rr.record_id)
            headers = self.repeater.get_headers(repeat_record)
            mock_request.assert_called_with(
                self.domain,
                self.connx.url,
                self.payload,
                auth_manager='MockAuthManager',
                headers=headers,
                notify_addresses=[],
                payload_id='ABC123CASEID',
                verify=self.repeater.verify,
                method="POST",
            )
Ejemplo n.º 32
0
 def repeat_records(cls, domain_name):
     return RepeatRecord.all(domain=domain_name,
                             due_before=datetime.utcnow())
Ejemplo n.º 33
0
 def handle(self, domain, **options):
     next_year = datetime.datetime.utcnow() + datetime.timedelta(days=365)
     records = RepeatRecord.all(domain=domain, due_before=next_year)  # Excludes succeeded and cancelled
     for record in records:
         record.fire(force_send=True)
         print('{} {}'.format(record._id, 'successful' if record.succeeded else 'failed'))
Ejemplo n.º 34
0
def get_domains_that_have_repeat_records():
    from .models import RepeatRecord
    return [
        row['key'][0] for row in RepeatRecord.view('repeaters/repeat_records',
                                                   group_level=1).all()
    ]
Ejemplo n.º 35
0
def cleanup_repeat_records_for_domain(domain):
    for repeat_record in RepeatRecord.all(domain=domain):
        repeat_record.delete()
Ejemplo n.º 36
0
def iterate_repeat_records_for_ids(doc_ids):
    from .models import RepeatRecord
    return (RepeatRecord.wrap(doc) for doc in iter_docs(RepeatRecord.get_db(), doc_ids))
Ejemplo n.º 37
0
 def test_skip_device_logs(self):
     devicelog_xml = XFORM_XML_TEMPLATE.format(DEVICE_LOG_XMLNS, USER_ID, '1234', '')
     self.post_xml(devicelog_xml, self.domain)
     repeat_records = RepeatRecord.all(domain=self.domain)
     for repeat_record in repeat_records:
         self.assertNotEqual(repeat_record.payload_id, '1234')
Ejemplo n.º 38
0
 def tearDownClass(cls):
     RepeatRecord.bulk_delete(cls.records)
     super(TestOtherDBAccessors, cls).tearDownClass()
Ejemplo n.º 39
0
 def test_skip_device_logs(self):
     devicelog_xml = XFORM_XML_TEMPLATE.format(DEVICE_LOG_XMLNS, USER_ID, '1234', '')
     self.post_xml(devicelog_xml, self.domain)
     repeat_records = RepeatRecord.all(domain=self.domain)
     for repeat_record in repeat_records:
         self.assertNotEqual(repeat_record.payload_id, '1234')
Ejemplo n.º 40
0
 def repeat_records(cls, domain_name):
     # Enqueued repeat records have next_check set 48 hours in the future.
     later = datetime.utcnow() + timedelta(hours=48 + 1)
     return RepeatRecord.all(domain=domain_name, due_before=later)
Ejemplo n.º 41
0
    def test_vaccination_payload(self, payload_doc_mock, connection_settings_mock):
        connection_settings_mock.return_value = ConnectionSettings(password="******")

        case_id = uuid.uuid4().hex
        case = CommCareCase(domain=self.domain, type='cowin_api_data', case_id=case_id,
                            server_modified_on=datetime.datetime.utcnow())
        payload_doc_mock.return_value = case

        repeater = BeneficiaryVaccinationRepeater()
        generator = BeneficiaryVaccinationPayloadGenerator(repeater)
        repeat_record = RepeatRecord()

        self.assertEqual(repeater.get_headers(repeat_record)['X-Api-Key'], "my-secure-api-key")

        # 1st dose
        case.case_json = {
            'beneficiary_reference_id': '1234567890123',
            'center_id': "1234",
            'vaccine': "COVISHIELD",
            'vaccine_batch': '123456',
            'dose': '1',
            'dose1_date': "2020-11-29",
            'vaccinator_name': 'Neelima',
        }

        payload = generator.get_payload(repeat_record=None, cowin_api_data_vaccination_case=case)
        self.assertDictEqual(
            json.loads(payload),
            {
                "beneficiary_reference_id": "1234567890123",
                "center_id": 1234,
                "vaccine": "COVISHIELD",
                "vaccine_batch": "123456",
                "dose": 1,
                "dose1_date": "29-11-2020",
                "vaccinator_name": "Neelima"
            }
        )

        # 2nd dose
        case.case_json = {
            'beneficiary_reference_id': '1234567890123',
            'center_id': "1234",
            'vaccine': "COVISHIELD",
            'vaccine_batch': '123456',
            'dose': '2',
            'dose2_date': "2020-12-29",
            'vaccinator_name': 'Sumanthra',
        }

        payload = generator.get_payload(repeat_record=None, cowin_api_data_vaccination_case=case)
        self.assertDictEqual(
            json.loads(payload),
            {
                "beneficiary_reference_id": "1234567890123",
                "center_id": 1234,
                "vaccine": "COVISHIELD",
                "vaccine_batch": "123456",
                "dose": 2,
                "dose2_date": "29-12-2020",
                "vaccinator_name": "Sumanthra"
            }
        )