diff --git a/web/simulation/simulation.go b/web/simulation/simulation.go index 8a1d44a1f..4d6793a2c 100644 --- a/web/simulation/simulation.go +++ b/web/simulation/simulation.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" + "github.com/nyaruka/gocommon/urns" "github.com/nyaruka/goflow/assets" "github.com/nyaruka/goflow/assets/static/types" "github.com/nyaruka/goflow/excellent/tools" @@ -21,6 +22,9 @@ import ( "github.com/pkg/errors" ) +var testChannel = assets.NewChannelReference("440099cf-200c-4d45-a8e7-4a564f4a0e8b", "Test Channel") +var testURN = urns.URN("tel:+12065551212") + func init() { web.RegisterJSONRoute(http.MethodPost, "/mr/sim/start", web.RequireAuthToken(handleStart)) web.RegisterJSONRoute(http.MethodPost, "/mr/sim/resume", web.RequireAuthToken(handleResume)) @@ -230,8 +234,18 @@ func handleResume(ctx context.Context, rt *runtime.Runtime, r *http.Request) (in } if triggeredFlow != nil { - trigger := triggers.NewBuilder(oa.Env(), triggeredFlow.FlowReference(), resume.Contact()).Msg(msgResume.Msg()).WithMatch(trigger.Match()).Build() - return triggerFlow(ctx, rt, oa, trigger) + tb := triggers.NewBuilder(oa.Env(), triggeredFlow.FlowReference(), resume.Contact()) + + var sessionTrigger flows.Trigger + if triggeredFlow.FlowType() == models.FlowTypeVoice { + // TODO this should trigger a msg trigger with a connection but first we need to rework + // non-simulation IVR triggers to use that so that this is consistent. + sessionTrigger = tb.Manual().WithConnection(testChannel, testURN).Build() + } else { + sessionTrigger = tb.Msg(msgResume.Msg()).WithMatch(trigger.Match()).Build() + } + + return triggerFlow(ctx, rt, oa, sessionTrigger) } } } diff --git a/web/simulation/simulation_test.go b/web/simulation/simulation_test.go index bc1d641ff..bc7033772 100644 --- a/web/simulation/simulation_test.go +++ b/web/simulation/simulation_test.go @@ -88,60 +88,7 @@ const ( "name": "Twitter", "uuid": "0f661e8b-ea9d-4bd3-9953-d368340acf91" }, - "text": "I like blue!", - "urn": "tel:+12065551212", - "uuid": "9bf91c2b-ce58-4cef-aacc-281e03f69ab5" - }, - "resumed_on": "2000-01-01T00:00:00.000000000-00:00", - "type": "msg" - }, - "assets": { - "channels": [ - { - "uuid": "440099cf-200c-4d45-a8e7-4a564f4a0e8b", - "name": "Test Channel", - "address": "+18005551212", - "schemes": ["tel"], - "roles": ["send", "receive", "call"], - "country": "US" - } - ] - }, - "session": $$SESSION$$ - }` - - triggerResumeBody = ` - { - "org_id": 1, - "resume": { - "contact": { - "created_on": "2000-01-01T00:00:00.000000000-00:00", - "fields": {}, - "id": 1234567, - "language": "eng", - "name": "Ben Haggerty", - "timezone": "America/Guayaquil", - "urns": [ - "tel:+12065551212" - ], - "uuid": "ba96bf7f-bc2a-4873-a7c7-254d1927c4e3" - }, - "environment": { - "allowed_languages": [ - "eng", - "fra" - ], - "date_format": "YYYY-MM-DD", - "default_language": "eng", - "time_format": "hh:mm", - "timezone": "America/New_York" - }, - "msg": { - "channel": { - "name": "Twitter", - "uuid": "0f661e8b-ea9d-4bd3-9953-d368340acf91" - }, - "text": "trigger", + "text": "$$MESSAGE$$", "urn": "tel:+12065551212", "uuid": "9bf91c2b-ce58-4cef-aacc-281e03f69ab5" }, @@ -263,39 +210,52 @@ func TestServer(t *testing.T) { time.Sleep(time.Second) defer server.Stop() - session := "" + + var session json.RawMessage // add a trigger for our campaign flow with 'trigger' testdata.InsertKeywordTrigger(db, testdata.Org1, testdata.CampaignFlow, "trigger", models.MatchOnly, nil, nil) + // and a trigger which will trigger an IVR flow + testdata.InsertKeywordTrigger(db, testdata.Org1, testdata.IVRFlow, "ivr", models.MatchOnly, nil, nil) + // also add a catch all testdata.InsertCatchallTrigger(db, testdata.Org1, testdata.CampaignFlow, nil, nil) tcs := []struct { - URL string - Method string - Body string - Status int - Response string + URL string + Method string + Body string + Message string + ExpectedStatus int + ExpectedResponse string }{ - {"/mr/sim/start", "GET", "", 405, "illegal"}, - {"/mr/sim/start", "POST", startBody, 200, "What is your favorite color?"}, - {"/mr/sim/resume", "GET", "", 405, "illegal"}, - {"/mr/sim/resume", "POST", resumeBody, 200, "Good choice, I like Blue too! What is your favorite beer?"}, - {"/mr/sim/start", "POST", customStartBody, 200, "Your channel is Test Channel"}, - {"/mr/sim/start", "POST", startBody, 200, "What is your favorite color?"}, - {"/mr/sim/resume", "POST", triggerResumeBody, 200, "it is time to consult with your patients"}, - {"/mr/sim/resume", "POST", resumeBody, 200, "it is time to consult with your patients"}, + {"/mr/sim/start", "GET", "", "", 405, "illegal"}, + {"/mr/sim/start", "POST", startBody, "", 200, "What is your favorite color?"}, + {"/mr/sim/resume", "POST", resumeBody, "I like blue!", 200, "Good choice, I like Blue too! What is your favorite beer?"}, + + // start with a definition of the flow to override what we have in assets + {"/mr/sim/start", "POST", customStartBody, "", 200, "Your channel is Test Channel"}, + + // start regular flow again but resume with a message that matches the campaign flow trigger + {"/mr/sim/start", "POST", startBody, "", 200, "What is your favorite color?"}, + {"/mr/sim/resume", "POST", resumeBody, "trigger", 200, "it is time to consult with your patients"}, + {"/mr/sim/resume", "POST", resumeBody, "I like blue!", 200, "it is time to consult with your patients"}, + + // start favorties again but this time resume with a message that matches the IVR flow trigger + {"/mr/sim/start", "POST", startBody, "", 200, "What is your favorite color?"}, + {"/mr/sim/resume", "POST", resumeBody, "ivr", 200, "Hello there. Please enter one or two."}, } for i, tc := range tcs { - var body io.Reader + bodyStr := strings.Replace(tc.Body, "$$MESSAGE$$", tc.Message, -1) // in the case of a resume, we have to sub in our session body from our start - tc.Body = strings.Replace(tc.Body, "$$SESSION$$", session, -1) + bodyStr = strings.Replace(bodyStr, "$$SESSION$$", string(session), -1) + var body io.Reader if tc.Body != "" { - body = bytes.NewReader([]byte(tc.Body)) + body = bytes.NewReader([]byte(bodyStr)) } req, err := http.NewRequest(tc.Method, "http://localhost:8090"+tc.URL, body) @@ -304,7 +264,7 @@ func TestServer(t *testing.T) { resp, err := http.DefaultClient.Do(req) assert.NoError(t, err, "%d: error making request", i) - assert.Equal(t, tc.Status, resp.StatusCode, "%d: unexpected status", i) + assert.Equal(t, tc.ExpectedStatus, resp.StatusCode, "%d: unexpected status", i) content, err := ioutil.ReadAll(resp.Body) assert.NoError(t, err, "%d: error reading body", i) @@ -313,9 +273,8 @@ func TestServer(t *testing.T) { if resp.StatusCode == 200 { // save the session for use in a resume parsed := make(map[string]interface{}) - json.Unmarshal(content, &parsed) - sessionJSON := jsonx.MustMarshal(parsed["session"]) - session = string(sessionJSON) + jsonx.MustUnmarshal(content, &parsed) + session = jsonx.MustMarshal(parsed["session"]) context, hasContext := parsed["context"] if hasContext { @@ -324,6 +283,6 @@ func TestServer(t *testing.T) { } } - assert.True(t, strings.Contains(string(content), tc.Response), "%d: did not find string: %s in body: %s", i, tc.Response, string(content)) + assert.Contains(t, string(content), tc.ExpectedResponse, "%d: did not find expected response content") } }