def test_sync_from_remote(self): # no existing contact with same identity remote = TembaContact.create(uuid="C-002", name="Frank", blocked=False) self.assertEqual(sync_from_remote(self.unicef, self.syncer, remote), SyncOutcome.created) Contact.objects.get(org=self.unicef, uuid="C-002", name="Frank", backend=self.rapidpro_backend, is_active=True) self.assertIsNone(Contact.objects.filter(org=self.unicef, uuid="C-002", name="Frank", backend=self.floip_backend, is_active=True).first()) remote = TembaContact.create(uuid="CF-002", name="Frank", blocked=False) self.assertEqual(sync_from_remote(self.unicef, self.syncer2, remote), SyncOutcome.created) Contact.objects.get(org=self.unicef, uuid="CF-002", name="Frank", backend=self.floip_backend, is_active=True) # no significant change remote = TembaContact.create(uuid="C-002", name="Frank", blocked=False) self.assertEqual(sync_from_remote(self.unicef, self.syncer, remote), SyncOutcome.ignored) Contact.objects.get(org=self.unicef, uuid="C-002", name="Frank", backend=self.rapidpro_backend, is_active=True) # significant change (name) remote = TembaContact.create(uuid="C-002", name="Franky", blocked=False) self.assertEqual(sync_from_remote(self.unicef, self.syncer, remote), SyncOutcome.updated) Contact.objects.get(org=self.unicef, uuid="C-002", name="Franky", backend=self.rapidpro_backend, is_active=True) # change to something we don't want locally remote = TembaContact.create(uuid="C-002", name="Franky", blocked=True) self.assertEqual(sync_from_remote(self.unicef, self.syncer, remote), SyncOutcome.deleted) Contact.objects.get(org=self.unicef, uuid="C-002", name="Franky", backend=self.rapidpro_backend, is_active=False)
def test_local_kwargs(self): remote = TembaContact.create(uuid="C-002", name="Frank", blocked=False) kwargs = self.syncer.local_kwargs(self.unicef, remote) self.assertEqual(kwargs, {'org': self.unicef, 'uuid': "C-002", 'name': "Frank", 'backend': self.rapidpro_backend}) remote = TembaContact.create(uuid="CF-002", name="Frank", blocked=False) kwargs = self.syncer2.local_kwargs(self.unicef, remote) self.assertEqual(kwargs, {'org': self.unicef, 'uuid': "CF-002", 'name': "Frank", 'backend': self.floip_backend}) remote = TembaContact.create(uuid="C-002", name="Frank", blocked=True) self.assertIsNone(self.syncer.local_kwargs(self.unicef, remote)) remote = TembaContact.create(uuid="CF-002", name="Frank", blocked=True) self.assertIsNone(self.syncer2.local_kwargs(self.unicef, remote))
def make_contact(phone_number='5551234567', groups=None): if groups is None: groups = [] return Contact.create(urns=[f'tel:+1{phone_number}'], groups=groups, modified_on=make_aware(datetime(2018, 1, 2, 3, 4, 5)))
def test_local_kwargs(self): kwargs = self.syncer.local_kwargs( self.unicef, TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={"age": "34"}, stopped=False, blocked=False, ), ) self.assertEqual( kwargs, { "org": self.unicef, "uuid": "C-001", "name": "Bob McFlow", "language": "eng", "is_blocked": False, "is_stopped": False, "is_stub": False, "fields": {"age": "34"}, "__data__groups": [("G-001", "Customers")], }, )
def make_contact(phone_number='5551234567', groups=None, uuid="blarg"): if groups is None: groups = [] return Contact.create(uuid=uuid, urns=[make_phone_number_urn(phone_number)], groups=groups, modified_on=make_aware(datetime(2018, 1, 2, 3, 4, 5)))
def test_wont_add_contact_to_group_if_they_have_blocked_or_stopped_us( self): contact = Contact.create(groups=["FAKE ARG GROUP"], fields={"fake_field": "blah"}, blocked=True) client, _ = make_client_mocks("get_contacts", contact) mock_query(client, "get_groups", "FAKE BOOP GROUP") campaign = FollowupCampaign("Boop Group", "date_of_boop") with freeze_time("2018-01-02"): campaign.add_contact(client, "Narf Jones", "5551234567", "en") client.update_contact.assert_not_called()
def get_contacts(self, uuids=None, urns=None, groups=None, after=None, before=None, pager=None): return [ TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=["000-002"], fields=dict(state="Lagos", lga="Oyo", gender="Female", born="1990"), language="eng", modified_on=timezone.now(), ) ]
def test_sync_local_to_set(self): Contact.objects.all().delete() # start with no contacts... remote_set = [ TembaContact.create(uuid="C-001", name="Anne", blocked=False), TembaContact.create(uuid="C-002", name="Bob", blocked=False), TembaContact.create(uuid="C-003", name="Colin", blocked=False), TembaContact.create(uuid="C-004", name="Donald", blocked=True) ] self.assertEqual(sync_local_to_set(self.unicef, self.syncer, remote_set), (3, 0, 0, 1)) self.assertEqual(Contact.objects.count(), 3) remote_set = [ # first contact removed TembaContact.create(uuid="C-002", name="Bob", blocked=False), # no change TembaContact.create(uuid="C-003", name="Colm", blocked=False), # changed name TembaContact.create(uuid="C-005", name="Edward", blocked=False) # new contact ] self.assertEqual(sync_local_to_set(self.unicef, self.syncer, remote_set), (1, 1, 1, 1)) self.assertEqual(Contact.objects.count(), 4) Contact.objects.get(org=self.unicef, uuid="C-001", name="Anne", is_active=False) Contact.objects.get(org=self.unicef, uuid="C-002", name="Bob", is_active=True) Contact.objects.get(org=self.unicef, uuid="C-003", name="Colm", is_active=True) Contact.objects.get(org=self.unicef, uuid="C-005", name="Edward", is_active=True) remote_set = [ # first contact removed TembaContact.create(uuid="CF-002", name="Bob", blocked=False), # no change TembaContact.create(uuid="CF-003", name="Colm", blocked=False), # changed name TembaContact.create(uuid="CF-005", name="Edward", blocked=False) # new contact ] self.assertEqual(sync_local_to_set(self.unicef, self.syncer2, remote_set), (3, 0, 0, 0)) self.assertEqual(Contact.objects.count(), 7) Contact.objects.get(org=self.unicef, uuid="CF-002", name="Bob", backend=self.floip_backend, is_active=True) Contact.objects.get(org=self.unicef, uuid="CF-003", name="Colm", backend=self.floip_backend, is_active=True) Contact.objects.get(org=self.unicef, uuid="CF-005", name="Edward", backend=self.floip_backend, is_active=True)
def test_add_contact_works(self): contact = Contact.create(groups=["FAKE ARG GROUP"], fields={'fake_field': 'blah'}) client, _ = make_client_mocks('get_contacts', contact) mock_query(client, 'get_groups', "FAKE BOOP GROUP") campaign = FollowupCampaign('Boop Group', 'date_of_boop') with freeze_time('2018-01-02'): campaign.add_contact(client, "Narf Jones", "5551234567") client.update_contact.assert_called_once_with( contact, groups=["FAKE ARG GROUP", "FAKE BOOP GROUP"], fields={ 'fake_field': 'blah', 'date_of_boop': '2018-01-02T00:00:00.000000Z' })
def test_add_contact_works(self): contact = Contact.create(groups=["FAKE ARG GROUP"], fields={"fake_field": "blah"}) client, _ = make_client_mocks("get_contacts", contact) mock_query(client, "get_groups", "FAKE BOOP GROUP") campaign = FollowupCampaign("Boop Group", "date_of_boop") with freeze_time("2018-01-02"): campaign.add_contact(client, "Narf Jones", "5551234567", "en") client.update_contact.assert_called_once_with( contact, groups=["FAKE ARG GROUP", "FAKE BOOP GROUP"], fields={ "fake_field": "blah", "date_of_boop": "2018-01-02T00:00:00.000000Z" }, )
def test_local_kwargs(self): kwargs = self.syncer.local_kwargs(self.unicef, TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={'age': "34"}, failed=False, blocked=False )) self.assertEqual(kwargs, { 'org': self.unicef, 'uuid': "C-001", 'name': "Bob McFlow", 'language': "eng", 'is_stub': False, 'fields': {'age': "34"}, '__data__groups': [("G-001", "Customers")], })
def get_contacts(self, uuids=None, urns=None, groups=None, after=None, before=None, pager=None): return [ TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=["000-002"], fields=dict(state="Lagos", lga="Oyo", gender="Female", born="1990"), language="eng", modified_on=timezone.now(), ) ]
def test_local_kwargs(self): kwargs = self.syncer.local_kwargs(self.unicef, TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={'age': "34"}, stopped=False, blocked=False )) self.assertEqual(kwargs, { 'org': self.unicef, 'uuid': "C-001", 'name': "Bob McFlow", 'language': "eng", 'is_blocked': False, 'is_stopped': False, 'is_stub': False, 'fields': {'age': "34"}, '__data__groups': [("G-001", "Customers")], })
def test_pull_contacts(self, mock_get_contacts): Contact.objects.all().delete() # empty fetches mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery([]), # second call to get deleted contacts MockClientQuery([]) ] with self.assertNumQueries(0): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 0)) # fecthed contact not in configured group get ignored mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={'age': "34"}, failed=False, blocked=False ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': "67"}, failed=False, blocked=False ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={'age': "35"}, failed=True, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(4): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 3)) mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "34"}, failed=False, blocked=False ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': "67"}, failed=False, blocked=False ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={'age': "35"}, failed=True, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(8): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (1, 0, 0, 2)) Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "34"}, failed=False, blocked=False ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "67"}, failed=False, blocked=False ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={'age': "35"}, failed=True, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(9): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (2, 0, 0, 1)) Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts # all included in the reporters MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "34"}, failed=False, blocked=False ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "67"}, failed=False, blocked=False ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "35"}, failed=True, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) contact_jan = Contact.objects.filter(uuid='C-001').first() self.assertFalse(contact_jan.born) self.assertFalse(contact_jan.state) mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery( [ TembaContact.create(uuid='C-001', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': '2014-01-02T03:04:05.000000Z', 'state':'Lagos', 'lga': 'Oyo', 'occupation': 'Student', 'born': '1990', 'gender': 'Male'}, language='eng'), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={'age': "67", "born": "1992"}, failed=False, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(8): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 2, 0, 0)) contact_jan = Contact.objects.filter(uuid='C-001').first() self.assertTrue(contact_jan.born) self.assertEqual(contact_jan.born, 1990) self.assertTrue(contact_jan.state) self.assertEqual(contact_jan.state, 'R-LAGOS') self.assertTrue(Contact.objects.filter(uuid='C-002', is_active=True)) mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery([] ), # second call to get deleted contacts MockClientQuery( [ TembaContact.create( uuid="C-002", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(2): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 1, 0)) self.assertFalse(Contact.objects.filter(uuid='C-002', is_active=True))
def test_local_kwargs(self): temba_contact = TembaContact.create(uuid='C-006', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='Musicians'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': None, 'state': None, 'lga': None, 'occupation': None, 'born': None, 'gender': None}, language='eng') self.assertIsNone(self.syncer.local_kwargs(self.nigeria, temba_contact)) temba_contact = TembaContact.create(uuid='C-006', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': None, 'state': None, 'lga': None, 'occupation': None, 'born': None, 'gender': None}, language='eng') self.assertEqual(self.syncer.local_kwargs(self.nigeria, temba_contact), {'org': self.nigeria, 'uuid': 'C-006', 'gender': '', 'born': 0, 'occupation': '', 'registered_on': None, 'state': '', 'district': ''}) temba_contact = TembaContact.create(uuid='C-007', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': '2014-01-02T03:04:05.000000Z', 'state': 'Kigali', 'lga': 'Oyo', 'occupation': 'Student', 'born': '1990', 'gender': 'Male'}, language='eng') self.assertEqual(self.syncer.local_kwargs(self.nigeria, temba_contact), {'org': self.nigeria, 'uuid': 'C-007', 'gender': 'M', 'born': 1990, 'occupation': 'Student', 'registered_on': json_date_to_datetime('2014-01-02T03:04:05.000'), 'state': '', 'district': ''}) temba_contact = TembaContact.create(uuid='C-008', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': '2014-01-02T03:04:05.000000Z', 'state':'Lagos', 'lga': 'Oyo', 'occupation': 'Student', 'born': '1990', 'gender': 'Male'}, language='eng') self.assertEqual(self.syncer.local_kwargs(self.nigeria, temba_contact), {'org': self.nigeria, 'uuid': 'C-008', 'gender': 'M', 'born': 1990, 'occupation': 'Student', 'registered_on': json_date_to_datetime('2014-01-02T03:04:05.000'), 'state': 'R-LAGOS', 'district': 'R-OYO'}) temba_contact = TembaContact.create(uuid='C-008', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': '2014-01-02T03:04:05.000000Z', 'state':'Lagos', 'lga': 'Oyo', 'occupation': 'Student', 'born': '-1', 'gender': 'Male'}, language='eng') self.assertEqual(self.syncer.local_kwargs(self.nigeria, temba_contact), {'org': self.nigeria, 'uuid': 'C-008', 'gender': 'M', 'born': 0, 'occupation': 'Student', 'registered_on': json_date_to_datetime('2014-01-02T03:04:05.000'), 'state': 'R-LAGOS', 'district': 'R-OYO'}) temba_contact = TembaContact.create(uuid='C-008', name="Jan", urns=['tel:123'], groups=[ObjectRef.create(uuid='G-001', name='ureporters'), ObjectRef.create(uuid='G-007', name='Actors')], fields={'registration_date': '2014-01-02T03:04:05.000000Z', 'state':'Lagos', 'lga': 'Oyo', 'occupation': 'Student', 'born': '2147483648', 'gender': 'Male'}, language='eng') self.assertEqual(self.syncer.local_kwargs(self.nigeria, temba_contact), {'org': self.nigeria, 'uuid': 'C-008', 'gender': 'M', 'born': 0, 'occupation': 'Student', 'registered_on': json_date_to_datetime('2014-01-02T03:04:05.000'), 'state': 'R-LAGOS', 'district': 'R-OYO'})
def get_contacts(self, uuids=None, urns=None, groups=None, after=None, before=None, pager=None): return [TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=['000-002'], fields=dict(state="Lagos", lga="Oyo", gender='Female', born="1990"), language='eng', modified_on=timezone.now())]
def test_update_required(self): # create stub contact local = Contact.get_or_create(self.unicef, "C-001", "Ann") # a stub contact should always be updated self.assertTrue( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=[], fields={}, language=None, blocked=False, stopped=False, modified_on=now(), ), {}, ) ) local.groups.add(self.reporters) local.language = "eng" local.is_stub = False local.fields = {"chat_name": "ann"} local.save() # no differences (besides null field value which is ignored) self.assertFalse( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=[ObjectRef.create(uuid="G-003", name="Reporters")], fields={"chat_name": "ann", "age": None}, language="eng", blocked=False, stopped=False, modified_on=now(), ), {}, ) ) # name change self.assertTrue( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Annie", urns=["tel:1234"], groups=[ObjectRef.create(uuid="G-003", name="Reporters")], fields={"chat_name": "ann"}, language="eng", blocked=False, stopped=False, modified_on=now(), ), {}, ) ) # group change self.assertTrue( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=[ObjectRef.create(uuid="G-002", name="Females")], fields={"chat_name": "ann"}, language="eng", blocked=False, stopped=False, modified_on=now(), ), {}, ) ) # field value change self.assertTrue( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=[ObjectRef.create(uuid="G-003", name="Reporters")], fields={"chat_name": "ann8111"}, language="eng", blocked=False, stopped=False, modified_on=now(), ), {}, ) ) # new field self.assertTrue( self.syncer.update_required( local, TembaContact.create( uuid="000-001", name="Ann", urns=["tel:1234"], groups=[ObjectRef.create(uuid="G-003", name="Reporters")], fields={"chat_name": "ann", "age": "35"}, language="eng", blocked=False, stopped=False, modified_on=now(), ), {}, ) )
def test_pull_contacts(self, mock_get_contacts): # start with nothing... Group.objects.all().delete() Field.objects.all().delete() Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={"age": "34"}, stopped=False, blocked=False, ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={"age": "67"}, stopped=False, blocked=False, ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={"age": "35"}, stopped=True, blocked=False, ) ], ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(16): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) bob = Contact.objects.get(uuid="C-001") jim = Contact.objects.get(uuid="C-002") ann = Contact.objects.get(uuid="C-003") self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, jim, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), set()) # stub contact groups will have been created too customers = Group.objects.get(org=self.unicef, uuid="G-001", name="Customers", is_active=False) spammers = Group.objects.get(org=self.unicef, uuid="G-002", name="Spammers", is_active=False) self.assertEqual(bob.name, "Bob McFlow") self.assertEqual(bob.language, "eng") self.assertEqual(set(bob.groups.all()), {customers}) self.assertEqual(bob.get_fields(), {"age": "34"}) mock_get_contacts.side_effect = [ # first call to get active contacts will just one updated contact MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlough", language="fre", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={"age": "35"}, stopped=True, blocked=False, ) ] ), # second call to get deleted contacts returns Jim MockClientQuery( [ TembaContact.create( uuid="C-002", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(13): self.assertEqual(self.backend.pull_contacts(self.unicef, None, None), (0, 1, 1, 0)) self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), {jim}) self.assertEqual(jim.groups.count(), 0) # de-activated contacts are removed from groups bob.refresh_from_db() self.assertEqual(bob.name, "Bob McFlough") self.assertEqual(bob.language, "fre") self.assertEqual(set(bob.groups.all()), {spammers}) self.assertEqual(bob.get_fields(), {"age": "35"}) mock_get_contacts.side_effect = [ # first call to get active contacts will return a contact with only a change to URNs.. which we don't track MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlough", language="fre", urns=["twitter:bobflow22"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={"age": "35"}, stopped=True, blocked=False, ) ] ), MockClientQuery([]), ] with self.assertNumQueries(3): self.assertEqual(self.backend.pull_contacts(self.unicef, None, None), (0, 0, 0, 1)) self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), {jim})
def test_contact_sync(self, mock_get_groups, mock_get_fields, mock_get_contacts): # start with no groups or fields Group.objects.all().delete() Field.objects.all().delete() fetch_size = 250 num_fetches = 4 num_groups = 50 num_fields = 50 names = ["Ann", "Bob", "Cat"] field_values = ["12345", None] groups_in = 5 # setup get_fields fields = [ TembaField.create(key="field_%d" % f, label="Field #%d" % f, value_type="text") for f in range(0, num_fields) ] mock_get_fields.return_value = MockClientQuery(fields) # sync fields start = time.time() self.assertEqual((num_fields, 0, 0, 0), self.backend.pull_fields(self.unicef)) print("Initial field sync: %f secs" % (time.time() - start)) # setup get_groups groups = [ TembaGroup.create(uuid="G0000000-0000-0000-0000-00000000%04d" % g, name="Group #%d" % g, count=0) for g in range(0, num_groups) ] mock_get_groups.return_value = MockClientQuery(groups) # sync groups start = time.time() self.assertEqual((num_groups, 0, 0, 0), self.backend.pull_groups(self.unicef)) print("Initial group sync: %f secs" % (time.time() - start)) # setup get_contacts to return multiple fetches of contacts active_fetches = [] for b in range(0, num_fetches): batch = [] for c in range(0, fetch_size): num = b * fetch_size + c batch.append( TembaContact.create( uuid="C0000000-0000-0000-0000-00000000%04d" % num, name=names[num % len(names)], language="eng", urns=["tel:+26096415%04d" % num], groups=[ ObjectRef.create(uuid="G0000000-0000-0000-0000-00000000%04d" % g, name="Group #%d" % g) for g in range(0, groups_in) ], fields={ "custom_field_%d" % f: field_values[f % len(field_values)] for f in range(0, num_fields) }, stopped=False, blocked=False, ) ) active_fetches.append(batch) mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] # no deleted contacts start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) print("Initial contact sync: %f secs" % (time.time() - start)) self.assertEqual((num_created, num_updated, num_deleted), (num_fetches * fetch_size, 0, 0)) # slowest_queries = sorted(connection.queries, key=lambda q: q['time'], reverse=True)[:10] # for q in slowest_queries: # print "%s -- %s" % (q['time'], q['sql']) # simulate a subsequent sync with no changes mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, 0, 0)) print("Contact sync with no changes: %f secs" % (time.time() - start)) # simulate an update of 1 field value for batch in active_fetches: for c in batch: c.fields["custom_field_1"] = "UPDATED" mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, num_fetches * fetch_size, 0)) print("Contact sync with 1 field value changes: %f secs" % (time.time() - start)) # simulate an update of 10 field values for batch in active_fetches: for c in batch: for f in (10, 11, 12, 13, 14, 15, 16, 17, 18, 19): c.fields["custom_field_%d" % f] = "UPDATED" mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, num_fetches * fetch_size, 0)) print("Contact sync with 10 field value changes: %f secs" % (time.time() - start))
def test_update_required(self): # create stub contact local = Contact.get_or_create(self.unicef, 'C-001', "Ann") # a stub contact should always be updated self.assertTrue(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=[], fields={}, language=None, modified_on=now() ), {})) local.groups.add(self.reporters) local.language = "eng" local.is_stub = False local.fields = {'chat_name': "ann"} local.save() # no differences (besides null field value which is ignored) self.assertFalse(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=[ObjectRef.create(uuid='G-003', name="Reporters")], fields={'chat_name': "ann", 'age': None}, language='eng', modified_on=now() ), {})) # name change self.assertTrue(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Annie", urns=['tel:1234'], groups=[ObjectRef.create(uuid='G-003', name="Reporters")], fields={'chat_name': "ann"}, language='eng', modified_on=now() ), {})) # group change self.assertTrue(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=[ObjectRef.create(uuid='G-002', name="Females")], fields={'chat_name': "ann"}, language='eng', modified_on=now() ), {})) # field value change self.assertTrue(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=[ObjectRef.create(uuid='G-003', name="Reporters")], fields={'chat_name': "ann8111"}, language='eng', modified_on=now() ), {})) # new field self.assertTrue(self.syncer.update_required(local, TembaContact.create( uuid='000-001', name="Ann", urns=['tel:1234'], groups=[ObjectRef.create(uuid='G-003', name="Reporters")], fields={'chat_name': "ann", 'age': "35"}, language='eng', modified_on=now() ), {}))
def test_local_kwargs(self): temba_contact = TembaContact.create( uuid="C-006", name="Jan", urns=["tel:123"], groups=[ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors")], fields={ "registration_date": None, "state": None, "lga": None, "occupation": None, "born": None, "gender": None, }, language="eng", ) self.assertEqual( self.syncer.local_kwargs(self.nigeria, temba_contact), { "backend": self.floip_backend, "org": self.nigeria, "uuid": "C-006", "gender": "", "born": 0, "occupation": "", "registered_on": None, "state": "", "district": "", "ward": "", }, ) temba_contact = TembaContact.create( uuid="C-007", name="Jan", urns=["tel:123"], groups=[ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors")], fields={ "registration_date": "2014-01-02T03:04:05.000000Z", "state": "Kigali", "lga": "Oyo", "occupation": "Student", "born": "1990", "gender": "Male", }, language="eng", ) self.assertEqual( self.syncer.local_kwargs(self.nigeria, temba_contact), { "backend": self.floip_backend, "org": self.nigeria, "uuid": "C-007", "gender": "M", "born": 1990, "occupation": "Student", "registered_on": json_date_to_datetime("2014-01-02T03:04:05.000"), "state": "", "district": "", "ward": "", }, ) temba_contact = TembaContact.create( uuid="C-008", name="Jan", urns=["tel:123"], groups=[ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors")], fields={ "registration_date": "2014-01-02T03:04:05.000000Z", "state": "Lagos", "lga": "Oyo", "ward": "Ikeja", "occupation": "Student", "born": "1990", "gender": "Male", }, language="eng", ) self.assertEqual( self.syncer.local_kwargs(self.nigeria, temba_contact), { "backend": self.floip_backend, "org": self.nigeria, "uuid": "C-008", "gender": "M", "born": 1990, "occupation": "Student", "registered_on": json_date_to_datetime("2014-01-02T03:04:05.000"), "state": "R-LAGOS", "district": "R-OYO", "ward": "R-IKEJA", }, ) temba_contact = TembaContact.create( uuid="C-008", name="Jan", urns=["tel:123"], groups=[ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors")], fields={ "registration_date": "2014-01-02T03:04:05.000000Z", "state": "Lagos", "lga": "Oyo", "occupation": "Student", "born": "-1", "gender": "Male", }, language="eng", ) self.assertEqual( self.syncer.local_kwargs(self.nigeria, temba_contact), { "backend": self.floip_backend, "org": self.nigeria, "uuid": "C-008", "gender": "M", "born": 0, "occupation": "Student", "registered_on": json_date_to_datetime("2014-01-02T03:04:05.000"), "state": "R-LAGOS", "district": "R-OYO", "ward": "", }, ) temba_contact = TembaContact.create( uuid="C-008", name="Jan", urns=["tel:123"], groups=[ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors")], fields={ "registration_date": "2014-01-02T03:04:05.000000Z", "state": "Lagos", "lga": "Oyo", "occupation": "Student", "born": "2147483648", "gender": "Male", }, language="eng", ) self.assertEqual( self.syncer.local_kwargs(self.nigeria, temba_contact), { "backend": self.floip_backend, "org": self.nigeria, "uuid": "C-008", "gender": "M", "born": 0, "occupation": "Student", "registered_on": json_date_to_datetime("2014-01-02T03:04:05.000"), "state": "R-LAGOS", "district": "R-OYO", "ward": "", }, )
def test_pull_contacts(self, mock_get_contacts): Contact.objects.all().delete() # empty fetches mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery([]), # second call to get deleted contacts MockClientQuery([]), ] with self.assertNumQueries(0): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 0)) # fecthed contact not in configured group get ignored mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={"age": "34"}, stopped=False, blocked=False, ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={"age": "67"}, stopped=False, blocked=False, ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={"age": "35"}, stopped=True, blocked=False, ) ], ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "34"}, stopped=False, blocked=False, ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={"age": "67"}, stopped=False, blocked=False, ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={"age": "35"}, stopped=True, blocked=False, ) ], ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 3)) Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "34"}, stopped=False, blocked=False, ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "67"}, stopped=False, blocked=False, ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={"age": "35"}, stopped=True, blocked=False, ) ], ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts # all included in the reporters MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "34"}, stopped=False, blocked=False, ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "67"}, stopped=False, blocked=False, ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "35"}, stopped=True, blocked=False, ) ], ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) contact_jan = Contact.objects.filter(uuid="C-001").first() self.assertFalse(contact_jan.born) self.assertFalse(contact_jan.state) mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Jan", urns=["tel:123"], groups=[ ObjectRef.create(uuid="G-001", name="ureporters"), ObjectRef.create(uuid="G-007", name="Actors"), ], fields={ "registration_date": "2014-01-02T03:04:05.000000Z", "state": "Nigeria > Lagos", "lga": "Nigeria > Lagos > Oyo", "occupation": "Student", "born": "1990", "gender": "Male", }, language="eng", ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-001", name="ureporters")], fields={"age": "67", "born": "1992"}, stopped=False, blocked=False, ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(10): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 2, 0, 0)) contact_jan = Contact.objects.filter(uuid="C-001").first() self.assertTrue(contact_jan.born) self.assertEqual(contact_jan.born, 1990) self.assertTrue(contact_jan.state) self.assertEqual(contact_jan.state, "R-LAGOS") self.assertTrue(Contact.objects.filter(uuid="C-002", is_active=True)) mock_get_contacts.side_effect = [ # first call to get active contacts MockClientQuery([]), # second call to get deleted contacts MockClientQuery( [ TembaContact.create( uuid="C-002", name=None, language=None, urns=[], groups=[], fields=None, stopped=True, blocked=False, ) ] ), ] with self.assertNumQueries(3): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.nigeria, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 1, 0)) self.assertFalse(Contact.objects.filter(uuid="C-002", is_active=True))
def test_contact_sync(self, mock_get_groups, mock_get_fields, mock_get_contacts): # start with no groups or fields Group.objects.all().delete() Field.objects.all().delete() fetch_size = 250 num_fetches = 4 num_groups = 50 num_fields = 50 names = ["Ann", "Bob", "Cat"] field_values = ["12345", None] groups_in = 5 # setup get_fields fields = [TembaField.create(key='field_%d' % f, label='Field #%d' % f, value_type='text') for f in range(0, num_fields)] mock_get_fields.return_value = MockClientQuery(fields) # sync fields start = time.time() self.assertEqual((num_fields, 0, 0, 0), self.backend.pull_fields(self.unicef)) print "Initial field sync: %f secs" % (time.time() - start) # setup get_groups groups = [TembaGroup.create(uuid="G0000000-0000-0000-0000-00000000%04d" % g, name="Group #%d" % g, count=0) for g in range(0, num_groups)] mock_get_groups.return_value = MockClientQuery(groups) # sync groups start = time.time() self.assertEqual((num_groups, 0, 0, 0), self.backend.pull_groups(self.unicef)) print "Initial group sync: %f secs" % (time.time() - start) # setup get_contacts to return multiple fetches of contacts active_fetches = [] for b in range(0, num_fetches): batch = [] for c in range(0, fetch_size): num = b * fetch_size + c batch.append(TembaContact.create( uuid="C0000000-0000-0000-0000-00000000%04d" % num, name=names[num % len(names)], language="eng", urns=["tel:+26096415%04d" % num], groups=[ ObjectRef.create(uuid="G0000000-0000-0000-0000-00000000%04d" % g, name="Group #%d" % g) for g in range(0, groups_in) ], fields={'custom_field_%d' % f: field_values[f % len(field_values)] for f in range(0, num_fields)}, failed=False, blocked=False )) active_fetches.append(batch) mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] # no deleted contacts start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) print "Initial contact sync: %f secs" % (time.time() - start) self.assertEqual((num_created, num_updated, num_deleted), (num_fetches * fetch_size, 0, 0)) # slowest_queries = sorted(connection.queries, key=lambda q: q['time'], reverse=True)[:10] # for q in slowest_queries: # print "%s -- %s" % (q['time'], q['sql']) # simulate a subsequent sync with no changes mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, 0, 0)) print "Contact sync with no changes: %f secs" % (time.time() - start) # simulate an update of 1 field value for batch in active_fetches: for c in batch: c.fields['custom_field_1'] = "UPDATED" mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, num_fetches * fetch_size, 0)) print "Contact sync with 1 field value changes: %f secs" % (time.time() - start) # simulate an update of 10 field values for batch in active_fetches: for c in batch: for f in (10, 11, 12, 13, 14, 15, 16, 17, 18, 19): c.fields['custom_field_%d' % f] = "UPDATED" mock_get_contacts.side_effect = [MockClientQuery(*active_fetches), MockClientQuery([])] start = time.time() num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted), (0, num_fetches * fetch_size, 0)) print "Contact sync with 10 field value changes: %f secs" % (time.time() - start)
def test_pull_contacts(self, mock_get_contacts): # start with nothing... Group.objects.all().delete() Field.objects.all().delete() Contact.objects.all().delete() mock_get_contacts.side_effect = [ # first call to get active contacts will return two fetches of 2 and 1 contacts MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlow", language="eng", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-001", name="Customers")], fields={'age': "34"}, failed=False, blocked=False ), TembaContact.create( uuid="C-002", name="Jim McMsg", language="fre", urns=["tel:+250783835665"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': "67"}, failed=False, blocked=False ), ], [ TembaContact.create( uuid="C-003", name="Ann McPoll", language="eng", urns=["tel:+250783835664"], groups=[], fields={'age': "35"}, failed=True, blocked=False ), ] ), # second call to get deleted contacts returns a contact we don't have MockClientQuery( [ TembaContact.create( uuid="C-004", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(15): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_contacts(self.unicef, None, None) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (3, 0, 0, 0)) bob = Contact.objects.get(uuid="C-001") jim = Contact.objects.get(uuid="C-002") ann = Contact.objects.get(uuid="C-003") self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, jim, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), set()) # stub contact groups will have been created too customers = Group.objects.get(org=self.unicef, uuid="G-001", name="Customers", is_active=False) spammers = Group.objects.get(org=self.unicef, uuid="G-002", name="Spammers", is_active=False) self.assertEqual(bob.name, "Bob McFlow") self.assertEqual(bob.language, "eng") self.assertEqual(set(bob.groups.all()), {customers}) self.assertEqual(bob.get_fields(), {'age': "34"}) mock_get_contacts.side_effect = [ # first call to get active contacts will just one updated contact MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlough", language="fre", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': "35"}, failed=True, blocked=False ) ] ), # second call to get deleted contacts returns Jim MockClientQuery( [ TembaContact.create( uuid="C-002", name=None, language=None, urns=[], groups=[], fields=None, failed=True, blocked=False ), ] ) ] with self.assertNumQueries(12): self.assertEqual(self.backend.pull_contacts(self.unicef, None, None), (0, 1, 1, 0)) self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), {jim}) self.assertEqual(jim.groups.count(), 0) # de-activated contacts are removed from groups bob.refresh_from_db() self.assertEqual(bob.name, "Bob McFlough") self.assertEqual(bob.language, "fre") self.assertEqual(set(bob.groups.all()), {spammers}) self.assertEqual(bob.get_fields(), {'age': "35"}) mock_get_contacts.side_effect = [ # first call to get active contacts will return a contact with only a change to URNs.. which we don't track MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlough", language="fre", urns=["twitter:bobflow22"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': "35"}, failed=True, blocked=False ) ] ), MockClientQuery([]) ] with self.assertNumQueries(2): self.assertEqual(self.backend.pull_contacts(self.unicef, None, None), (0, 0, 0, 1)) self.assertEqual(set(Contact.objects.filter(is_active=True)), {bob, ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), {jim}) mock_get_contacts.side_effect = [ # first call to get active contacts will show one contact is now blocked MockClientQuery( [ TembaContact.create( uuid="C-001", name="Bob McFlough", language="fre", urns=["twitter:bobflow"], groups=[ObjectRef.create(uuid="G-002", name="Spammers")], fields={'age': 35}, failed=True, blocked=True ) ] ), MockClientQuery([]) ] with self.assertNumQueries(5): self.assertEqual(self.backend.pull_contacts(self.unicef, None, None), (0, 0, 1, 0)) # blocked = deleted self.assertEqual(set(Contact.objects.filter(is_active=True)), {ann}) self.assertEqual(set(Contact.objects.filter(is_active=False)), {bob, jim})
def test_sync_local_to_changes(self): Contact.objects.all().delete() # start with no contacts... fetches = MockClientQuery([ TembaContact.create(uuid="C-001", name="Anne", blocked=False), TembaContact.create(uuid="C-002", name="Bob", blocked=False), TembaContact.create(uuid="C-003", name="Colin", blocked=False), TembaContact.create(uuid="C-004", name="Donald", blocked=True) ]) deleted_fetches = MockClientQuery([]) # no deleted contacts this time self.assertEqual(sync_local_to_changes(self.unicef, self.syncer, fetches, deleted_fetches), (3, 0, 0, 1)) fetches = MockClientQuery([ TembaContact.create(uuid="C-005", name="Edward", blocked=False), # new contact TembaContact.create(uuid="C-006", name="Frank", blocked=False), # new contact ]) deleted_fetches = MockClientQuery([ TembaContact.create(uuid="C-001", name=None, blocked=None), # deleted ]) self.assertEqual(sync_local_to_changes(self.unicef, self.syncer, fetches, deleted_fetches), (2, 0, 1, 0)) fetches = MockClientQuery([ TembaContact.create(uuid="C-002", name="Bob", blocked=True), # blocked so locally invalid TembaContact.create(uuid="C-003", name="Colm", blocked=False), # changed name ]) deleted_fetches = MockClientQuery([]) self.assertEqual(sync_local_to_changes(self.unicef, self.syncer, fetches, deleted_fetches), (0, 1, 1, 0)) fetches = MockClientQuery([ TembaContact.create(uuid="CF-001", name="Anne", blocked=False), TembaContact.create(uuid="CF-002", name="Bob", blocked=False), TembaContact.create(uuid="CF-003", name="Colin", blocked=False), TembaContact.create(uuid="CF-004", name="Donald", blocked=True) ]) deleted_fetches = MockClientQuery([]) # no deleted contacts this time self.assertEqual(sync_local_to_changes(self.unicef, self.syncer2, fetches, deleted_fetches), (3, 0, 0, 1)) fetches = MockClientQuery([ TembaContact.create(uuid="CF-005", name="Edward", blocked=False), # new contact TembaContact.create(uuid="CF-006", name="Frank", blocked=False), # new contact ]) deleted_fetches = MockClientQuery([ TembaContact.create(uuid="CF-001", name=None, blocked=None), # deleted ]) self.assertEqual(sync_local_to_changes(self.unicef, self.syncer2, fetches, deleted_fetches), (2, 0, 1, 0)) fetches = MockClientQuery([ TembaContact.create(uuid="CF-002", name="Bob", blocked=True), # blocked so locally invalid TembaContact.create(uuid="CF-003", name="Colm", blocked=False), # changed name ]) deleted_fetches = MockClientQuery([]) self.assertEqual(sync_local_to_changes(self.unicef, self.syncer2, fetches, deleted_fetches), (0, 1, 1, 0))