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, ) 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, ) self.form_repeater.save() self.log = [] with patch('corehq.motech.repeaters.models.simple_post', 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 test_get_list(self): # Add a form repeater and check that it comes back form_repeater = FormRepeater(domain=self.domain.name, url='http://example.com/forwarding/form') form_repeater.save() self.addCleanup(form_repeater.delete) backend_id = form_repeater._id response = self._assert_auth_get_resource(self.list_endpoint) self.assertEqual(response.status_code, 200) api_repeaters = json.loads(response.content)['objects'] self.assertEqual(len(api_repeaters), 1) self.assertEqual(api_repeaters[0]['id'], backend_id) self.assertEqual(api_repeaters[0]['url'], form_repeater.url) self.assertEqual(api_repeaters[0]['domain'], form_repeater.domain) self.assertEqual(api_repeaters[0]['type'], 'FormRepeater') # Add a case repeater and check that both come back case_repeater = CaseRepeater(domain=self.domain.name, url='http://example.com/forwarding/case') case_repeater.save() self.addCleanup(case_repeater.delete) backend_id = case_repeater._id response = self._assert_auth_get_resource(self.list_endpoint) self.assertEqual(response.status_code, 200) api_repeaters = json.loads(response.content)['objects'] self.assertEqual(len(api_repeaters), 2) api_case_repeater = [r for r in api_repeaters if r['type'] == 'CaseRepeater'][0] self.assertEqual(api_case_repeater['id'], case_repeater._id) self.assertEqual(api_case_repeater['url'], case_repeater.url) self.assertEqual(api_case_repeater['domain'], case_repeater.domain)
def test_clone_repeaters(self): from corehq.motech.repeaters.models import Repeater from corehq.motech.repeaters.models import CaseRepeater from corehq.motech.repeaters.models import FormRepeater self.assertEqual(0, len(Repeater.by_domain(self.new_domain))) case_repeater = CaseRepeater( domain=self.old_domain, url='case-repeater-url', ) case_repeater.save() self.addCleanup(case_repeater.delete) form_repeater = FormRepeater( domain=self.old_domain, url='form-repeater-url', ) form_repeater.save() self.addCleanup(form_repeater.delete) self.make_clone(include=['repeaters']) cloned_repeaters = Repeater.by_domain(self.new_domain) self.assertEqual(2, len(cloned_repeaters)) self.assertEqual({'CaseRepeater', 'FormRepeater'}, {repeater.doc_type for repeater in cloned_repeaters})
def setUpClass(cls): super(TestRepeatersDBAccessors, cls).setUpClass() repeater = CaseRepeater(domain=cls.domain, ) cls.repeaters = [repeater] for repeater in cls.repeaters: repeater.save()
def setUpClass(cls): cls.domain_1 = 'caserepeater-migration' cls.domain_2 = 'migration-caserepeater' cls.date = datetime.utcnow().strftime('%Y-%m-%dT%H-%M-%S') cls.conn = ConnectionSettings(domain=cls.domain_1, url='http://url.com') cls.conn.save() cls.couch_repeater_1 = CaseRepeater( domain=cls.domain_1, connection_settings_id=cls.conn.id, format='case_json', ) cls.couch_repeater_2 = CaseRepeater( domain=cls.domain_2, connection_settings_id=cls.conn.id, format='case_json', ) cls.couch_repeater_3 = CaseRepeater( domain=cls.domain_1, connection_settings_id=cls.conn.id, format='case_json', ) cls.repeaters = [ cls.couch_repeater_1, cls.couch_repeater_2, cls.couch_repeater_3 ] for repeater in cls.repeaters: repeater.save(sync_to_sql=False) return super(TestMigrationCommand, cls).setUpClass()
def setUp(self): super().setUp() self.repeater = CaseRepeater( domain=self.domain, url="case-repeater-url", ) self.repeater.save()
def setUp(self): super().setUp() self.repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain)
def test_repeaters_are_synced_to_couch(self): for sql_repeater in self.get_sql_objects(SQLCaseRepeater): sql_repeater.save() couch_repeater_dict = CaseRepeater.get_db().get( sql_repeater.repeater_id) self.assertIsNotNone(couch_repeater_dict) couch_repeater = CaseRepeater.wrap(couch_repeater_dict) self.addCleanup(couch_repeater.delete) self._assert_same_repeater_objects(sql_repeater, couch_repeater)
def setUpClass(cls): super(TestRepeatersDBAccessors, cls).setUpClass() repeater = CaseRepeater( domain=cls.domain, ) cls.repeaters = [ repeater ] for repeater in cls.repeaters: repeater.save()
def setUp(self): super(RepeaterFailureTest, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name)
def setUp(self): super(TestRepeaterFormat, self).setUp() self.post_xml(self.xform_xml, self.domain) self.repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', format='new_format', ) self.repeater.save()
def setUp(self): super().setUp() self.connx = ConnectionSettings.objects.create( domain=self.domain, url="case-repeater-url", ) self.repeater = CaseRepeater( domain=self.domain, connection_settings_id=self.connx.id, ) self.repeater.save()
def setUp(self): super().setUp() self.connx = ConnectionSettings.objects.create( domain=self.domain, url='case-repeater-url', ) self.repeater = CaseRepeater( domain=self.domain, connection_settings_id=self.connx.id, ) self.repeater.save() self.post_xml(self.xform_xml, self.domain)
def setUp(self): super(TestRepeaterDeleted, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) self.repeat_record = self.repeater.register( CaseAccessors(self.domain).get_case(CASE_ID))
class RepeaterFailureTest(BaseRepeaterTest): domain = 'repeat-fail' def setUp(self): super().setUp() # Create the case before creating the repeater, so that the # repeater doesn't fire for the case creation. Each test # registers this case, and the repeater will fire then. 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='case_json', ) self.repeater.save() def tearDown(self): self.repeater.delete() self.connx.delete() FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain) delete_all_repeat_records() super().tearDown() def test_get_payload_exception(self): repeat_record = self.repeater.register( CommCareCase.objects.get_case(CASE_ID, self.domain)) with self.assertRaises(Exception): with patch.object(CaseRepeater, 'get_payload', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEqual(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) def test_failure(self): case = CommCareCase.objects.get_case(CASE_ID, self.domain) 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 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)
class TestRepeaterPause(BaseRepeaterTest): domain = 'rep-pause' def setUp(self): super().setUp() self.connx = ConnectionSettings.objects.create( domain=self.domain, url='case-repeater-url', ) self.repeater = CaseRepeater( domain=self.domain, connection_settings_id=self.connx.id, ) self.repeater.save() self.post_xml(self.xform_xml, self.domain) self.repeater = reloaded(self.repeater) def tearDown(self): self.repeater.delete() self.connx.delete() FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain) delete_all_repeat_records() super(TestRepeaterPause, self).tearDown() @run_with_all_backends 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_obj).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)
def test_get_format_by_deprecated_name(self): self.assertIsInstance( CaseRepeater( domain=self.domain, url='case-repeater-url', format='new_format_alias', ).generator, self.new_generator)
def test_save_with_no_connection_settings(self): repeater = CaseRepeater( domain='test-domain', url='https://example.com/create-case/', format='case_json', white_listed_case_types=['test_case_type'], ) self.addCleanup(repeater.delete) repeater.save() num_case_repeaters = SQLCaseRepeater.objects.filter( repeater_id=repeater._id).count() self.assertEqual(num_case_repeaters, 1) num_repeaters = SQLRepeater.objects.filter( repeater_id=repeater._id).count() self.assertEqual(num_repeaters, 1)
def setUpClass(cls): domain = 'caserepeater-migration' cls.conn = ConnectionSettings(domain=domain, url='http://url.com') cls.conn.save() cls.couch_repeater_obj = CaseRepeater( _id='id_1', domain=domain, connection_settings_id=cls.conn.id, white_listed_case_types=['white_case', 'black_case'], black_listed_users=['user1'], paused=False, format='case_json', ) cls.sql_repeater_obj = SQLCaseRepeater( domain=domain, connection_settings=cls.conn, white_listed_case_types=['white_case', 'black_case'], black_listed_users=['user1'], is_paused=False, format='case_json', repeater_id='id_1', ) cls.incorrect_sql_repeater_obj = SQLCaseRepeater( domain=domain, connection_settings=cls.conn, white_listed_case_types=['black_case'], black_listed_users=['user2'], is_paused=True, format='case_json', repeater_id='id_1', ) super().setUpClass()
def setUp(self): super(RepeaterTest, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.case_repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', ) self.case_repeater.save() self.form_repeater = FormRepeater( domain=self.domain, url='form-repeater-url', ) self.form_repeater.save() self.log = [] self.post_xml(self.xform_xml, self.domain)
def allowed_to_forward(self, payload): """ Forward the payload if ... * it did not come from OpenMRS, and * CaseRepeater says it's OK for the case types and users of any of the payload's cases, and * this repeater forwards to the right OpenMRS server for any of the payload's cases. :param payload: An XFormInstance (not a case) """ if payload.xmlns == XMLNS_OPENMRS: # payload came from OpenMRS. Don't send it back. return False case_blocks = extract_case_blocks(payload) case_ids = [case_block['@case_id'] for case_block in case_blocks] cases = CaseAccessors(payload.domain).get_cases(case_ids, ordered=True) if not any(CaseRepeater.allowed_to_forward(self, case) for case in cases): # If none of the case updates in the payload are allowed to # be forwarded, drop it. return False repeaters = [repeater for case in cases for repeater in get_case_location_ancestor_repeaters(case)] if repeaters and self not in repeaters: # This repeater points to the wrong OpenMRS server for this # payload. Let the right repeater handle it. return False return True
def setUpClass(cls): super().setUpClass() cls.repeater = CaseRepeater( domain=cls.domain, url="case-repeater-url", ) cls.repeater.save()
def setUp(self): super().setUp() # Create the case before creating the repeater, so that the # repeater doesn't fire for the case creation. Each test # registers this case, and the repeater will fire then. 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='case_json', ) self.repeater.save()
class TestRepeaterPause(BaseRepeaterTest): def setUp(self): super(TestRepeaterPause, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) self.repeat_record = self.repeater.register( CaseAccessors(self.domain).get_case(CASE_ID)) @run_with_all_backends @flag_enabled('ENABLE_REPEATER_EDIT_AND_PAUSE') 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) def tearDown(self): self.domain.delete() self.repeater.delete() delete_all_repeat_records() super(TestRepeaterPause, self).tearDown()
class RepeaterFailureTest(BaseRepeaterTest): domain = 'repeat-fail' def setUp(self): super().setUp() self.connx = ConnectionSettings.objects.create( domain=self.domain, url='case-repeater-url', ) self.repeater = CaseRepeater( domain=self.domain, connection_settings_id=self.connx.id, ) self.repeater.save() self.post_xml(self.xform_xml, self.domain) def tearDown(self): self.repeater.delete() self.connx.delete() FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain) delete_all_repeat_records() super().tearDown() @run_with_all_backends def test_get_payload_exception(self): repeat_record = self.repeater.register( CaseAccessors(self.domain).get_case(CASE_ID)) with self.assertRaises(Exception): with patch.object(CaseRepeater, 'get_payload', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEqual(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) @run_with_all_backends def test_failure(self): repeat_record = self.repeater.register( CaseAccessors(self.domain).get_case(CASE_ID)) with patch('corehq.motech.repeaters.models.simple_post', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEqual(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) @run_with_all_backends def test_success(self): repeat_record = self.repeater.register( CaseAccessors(self.domain).get_case(CASE_ID)) repeat_record = RepeatRecord.get(repeat_record.record_id) # Should be marked as successful after a successful run with patch('corehq.motech.repeaters.models.simple_post' ) as mock_simple_post: mock_simple_post.return_value.status_code = 200 repeat_record.fire() self.assertTrue(repeat_record.succeeded)
def setUp(self): super(RepeaterTest, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.case_repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', ) self.case_repeater.save() self.form_repeater = FormRepeater( domain=self.domain, url='form-repeater-url', ) self.form_repeater.save() self.log = [] with patch('corehq.motech.repeaters.models.simple_post') as mock_fire: self.post_xml(self.xform_xml, self.domain) self.initial_fire_call_count = mock_fire.call_count
def setUpClass(cls): super(TestRepeatersDBAccessors, cls).setUpClass() cls.conn = ConnectionSettings(domain=cls.domain_1, url='http://url.com') cls.conn.save() repeater_1 = CaseRepeater( domain=cls.domain_1, format='case_json', connection_settings_id=cls.conn.id, ) repeater_2 = CaseRepeater( domain=cls.domain_2, connection_settings_id=cls.conn.id, format='case_json', ) cls.repeaters = [repeater_1, repeater_2] for repeater in cls.repeaters: repeater.save()
def setUpClass(cls): super(CaseRepeaterTest, cls).setUpClass() cls.domain_name = "test-domain" cls.domain = create_domain(cls.domain_name) cls.repeater = CaseRepeater( domain=cls.domain_name, url="case-repeater-url", ) cls.repeater.save()
def setUp(self): super(TestRepeaterDeleted, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name)
class TestRepeaterPause(BaseRepeaterTest): def setUp(self): super(TestRepeaterPause, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) @run_with_all_backends 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) def tearDown(self): self.domain.delete() self.repeater.delete() delete_all_repeat_records() super(TestRepeaterPause, self).tearDown()
def setUp(self): super(TestRepeaterFormat, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.post_xml(self.xform_xml, self.domain) self.repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', format='new_format', ) self.repeater.save()
def setUp(self): super(TestRepeaterDeleted, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) self.repeat_record = self.repeater.register(CaseAccessors(self.domain).get_case(CASE_ID))
def test_clone_repeaters(self): from corehq.motech.repeaters.models import Repeater from corehq.motech.repeaters.models import CaseRepeater from corehq.motech.repeaters.models import FormRepeater from custom.enikshay.integrations.nikshay.repeaters import NikshayRegisterPatientRepeater self.assertEqual(0, len(Repeater.by_domain(self.new_domain))) self.assertEqual( 0, len(NikshayRegisterPatientRepeater.by_domain(self.new_domain))) case_repeater = CaseRepeater( domain=self.old_domain, url='case-repeater-url', ) case_repeater.save() self.addCleanup(case_repeater.delete) form_repeater = FormRepeater( domain=self.old_domain, url='form-repeater-url', ) form_repeater.save() self.addCleanup(form_repeater.delete) custom_repeater = NikshayRegisterPatientRepeater( domain=self.old_domain, url='99dots') custom_repeater.save() self.addCleanup(custom_repeater.delete) self.make_clone(include=['repeaters']) cloned_repeaters = Repeater.by_domain(self.new_domain) self.assertEqual(3, len(cloned_repeaters)) self.assertEqual( {'CaseRepeater', 'FormRepeater', 'NikshayRegisterPatientRepeater'}, {repeater.doc_type for repeater in cloned_repeaters}) # test cache clearing cloned_niksay_repeaters = NikshayRegisterPatientRepeater.by_domain( self.new_domain) self.assertEqual(1, len(cloned_niksay_repeaters))
class RepeaterFailureTest(BaseRepeaterTest): def setUp(self): super(RepeaterFailureTest, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) def tearDown(self): self.domain.delete() self.repeater.delete() delete_all_repeat_records() super(RepeaterFailureTest, self).tearDown() @run_with_all_backends def test_get_payload_exception(self): repeat_record = self.repeater.register( CaseAccessors(self.domain_name).get_case(CASE_ID)) with self.assertRaises(Exception): with patch.object(CaseRepeater, 'get_payload', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEquals(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) @run_with_all_backends def test_failure(self): repeat_record = self.repeater.register( CaseAccessors(self.domain_name).get_case(CASE_ID)) with patch('corehq.motech.repeaters.models.simple_post', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEquals(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) # Should be marked as successful after a successful run with patch('corehq.motech.repeaters.models.simple_post' ) as mock_simple_post: mock_simple_post.return_value.status_code = 200 repeat_record.fire() self.assertTrue(repeat_record.succeeded)
class RepeaterFailureTest(BaseRepeaterTest): def setUp(self): super(RepeaterFailureTest, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) def tearDown(self): self.domain.delete() self.repeater.delete() delete_all_repeat_records() super(RepeaterFailureTest, self).tearDown() @run_with_all_backends def test_get_payload_exception(self): repeat_record = self.repeater.register(CaseAccessors(self.domain_name).get_case(CASE_ID)) with self.assertRaises(Exception): with patch.object(CaseRepeater, 'get_payload', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEquals(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) @run_with_all_backends def test_failure(self): repeat_record = self.repeater.register(CaseAccessors(self.domain_name).get_case(CASE_ID)) with patch('corehq.motech.repeaters.models.simple_post', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEquals(repeat_record.failure_reason, 'Boom!') self.assertFalse(repeat_record.succeeded) # Should be marked as successful after a successful run with patch('corehq.motech.repeaters.models.simple_post') as mock_simple_post: mock_simple_post.return_value.status_code = 200 repeat_record.fire() self.assertTrue(repeat_record.succeeded)
class RepeaterTest(BaseRepeaterTest): def setUp(self): super(RepeaterTest, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.case_repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', ) self.case_repeater.save() self.form_repeater = FormRepeater( domain=self.domain, url='form-repeater-url', ) self.form_repeater.save() self.log = [] with patch('corehq.motech.repeaters.models.simple_post') 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.form_repeater.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) @run_with_all_backends 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') @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends def test_repeater_successful_send(self): repeat_records = self.repeat_records() 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 = 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) @run_with_all_backends 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_post') as mock_fire: check_repeaters() self.assertEqual(mock_fire.call_count, 0) @run_with_all_backends 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_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 self.repeat_records(): 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 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_post') 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) @run_with_all_backends def test_process_repeat_record_locking(self): self.assertEqual(len(self.repeat_records()), 2) with patch('corehq.motech.repeaters.tasks.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.process_repeat_record') as mock_process: check_repeaters() self.assertEqual(mock_process.delay.call_count, 2) @run_with_all_backends def test_automatic_cancel_repeat_record(self): repeat_record = self.case_repeater.register(CaseAccessors(self.domain).get_case(CASE_ID)) self.assertEqual(1, repeat_record.overall_tries) with patch('corehq.motech.repeaters.models.simple_post', 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)
class RepeaterTest(BaseRepeaterTest): def setUp(self): super(RepeaterTest, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.case_repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', ) self.case_repeater.save() self.form_repeater = FormRepeater( domain=self.domain, url='form-repeater-url', ) self.form_repeater.save() self.log = [] self.post_xml(self.xform_xml, self.domain) def tearDown(self): self.case_repeater.delete() self.form_repeater.delete() FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain) delete_all_repeat_records() super(RepeaterTest, self).tearDown() @run_with_all_backends 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') @run_with_all_backends 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) @run_with_all_backends def test_repeater_failed_sends(self): """ This tests records that fail are requeued later """ def now(): return datetime.utcnow() repeat_records = RepeatRecord.all(domain=self.domain, due_before=now()) 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) next_check_time = now() + timedelta(minutes=60) 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) @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends 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) @run_with_all_backends def test_automatic_cancel_repeat_record(self): repeat_record = self.case_repeater.register( CaseAccessors(self.domain).get_case(CASE_ID)) repeat_record.overall_tries = 1 with patch('corehq.motech.repeaters.models.simple_post', side_effect=Exception('Boom!')): repeat_record.fire() self.assertEqual(2, repeat_record.overall_tries) with patch('corehq.motech.repeaters.models.simple_post', side_effect=Exception('Boom!')): 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)
class TestRepeaterFormat(BaseRepeaterTest): @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(TestRepeaterFormat, self).setUp() self.domain = "test-domain" create_domain(self.domain) self.post_xml(self.xform_xml, self.domain) self.repeater = CaseRepeater( domain=self.domain, url='case-repeater-url', format='new_format', ) self.repeater.save() def tearDown(self): self.repeater.delete() FormProcessorTestUtils.delete_all_cases_forms_ledgers(self.domain) delete_all_repeat_records() super(TestRepeaterFormat, self).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) @run_with_all_backends def test_new_format_payload(self): repeat_record = self.repeater.register(CaseAccessors(self.domain).get_case(CASE_ID)) with patch('corehq.motech.repeaters.models.simple_post') as mock_post: mock_post.return_value.status_code = 200 repeat_record.fire() headers = self.repeater.get_headers(repeat_record) mock_post.assert_called_with( self.payload, self.repeater.url, headers=headers, timeout=POST_TIMEOUT, auth=self.repeater.get_auth(), verify=self.repeater.verify, ) def test_get_format_by_deprecated_name(self): self.assertIsInstance(CaseRepeater( domain=self.domain, url='case-repeater-url', format='new_format_alias', ).generator, self.new_generator)
class TestRepeaterDeleted(BaseRepeaterTest): def setUp(self): super(TestRepeaterDeleted, self).setUp() self.domain_name = "test-domain" self.domain = create_domain(self.domain_name) self.repeater = CaseRepeater( domain=self.domain_name, url='case-repeater-url', ) self.repeater.save() self.post_xml(self.xform_xml, self.domain_name) def tearDown(self): self.domain.delete() self.repeater.delete() delete_all_repeat_records() super(TestRepeaterDeleted, self).tearDown() @run_with_all_backends def test_trigger_when_deleted(self): self.repeater.retire() with patch.object(RepeatRecord, 'fire') as mock_fire: self.repeat_record = self.repeater.register(CaseAccessors(self.domain).get_case(CASE_ID)) process_repeat_record(self.repeat_record) self.assertEqual(mock_fire.call_count, 0) self.assertEqual(self.repeat_record.doc_type, "RepeatRecord-Deleted") @run_with_all_backends def test_paused_then_deleted(self): self.repeater.pause() self.repeater.retire() with patch.object(RepeatRecord, 'fire') as mock_fire: self.repeat_record = self.repeater.register(CaseAccessors(self.domain).get_case(CASE_ID)) process_repeat_record(self.repeat_record) self.assertEqual(mock_fire.call_count, 0) self.assertEqual(self.repeat_record.doc_type, "RepeatRecord-Deleted")