def test_push_label(self, mock_get_labels, mock_create_label): mock_get_labels.return_value = MockClientQuery([TembaLabel.create(uuid="L-011", name="Tea", count=213)]) # check when label with name exists self.tea.uuid = None self.tea.save() self.backend.push_label(self.unicef, self.tea) self.tea.refresh_from_db() self.assertEqual(self.tea.uuid, "L-011") self.assertNotCalled(mock_create_label) # check when label doesn't exist mock_get_labels.return_value = MockClientQuery([]) mock_create_label.return_value = TembaLabel.create(uuid="L-012", name="Tea", count=0) self.tea.uuid = None self.tea.save() self.backend.push_label(self.unicef, self.tea) self.tea.refresh_from_db() self.assertEqual(self.tea.uuid, "L-012") mock_create_label.assert_called_once_with(name="Tea")
def test_pull_labels(self, mock_get_labels): # start with one un-synced label Label.objects.all().delete() self.create_label(self.unicef, None, "Local", "Desc", ["local"], is_synced=False) mock_get_labels.return_value = MockClientQuery( [ TembaLabel.create(uuid="L-001", name="Requests", count=45), TembaLabel.create(uuid="L-002", name="Feedback", count=32), TembaLabel.create(uuid="L-009", name="Flagged", count=21), # should be ignored TembaLabel.create(uuid="L-010", name="Local", count=0), # should be ignored ] ) self.unicef = Org.objects.prefetch_related("labels").get(pk=self.unicef.pk) with self.assertNumQueries(8): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_labels(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (2, 0, 0, 2)) Label.objects.get(uuid=None, name="Local", is_active=True) Label.objects.get(uuid="L-001", name="Requests", is_active=True) Label.objects.get(uuid="L-002", name="Feedback", is_active=True) self.assertEqual(Label.objects.filter(name="Flagged").count(), 0) mock_get_labels.return_value = MockClientQuery( [ TembaLabel.create(uuid="L-002", name="Complaints", count=32), TembaLabel.create(uuid="L-003", name="Spam", count=13), ] ) with self.assertNumQueries(7): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_labels(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (1, 1, 1, 0)) Label.objects.get(uuid=None, name="Local", is_active=True) Label.objects.get(uuid="L-001", name="Requests", is_active=False) Label.objects.get(uuid="L-002", name="Complaints", is_active=True) Label.objects.get(uuid="L-003", name="Spam", is_active=True) # check that no changes means no updates with self.assertNumQueries(4): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_labels(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 2))
def test_fetch_flows(self, mock_get_flows): mock_get_flows.side_effect = [ MockClientQuery([Flow.create(name='Flow 1', uuid='uuid-25', labels=[], archived=False, expires=720, created_on=json_date_to_datetime("2015-04-08T12:48:44.320Z"), runs=Flow.Runs.create(completed=120, active=50, expired=100, interrupted=30)) ])] with patch("ureport.utils.datetime_to_ms") as mock_datetime_ms: mock_datetime_ms.return_value = 500 with patch('django.core.cache.cache.set') as cache_set_mock: flows = fetch_flows(self.org, self.rapidpro_backend) expected = dict() expected['uuid-25'] = dict(uuid='uuid-25', date_hint="2015-04-08", created_on="2015-04-08T12:48:44.320Z", name="Flow 1", runs=300, completed_runs=120, archived=False) self.assertEqual(flows, expected) cache_set_mock.assert_called_once_with('org:%d:backend:%s:flows' % (self.org.pk, self.rapidpro_backend.slug), dict(time=500, results=expected), UREPORT_ASYNC_FETCHED_DATA_CACHE_TIME)
def test_fetch_flows(self, mock_get_flows): mock_get_flows.side_effect = [ MockClientQuery( [ Flow.create( name="Flow 1", uuid="uuid-25", labels=[], archived=False, expires=720, created_on=json_date_to_datetime("2015-04-08T12:48:44.320Z"), results=[ Flow.FlowResult.create( key="color", name="Color", categories=["Orange", "Blue", "Other", "Nothing"], node_uuids=["42a8e177-9e88-429b-b70a-7d4854423092"], ) ], runs=Flow.Runs.create(completed=120, active=50, expired=100, interrupted=30), ) ] ) ] with patch("ureport.utils.datetime_to_ms") as mock_datetime_ms: mock_datetime_ms.return_value = 500 with patch("django.core.cache.cache.set") as cache_set_mock: flows = fetch_flows(self.org, self.rapidpro_backend) expected = dict() expected["uuid-25"] = dict( uuid="uuid-25", date_hint="2015-04-08", created_on="2015-04-08T12:48:44.320Z", name="Flow 1", runs=300, completed_runs=120, archived=False, results=[ dict( key="color", name="Color", categories=["Orange", "Blue", "Other", "Nothing"], node_uuids=["42a8e177-9e88-429b-b70a-7d4854423092"], ) ], ) self.assertEqual(flows, expected) cache_set_mock.assert_called_once_with( "org:%d:backend:%s:flows" % (self.org.pk, self.rapidpro_backend.slug), dict(time=500, results=expected), UREPORT_ASYNC_FETCHED_DATA_CACHE_TIME, )
def test_pull_groups(self, mock_get_groups): # start with no groups Group.objects.all().delete() mock_get_groups.return_value = MockClientQuery( [ TembaGroup.create(uuid="G-001", name="Customers", query=None, count=45), TembaGroup.create(uuid="G-002", name="Developers", query="isdev=yes", count=32), ] ) with self.assertNumQueries(6): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_groups(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (2, 0, 0, 0)) Group.objects.get(uuid="G-001", name="Customers", count=45, is_dynamic=False, is_active=True) Group.objects.get(uuid="G-002", name="Developers", count=32, is_dynamic=True, is_active=True) mock_get_groups.return_value = MockClientQuery( [ TembaGroup.create(uuid="G-002", name="Devs", query="isdev=yes", count=32), TembaGroup.create(uuid="G-003", name="Spammers", query=None, count=13), ] ) with self.assertNumQueries(7): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_groups(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (1, 1, 1, 0)) Group.objects.get(uuid="G-001", name="Customers", count=45, is_dynamic=False, is_active=False) Group.objects.get(uuid="G-002", name="Devs", count=32, is_dynamic=True, is_active=True) Group.objects.get(uuid="G-003", name="Spammers", count=13, is_dynamic=False, is_active=True) # check that no changes means no updates with self.assertNumQueries(4): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_groups(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 2))
def test_pull_fields(self, mock_get_fields): # start with no fields Field.objects.all().delete() mock_get_fields.return_value = MockClientQuery( [ TembaField.create(key="nick_name", label="Nickname", value_type="text"), TembaField.create(key="age", label="Age", value_type="numeric"), ] ) with self.assertNumQueries(6): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_fields(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (2, 0, 0, 0)) Field.objects.get(key="nick_name", label="Nickname", value_type="T", is_active=True) Field.objects.get(key="age", label="Age", value_type="N", is_active=True) mock_get_fields.return_value = MockClientQuery( [ TembaField.create(key="age", label="Age (Years)", value_type="numeric"), TembaField.create(key="homestate", label="Homestate", value_type="state"), ] ) with self.assertNumQueries(7): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_fields(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (1, 1, 1, 0)) Field.objects.get(key="nick_name", label="Nickname", value_type="T", is_active=False) Field.objects.get(key="age", label="Age (Years)", value_type="N", is_active=True) Field.objects.get(key="homestate", label="Homestate", value_type="S", is_active=True) # check that no changes means no updates with self.assertNumQueries(4): num_created, num_updated, num_deleted, num_ignored = self.backend.pull_fields(self.unicef) self.assertEqual((num_created, num_updated, num_deleted, num_ignored), (0, 0, 0, 2))
def test_fetch_flows(self, mock_get_flows): mock_get_flows.return_value = MockClientQuery( [ TembaFlow.create(uuid="0001-0001", name="Registration", archived=False,), TembaFlow.create(uuid="0002-0002", name="Follow Up", archived=False,), TembaFlow.create(uuid="0003-0003", name="Other Flow", archived=True,), ] ) flows = self.backend.fetch_flows(self.unicef) self.assertEqual(flows, [Flow("0002-0002", "Follow Up"), Flow("0001-0001", "Registration")]) mock_get_flows.assert_called_once_with()
def test_fetch_contact_messages(self, mock_get_messages): d1 = datetime(2015, 1, 2, 13, 0, tzinfo=pytz.UTC) d2 = datetime(2015, 1, 2, 14, 0, tzinfo=pytz.UTC) d3 = datetime(2015, 1, 2, 15, 0, tzinfo=pytz.UTC) mock_get_messages.return_value = MockClientQuery( [ TembaMessage.create( id=102, broadcast=201, contact=ObjectRef.create(uuid="C-001", name="Ann"), text="Welcome", type="inbox", direction="out", visibility="visible", labels=[], created_on=d3, ), TembaMessage.create( id=101, broadcast=None, contact=ObjectRef.create(uuid="C-001", name="Ann"), text="Hello", type="inbox", direction="in", visibility="archived", labels=[ ObjectRef.create(uuid="L-001", name="AIDS"), ObjectRef.create(uuid="L-111", name="Flagged"), ], created_on=d2, ), ] ) messages = self.backend.fetch_contact_messages(self.unicef, self.ann, d1, d3) self.assertEqual(len(messages), 1) self.assertIsInstance(messages[0], Outgoing) self.assertEqual(messages[0].backend_broadcast_id, 201) self.assertEqual(messages[0].contact, self.ann) self.assertEqual(messages[0].text, "Welcome") self.assertEqual(messages[0].created_on, d3)
def test_pull_messages(self, mock_get_messages): d1 = now() - timedelta(hours=10) d2 = now() - timedelta(hours=9) d3 = now() - timedelta(hours=8) d4 = now() - timedelta(hours=7) d5 = now() - timedelta(hours=6) mock_get_messages.side_effect = [ MockClientQuery( [ TembaMessage.create( id=101, contact=ObjectRef.create(uuid="C-001", name="Ann"), type="inbox", text="What is aids?", visibility="visible", labels=[ ObjectRef.create(uuid="L-001", name="AIDS"), # existing label ObjectRef.create(uuid="L-009", name="Flagged"), # pseudo-label ], created_on=d1, ), TembaMessage.create( id=102, contact=ObjectRef.create(uuid="C-002", name="Bob"), type="inbox", text="Can I catch Hiv?", visibility="visible", labels=[ObjectRef.create(uuid="L-007", name="Important")], # new label created_on=d2, ), TembaMessage.create( id=103, contact=ObjectRef.create(uuid="C-003", name="Cat"), type="inbox", text="I think I'm pregnant", visibility="visible", labels=[], created_on=d3, ), TembaMessage.create( id=104, contact=ObjectRef.create(uuid="C-004", name="Don"), type="flow", text="Php is amaze", visibility="visible", labels=[], created_on=d4, ), TembaMessage.create( id=105, contact=ObjectRef.create(uuid="C-005", name="Eve"), type="flow", text="Thanks for the pregnancy/HIV info", visibility="visible", labels=[], created_on=d5, ), ] ) ] self.assertEqual(self.backend.pull_messages(self.unicef, d1, d5), (5, 0, 0, 0)) self.assertEqual(Contact.objects.filter(is_stub=False).count(), 2) self.assertEqual(Contact.objects.filter(is_stub=True).count(), 3) self.assertEqual(Message.objects.filter(is_handled=False).count(), 5) msg1 = Message.objects.get(backend_id=101, type="I", text="What is aids?", is_archived=False, is_flagged=True) important = Label.objects.get(org=self.unicef, uuid="L-007", name="Important") self.assertEqual(set(msg1.labels.all()), {self.aids}) # a message is updated in RapidPro mock_get_messages.side_effect = [ MockClientQuery( [ TembaMessage.create( id=101, contact=ObjectRef.create(uuid="C-001", name="Ann"), type="inbox", text="What is aids?", visibility="archived", labels=[ ObjectRef.create(uuid="L-001", name="AIDS"), ObjectRef.create(uuid="L-007", name="Important"), ], created_on=d1, ) ] ) ] self.assertEqual(self.backend.pull_messages(self.unicef, d1, d5), (0, 1, 0, 0)) msg1 = Message.objects.get(backend_id=101, type="I", text="What is aids?", is_archived=True, is_flagged=False) self.assertEqual(set(msg1.labels.all()), {self.aids, important})
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_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_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))