diff --git a/media/test_flows/color.json b/media/test_flows/color.json deleted file mode 100644 index f25c355a415..00000000000 --- a/media/test_flows/color.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "version": 8, - "site": "http://rapidpro.io", - "flows": [ - { - "version": 8, - "flow_type": "F", - "base_language": "base", - "metadata": { - "uuid": "2a385c5b-e27c-43ac-bbc6-49653fede421", - "author": "Ryan Lewis", - "name": "Color Flow" - }, - "entry": "d51ec25f-04e6-4349-a448-e7c4d93d4597", - "action_sets": [ - { - "y": 1, - "x": 1, - "destination": "bd531ace-911e-4722-8e53-6730d6122fe1", - "uuid": "d51ec25f-04e6-4349-a448-e7c4d93d4597", - "actions": [ - { - "msg": { - "base": "What is your favorite color?", - "fre": "Quelle est votre couleur pr\u00e9f\u00e9r\u00e9e?" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "98388930-7a0f-4eb8-9a0a-09be2f006420" - } - ] - }, - { - "y": 2, - "x": 2, - "destination": null, - "uuid": "7d40faea-723b-473d-8999-59fb7d3c3ca2", - "actions": [ - { - "msg": { - "base": "I love orange too! You said: @step.value which is category: @flow.color.category You are: @step.contact.tel SMS: @step Flow: @flow" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "cf57f270-c9d7-4826-b3cc-7bfc22ac4ef6" - } - ] - }, - { - "y": 3, - "x": 3, - "destination": null, - "uuid": "c12f37e2-8e6c-4c81-ba6d-941bb3caf93f", - "actions": [ - { - "msg": { - "base": "Blue is sad. :(" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "d6aee40b-3710-4358-b0a6-c0ddc1d7734e" - } - ] - }, - { - "y": 4, - "x": 4, - "destination": "bd531ace-911e-4722-8e53-6730d6122fe1", - "uuid": "1cb6d8da-3749-45b2-9382-3f756e3ca71f", - "actions": [ - { - "msg": { - "base": "That is a funny color. Try again." - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "ca798d2d-2c95-468a-a857-74797a4d5301" - } - ] - } - ], - "rule_sets": [ - { - "uuid": "bd531ace-911e-4722-8e53-6730d6122fe1", - "rules": [ - { - "category": { - "base": "Orange" - }, - "test": { - "test": { - "base": "orange" - }, - "type": "contains" - }, - "destination": "7d40faea-723b-473d-8999-59fb7d3c3ca2", - "uuid": "1c75fd71-027b-40e8-a819-151a0f8140e6", - "destination_type": "A" - }, - { - "category": { - "base": "Blue" - }, - "test": { - "test": { - "base": "blue" - }, - "type": "contains" - }, - "destination": "c12f37e2-8e6c-4c81-ba6d-941bb3caf93f", - "uuid": "40cc7c36-b7c8-4f05-ae82-25275607e5aa", - "destination_type": "A" - }, - { - "category": { - "base": "Other" - }, - "test": { - "type": "true" - }, - "destination": "1cb6d8da-3749-45b2-9382-3f756e3ca71f", - "uuid": "93998b50-6580-4574-8f60-74654df7d243", - "destination_type": "A" - }, - { - "category": { - "base": "Nothing" - }, - "test": { - "type": "true" - }, - "uuid": "a51ff58e-17c2-4b00-8c8f-a6b6948aaa0b" - } - ], - "ruleset_type": "wait_message", - "label": "color", - "y": 5, - "finished_key": null, - "response_type": "", - "operand": null, - "x": 5, - "config": {} - } - ] - } - ], - "triggers": [] -} \ No newline at end of file diff --git a/media/test_flows/favorites_v4.json b/media/test_flows/favorites_v4.json deleted file mode 100644 index 61e6ce4bab4..00000000000 --- a/media/test_flows/favorites_v4.json +++ /dev/null @@ -1,332 +0,0 @@ -{ - "version": 4, - "flows": [ - { - "definition": { - "base_language": "base", - "action_sets": [ - { - "y": 0, - "x": 100, - "destination": "0ecf7914-05e0-4b71-8816-495d2c0921b5", - "uuid": "a6676605-332a-4309-a8b8-79b33e73adcd", - "actions": [ - { - "msg": { - "base": "What is your favorite color?" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "98388930-7a0f-4eb8-9a0a-09be2f006420" - } - ] - }, - { - "y": 237, - "x": 131, - "destination": "58ec23b9-70bb-4d70-a739-8cee2d2f1e75", - "uuid": "00c0ebde-1d4f-4bf5-b5db-22f72b2551b7", - "actions": [ - { - "msg": { - "base": "Good choice, I like @flow.color.category too! What is your favorite beer?" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "cf57f270-c9d7-4826-b3cc-7bfc22ac4ef6" - } - ] - }, - { - "y": 8, - "x": 456, - "destination": "0ecf7914-05e0-4b71-8816-495d2c0921b5", - "uuid": "37f62180-025e-4360-a72b-59af7ac6d1ab", - "actions": [ - { - "msg": { - "base": "I don't know that color. Try again." - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "d6aee40b-3710-4358-b0a6-c0ddc1d7734e" - } - ] - }, - { - "y": 535, - "x": 191, - "destination": "c85670d3-e550-40f7-9ce2-e22c5d3fbcea", - "uuid": "92a6a4c6-c976-405a-97c8-76bf7edd214a", - "actions": [ - { - "msg": { - "base": "Mmmmm... delicious @flow.beer.category. If only they made @(LOWER(flow.color)) @flow.beer.category! Lastly, what is your name?" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "ca798d2d-2c95-468a-a857-74797a4d5301" - } - ] - }, - { - "y": 265, - "x": 512, - "destination": "58ec23b9-70bb-4d70-a739-8cee2d2f1e75", - "uuid": "7c3c0319-20ee-4c30-a276-55dba0d049de", - "actions": [ - { - "msg": { - "base": "I don't know that one, try again please." - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "be5c0c50-b3a4-486f-9e2e-335bdb542385" - } - ] - }, - { - "y": 805, - "x": 191, - "destination": null, - "uuid": "fbb7df74-627a-45bb-83f6-e3e4d2d8020c", - "actions": [ - { - "msg": { - "base": "Thanks @flow.name, we are all done!" - }, - "media": {}, - "send_all": false, - "type": "reply", - "uuid": "512aa0ca-0c57-4b99-a7ad-e67d290e0c2c" - } - ] - } - ], - "rule_sets": [ - { - "uuid": "0ecf7914-05e0-4b71-8816-495d2c0921b5", - "rules": [ - { - "test": { - "test": { - "base": "Red" - }, - "type": "contains_any" - }, - "category": { - "base": "Red" - }, - "destination": "00c0ebde-1d4f-4bf5-b5db-22f72b2551b7", - "uuid": "663f667d-561a-4920-9375-3ce367615bdc", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Green" - }, - "type": "contains_any" - }, - "category": { - "base": "Green" - }, - "destination": "00c0ebde-1d4f-4bf5-b5db-22f72b2551b7", - "uuid": "8977bc24-d10c-4b1a-9b07-13e3447165d1", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Blue" - }, - "type": "contains_any" - }, - "category": { - "base": "Blue" - }, - "destination": "00c0ebde-1d4f-4bf5-b5db-22f72b2551b7", - "uuid": "56e47151-0a7d-4dd8-89cf-35fdcb5288ef", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Navy" - }, - "type": "contains_any" - }, - "category": { - "base": "Blue" - }, - "destination": "00c0ebde-1d4f-4bf5-b5db-22f72b2551b7", - "uuid": "08403c82-043d-4744-8e1a-c863e5e92fb7", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Cyan" - }, - "type": "contains_any" - }, - "category": { - "base": "Cyan" - }, - "destination": null, - "uuid": "cc43e621-c759-4976-8088-e89a0bce7749", - "destination_type": null - }, - { - "test": { - "test": "true", - "type": "true" - }, - "category": { - "base": "Other" - }, - "destination": null, - "uuid": "955bd46a-29b2-49eb-bc70-0fc573d1cceb", - "destination_type": null - } - ], - "ruleset_type": null, - "label": "Color", - "finished_key": null, - "response_type": "C", - "y": 129, - "x": 98, - "webhook": "http://localhost:49999/status", - "webhook_action": "POST", - "operand": "@extra.value", - "config": {} - }, - { - "uuid": "58ec23b9-70bb-4d70-a739-8cee2d2f1e75", - "rules": [ - { - "test": { - "test": { - "base": "Mutzig" - }, - "type": "contains_any" - }, - "category": { - "base": "Mutzig" - }, - "destination": "92a6a4c6-c976-405a-97c8-76bf7edd214a", - "uuid": "d9c89b0e-2083-42e4-93c9-4d75e5f6c86f", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Primus" - }, - "type": "contains_any" - }, - "category": { - "base": "Primus" - }, - "destination": "92a6a4c6-c976-405a-97c8-76bf7edd214a", - "uuid": "777a04d2-aa27-4024-9b15-99f699a65a2f", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Turbo King" - }, - "type": "contains_any" - }, - "category": { - "base": "Turbo King" - }, - "destination": "92a6a4c6-c976-405a-97c8-76bf7edd214a", - "uuid": "ad519b79-9738-449d-80a1-e8fc3aebd08e", - "destination_type": "A" - }, - { - "test": { - "test": { - "base": "Skol" - }, - "type": "contains_any" - }, - "category": { - "base": "Skol" - }, - "destination": "92a6a4c6-c976-405a-97c8-76bf7edd214a", - "uuid": "c27f16dc-519c-44a9-bee7-fbfe76ade983", - "destination_type": "A" - }, - { - "test": { - "test": "true", - "type": "true" - }, - "category": { - "base": "Other" - }, - "destination": "7c3c0319-20ee-4c30-a276-55dba0d049de", - "uuid": "fbccf8e5-b167-43f1-ace3-72802ba6db92", - "destination_type": "A" - } - ], - "ruleset_type": null, - "label": "Beer", - "operand": "@step.value|lower_case", - "finished_key": null, - "response_type": "C", - "y": 387, - "x": 112, - "config": {} - }, - { - "uuid": "c85670d3-e550-40f7-9ce2-e22c5d3fbcea", - "rules": [ - { - "test": { - "test": "true", - "type": "true" - }, - "category": { - "base": "All Responses" - }, - "destination": "fbb7df74-627a-45bb-83f6-e3e4d2d8020c", - "uuid": "cf3633cc-d2e4-4f25-b318-a2ddc61b6849", - "destination_type": "A" - } - ], - "ruleset_type": null, - "label": "Name", - "operand": "@step.value", - "finished_key": null, - "response_type": "C", - "y": 702, - "x": 191, - "config": {} - } - ], - "metadata": { - "uuid": "77ae372d-a937-4d9b-a703-cc1c75c4c6f1", - "notes": [], - "expires": 720, - "name": "Favorites", - "revision": 1, - "saved_on": "2017-08-16T23:10:18.579169Z" - } - }, - "version": 4, - "flow_type": "F", - "name": "Favorites", - "entry": "a6676605-332a-4309-a8b8-79b33e73adcd" - } - ], - "triggers": [] -} \ No newline at end of file diff --git a/media/test_flows/color_v11.json b/media/test_flows/legacy/color_v11.json similarity index 100% rename from media/test_flows/color_v11.json rename to media/test_flows/legacy/color_v11.json diff --git a/media/test_flows/send_only_v13.json b/media/test_flows/send_only_v13.json deleted file mode 100644 index 38aa94fed4e..00000000000 --- a/media/test_flows/send_only_v13.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "version": "13", - "flows": [ - { - "uuid": "1a737778-2cef-4e2f-830e-33a9d3921741", - "name": "Send Only", - "spec_version": "13.0.0", - "language": "eng", - "type": "messaging", - "revision": 3, - "expire_after_minutes": 10080, - "localization": {}, - "nodes": [ - { - "uuid": "bbfb4d96-3963-4b36-8faa-1f46144b8ef8", - "actions": [ - { - "uuid": "eaac3f31-c181-48c4-a008-eb9ecfdfdfac", - "type": "send_msg", - "text": "This is the first message." - }, - { - "uuid": "6fe55458-4055-4a2a-b79c-52a878358851", - "type": "send_msg", - "text": "This is the second message." - } - ], - "exits": [ - { - "uuid": "ec43a6c3-9a78-47d9-a22e-57a5382936af" - } - ] - } - ], - "_ui": { - "nodes": { - "bbfb4d96-3963-4b36-8faa-1f46144b8ef8": { - "type": "execute_actions", - "position": { - "left": 100, - "top": 0 - } - } - }, - "stickies": {} - } - } - ], - "triggers": [] -} \ No newline at end of file diff --git a/temba/api/v2/tests/test_flows.py b/temba/api/v2/tests/test_flows.py index 3683ba57dba..762561b2a1c 100644 --- a/temba/api/v2/tests/test_flows.py +++ b/temba/api/v2/tests/test_flows.py @@ -17,7 +17,7 @@ def test_endpoint(self): self.assertDeleteNotAllowed(endpoint_url) survey = self.get_flow("media_survey") - color = self.get_flow("color") + color = self.get_flow("color_v13") archived = self.get_flow("favorites") archived.archive(self.admin) @@ -76,16 +76,16 @@ def test_endpoint(self): }, { "uuid": color.uuid, - "name": "Color Flow", + "name": "Colors", "type": "message", "archived": False, "labels": [{"uuid": str(reporting.uuid), "name": "Reporting"}], - "expires": 10080, + "expires": 720, "runs": {"active": 0, "waiting": 0, "completed": 1, "interrupted": 0, "expired": 0, "failed": 0}, "results": [ { "key": "color", - "name": "color", + "name": "Color", "categories": ["Orange", "Blue", "Other", "Nothing"], "node_uuids": [matchers.UUID4String()], } diff --git a/temba/flows/tests/test_export.py b/temba/flows/tests/test_export.py index e64553fb760..38458474365 100644 --- a/temba/flows/tests/test_export.py +++ b/temba/flows/tests/test_export.py @@ -539,32 +539,23 @@ def test_anon_org(self): self.org.timezone, ) - def test_broadcast_only_flow(self): - flow = self.get_flow("send_only_v13") - send_node = flow.get_definition()["nodes"][0] + def test_flow_without_results(self): + flow = self.create_flow("Test") today = timezone.now().astimezone(self.org.timezone).date() - for contact in [self.contact, self.contact2, self.contact3]: - ( - MockSessionWriter(contact, flow) - .visit(send_node) - .send_msg("This is the first message.", self.channel) - .send_msg("This is the second message.", self.channel) - .complete() - .save() - ).session.runs.get() - for contact in [self.contact, self.contact2]: - ( - MockSessionWriter(contact, flow) - .visit(send_node) - .send_msg("This is the first message.", self.channel) - .send_msg("This is the second message.", self.channel) - .complete() - .save() - ).session.runs.get() + flow.runs.create( + org=contact.org, + contact=contact, + status=FlowRun.STATUS_COMPLETED, + path=[], + results={}, + created_on=timezone.now(), + modified_on=timezone.now(), + exited_on=timezone.now(), + ) - contact1_run1, contact2_run1, contact3_run1, contact1_run2, contact2_run2 = FlowRun.objects.order_by("id") + contact1_run1, contact2_run1 = flow.runs.order_by("id") with self.assertNumQueries(17): workbook = self._export(flow, start_date=today - timedelta(days=7), end_date=today) @@ -574,7 +565,7 @@ def test_broadcast_only_flow(self): (sheet_runs,) = workbook.worksheets # check runs sheet... - self.assertEqual(6, len(list(sheet_runs.rows))) # header + 5 runs + self.assertEqual(3, len(list(sheet_runs.rows))) # header + 2 runs self.assertEqual(8, len(list(sheet_runs.columns))) self.assertExcelRow( @@ -613,51 +604,6 @@ def test_broadcast_only_flow(self): ], tz, ) - self.assertExcelRow( - sheet_runs, - 3, - [ - contact3_run1.contact.uuid, - "Norbert", - "tel", - "+250788123456", - contact3_run1.created_on, - contact3_run1.modified_on, - contact3_run1.exited_on, - contact3_run1.uuid, - ], - tz, - ) - self.assertExcelRow( - sheet_runs, - 4, - [ - contact1_run2.contact.uuid, - "Eric", - "tel", - "+250788382382", - contact1_run2.created_on, - contact1_run2.modified_on, - contact1_run2.exited_on, - contact1_run2.uuid, - ], - tz, - ) - self.assertExcelRow( - sheet_runs, - 5, - [ - contact2_run2.contact.uuid, - "Nic", - "tel", - "+250788383383", - contact2_run2.created_on, - contact2_run2.modified_on, - contact2_run2.exited_on, - contact2_run2.uuid, - ], - tz, - ) # test without unresponded with self.assertNumQueries(10): diff --git a/temba/flows/tests/test_flowcrudl.py b/temba/flows/tests/test_flowcrudl.py index d2b3baca0e5..68135e3e293 100644 --- a/temba/flows/tests/test_flowcrudl.py +++ b/temba/flows/tests/test_flowcrudl.py @@ -1,5 +1,6 @@ import io from datetime import date, datetime, timedelta, timezone as tzone +from decimal import Decimal from unittest.mock import patch from django_redis import get_redis_connection @@ -15,7 +16,9 @@ from temba.templates.models import TemplateTranslation from temba.tests import CRUDLTestMixin, TembaTest, matchers, mock_mailroom from temba.tests.base import get_contact_search +from temba.tests.requests import MockJsonResponse from temba.triggers.models import Trigger +from temba.utils import json from temba.utils.uuid import uuid4 from temba.utils.views.mixins import TEMBA_MENU_SELECTION @@ -676,8 +679,8 @@ def test_get_definition(self): self.assertEqual("Amazing Flow", flow.get_definition()["name"]) # make a flow that looks like a legacy flow - flow = self.get_flow("color_v11") - original_def = self.load_json("test_flows/color_v11.json")["flows"][0] + flow = self.get_flow("legacy/color_v11") + original_def = self.load_json("test_flows/legacy/color_v11.json")["flows"][0] flow.version_number = "11.12" flow.save(update_fields=("version_number",)) @@ -703,11 +706,11 @@ def test_get_definition(self): self.assertEqual("Amazing Flow 2", flow.get_definition()["metadata"]["name"]) def test_revisions(self): - flow = self.get_flow("color_v11") + flow = self.get_flow("legacy/color_v11") revisions_url = reverse("flows.flow_revisions", args=[flow.uuid]) - original_def = self.load_json("test_flows/color_v11.json")["flows"][0] + original_def = self.load_json("test_flows/legacy/color_v11.json")["flows"][0] # rewind definition to legacy spec revision = flow.revisions.get() @@ -1329,7 +1332,7 @@ def test_broadcast_background_flow(self, mr_mocks): self.assertEqual('name ~ "frank"', start.query) def test_copy_view(self): - flow = self.get_flow("color") + flow = self.get_flow("color_v13") self.login(self.admin) @@ -1862,6 +1865,108 @@ def test_export_results(self): export.config, ) + def test_simulate(self): + flow = self.create_flow("Test") + + # create our payload + payload = dict(version=2, trigger={}, flow={}) + + self.login(self.admin) + simulate_url = reverse("flows.flow_simulate", args=[flow.pk]) + + with override_settings(MAILROOM_AUTH_TOKEN="sesame", MAILROOM_URL="https://mailroom.temba.io"): + with patch("requests.post") as mock_post: + mock_post.return_value = MockJsonResponse(400, {"session": {}}) + response = self.client.post(simulate_url, json.dumps(payload), content_type="application/json") + self.assertEqual(500, response.status_code) + + # start a flow + with patch("requests.post") as mock_post: + mock_post.return_value = MockJsonResponse(200, {"session": {}}) + response = self.client.post(simulate_url, json.dumps(payload), content_type="application/json") + self.assertEqual(200, response.status_code) + self.assertEqual({}, response.json()["session"]) + + actual_url = mock_post.call_args_list[0][0][0] + actual_payload = json.loads(mock_post.call_args_list[0][1]["data"]) + actual_headers = mock_post.call_args_list[0][1]["headers"] + + self.assertEqual(actual_url, "https://mailroom.temba.io/mr/sim/start") + self.assertEqual(actual_payload["org_id"], flow.org_id) + self.assertEqual(actual_payload["trigger"]["environment"]["date_format"], "DD-MM-YYYY") + self.assertEqual(len(actual_payload["assets"]["channels"]), 1) # fake channel + self.assertEqual(len(actual_payload["flows"]), 1) + self.assertEqual(actual_headers["Authorization"], "Token sesame") + self.assertEqual(actual_headers["Content-Type"], "application/json") + + # try a resume + payload = { + "version": 2, + "session": {"contact": {"fields": {"age": Decimal("39")}}}, + "resume": {}, + "flow": {}, + } + + with patch("requests.post") as mock_post: + mock_post.return_value = MockJsonResponse(400, {"session": {}}) + response = self.client.post(simulate_url, json.dumps(payload), content_type="application/json") + self.assertEqual(500, response.status_code) + + with patch("requests.post") as mock_post: + mock_post.return_value = MockJsonResponse(200, {"session": {}}) + response = self.client.post(simulate_url, json.dumps(payload), content_type="application/json") + self.assertEqual(200, response.status_code) + self.assertEqual({}, response.json()["session"]) + + actual_url = mock_post.call_args_list[0][0][0] + actual_payload = json.loads(mock_post.call_args_list[0][1]["data"]) + actual_headers = mock_post.call_args_list[0][1]["headers"] + + self.assertEqual(actual_url, "https://mailroom.temba.io/mr/sim/resume") + self.assertEqual(actual_payload["org_id"], flow.org_id) + self.assertEqual(actual_payload["resume"]["environment"]["date_format"], "DD-MM-YYYY") + self.assertEqual(len(actual_payload["assets"]["channels"]), 1) # fake channel + self.assertEqual(len(actual_payload["flows"]), 1) + self.assertEqual(actual_headers["Authorization"], "Token sesame") + self.assertEqual(actual_headers["Content-Type"], "application/json") + + def test_simulate_voice(self): + flow = self.create_flow("Test", flow_type=Flow.TYPE_VOICE) + + self.login(self.admin) + simulate_url = reverse("flows.flow_simulate", args=[flow.id]) + + with override_settings(MAILROOM_AUTH_TOKEN="sesame", MAILROOM_URL="https://mailroom.temba.io"): + with patch("requests.post") as mock_post: + mock_post.return_value = MockJsonResponse(200, {"session": {}}) + response = self.client.post( + simulate_url, {"version": 2, "trigger": {}, "flow": {}}, content_type="application/json" + ) + + self.assertEqual(response.status_code, 200) + self.assertEqual(response.json(), {"session": {}}) + + # since this is an IVR flow, the session trigger will have a connection + self.assertEqual( + { + "call": { + "channel": {"uuid": "440099cf-200c-4d45-a8e7-4a564f4a0e8b", "name": "Test Channel"}, + "urn": "tel:+12065551212", + }, + "environment": { + "date_format": "DD-MM-YYYY", + "time_format": "tt:mm", + "timezone": "Africa/Kigali", + "allowed_languages": ["eng", "kin"], + "default_country": "RW", + "redaction_policy": "none", + "input_collation": "default", + }, + "user": {"email": "admin@textit.com", "name": "Andy"}, + }, + json.loads(mock_post.call_args[1]["data"])["trigger"], + ) + def test_export_and_download_translation(self): self.org.set_flow_languages(self.admin, ["spa"]) diff --git a/temba/flows/tests/test_simulation.py b/temba/flows/tests/test_simulation.py deleted file mode 100644 index d7f250005bf..00000000000 --- a/temba/flows/tests/test_simulation.py +++ /dev/null @@ -1,136 +0,0 @@ -import decimal -from unittest.mock import patch - -from django.test.utils import override_settings -from django.urls import reverse -from django.utils import timezone - -from temba.tests import MockJsonResponse, TembaTest -from temba.utils import json -from temba.utils.uuid import uuid4 - - -class SimulationTest(TembaTest): - def add_message(self, payload, text): - """ - Add a message to the payload for the flow server using the default contact - """ - payload["resume"] = { - "type": "msg", - "resumed_on": timezone.now().isoformat(), - "msg": {"text": text, "uuid": str(uuid4()), "urn": "tel:+12065551212"}, - } - - def get_replies(self, response): - """ - Gets any replies in a response from the flow server as a list of strings - """ - replies = [] - for event in response.get("events", []): - if event["type"] == "broadcast_created": - replies.append(event["translations"][event["base_language"]]["text"]) - elif event["type"] == "msg_created": - replies.append(event["msg"]["text"]) - return replies - - def test_simulation_ivr(self): - self.login(self.admin) - flow = self.get_flow("ivr") - - # create our payload - payload = {"version": 2, "trigger": {}, "flow": {}} - url = reverse("flows.flow_simulate", args=[flow.id]) - - with override_settings(MAILROOM_AUTH_TOKEN="sesame", MAILROOM_URL="https://mailroom.temba.io"): - with patch("requests.post") as mock_post: - mock_post.return_value = MockJsonResponse(200, {"session": {}}) - response = self.client.post(url, payload, content_type="application/json") - - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json(), {"session": {}}) - - # since this is an IVR flow, the session trigger will have a connection - self.assertEqual( - { - "call": { - "channel": {"uuid": "440099cf-200c-4d45-a8e7-4a564f4a0e8b", "name": "Test Channel"}, - "urn": "tel:+12065551212", - }, - "environment": { - "date_format": "DD-MM-YYYY", - "time_format": "tt:mm", - "timezone": "Africa/Kigali", - "allowed_languages": ["eng", "kin"], - "default_country": "RW", - "redaction_policy": "none", - "input_collation": "default", - }, - "user": {"email": "admin@textit.com", "name": "Andy"}, - }, - json.loads(mock_post.call_args[1]["data"])["trigger"], - ) - - def test_simulation(self): - self.login(self.admin) - flow = self.get_flow("favorites") - - # create our payload - payload = dict(version=2, trigger={}, flow={}) - - url = reverse("flows.flow_simulate", args=[flow.pk]) - - with override_settings(MAILROOM_AUTH_TOKEN="sesame", MAILROOM_URL="https://mailroom.temba.io"): - with patch("requests.post") as mock_post: - mock_post.return_value = MockJsonResponse(400, {"session": {}}) - response = self.client.post(url, json.dumps(payload), content_type="application/json") - self.assertEqual(500, response.status_code) - - # start a flow - with patch("requests.post") as mock_post: - mock_post.return_value = MockJsonResponse(200, {"session": {}}) - response = self.client.post(url, json.dumps(payload), content_type="application/json") - self.assertEqual(200, response.status_code) - self.assertEqual({}, response.json()["session"]) - - actual_url = mock_post.call_args_list[0][0][0] - actual_payload = json.loads(mock_post.call_args_list[0][1]["data"]) - actual_headers = mock_post.call_args_list[0][1]["headers"] - - self.assertEqual(actual_url, "https://mailroom.temba.io/mr/sim/start") - self.assertEqual(actual_payload["org_id"], flow.org_id) - self.assertEqual(actual_payload["trigger"]["environment"]["date_format"], "DD-MM-YYYY") - self.assertEqual(len(actual_payload["assets"]["channels"]), 1) # fake channel - self.assertEqual(len(actual_payload["flows"]), 1) - self.assertEqual(actual_headers["Authorization"], "Token sesame") - self.assertEqual(actual_headers["Content-Type"], "application/json") - - # try a resume - payload = { - "version": 2, - "session": {"contact": {"fields": {"age": decimal.Decimal("39")}}}, - "resume": {}, - "flow": {}, - } - - with patch("requests.post") as mock_post: - mock_post.return_value = MockJsonResponse(400, {"session": {}}) - response = self.client.post(url, json.dumps(payload), content_type="application/json") - self.assertEqual(500, response.status_code) - - with patch("requests.post") as mock_post: - mock_post.return_value = MockJsonResponse(200, {"session": {}}) - response = self.client.post(url, json.dumps(payload), content_type="application/json") - self.assertEqual(200, response.status_code) - self.assertEqual({}, response.json()["session"]) - - actual_url = mock_post.call_args_list[0][0][0] - actual_payload = json.loads(mock_post.call_args_list[0][1]["data"]) - actual_headers = mock_post.call_args_list[0][1]["headers"] - - self.assertEqual(actual_url, "https://mailroom.temba.io/mr/sim/resume") - self.assertEqual(actual_payload["org_id"], flow.org_id) - self.assertEqual(actual_payload["resume"]["environment"]["date_format"], "DD-MM-YYYY") - self.assertEqual(len(actual_payload["assets"]["channels"]), 1) # fake channel - self.assertEqual(len(actual_payload["flows"]), 1) - self.assertEqual(actual_headers["Authorization"], "Token sesame") - self.assertEqual(actual_headers["Content-Type"], "application/json") diff --git a/temba/orgs/tests.py b/temba/orgs/tests.py index acb8efa86aa..679a5d0de21 100644 --- a/temba/orgs/tests.py +++ b/temba/orgs/tests.py @@ -1248,7 +1248,7 @@ def test_import(self): # try a file which can be migrated forwards response = self.client.post( create_url, - {"file": open("%s/test_flows/favorites_v4.json" % settings.MEDIA_ROOT, "rb")}, + {"file": open("%s/test_flows/legacy/migrations/favorites_v4.json" % settings.MEDIA_ROOT, "rb")}, ) self.assertEqual(302, response.status_code) @@ -1381,7 +1381,7 @@ def test_import_flow_issues(self, mr_mocks): # final call is after new flows and dependencies have been committed so mailroom can see them mr_mocks.flow_inspect(dependencies=[{"key": "age", "name": "", "type": "field", "missing": False}]) - self.import_file("test_flows/color.json") + self.import_file("test_flows/color_v13.json") flow = Flow.objects.get() @@ -1826,9 +1826,7 @@ def assert_object_counts(): self.assertNotContains(response, "Register Patient") def test_prevent_flow_type_changes(self): - flow1 = self.get_flow("favorites") - flow1.name = "Background" - flow1.save(update_fields=("name",)) + flow1 = self.create_flow("Background") flow2 = self.get_flow("background") # contains a flow called Background