def test_group_changes(self): flow = self.create_flow("Test") nodes = flow.get_definition()["nodes"] contact1 = self.create_contact("Joe", phone="1234") contact2 = self.create_contact("Frank", phone="2345") contact3 = self.create_contact("Anne", phone="3456") group1 = self.create_group("Group 1", contacts=[contact3]) group2 = self.create_group("Group 2", contacts=[]) group3 = self.create_group("Group 3", contacts=[contact1, contact2]) # simulate a flow start which adds contacts 1 and 2 to groups 1 and 2, and removes them from group 3 start1 = FlowStart.create(flow, self.admin, contacts=[contact1, contact2]) (MockSessionWriter(contact1, flow, start=start1).visit(nodes[0]).add_contact_groups([ group1, group2 ]).remove_contact_groups([group3 ]).complete().save()) (MockSessionWriter(contact2, flow, start=start1).visit(nodes[0]).add_contact_groups([ group1, group2 ]).remove_contact_groups([group3 ]).complete().save()) # and another which adds contact 3 to group 3 start2 = FlowStart.create(flow, self.admin, contacts=[contact3]) (MockSessionWriter(contact3, flow, start=start2).visit( nodes[0]).add_contact_groups([group3]).complete().save()) t0 = timezone.now() self.assertEqual({contact1, contact2, contact3}, set(group1.contacts.all())) self.assertEqual({contact1, contact2}, set(group2.contacts.all())) self.assertEqual({contact3}, set(group3.contacts.all())) # can run with --dry-run to preview changes call_command("undo_footgun", start=start1.id, dry_run=True, quiet=True) self.assertEqual({contact1, contact2, contact3}, set(group1.contacts.all())) self.assertEqual({contact1, contact2}, set(group2.contacts.all())) self.assertEqual({contact3}, set(group3.contacts.all())) # no contacts will have had modified_on updated self.assertEqual(0, Contact.objects.filter(modified_on__gt=t0).count()) # and then actually make database changes call_command("undo_footgun", start=start1.id, quiet=True) self.assertEqual({contact3}, set(group1.contacts.all())) self.assertEqual(set(), set(group2.contacts.all())) self.assertEqual({contact1, contact2, contact3}, set(group3.contacts.all())) # contacts 1 and 2 will have had modified_on updated self.assertEqual(2, Contact.objects.filter(modified_on__gt=t0).count())
def test_queue_interrupt_by_session(self): jim = self.create_contact("Jim", "+12065551212") flow = self.get_flow("favorites") flow_nodes = flow.as_json()["nodes"] color_prompt = flow_nodes[0] color_split = flow_nodes[2] (MockSessionWriter(jim, flow).visit(color_prompt).send_msg( "What is your favorite color?", self.channel).visit(color_split).wait().save()) run = FlowRun.objects.get(contact=jim) session = run.session run.release("U") self.assert_org_queued(self.org, "batch") self.assert_queued_batch_task( self.org, { "type": "interrupt_sessions", "org_id": self.org.id, "task": { "session_ids": [session.id] }, "queued_on": matchers.ISODate(), }, )
def test_from_flow_run(self): contact = self.create_contact("Jim", phone="0979111111") flow = self.get_flow("color_v13") nodes = flow.get_definition()["nodes"] (MockSessionWriter(contact, flow).visit(nodes[0]).send_msg( "What is your favorite color?", self.channel).wait().save()) run = contact.runs.get() self.assertEqual( { "type": "flow_entered", "created_on": matchers.ISODate(), "flow": { "uuid": str(flow.uuid), "name": "Colors" }, "logs_url": None, }, Event.from_flow_run(self.org, self.admin, run), ) # customer support get access to logs self.assertEqual( { "type": "flow_entered", "created_on": matchers.ISODate(), "flow": { "uuid": str(flow.uuid), "name": "Colors" }, "logs_url": f"/flowsession/json/{run.session.uuid}/", }, Event.from_flow_run(self.org, self.customer_support, run), )
def test_status_changes(self): flow = self.create_flow("Test") nodes = flow.get_definition()["nodes"] contact1 = self.create_contact("Joe", phone="1234") contact2 = self.create_contact("Frank", phone="2345") contact3 = self.create_contact("Anne", phone="3456") # simulate a flow start which adds blocks contact1 and stops contact2 start1 = FlowStart.create(flow, self.admin, contacts=[contact1, contact2]) (MockSessionWriter(contact1, flow, start=start1).visit( nodes[0]).set_contact_status("blocked").complete().save()) (MockSessionWriter(contact2, flow, start=start1).visit( nodes[0]).set_contact_status("stopped").complete().save()) t0 = timezone.now() self.assertEqual({contact1}, set(Contact.objects.filter(status="B"))) self.assertEqual({contact2}, set(Contact.objects.filter(status="S"))) self.assertEqual({contact3}, set(Contact.objects.filter(status="A"))) # can run with --dry-run to preview changes call_command("undo_footgun", start=start1.id, dry_run=True, quiet=True) self.assertEqual({contact1}, set(Contact.objects.filter(status="B"))) self.assertEqual({contact2}, set(Contact.objects.filter(status="S"))) self.assertEqual({contact3}, set(Contact.objects.filter(status="A"))) # no contacts will have had modified_on updated self.assertEqual(0, Contact.objects.filter(modified_on__gt=t0).count()) # and then actually make database changes call_command("undo_footgun", start=start1.id, quiet=True) self.assertEqual({contact1, contact2, contact3}, set(Contact.objects.filter(status="A")))
def test_recalc_node_counts(self): contact1 = self.create_contact("Ben Haggerty", phone="+12065552020") contact2 = self.create_contact("Joe", phone="+12065550002") contact3 = self.create_contact("Frank", phone="+12065550003") def check_node_count_rebuild(flow, assert_count): node_counts = FlowNodeCount.get_totals(flow) call_command("recalc_node_counts", flow_id=flow.id) new_counts = FlowNodeCount.get_totals(flow) self.assertEqual(new_counts, node_counts) self.assertEqual(assert_count, sum(new_counts.values())) flow = self.get_flow("favorites_v13") nodes = flow.get_definition()["nodes"] color_prompt = nodes[0] color_other = nodes[1] color_split = nodes[2] beer_prompt = nodes[3] beer_split = nodes[5] name_prompt = nodes[6] name_split = nodes[7] name_reply = nodes[8] session1 = MockSessionWriter( contact1, flow).visit(color_prompt).visit(color_split).wait().save() session2 = MockSessionWriter( contact2, flow).visit(color_prompt).visit(color_split).wait().save() session3 = MockSessionWriter( contact3, flow).visit(color_prompt).visit(color_split).wait().save() # recalculate node counts and check they are the same check_node_count_rebuild(flow, 3) (session1.resume(self.create_incoming_msg( contact1, "Blue")).visit(beer_prompt).visit(beer_split).wait().save()) (session2.resume(self.create_incoming_msg( contact2, "Beige")).visit(color_other).visit(color_split).wait().save()) (session3.resume(self.create_incoming_msg( contact3, "Amber")).visit(color_other).visit(color_split).wait().save()) check_node_count_rebuild(flow, 3) (session1.resume(self.create_incoming_msg( contact1, "Primus")).visit(name_prompt).visit(name_split).wait().save()) (session2.resume(self.create_incoming_msg( contact2, "Orange")).visit(color_other).visit(color_split).wait().save()) (session3.resume(self.create_incoming_msg( contact3, "Amber")).visit(color_other).visit(color_split).wait().save()) check_node_count_rebuild(flow, 3) # contact1 replies with name to complete the flow (session1.resume(self.create_incoming_msg( contact1, "Bob")).visit(name_reply).complete().save()) check_node_count_rebuild(flow, 2)