Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit ec949d34ca3e11a736eee2da81227c774ef30872 1 parent 676e913
@mpermar mpermar authored
View
87 test/unit/com/tropo/grails/MockHTTPHelper.groovy
@@ -0,0 +1,87 @@
+package com.tropo.grails
+
+import grails.converters.JSON;
+
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import static groovyx.net.http.ContentType.*
+import static groovyx.net.http.Method.*
+
+class MockHTTPHelper extends HTTPHelper {
+
+ private launch_session_response_json = JSONObject.fromObject("{id='e81f20b21c9e2ee5fe874b9c578f2ab0', requestParams={token='72979191d971e344b46a0e4a3485571844250e689bb13548a75f1cce2ce9a53dde82c3fe944479bcb650500e'}, success='true', token='72979191d971e344b46a0e4a3485571844250e689bb13548a75f1cce2ce9a53dde82c3fe944479bcb650500e'}")
+ private launch_session_response_json_multiple_params = JSONObject.fromObject("{id:'e81f20b21c9e2ee5fe874b9c578f2ab0', requestParams:{token='72979191d971e344b46a0e4a3485571844250e689bb13548a75f1cce2ce9a53dde82c3fe944479bcb650500e', customerName='JohnDyer', numberToDial='4075551212', msg='the sky is falling.'}, success='true', token='72979191d971e344b46a0e4a3485571844250e689bb13548a75f1cce2ce9a53dde82c3fe944479bcb650500e'}")
+ private list_applications = [['id':'136290','href':'https://api.tropo.com/v1/applications/136290','name':'GrailsPluginTestsApp','platform':'scripting','voiceUrl':'http://www.website.com/index.json','messagingUrl':'http://www.website2.com/index.json','partition':'staging'],['id':'136168','href':'https://api.tropo.com/v1/applications/136168','name':'GrailsTropoApp','platform':'webapi','voiceUrl':'http://77.27.59.2:8080/tropo-app/tropo/jordi','messagingUrl':'http://77.27.59.2:8080/tropo-app/tropo/json','partition':'staging'],['id':'134827','href':'https://api.tropo.com/v1/applications/134827','name':'Placeo','platform':'webapi','voiceUrl':'http://77.27.59.2:8080/placeo/placeo/json','messagingUrl':'http://77.27.59.2:8080/placeo/placeo/json','partition':'staging'],['id':'134167','href':'https://api.tropo.com/v1/applications/134167','name':'test','platform':'scripting','voiceUrl':'http://test.com/test.rb','messagingUrl':'http://test.com/test.rb','partition':'staging'],['id':'134153','href':'https://api.tropo.com/v1/applications/134153','name':'TestMartinScripting','platform':'scripting','voiceUrl':'http://hosting.tropo.com/58863/www/testmartin.js','messagingUrl':'http://hosting.tropo.com/58863/www/testmartin.js','partition':'staging'],['id':'134109','href':'https://api.tropo.com/v1/applications/134109','name':'TestMartin','platform':'webapi','voiceUrl':'http://77.27.59.2:8080/tropo-test/tropo/json','messagingUrl':'http://77.27.59.2:8080/tropo-test/tropo/jsonsms','partition':'staging']]
+ private create_application = JSONObject.fromObject("{href:'https://api.tropo.com/v1/applications/136472', requestParams:{name='testapp516647780', voiceUrl='http://website.com', messagingUrl='http://website2.com', platform='scripting', partition:'staging'}, appId='136472'}")
+ private delete = JSONObject.fromObject("{'message':'delete successful','requestParams':{}}")
+ private add_number_prefix_1 = ['href':'https://api.tropo.com/v1/applications/136290/addresses/number/+14076800712', 'requestParams':['type':'number', 'prefix':'1407'], 'appId':'136290', 'numberId':'+14076800712']
+ private add_number_prefix_2 = ['href':'https://api.tropo.com/v1/applications/136290/addresses/number/+34000111000', 'requestParams':['type':'number', 'prefix':'34'], 'appId':'136290', 'numberId':'+134000111000']
+ private add_number_prefix_3 = ['href':'https://api.tropo.com/v1/applications/136290/addresses/number/+1886000111000', 'requestParams':['type':'number', 'prefix':'34'], 'appId':'136290', 'numberId':'+1886000111000']
+ private add_token = ['href':'https://api.tropo.com/v1/applications/136290/addresses/token/949a4221be165645ba227de3b4d1a1d9cb41377b972f66595115a1832ee1491c9f326f8236d17e2e613be80e', 'requestParams':['type':'token', 'channel':'voice'], 'appId':'136290', 'token':'949a4221be165645ba227de3b4d1a1d9cb41377b972f66595115a1832ee1491c9f326f8236d17e2e613be80e']
+ private list_addresses = [['href':'https://api.tropo.com/v1/applications/136290/addresses/sip/9992003056@sip.tropo.com', 'type':'sip', 'address':'9992003056@sip.tropo.com'], ['href':'https://api.tropo.com/v1/applications/136290/addresses/skype/+990009369992003056', 'type':'skype', 'number':'+990009369992003056']]
+ private list_exchanges = [['prefix':'1510', 'city':'Richmond', 'state':'CA', 'country':'United States', 'description':'Phone Number w/ SMS'], ['prefix':'1407', 'city':'Orlando', 'state':'FL', 'country':'United States', 'description':'Phone Number w/ SMS']]
+ private send_signal = ['requestParams':['value':'exit'], 'status':'QUEUED']
+ private update_application = ['requestParams':['name':'GrailsPluginTestsApp', 'platform':'webapi', 'partition': 'staging','appId':'136290'],'name':'GrailsPluginTestsApp', 'platform':'webapi', 'partition': 'staging']
+ private add_aim = ['requestParams':['type':'aim', 'username':'tropocloud', 'password': 'password01','appId':'136290'],'href':'https://api.tropo.com/v1/applications/123456/addresses/aim/tropocloud']
+ private add_number = ['requestParams':['type':'number', 'number':'4075551235'],'href':'https://api.tropo.com/v1/applications/addresses/number/+14075551235']
+
+ public MockHTTPHelper(username, password) {
+
+ super(username,password)
+ }
+
+ def Object doRequest(url, params, method) {
+
+ println "Doing Fake Request : ${url} with params ${params} and method ${method}"
+ if (url == 'https://api.tropo.com/v1/sessions?action=create') {
+ if (params.customerName) {
+ return launch_session_response_json_multiple_params
+ } else {
+ return launch_session_response_json
+ }
+ } else if (url == 'https://api.tropo.com/v1/applications') {
+ if (method == POST) {
+ return create_application
+ } else if (method == GET) {
+ return list_applications
+ }
+ } else if (url == 'https://api.tropo.com/v1/applications/136472') {
+ if (method == DELETE) {
+ return delete
+ }
+ } else if (url == 'https://api.tropo.com/v1/applications/136290') {
+ if (method == PUT) {
+ return update_application
+ }
+ } else if (url == 'https://api.tropo.com/v1/applications/136290/addresses') {
+ if (params.prefix) {
+ if (params.prefix == '1407') {
+ return add_number_prefix_1
+ } else if (params.prefix == '34') {
+ return add_number_prefix_2
+ } else if (params.prefix == '1886') {
+ return add_number_prefix_3
+ }
+ } else if (params.type == 'token') {
+ return add_token
+ } else if (params.type == 'aim') {
+ return add_aim
+ } else if (params.type == 'number') {
+ return add_number
+ } else if (url == 'https://api.tropo.com/v1/applications/136290/addresses') {
+ return list_addresses
+ }
+ } else if (url == 'https://api.tropo.com/v1/applications/136290/addresses/number/+14076800712') {
+ return delete
+ } else if (url == 'https://api.tropo.com/v1/applications/136290/addresses/number/+134000111000') {
+ return delete
+ } else if (url == 'https://api.tropo.com/v1/applications/136290/addresses/number/+1886000111000') {
+ return delete
+ } else if (url == 'https://api.tropo.com/v1/exchanges') {
+ return list_exchanges
+ } else if (url == 'https://api.tropo.com/v1/sessions/e81f20b21c9e2ee5fe874b9c578f2ab0/signals') {
+ return send_signal
+ }
+ }
+}
+
View
678 test/unit/com/tropo/grails/TropoBuilderTests.groovy
@@ -0,0 +1,678 @@
+package com.tropo.grails
+
+import groovy.util.GroovyTestCase;
+
+import java.util.Map
+
+
+class TropoBuilderTests extends GroovyTestCase {
+
+ public void testAskAction() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ ask(name : 'foo', bargein: true, timeout: 30, required: true)
+ }
+ assert builder.text() == "{\"tropo\":[{\"ask\":{\"name\":\"foo\",\"bargein\":true,\"timeout\":30,\"required\":true}}]}"
+ }
+
+ public void testAskWithSayBlock() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ ask(name : 'foo', bargein: true, timeout: 30, required: true, choices: '[5 DIGITS]') {
+ say('Please say your account number')
+ }
+ }
+ assert builder.text() == "{\"tropo\":[{\"ask\":{\"name\":\"foo\",\"bargein\":true,\"timeout\":30,\"required\":true,\"choices\":[\"5 DIGITS\"],\"say\":[{\"value\":\"Please say your account number\"}]}}]}"
+
+ }
+
+ public void testAskWithSayAndOnBlocks() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ ask(name : 'foo', bargein: true, timeout: 30, required: true) {
+ say('Please say your account number')
+ on(event:'success',next:'/result.json')
+ choices(value: '[5 DIGITS]')
+ }
+ }
+ assert builder.text() == "{\"tropo\":[{\"ask\":{\"name\":\"foo\",\"bargein\":true,\"timeout\":30,\"required\":true,\"say\":[{\"value\":\"Please say your account number\"}],\"on\":[{\"event\":\"success\",\"next\":\"/result.json\"}],\"choices\":{\"value\":\"[5 DIGITS]\"}}}]}"
+ }
+
+ public void testFailsAskWithNoNameParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ ask(foo:'bar')
+ }
+ }
+ assert message == "Missing required property: 'name'"
+ }
+
+ public void testChoice() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ choices(value: '[5 DIGITS]')
+ }
+ assert builder.text() == "{\"tropo\":[{\"choices\":{\"value\":\"[5 DIGITS]\"}}]}"
+ }
+
+ public void testFailsChoicesWithUnsupportedMode() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ choices(value:'[5 DIGITS]', mode:'frootloops')
+ }
+ }
+ assert message == "If mode is provided, only 'dtmf', 'speech' or 'any' is supported"
+ }
+
+ public void testChoiceWithMode() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ choices(value: '[5 DIGITS]', mode: 'dtmf')
+ }
+ assert builder.text() == "{\"tropo\":[{\"choices\":{\"value\":\"[5 DIGITS]\",\"mode\":\"dtmf\"}}]}"
+ }
+
+ public void testConference() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ conference(name : 'foo', id: '1234', mute: false, send_tones: false, exit_tone: '#')
+ }
+ assert builder.text() == "{\"tropo\":[{\"conference\":{\"name\":\"foo\",\"id\":\"1234\",\"mute\":false,\"send_tones\":false,\"exit_tone\":\"#\"}}]}"
+ }
+
+ public void testConferenceWithOnAndSayBlocks() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ conference(name: 'foo', id: '1234', mute: false, send_tones: false, exit_tone: '#') {
+ on(event: 'join') {
+ say(value: 'Welcome to the conference')
+ }
+ on(event:'leave') {
+ say(value: 'Someone has left the conference')
+ }
+ }
+ }
+ assert builder.text() == "{\"tropo\":[{\"conference\":{\"name\":\"foo\",\"id\":\"1234\",\"mute\":false,\"send_tones\":false,\"exit_tone\":\"#\",\"on\":[{\"event\":\"join\",\"say\":[{\"value\":\"Welcome to the conference\"}]},{\"event\":\"leave\",\"say\":[{\"value\":\"Someone has left the conference\"}]}]}}]}"
+ }
+
+ public void testFailsConferenceWithNoNameParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ conference(foo:'bar')
+ }
+ }
+ assert message == "Missing required property: 'name'"
+ }
+
+ public void testFailsConferenceWithNoIdParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ conference(name:'bar')
+ }
+ }
+ assert message == "Missing required property: 'id'"
+ }
+
+ public void testHangup() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ hangup()
+ }
+ assert builder.text() == "{\"tropo\":[{\"hangup\":null}]}"
+ }
+
+ public void testOn() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ on(event: 'hangup', next: 'myresource')
+ }
+ assert builder.text() == "{\"tropo\":[{\"on\":{\"event\":\"hangup\",\"next\":\"myresource\"}}]}"
+ }
+
+ public void testFailsOnWithNoEventParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ on(foo: 'bar', next: 'myresource')
+ }
+ }
+ assert message == "Missing required property: 'event'"
+ }
+
+ public void testRecord() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ record(name: 'foo', url: 'http://sendme.com/tropo', beep: true, send_tones: false, exit_tone: '#')
+ }
+ assert builder.text() == "{\"tropo\":[{\"record\":{\"name\":\"foo\",\"url\":\"http://sendme.com/tropo\",\"beep\":true,\"send_tones\":false,\"exit_tone\":\"#\"}}]}"
+ }
+
+ public void testFailsRecordWithNoNameParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ record(foo:'bar')
+ }
+ }
+ assert message == "Missing required property: 'name'"
+ }
+
+ public void testFailsRecordWithNoUrlParameter() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ record(name:'bar')
+ }
+ }
+ assert message == "Missing required property: 'url'"
+ }
+
+ public void testFailsRecordWithInvalidUrl() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ record(name: 'foo', url: 'invalid' )
+ }
+ }
+ assert message == "The 'url' parameter must be a valid URL"
+ }
+
+ public void testRecordAcceptsEmailAddress() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ record(name: 'foo', url: 'mailto:foo@bar.com', beep: true, send_tones: false, exit_tone: '#')
+ }
+ assert builder.text() == "{\"tropo\":[{\"record\":{\"name\":\"foo\",\"url\":\"foo@bar.com\",\"beep\":true,\"send_tones\":false,\"exit_tone\":\"#\"}}]}"
+ }
+
+ public void testRedirect() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ redirect(to: 'sip:1234', from: '4155551212')
+ }
+ assert builder.text() == "{\"tropo\":[{\"redirect\":{\"to\":\"sip:1234\",\"from\":\"4155551212\"}}]}"
+ }
+
+ public void testFailsNestedRedirect() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ conference(name: 'foo', id: '2334' ) {
+ redirect(to: 'sip:1234', from: '4155551212')
+ }
+ }
+ }
+ assert message == "Redirect should only be used alone and before the session is answered, use transfer instead"
+ }
+
+ public void testFailsRedirectWithNoTo() {
+
+ def builder = new TropoBuilder()
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ redirect(from: '4155551212')
+ }
+ }
+ assert message == "Missing required property: 'to'"
+ }
+
+ public void testReject() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ reject()
+ }
+ assert builder.text() == "{\"tropo\":[{\"reject\":null}]}"
+
+ }
+
+ public void testFailsOnEmptyBuilder() {
+
+ def message = shouldFail(TropoBuilderException) {
+ new TropoBuilder().text()
+ }
+ assert message == "You need a tropo root node!"
+ }
+
+ public void testTropoRoot() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {}
+ assert builder.text() == "{\"tropo\":[]}"
+ }
+
+ public void testSay() {
+
+ def builder = new TropoBuilder()
+
+ builder.tropo {
+ say('1234')
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"1234\"}]}]}"
+ }
+
+ public void testSayWithMapArgument() {
+
+ def builder = new TropoBuilder()
+
+ builder.tropo {
+ say(value:'1234')
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"1234\"}]}]}"
+ }
+
+ public void testFailsWithNumbers() {
+
+ def builder = new TropoBuilder()
+
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ say(1234)
+ }
+ }
+ assert message == "An invalid paramater type class java.lang.Integer has been passed"
+ }
+
+ public void testSayWithArrayArgument() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ say([value: '1234'], [value: 'abcd', event: 'nomatch:1'])
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"1234\"},{\"value\":\"abcd\",\"event\":\"nomatch:1\"}]}]}"
+ }
+
+ public void testSayWithMoreThanTwoArrayArguments() {
+
+ def builder = new TropoBuilder()
+
+ builder.tropo {
+ say([[value: '1234'], [value: 'abcd', event: 'nomatch:1'], [value: 'zywx', event: 'nomatch:2']])
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"1234\"},{\"value\":\"abcd\",\"event\":\"nomatch:1\"},{\"value\":\"zywx\",\"event\":\"nomatch:2\"}]}]}"
+ }
+
+ public void testFailsWithNoValuePassed() {
+
+ def builder = new TropoBuilder()
+
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ say(name:'blah')
+ }
+ }
+ assert message == "Missing required property: 'value'"
+ }
+
+ public void testSayAndOn() {
+
+ TropoBuilder builder = new TropoBuilder()
+ builder.tropo {
+ say(value:'blah')
+ on(event: 'error', next: 'error.json')
+
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"blah\"}]},{\"on\":{\"event\":\"error\",\"next\":\"error.json\"}}]}"
+ }
+
+ public void testStartRecording() {
+
+ TropoBuilder builder = new TropoBuilder()
+ builder.tropo {
+ startRecording(url:'http://postrecording.com/tropo')
+ }
+ assert builder.text() == "{\"tropo\":[{\"startRecording\":{\"url\":\"http://postrecording.com/tropo\"}}]}"
+ }
+
+ public void testStopRecording() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ stopRecording()
+ }
+ assert builder.text() == "{\"tropo\":[{\"stopRecording\":null}]}"
+
+ }
+
+ public void testTransfer() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ transfer(to: 'tel:+14157044517')
+ }
+ assert builder.text() == "{\"tropo\":[{\"transfer\":{\"to\":\"tel:+14157044517\"}}]}"
+ }
+
+ public void testTransferWithOnAndChoices() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ transfer(to: 'tel:+14157044517') {
+ on(event: 'unbounded', next: '/error.json')
+ choices(value: '[5 DIGITS]')
+ }
+ }
+ assert builder.text() == "{\"tropo\":[{\"transfer\":{\"to\":\"tel:+14157044517\",\"on\":[{\"event\":\"unbounded\",\"next\":\"/error.json\"}],\"choices\":{\"value\":\"[5 DIGITS]\"}}}]}"
+ }
+
+ public void testFailsTransferWithNoToParameter() {
+
+ def builder = new TropoBuilder()
+
+ def message = shouldFail(TropoBuilderException) {
+ builder.tropo {
+ transfer()
+ }
+ }
+ assert message == "Missing required property: 'to'"
+ }
+
+ public void testGenerateJsonWhenBlockIsPassed() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ say([value: '1234'], [value: 'abcd', event: 'nomatch:1'])
+ say([value: '0987'], [value: 'zyxw', event: 'nomatch:2'])
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"1234\"},{\"value\":\"abcd\",\"event\":\"nomatch:1\"}]},{\"say\":[{\"value\":\"0987\"},{\"value\":\"zyxw\",\"event\":\"nomatch:2\"}]}]}"
+ }
+
+ public void testParseJsonSession() {
+
+ def builder = new TropoBuilder()
+ def json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
+ def map = builder.parse(json_session)
+ def t = map.session.timestamp
+ assert map.session.timestamp == '2010-01-19T23:18:48.562Z'
+ }
+
+ public void testShouldSeeObjectOutsideBlock() {
+
+ def builder = new TropoBuilder()
+ def t = 'foobar'
+ def newt
+ builder.tropo {
+ newt = t
+ say(value:'blah')
+ on(event:'error', next:'error.json')
+ }
+ assert newt == 'foobar'
+ }
+
+ public void testTwoSaysInBlock() {
+
+ def builder = new TropoBuilder()
+ builder.tropo {
+ say('foo')
+ say('bar')
+ }
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"foo\"}]},{\"say\":[{\"value\":\"bar\"}]}]}"
+ }
+
+ public void testTwoSaysSeparated() {
+
+ def builder = new TropoBuilder()
+ builder.say('foo')
+ builder.say('bar')
+
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"foo\"}]},{\"say\":[{\"value\":\"bar\"}]}]}"
+ }
+
+ public void testSayOnAndRecordSeparated() {
+
+ def builder = new TropoBuilder()
+ builder.say('Welcome to the app')
+ builder.on(event: 'hangup', next: '/hangup.json')
+ builder.record(name: 'foo', beep: true, send_tones: false, exit_tone: '#', url: 'http://sendme.com/tropo') {
+ say(value: 'Please say your account number')
+ choices(value: '[5 DIGITS]')
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"say\":[{\"value\":\"Welcome to the app\"}]},{\"on\":{\"event\":\"hangup\",\"next\":\"/hangup.json\"}},{\"record\":{\"name\":\"foo\",\"beep\":true,\"send_tones\":false,\"exit_tone\":\"#\",\"url\":\"http://sendme.com/tropo\",\"say\":[{\"value\":\"Please say your account number\"}],\"choices\":{\"value\":\"[5 DIGITS]\"}}}]}"
+ }
+
+ public void testReset() {
+
+ def builder = new TropoBuilder()
+ builder.ask(name : 'foo', bargein: true, timeout: 30, required: true)
+ assert builder.text() == "{\"tropo\":[{\"ask\":{\"name\":\"foo\",\"bargein\":true,\"timeout\":30,\"required\":true}}]}"
+
+ builder.reset()
+ assert builder.text() == "{\"tropo\":[]}"
+ }
+
+ public void testResultWithActionIsParsed() {
+
+ def builder = new TropoBuilder()
+ def json_result = "{\"result\":{\"sessionId\":\"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20\",\"callState\":\"ANSWERED\",\"sessionDuration\":2,\"sequence\":1,\"complete\":true,\"error\":null,\"actions\":{\"name\":\"zip\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"}}}"
+ def map = builder.parse(json_result)
+
+ assert map.result.actions.name == 'zip'
+ }
+
+ public void testObjectArrivesInJson() {
+
+ def builder = new TropoBuilder()
+ def json_result = "{\"result\":{\"sessionId\":\"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20\",\"callState\":\"ANSWERED\",\"sessionDuration\":2,\"sequence\":1,\"complete\":true,\"error\":null,\"actions\":{\"name\":\"zip\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"}}}"
+ def map = builder.parse(json_result)
+
+ def a = map.result
+ assert map['result']['callState'] == 'ANSWERED'
+ assert map.result.callState == 'ANSWERED'
+ }
+
+ public void testStartRecordingLargeScript() {
+
+ def builder = new TropoBuilder()
+
+ builder.on(event: 'error', next:'/error.json') // For fatal programming errors. Log some details so we can fix it
+ builder.on(event: 'hangup', next:'/hangup.json') // When a user hangs or call is done. We will want to log some details.
+ builder.on(event: 'continue', next:'/next.json')
+ builder.say('Hello')
+ builder.startRecording(url: 'http://heroku-voip.marksilver.net/post_audio_to_s3?filename=foo.wav&unique_id=bar')
+ // [From this point, until stop_recording(), we will record what the caller *and* the IVR say]
+ builder.say 'You are now on the record.'
+ // Prompt the user to incriminate themselve on-the-record
+ builder.say 'Go ahead, sing-along.'
+ builder.say "http://denalidomain.com/music/keepers/HappyHappyBirthdaytoYou-Disney.mp3"
+
+ assert builder.text() == "{\"tropo\":[{\"on\":{\"event\":\"error\",\"next\":\"/error.json\"}},{\"on\":{\"event\":\"hangup\",\"next\":\"/hangup.json\"}},{\"on\":{\"event\":\"continue\",\"next\":\"/next.json\"}},{\"say\":[{\"value\":\"Hello\"}]},{\"startRecording\":{\"url\":\"http://heroku-voip.marksilver.net/post_audio_to_s3?filename=foo.wav&unique_id=bar\"}},{\"say\":[{\"value\":\"You are now on the record.\"}]},{\"say\":[{\"value\":\"Go ahead, sing-along.\"}]},{\"say\":[{\"value\":\"http://denalidomain.com/music/keepers/HappyHappyBirthdaytoYou-Disney.mp3\"}]}]}"
+ }
+
+ /*
+ public void testGenerateVoiceSession() {
+
+ def builder = new TropoBuilder()
+ def json_session = "{\"session\":{\"id\":\"0-13c4-4b563da3-7aecefda-46af-1d10bdd0\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:00.854Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"9991427589\",\"name\":\"unknown\",\"channel\":\"VOICE\",\"network\":\"PSTN\"},\"from\":{\"id\":\"jsgoecke\",\"name\":\"unknown\",\"channel\":\"VOICE\",\"network\":\"PSTN\"}}}"
+ def map = builder.parse(json_session)
+
+ assert builder.voiceSession == true
+ assert builder.textSession == false
+ }
+
+ public void testGenerateTextSession() {
+
+ def builder = new TropoBuilder()
+ def json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
+ def map = builder.parse(json_session)
+
+ assert builder.voiceSession == true
+ assert builder.textSession == false
+ }
+
+ */
+
+ public void testCall() {
+
+ def builder = new TropoBuilder()
+
+ builder.call(to: 'foo', from: 'bar', network: 'SMS', channel: 'TEXT', timeout: 10, answerOnMedia: false) {
+ headers(foo: 'foo', bar: 'bar')
+ recording(url: 'http://foobar', method: 'POST', format: 'audio/mp3', username: 'jose', password: 'passwd')
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"call\":{\"to\":\"foo\",\"from\":\"bar\",\"network\":\"SMS\",\"channel\":\"TEXT\",\"timeout\":10,\"answerOnMedia\":false,\"headers\":{\"foo\":\"foo\",\"bar\":\"bar\"},\"recording\":{\"url\":\"http://foobar\",\"method\":\"POST\",\"format\":\"audio/mp3\",\"username\":\"jose\",\"password\":\"passwd\"}}}]}"
+ }
+
+ public void testMessage() {
+
+ def builder = new TropoBuilder()
+
+ builder.message(to: 'foo', from: 'bar', network: 'SMS', channel: 'TEXT', timeout: 10, answerOnMedia: false) {
+ headers(foo: 'foo', bar: 'bar')
+ recording(url: 'http://foobar', method: 'POST', format: 'audio/mp3', username: 'jose', password: 'passwd')
+ say('Please say your account number')
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"message\":{\"to\":\"foo\",\"from\":\"bar\",\"network\":\"SMS\",\"channel\":\"TEXT\",\"timeout\":10,\"answerOnMedia\":false,\"headers\":{\"foo\":\"foo\",\"bar\":\"bar\"},\"recording\":{\"url\":\"http://foobar\",\"method\":\"POST\",\"format\":\"audio/mp3\",\"username\":\"jose\",\"password\":\"passwd\"},\"say\":[{\"value\":\"Please say your account number\"}]}}]}"
+ }
+
+ public void testRecordWithTranscriptionRequest() {
+
+ def builder = new TropoBuilder()
+
+ builder.record(name: 'foo', url: 'http://sendme.com/tropo', beep: true, sendTones: true, exitTone: '#') {
+ transcription(id: 'bling', url:'mailto:jose@voxeo.com', emailFormat: 'encoded')
+ say('Please say your account number')
+ choices(value: '[5 DIGITS]')
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"record\":{\"name\":\"foo\",\"url\":\"http://sendme.com/tropo\",\"beep\":true,\"sendTones\":true,\"exitTone\":\"#\",\"transcription\":{\"id\":\"bling\",\"url\":\"mailto:jose@voxeo.com\",\"emailFormat\":\"encoded\"},\"say\":[{\"value\":\"Please say your account number\"}],\"choices\":{\"value\":\"[5 DIGITS]\"}}}]}"
+ }
+
+
+ public void testUseMapsInsteadOfMethods() {
+
+ def builder = new TropoBuilder()
+
+ def help_stop_choices = '0(0,help,i do not know, agent, operator, assistance, representative, real person, human), 9(9,quit,stop,shut up)'
+ def yes_no_choices = 'true(1,yes,sure,affirmative), false(2,no,no thank you,negative),' + help_stop_choices
+ builder.ask(name: 'donate_to_id', bargein: true, timeout: 10, silenceTimeout: 10, attempts: 4) {
+ say([[event: 'timeout', value: 'Sorry, I did not hear anything.'],
+ [event: 'nomatch:1 nomatch:2 nomatch:3', value: "Sorry, that wasn't a valid answer. You can press or say 1 for 'yes', or 2 for 'no'."],
+ [value: 'You chose organization foobar. Are you ready to donate to them? If you say no, I will tell you a little more about the organization.'],
+ [event: 'nomatch:3', value: 'This is your last attempt.']])
+ choices(value: yes_no_choices)
+
+ }
+
+ assert builder.text() == "{\"tropo\":[{\"ask\":{\"name\":\"donate_to_id\",\"bargein\":true,\"timeout\":10,\"silenceTimeout\":10,\"attempts\":4,\"say\":[{\"event\":\"timeout\",\"value\":\"Sorry, I did not hear anything.\"},{\"event\":\"nomatch:1 nomatch:2 nomatch:3\",\"value\":\"Sorry, that wasn't a valid answer. You can press or say 1 for 'yes', or 2 for 'no'.\"},{\"value\":\"You chose organization foobar. Are you ready to donate to them? If you say no, I will tell you a little more about the organization.\"},{\"event\":\"nomatch:3\",\"value\":\"This is your last attempt.\"}],\"choices\":{\"value\":\"true(1,yes,sure,affirmative), false(2,no,no thank you,negative),0(0,help,i do not know, agent, operator, assistance, representative, real person, human), 9(9,quit,stop,shut up)\"}}}]}"
+ }
+
+ public void testVoice() {
+
+ def builder = new TropoBuilder()
+ assert builder.voice() == null
+
+ builder = new TropoBuilder(voice: 'barnie')
+ assert builder.voice() == 'barnie'
+
+ builder = new TropoBuilder()
+ builder.voice = 'barnie'
+ assert builder.voice() == 'barnie'
+ }
+
+
+ public void testVoiceHandling() {
+
+ def builder = new TropoBuilder()
+ builder.say('Hi There')
+ assert builder.json().tropo[0].say[0].voice == null
+
+ builder = new TropoBuilder()
+ builder.say('Hi there', voice: 'barnie')
+ assert builder.json().tropo[0].say[0].voice == 'barnie'
+
+ builder = new TropoBuilder(voice: 'barnie')
+ builder.say('Hi There')
+ builder.say('Wow!')
+ assert builder.json().tropo[0].say[0].voice == 'barnie'
+ assert builder.json().tropo[1].say[0].voice == 'barnie'
+
+ builder = new TropoBuilder(voice: 'barnie')
+ builder.say('Hi There')
+ builder.say('Wow!', voice: 'jack')
+ assert builder.json().tropo[0].say[0].voice == 'barnie'
+ assert builder.json().tropo[1].say[0].voice == 'jack'
+
+ builder = new TropoBuilder()
+ builder.voice = 'barnie'
+ builder.say('Hi There')
+ builder.say('Wow!', voice: 'jack')
+ assert builder.json().tropo[0].say[0].voice == 'barnie'
+ assert builder.json().tropo[1].say[0].voice == 'jack'
+ }
+
+ public void testRecognizer() {
+
+ def builder = new TropoBuilder()
+ assert builder.recognizer() == null
+
+ builder = new TropoBuilder(recognizer: 'fr-fr')
+ assert builder.recognizer() == 'fr-fr'
+
+ builder = new TropoBuilder()
+ builder.recognizer = 'fr-fr'
+ assert builder.recognizer() == 'fr-fr'
+ }
+
+ public void testRecognizerHandling() {
+
+ def builder = new TropoBuilder()
+ builder.ask(name: 'foo', bargein: true, timeout: 30, required: true)
+ assert builder.json().tropo[0].ask.recognizer == null
+
+ builder = new TropoBuilder(recognizer: 'fr-fr')
+ builder.ask(name: 'foo', bargein: true, timeout: 30, required: true)
+ assert builder.json().tropo[0].ask.recognizer == 'fr-fr'
+
+ builder = new TropoBuilder(recognizer: 'fr-fr')
+ builder.recognizer = 'fr-fr'
+ builder.ask(name: 'foo', bargein: true, timeout: 30, required: true)
+ assert builder.json().tropo[0].ask.recognizer == 'fr-fr'
+
+ builder = new TropoBuilder(recognizer: 'fr-fr')
+ builder.recognizer = 'fr-fr'
+ builder.ask(name: 'foo', bargein: true, timeout: 30, required: true)
+ builder.ask(name: 'foo', bargein: true, timeout: 30, required: true, recognizer: 'de-de')
+ assert builder.json().tropo[0].ask.recognizer == 'fr-fr'
+ assert builder.json().tropo[1].ask.recognizer == 'de-de'
+ }
+
+ public void testShouldParseJsonStringsAndMaps() {
+
+ def json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
+
+ def map = new TropoBuilder().parse(json_session)
+ assert map.session.userType == 'HUMAN'
+
+ map = new TropoBuilder().parse(map)
+ assert map.session.userType == 'HUMAN'
+ }
+}
View
274 test/unit/com/tropo/grails/TropoServiceTests.groovy
@@ -0,0 +1,274 @@
+package com.tropo.grails;
+
+import static org.junit.Assert.*;
+
+import java.util.Random;
+
+import groovy.util.GroovyTestCase;
+
+class TropoServiceTests extends GroovyTestCase {
+
+ private TESTING_APP_NAME = 'GrailsPluginTestsApp'
+ private TESTING_APP_ID = '136290'
+ private TESTING_APP_TOKEN = "72979191d971e344b46a0e4a3485571844250e689bb13548a75f1cce2ce9a53dde82c3fe944479bcb650500e"
+
+ private TropoService service
+
+ public void setUp() {
+
+ def username = System.getProperty("tropo.api.auth.username")
+ def password = System.getProperty("tropo.api.auth.password")
+
+ service = new TropoService(username,password)
+ service.baseUrl = "https://api.tropo.com/v1/"
+
+ // The tropo.api.prodtesting switch allows us to run this test suite agains production environment
+ def p = System.getProperty("tropo.api.prodtesting")
+ if (!(System.getProperty("tropo.api.prodtesting") == 'true')) {
+ service.httpHelper = new MockHTTPHelper(username, password)
+ }
+ }
+
+ public void testLaunchSession() {
+
+ def result = service.launchSession(token: TESTING_APP_TOKEN)
+ assert result.success == "true"
+ }
+
+ public void testFailsWithNoToken() {
+
+ def message = shouldFail(TropoException) {
+ service.launchSession()
+ }
+ assert message == "Missing parameter 'token'"
+ }
+
+ public void testLaunchSessionMultipleParameters() {
+
+ def result = service.launchSession(token: TESTING_APP_TOKEN, customerName:"JohnDyer",numberToDial:"4075551212",msg:"the sky is falling.")
+ assert result.success == "true"
+ assert result.requestParams['customerName'] == "JohnDyer"
+ }
+
+ public void testListApplications() {
+
+ def result = service.applications()
+ assertNotNull result
+ assert result.size() > 0
+ }
+
+ public void testOurTestingApplicationExists() {
+
+ // This testing application is used by several tests so it should exist
+
+ def result = service.applications()
+ def names = result.name
+ assert names.contains(TESTING_APP_NAME)
+
+ }
+
+ public void testCreateAndDeleteApplication() {
+
+ def result = service.createApplication(name: "testapp" + new Random().nextInt(),
+ voiceUrl: "http://website.com",
+ messagingUrl: "http://website2.com",
+ platform: "scripting",
+ partition: "staging")
+
+ assertNotNull result.href
+ assertNotNull result.appId
+ def appId = result.appId
+
+ // Delete
+ result = service.deleteApplication(appId: appId)
+
+ println result
+ assert result.message == 'delete successful'
+ }
+
+ public void testNumbersBasedOnPrefix() {
+
+ def result = service.addNumber(appId: TESTING_APP_ID, type: 'number', prefix: '1407')
+ assertNotNull result
+ assertNotNull result.numberId
+ assert result.numberId.startsWith('+1407')
+
+ def numberId = result.numberId
+
+ result = service.remove(numberId: numberId, appId: TESTING_APP_ID)
+ assert result.message == 'delete successful'
+ }
+
+ public void testTollFreeNumbers() {
+
+ // It needs billing account settings to work in production
+
+ def result = service.addNumber(appId: TESTING_APP_ID, type: 'number', prefix: '1886')
+ assertNotNull result
+ assertNotNull result.numberId
+ assert result.numberId.startsWith('+1886')
+
+ def numberId = result.numberId
+
+ result = service.remove(numberId: numberId, appId: TESTING_APP_ID)
+ assert result.message == 'delete successful'
+ }
+
+
+ public void testInternationalNumbers() {
+
+ def result = service.addNumber(appId: TESTING_APP_ID, type: 'number', prefix: '34')
+ assertNotNull result
+ assertNotNull result.numberId
+ assert result.numberId.startsWith('+134')
+
+ def numberId = result.numberId
+
+ result = service.remove(numberId: numberId, appId: TESTING_APP_ID)
+ assert result.message == 'delete successful'
+ }
+
+ public void testAddFailsWithNoAppId() {
+
+ def message = shouldFail(TropoException) {
+ service.addNumber(type: 'number', prefix: '34')()
+ }
+ assert message == "Missing parameter 'appId'"
+ }
+
+ public void testAddFailsWithNoType() {
+
+ def message = shouldFail(TropoException) {
+ service.addNumber(appId: TESTING_APP_ID, prefix: '34')()
+ }
+ assert message == "Missing parameter 'type'"
+ }
+
+ public void testAddFailsWithNoPrefix() {
+
+ def message = shouldFail(TropoException) {
+ service.addNumber(appId: TESTING_APP_ID, type: 'number')()
+ }
+ assert message == "Missing parameter 'prefix'"
+ }
+
+ public void testRemoveFailsWithNoNumberId() {
+
+ def message = shouldFail(TropoException) {
+ service.remove(appId: TESTING_APP_ID)
+ }
+ assert message == "Missing parameter 'numberId'"
+ }
+
+ public void testRemoveFailsWithNoAppId() {
+
+ def message = shouldFail(TropoException) {
+ service.remove(numberId: '1234')
+ }
+ assert message == "Missing parameter 'appId'"
+ }
+
+ public void testMoveSpecificNumbers() {
+
+ def result = service.move(appId: TESTING_APP_ID, type: 'number', number: '4075551235')
+ assertNotNull result
+ assertNotNull result.href
+ }
+
+ public void testMoveFailsWithNoAppId() {
+
+ def message = shouldFail(TropoException) {
+ service.move(type: 'number', number: '4075551235')
+ }
+ assert message == "Missing parameter 'appId'"
+ }
+
+ public void testMoveFailsWithNoNumber() {
+
+ def message = shouldFail(TropoException) {
+ service.move(appId: TESTING_APP_ID, type: 'number')
+ }
+ assert message == "Missing parameter 'number'"
+ }
+
+ public void testMoveFailsWithNoType() {
+
+ def message = shouldFail(TropoException) {
+ service.move(appId: TESTING_APP_ID, number: '4075551235')
+ }
+ assert message == "Missing parameter 'type'"
+ }
+
+ public void testAddIMAccounts() {
+
+ def result = service.addIM(appId: TESTING_APP_ID, type: 'aim', username: 'tropocloud', password: 'password01')
+ assertNotNull result
+ assertNotNull result.href
+ }
+
+ public void testAddToken() {
+
+ def result = service.addToken(appId: TESTING_APP_ID, type: 'token', channel: 'voice')
+ assertNotNull result
+ assertNotNull result.token
+ }
+
+ public void testUpdateApplication() {
+
+ def result = service.updateApplication(appId: TESTING_APP_ID, name: TESTING_APP_NAME, partition: 'staging', platform: 'webapi')
+ assertNotNull result
+ assert result.partition == 'staging'
+ assert result.platform == 'webapi'
+ }
+
+ public void testListApplicationAddresses() {
+
+ def result = service.addresses(appId: TESTING_APP_ID)
+ assertNotNull result
+ assert result.size() > 0
+ assert result.channel.size() > 0
+ }
+
+ public void testListAddressesFailsWithNoAppId() {
+
+ def message = shouldFail(TropoException) {
+ service.move(foo: 'bar')
+ }
+ assert message == "Missing parameter 'appId'"
+ }
+
+ public void testListExchanges() {
+
+ def result = service.exchanges()
+ assertNotNull result
+ assert result.size() > 0
+ assert result.prefix.size() > 0
+ }
+
+ public void testSendingSignal() {
+
+ def result = service.launchSession(token: TESTING_APP_TOKEN)
+ assert result.success == "true"
+ def sessionId = result.id
+
+ result = service.sendSignal(sessionId: sessionId, value: 'exit')
+ assertNotNull result
+ assert result.status == 'QUEUED' || 'NOTFOUND' // If its not quick enough we will get a NOTFOUND
+ }
+
+ public void testSendingSignalFailsWithNoSessionId() {
+
+ def message = shouldFail(TropoException) {
+ service.sendSignal(value: 'exit')
+ }
+ assert message == "Missing parameter 'sessionId'"
+ }
+
+ public void testSendingSignalFailsWithNoValue() {
+
+ def message = shouldFail(TropoException) {
+ service.sendSignal(sessionId: '111')
+ }
+ assert message == "Missing parameter 'value'"
+ }
+}
View
17 test/unit/grails/tropo/plugin/TropoServiceTests.groovy
@@ -0,0 +1,17 @@
+package grails.tropo.plugin
+
+import grails.test.*
+
+class TropoServiceTests extends GrailsUnitTestCase {
+ protected void setUp() {
+ super.setUp()
+ }
+
+ protected void tearDown() {
+ super.tearDown()
+ }
+
+ void testSomething() {
+
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.