text:
package com.almende.dialog.adapter;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.UUID;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URIBuilder;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mockito;
import org.w3c.dom.Document;
import com.almende.dialog.IntegrationTest;
import com.almende.dialog.Settings;
import com.almende.dialog.TestFramework;
import com.almende.dialog.accounts.AdapterConfig;
import com.almende.dialog.accounts.Dialog;
import com.almende.dialog.agent.AdapterAgent;
import com.almende.dialog.agent.DDRRecordAgent;
import com.almende.dialog.agent.DialogAgent;
import com.almende.dialog.example.agent.TestServlet;
import com.almende.dialog.example.agent.TestServlet.QuestionInRequest;
import com.almende.dialog.model.Session;
import com.almende.dialog.model.ddr.DDRPrice;
import com.almende.dialog.model.ddr.DDRPrice.UnitType;
import com.almende.dialog.model.ddr.DDRRecord;
import com.almende.dialog.model.ddr.DDRType;
import com.almende.dialog.sim.TwilioSimulator;
import com.almende.dialog.util.ServerUtils;
import com.askfast.commons.RestResponse;
import com.askfast.commons.entity.AdapterProviders;
import com.askfast.commons.entity.AdapterType;
import com.askfast.commons.entity.DDRRecord.CommunicationStatus;
import com.askfast.commons.entity.DDRType.DDRTypeCategory;
import com.askfast.commons.entity.DialogRequest;
import com.askfast.commons.entity.Language;
import com.askfast.commons.entity.TTSInfo;
import com.askfast.commons.entity.TTSInfo.TTSProvider;
import com.askfast.commons.utils.PhoneNumberUtils;
import com.askfast.commons.utils.TimeUtils;
import com.twilio.sdk.verbs.Gather;
import com.twilio.sdk.verbs.Hangup;
import com.twilio.sdk.verbs.Redirect;
import com.twilio.sdk.verbs.Say;
import com.twilio.sdk.verbs.TwiMLResponse;

@Category(IntegrationTest.class)
public class TwilioAdapterIT extends TestFramework {

    protected static final String COMMENT_QUESTION_AUDIO = "http://audio";
    private DialogAgent dialogAgent = null;
    private static final String TEST_MESSAGE = "How are you doing? today";

    /**
     * This test checks if a sequence of people are getting called properly when
     * a preconnect is expected
     *
     * @throws Exception
     */
    @Test
    public void sequencialCallingPreconnectTest() throws Exception {

        super.createTestDDRPrice(DDRTypeCategory.INCOMING_COMMUNICATION_COST, 0.5, "incoming calls", UnitType.SECOND,
                                 AdapterType.CALL, "");
        super.createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.5, "outgoing calls", UnitType.SECOND,
                                 AdapterType.CALL, "");

        String secondRemoteAddress = "0622222222";
        String inboundAddress = "0103030000";
        String testCallId = UUID.randomUUID().toString(); //used for the main incoming call
        String testCallId1 = UUID.randomUUID().toString(); //used for the first redirection call
        String testCallId2 = UUID.randomUUID().toString(); //used for the second redirection call

        String preconnectUrl = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                                 QuestionInRequest.CLOSED_YES_NO.name());
        preconnectUrl = ServerUtils.getURLWithQueryParams(preconnectUrl, "question", "Incoming call");

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.REFERRAL.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", COMMENT_QUESTION_AUDIO);
        url = ServerUtils.getURLWithQueryParams(url, "address", remoteAddressVoice);
        url = ServerUtils.getURLWithQueryParams(url, "preconnect", preconnectUrl);
        url = ServerUtils.getURLWithQueryParams(url, "answerText", "Connecting next number");
        url = ServerUtils.getURLWithQueryParams(url, "next",
                                                ServerUtils.getURLWithQueryParams(url, "address", secondRemoteAddress));

        //create dialog
        Dialog dialog = new Dialog("Sequencial dialog", url);
        dialog.setOwner(TEST_PUBLIC_KEY);
        dialog.storeOrUpdate();

        //update adapter with dialog
        AdapterConfig adapterConfig = createTwilioAdapter();
        adapterConfig.setDialogId(dialog.getId());
        adapterConfig.update();

        TwilioAdapter twilioAdapter = Mockito.spy(new TwilioAdapter());

        //trigger an incoming call
        Response newInboundResponse = twilioAdapter.getNewDialogPost(testCallId, TEST_ACCOUNT_ID, inboundAddress,
                                                                     adapterConfig.getMyAddress(), "inbound", null,
                                                                     "ringing", null);
        //validate that a session is created with a ddr record
        List<Session> allSessions = Session.getAllSessions();
        Assert.assertThat(allSessions.size(), Matchers.is(2));
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        Assert.assertThat(ddrRecords.size(), Matchers.is(2));
        for (Session session : allSessions) {
            DDRRecord ddrRecord = DDRRecord.getDDRRecord(session.getDdrRecordId(), TEST_ACCOUNT_ID);
            Assert.assertThat(ddrRecord, Matchers.notNullValue());
            if(DDRTypeCategory.INCOMING_COMMUNICATION_COST.equals(ddrRecord.getTypeCategory())) {

                assertThat(ddrRecord.getToAddress().keySet().iterator().next(),
                           Matchers.is(adapterConfig.getFormattedMyAddress()));
                assertTrue(ddrRecord.getFromAddress().equals(PhoneNumberUtils.formatNumber(inboundAddress, null)));
            }
            else {
                assertThat(ddrRecord.getFromAddress(), Matchers.is(adapterConfig.getFormattedMyAddress()));
                assertTrue(ddrRecord.getToAddress().keySet()
                                    .contains(PhoneNumberUtils.formatNumber(remoteAddressVoice, null)));
            }
        }

        //new inbound call should trigger a redirect with preconnect
        assertXMLGeneratedByTwilioLibrary(String.format(
            "<Response><Play>%s</Play><Dial method=\"GET\" action=\"http://%s/dialoghandler/rest/twilio/answer\"  " +
                "callerId =\"%s\" timeout=\"30\"><Number method=\"GET\" url=\"http://%s/dialoghandler/rest/twilio/preconnect\" " +
                "statusCallback=\"http://%s/dialoghandler/rest/twilio/cc\" statusCallbackEvent=\"initiated ringing answered completed\" statusCallbackMethod=\"GET\">" +
                "%s</Number></Dial></Response>",
            COMMENT_QUESTION_AUDIO, Settings.HOST, adapterConfig.getMyAddress(), Settings.HOST, Settings.HOST,
            PhoneNumberUtils.formatNumber(remoteAddressVoice, null)), newInboundResponse.getEntity().toString());

        Mockito.when(twilioAdapter.fetchSessionFromParent(null, null, null, null, null))
               .thenReturn(Session.getSessionFromParentExternalId(testCallId1, testCallId,
                                                                  PhoneNumberUtils.formatNumber(remoteAddressVoice,
                                                                                null)));

        //select to ignore the call in the preconnect options
        Response preconnect = twilioAdapter.preconnect(adapterConfig.getMyAddress(), TEST_PUBLIC_KEY,
                                                       remoteAddressVoice, "outbound-dial", testCallId1, testCallId);
        assertXMLGeneratedByTwilioLibrary(String.format("<Response><Gather method=\"GET\" numDigits=\"1\" finishOnKey=\"\" action=\"http://%s/dialoghandler/rest/twilio/answer\" "
                                                            + "timeout=\"5\"><Say language=\"nl-nl\">%s</Say><Say language=\"nl-nl\">"
                                                            + "%s</Say><Say language=\"nl-nl\">%s</Say></Gather><Redirect method=\"GET\">"
                                                            + "http://%s/dialoghandler/rest/twilio/timeout</Redirect></Response>",
                                                        Settings.HOST, "Incoming call", "1", "2", Settings.HOST),
                                          preconnect.getEntity().toString());

        //answer the preconnect with the ignore reply
        Response answer = twilioAdapter.answer(null, "2", adapterConfig.getMyAddress(), remoteAddressVoice,
                                               "outbound-api", null, null, null, testCallId1, "in-progress", null);
        assertEquals("<Response><Say language=\"nl-nl\">You chose 2</Say><Hangup></Hangup></Response>".toLowerCase(),
                     answer.getEntity().toString().toLowerCase());
        twilioAdapter.receiveCCMessage(testCallId1, adapterConfig.getMyAddress(), remoteAddressVoice, "outbound-api",
                                       "completed");

        //mock new redirect call to the second number
        answer = twilioAdapter.answer(null, null, adapterConfig.getMyAddress(), inboundAddress, "inbound", null, null,
                                      null, testCallId, "in-progress", null);

        //a new referral session must have been created from testCallId as the parent external sessionId
        Session sessionFromParentExternalId = Session.getSessionFromParentExternalId(testCallId2,
                                                                                testCallId,
                                                                                PhoneNumberUtils.formatNumber(secondRemoteAddress,
                                                                                null));
        Assert.assertThat(sessionFromParentExternalId, Matchers.notNullValue());

        assertXMLGeneratedByTwilioLibrary(String.format(
            "<Response><Play>%s</Play><Dial method=\"GET\" action=\"http://%s/dialoghandler/rest/twilio/answer\"  " +
                "callerId =\"%s\" timeout=\"30\"><Number method=\"GET\" url=\"http://%s/dialoghandler/rest/twilio/preconnect\" " +
                "statusCallback=\"http://%s/dialoghandler/rest/twilio/cc\" statusCallbackEvent=\"initiated ringing answered completed\" statusCallbackMethod=\"GET\">" +
                "%s</Number></Dial></Response>",
            COMMENT_QUESTION_AUDIO, Settings.HOST, adapterConfig.getMyAddress(), Settings.HOST, Settings.HOST,
            PhoneNumberUtils.formatNumber(secondRemoteAddress, null)), answer.getEntity().toString());

        preconnect = twilioAdapter.preconnect(adapterConfig.getMyAddress(), TEST_PUBLIC_KEY, secondRemoteAddress,
                                              "outbound-dial", testCallId2, testCallId);
        assertXMLGeneratedByTwilioLibrary(String.format("<Response><Gather numDigits=\"1\" finishOnKey=\"\" action=\"http://%s/dialoghandler/rest/twilio/answer\" "
                                                            + "method=\"GET\" timeout=\"5\"><Say language=\"nl-nl\">%s</Say><Say language=\"nl-nl\">"
                                                            + "%s</Say><Say language=\"nl-nl\">%s</Say></Gather><Redirect method=\"GET\">"
                                                            + "http://%s/dialoghandler/rest/twilio/timeout</Redirect></Response>",
                                                        Settings.HOST, "Incoming call", "1", "2", Settings.HOST),
                                          preconnect.getEntity().toString());

        answer = twilioAdapter.answer(null, "1", adapterConfig.getMyAddress(), inboundAddress, "inbound", null, null,
                                      null, testCallId2, "in-progress", null);
        assertXMLGeneratedByTwilioLibrary("<Response><Say language=\"nl-nl\">You chose 1</Say></Response>",
                                          answer.getEntity().toString());
        ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        Assert.assertThat(ddrRecords.size(), Matchers.is(3));
        int statusCount = 0;
        for (DDRRecord ddrRecord : ddrRecords) {

            Assert.assertThat(ddrRecord, Matchers.notNullValue());
            if (DDRTypeCategory.INCOMING_COMMUNICATION_COST.equals(ddrRecord.getTypeCategory())) {

                assertThat(ddrRecord.getToAddress().keySet().iterator().next(),
                           Matchers.is(adapterConfig.getFormattedMyAddress()));
                assertTrue(ddrRecord.getFromAddress().equals(PhoneNumberUtils.formatNumber(inboundAddress, null)));
            }
            else if (DDRTypeCategory.OUTGOING_COMMUNICATION_COST.equals(ddrRecord.getTypeCategory())) {
                assertThat(ddrRecord.getFromAddress(), Matchers.is(adapterConfig.getFormattedMyAddress()));
                if (ddrRecord.getToAddress().keySet().contains(PhoneNumberUtils.formatNumber(remoteAddressVoice, null))) {
                    assertEquals(CommunicationStatus.MISSED,
                                 ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber(remoteAddressVoice, null)));
                    statusCount++;
                }
                else if (ddrRecord.getToAddress().keySet()
                                  .contains(PhoneNumberUtils.formatNumber(secondRemoteAddress, null))) {
                    assertEquals(CommunicationStatus.RECEIVED,
                                 ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber(secondRemoteAddress, null)));
                    statusCount++;
                }
            }
        }
        assertEquals(2, statusCount);
    }

    @Test
    public void inboundPhoneCall_CommentTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();

        String accountSid = UUID.randomUUID().toString();
        String callSid = UUID.randomUUID().toString();
        TwilioSimulator simulator = new TwilioSimulator(TestFramework.host, accountSid);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        url = ServerUtils.getURLWithQueryParams(url, "lang", Language.ENGLISH_UNITEDSTATES.getCode());

        //create a dialog
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_PUBLIC_KEY);

        //create SMS adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        String resp = simulator.initiateInboundCall(callSid, remoteAddressVoice, localAddressBroadsoft);
        System.out.println(resp);
        TwiMLResponse expected = new TwiMLResponse();
        Say say = new Say(TEST_MESSAGE);
        say.setLanguage(Language.ENGLISH_UNITEDSTATES.getCode());
        expected.append(say);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);
        //check all the ddrs created
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertEquals(ddrRecords.size(), 1);
        for (DDRRecord ddrRecord : ddrRecords) {
            assertEquals("inbound", ddrRecord.getDirection());
            assertEquals(adapterConfig.getFormattedMyAddress(), ddrRecord.getToAddress().keySet().iterator().next());
            assertEquals(PhoneNumberUtils.formatNumber(remoteAddressVoice, null), ddrRecord.getFromAddress());
        }
    }

    @Test
    public void inboundPhoneCall_InvalidReferralTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();
        String invalidNumber = "+3161234567";
        String accountSid = UUID.randomUUID().toString();
        String callSid = UUID.randomUUID().toString();
        TwilioSimulator simulator = new TwilioSimulator(TestFramework.host, accountSid);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.REFERRAL.name());
        url = ServerUtils.getURLWithQueryParams(url, "address", invalidNumber); //invalid address
        url = ServerUtils.getURLWithQueryParams(url, "question", "Hello...");

        //create a dialog
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_PUBLIC_KEY);

        //create SMS adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        String initiateInboundCall = simulator.initiateInboundCall(callSid, remoteAddressVoice, localAddressBroadsoft);
        assertThat(initiateInboundCall,
                   Matchers.not(Matchers.containsString(invalidNumber)));
        List<Session> allSessions = Session.getAllSessions();
        //all sessions must now be flushed
        assertThat(allSessions.size(), Matchers.is(0));
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertThat(ddrRecords.size(), Matchers.is(1));
        int ddrInfoCount = 0;
        DDRRecord ddrRecord = ddrRecords.iterator().next();
        for (String infoKey : ddrRecord.getAdditionalInfo().keySet()) {
            if (invalidNumber.equals(infoKey)) {
                assertThat(ddrRecord.getAdditionalInfo().get(infoKey).toString(), Matchers.is("Invalid address"));
                ddrInfoCount++;
            }
        }
        assertThat(ddrInfoCount, Matchers.is(1));
    }

    @Test
    public void inboundPhoneCall_ClosedTest() throws Exception {

        //new DDRRecordAgent().generateDefaultDDRTypes();

        String accountSid = UUID.randomUUID().toString();
        String callSid = UUID.randomUUID().toString();
        TwilioSimulator simulator = new TwilioSimulator(TestFramework.host, accountSid);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.CLOSED_YES_NO.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        url = ServerUtils.getURLWithQueryParams(url, "lang", Language.ENGLISH_UNITEDSTATES.getCode());

        //create a dialog
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_PUBLIC_KEY);

        //create Twilio adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        String resp = simulator.initiateInboundCall(callSid, remoteAddressVoice, localAddressBroadsoft);

        String lang = Language.ENGLISH_UNITEDSTATES.getCode();
        TwiMLResponse expected = new TwiMLResponse();
        Gather gather = new Gather();
        gather.getAttributes().put("action", TestFramework.host + "/rest/twilio/answer");
        gather.getAttributes().put("numDigits", "1");
        gather.getAttributes().put("finishOnKey", "");
        gather.getAttributes().put("method", "GET");
        gather.getAttributes().put("timeout", "5");
        Say say = new Say(TEST_MESSAGE);
        say.setLanguage(lang);
        gather.append(say);
        say = new Say("1");
        say.setLanguage(lang);
        gather.append(say);
        say = new Say("2");
        say.setLanguage(lang);
        gather.append(say);
        expected.append(gather);
        Redirect redirect = new Redirect(TestFramework.host + "/rest/twilio/timeout");
        redirect.getAttributes().put("method", "GET");
        expected.append(redirect);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);

        resp = simulator.nextQuestion("1");

        expected = new TwiMLResponse();
        say = new Say("You chose 1");
        say.setLanguage(lang);
        expected.append(say);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);
    }

    @Test
    public void inboundPhoneCall_ClosedTest_WithTimeout() throws Exception {

        String accountSid = UUID.randomUUID().toString();
        String callSid = UUID.randomUUID().toString();
        TwilioSimulator simulator = new TwilioSimulator(TestFramework.host, accountSid);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.CLOSED_YES_NO.name());
        url = ServerUtils.getURLWithQueryParams(url, "preMessage", "Hi there");
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        url = ServerUtils.getURLWithQueryParams(url, "lang", Language.ENGLISH_UNITEDSTATES.getCode());

        //create a dialog
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_PUBLIC_KEY);

        //create Twilio adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        String resp = simulator.initiateInboundCall(callSid, remoteAddressVoice, localAddressBroadsoft);

        // Load the premessage
        resp = simulator.nextQuestion(null);

        String lang = Language.ENGLISH_UNITEDSTATES.getCode();
        TwiMLResponse expected = new TwiMLResponse();
        Gather gather = new Gather();
        gather.getAttributes().put("action", TestFramework.host + "/rest/twilio/answer");
        gather.getAttributes().put("numDigits", "1");
        gather.getAttributes().put("finishOnKey", "");
        gather.getAttributes().put("method", "GET");
        gather.getAttributes().put("timeout", "5");
        Say say = new Say(TEST_MESSAGE);
        say.setLanguage(lang);
        gather.append(say);
        say = new Say("1");
        say.setLanguage(lang);
        gather.append(say);
        say = new Say("2");
        say.setLanguage(lang);
        gather.append(say);
        expected.append(gather);
        Redirect redirect = new Redirect(TestFramework.host + "/rest/twilio/timeout");
        redirect.getAttributes().put("method", "GET");
        expected.append(redirect);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);

        // trigger the timeout
        resp = simulator.timeout();

        // expect the last message
        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);

        // send the actual result
        resp = simulator.nextQuestion("1");

        expected = new TwiMLResponse();
        say = new Say("You chose 1");
        say.setLanguage(lang);
        expected.append(say);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);
    }

    /**
     * Test to check if answers with mixed dtmf key input works. E.g. should
     * work with both index based and dtmfKey:// prefix key based
     *
     * @throws Exception
     */
    @Test
    public void inboundPhoneCall_ClosedWithMixedDTMFKeyTest() throws Exception {

        //new DDRRecordAgent().generateDefaultDDRTypes();

        String accountSid = UUID.randomUUID().toString();
        String callSid = UUID.randomUUID().toString();
        TwilioSimulator simulator = new TwilioSimulator(TestFramework.host, accountSid);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.CLOSED_YES_NO.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        url = ServerUtils.getURLWithQueryParams(url, "prefix1", "null");
        url = ServerUtils.getURLWithQueryParams(url, "prefix2", "dtmfKey://");
        url = ServerUtils.getURLWithQueryParams(url, "lang", Language.ENGLISH_UNITEDSTATES.getCode());

        //create a dialog
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_PUBLIC_KEY);

        //create Twilio adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        String resp = simulator.initiateInboundCall(callSid, remoteAddressVoice, localAddressBroadsoft);

        String lang = Language.ENGLISH_UNITEDSTATES.getCode();
        TwiMLResponse expected = new TwiMLResponse();
        Gather gather = new Gather();
        gather.getAttributes().put("action", TestFramework.host + "/rest/twilio/answer");
        gather.getAttributes().put("numDigits", "1");
        gather.getAttributes().put("finishOnKey", "");
        gather.getAttributes().put("method", "GET");
        gather.getAttributes().put("timeout", "5");
        Say say = new Say(TEST_MESSAGE);
        say.setLanguage(lang);
        gather.append(say);
        expected.append(gather);
        Redirect redirect = new Redirect(TestFramework.host + "/rest/twilio/timeout");
        redirect.getAttributes().put("method", "GET");
        expected.append(redirect);

        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);

        resp = simulator.nextQuestion("1");
        //it should just repeat the question.. as the question is a mix of dtmf and null answer texts
        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);

        //but pressing 2 as it matches the dtmf key should work
        resp = simulator.nextQuestion("2");
        expected = new TwiMLResponse();
        say = new Say("You chose 2");
        say.setLanguage(lang);
        expected.append(say);
        expected.append(new Hangup());
        assertXMLGeneratedByTwilioLibrary(expected.toXML(), resp);
    }

    /**
     * This test is to check if the inbound functionality works for a dialog
     * with the right credentials for the secured url access along with TTSInfo
     * given in the dialog
     *
     * @throws Exception
     */
    @Test
    public void inboundPhoneCall_WithSecuredDialogAndTTSInfoTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        String ttsAccountId = UUID.randomUUID().toString();
        ttsInfo.setTtsAccountId(ttsAccountId);
        ttsInfo.setVoiceUsed("testtest");

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        Response securedDialogResponse = performSecuredCall("inbound", "testuserName", "testpassword", ttsInfo, url, "in-progress",
                                                            null);
        assertTrue(securedDialogResponse != null);
        //make sure that the tts source generated has a service and voice
        Document doc = getXMLDocumentBuilder(securedDialogResponse.getEntity().toString());
        String ttsURL = doc.getFirstChild().getFirstChild().getTextContent();
        URIBuilder uriBuilder = new URIBuilder(URLDecoder.decode(ttsURL, "UTF-8").replace(" ", "%20"));
        for (NameValuePair queryParams : uriBuilder.getQueryParams()) {
            if (queryParams.getName().equals("text")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_MESSAGE));
                continue;
            }
            else if (queryParams.getName().equals("codec")) {
                assertThat(queryParams.getValue(), Matchers.is("WAV"));
                continue;
            }
            else if (queryParams.getName().equals("speed")) {
                assertThat(queryParams.getValue(), Matchers.is("0"));
                continue;
            }
            else if (queryParams.getName().equals("format")) {
                assertThat(queryParams.getValue(), Matchers.is("8khz_8bit_mono"));
                continue;
            }
            else if (queryParams.getName().equals("type")) {
                assertThat(queryParams.getValue(), Matchers.is(".wav"));
                continue;
            }
            else if (queryParams.getName().equals("lang")) {
                assertThat(queryParams.getValue(), Matchers.is("nl-nl"));
                continue;
            }
            else if (queryParams.getName().equals("voice")) {
                assertThat(queryParams.getValue(), Matchers.is("testtest"));
                continue;
            }
            else if (queryParams.getName().equals("service")) {
                assertThat(queryParams.getValue(), Matchers.is("ACAPELA"));
                continue;
            }
            else if (queryParams.getName().equals("id")) {
                assertThat(queryParams.getValue(), Matchers.is(ttsAccountId));
                continue;
            }
            else if (queryParams.getName().equals("askFastAccountId")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_ACCOUNT_ID));
                continue;
            }
            assertTrue(String.format("query not found: %s=%s", queryParams.getName(), queryParams.getValue()), false);
        }
    }

    /**
     * /**
     * This test is to check if the inbound functionality works for a dialog
     * with the right credentials for the secured url access, but no ddr records
     * are created when a test flag is set to true
     *
     * @throws Exception
     */
    @Test
    public void inboundPhoneCall_DoesNotCreateDDRWithFlagTest() throws Exception {

        inboundPhoneCall_WithSecuredDialogAndTTSInfoTest();
        //validate that ddr records are created when isTest is set to false
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        Assert.assertThat(ddrRecords.size(), Matchers.equalTo(1));

        //trigger a second incoming call with test flag to be true. flush all sessions, adapters and ddrRecords
        setup();

        //trigger a second inbound call with test flag set to true
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.INCOMING_COMMUNICATION_COST, 0.1, "Test incoming costs", UnitType.MINUTE,
                           null, null);
        new DDRRecordAgent().generateDefaultDDRTypes();

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        String ttsAccountId = UUID.randomUUID().toString();
        ttsInfo.setTtsAccountId(ttsAccountId);
        ttsInfo.setVoiceUsed("testtest");

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        performSecuredCall("inbound", "testuserName", "testpassword", ttsInfo, url, "in-progress", true);

        //validate that ddr records are created when isTest is set to false
        ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        Assert.assertThat(ddrRecords.size(), Matchers.equalTo(0));
    }

    /**
     * This test is to check if the outbound functionality works for a dialog
     * with the right credentials for the secured url access along with TTSInfo
     * given in the dialog
     *
     * @throws Exception
     */
    @Test
    public void outboundPhoneCall_WithSecuredDialogAndTTSInfoTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        ttsInfo.setVoiceUsed("testtest");
        String ttsAccountId = UUID.randomUUID().toString();
        ttsInfo.setTtsAccountId(ttsAccountId);
        ttsInfo.setSpeed("0");

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        Response securedDialogResponse = performSecuredCall("outbound", "testuserName", "testpassword", ttsInfo, url, "in-progress",
                                                            null);
        assertNotNull(securedDialogResponse);
        //make sure that the tts source generated has a service and voice
        Document doc = getXMLDocumentBuilder(securedDialogResponse.getEntity().toString());
        String ttsURL = doc.getFirstChild().getFirstChild().getTextContent();
        URIBuilder uriBuilder = new URIBuilder(URLDecoder.decode(ttsURL, "UTF-8").replace(" ", "%20"));
        for (NameValuePair queryParams : uriBuilder.getQueryParams()) {
            if (queryParams.getName().equals("text")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_MESSAGE));
                continue;
            }
            else if (queryParams.getName().equals("codec")) {
                assertThat(queryParams.getValue(), Matchers.is("WAV"));
                continue;
            }
            else if (queryParams.getName().equals("speed")) {
                assertThat(queryParams.getValue(), Matchers.is("0"));
                continue;
            }
            else if (queryParams.getName().equals("format")) {
                assertThat(queryParams.getValue(), Matchers.is("8khz_8bit_mono"));
                continue;
            }
            else if (queryParams.getName().equals("type")) {
                assertThat(queryParams.getValue(), Matchers.is(".wav"));
                continue;
            }
            else if (queryParams.getName().equals("lang")) {
                assertThat(queryParams.getValue(), Matchers.is("nl-nl"));
                continue;
            }
            else if (queryParams.getName().equals("voice")) {
                assertThat(queryParams.getValue(), Matchers.is("testtest"));
                continue;
            }
            else if (queryParams.getName().equals("service")) {
                assertThat(queryParams.getValue(), Matchers.is("ACAPELA"));
                continue;
            }
            else if (queryParams.getName().equals("id")) {
                assertThat(queryParams.getValue(), Matchers.is(ttsAccountId));
                continue;
            }
            else if (queryParams.getName().equals("askFastAccountId")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_ACCOUNT_ID));
                continue;
            }
            assertTrue(String.format("query not found: %s=%s", queryParams.getName(), queryParams.getValue()), false);
        }
    }

    @Test
    public void inboundPhoneCall_ForTTSServiceCostProcessingTest() throws Exception {
        phoneCall_ForTTSServiceCostProcessingTest("inbound");
    }

    @Test
    public void outboundPhoneCall_ForTTSServiceCostProcessingTest() throws Exception {
        phoneCall_ForTTSServiceCostProcessingTest("outbound");
    }

    /**
     * This test is to check if tts service charges are attached to the inbound
     * functionality when the ttsAccountId is found. No tts costs must be seen
     *
     * @throws Exception
     */
    public void phoneCall_ForTTSServiceCostProcessingTest(String direction) throws Exception {

        DDRRecordAgent ddrRecordAgent = new DDRRecordAgent();
        ddrRecordAgent.createDDRPriceWithNewDDRType("TTS service costs", DDRTypeCategory.TTS_SERVICE_COST.name(), null,
                                                    null, 0.01, null, null, null, null, null, null, null);
        ddrRecordAgent.createDDRPriceWithNewDDRType("TTS service costs", DDRTypeCategory.TTS_COST.name(), null, null,
                                                    0.01, null, null, null, null, null, null, null);

        String ttsAccountId = UUID.randomUUID().toString();
        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        ttsInfo.setVoiceUsed("testtest");
        ttsInfo.setTtsAccountId(ttsAccountId);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        String message = "How are you doing? today";
        url = ServerUtils.getURLWithQueryParams(url, "question", message);
        Response securedDialogResponse = performSecuredCall(direction, "testuserName", "testpassword", ttsInfo, url, "in-progress",
                                                            null);
        assertTrue(securedDialogResponse != null);
        //check if ddr is created for ttsprocessing
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        int ttsServiceChargesAttached = 0;
        for (DDRRecord ddrRecord : ddrRecords) {
            Assert.assertFalse(ddrRecord.getDdrType().getCategory().equals(DDRTypeCategory.TTS_COST));
            if (ddrRecord.getDdrType().getCategory().equals(DDRTypeCategory.TTS_SERVICE_COST)) {
                ttsServiceChargesAttached++;
            }
        }
        assertEquals(1, ttsServiceChargesAttached);
    }

    @Test
    public void inboundPhoneCall_ForTTSCostProcessingTest() throws Exception {
        phoneCall_ForTTSCostProcessingTest("inbound");
    }

    @Test
    public void outboundPhoneCall_ForTTSCostProcessingTest() throws Exception {
        phoneCall_ForTTSCostProcessingTest("outbound");
    }

    /**
     * This test is to check if tts charges are attached to the inbound
     * functionality when the ttsAccountId is not found. No tts service costs
     * must be seen
     *
     * @throws Exception
     */
    public void phoneCall_ForTTSCostProcessingTest(String direction) throws Exception {

        DDRRecordAgent ddrRecordAgent = new DDRRecordAgent();
        ddrRecordAgent.createDDRPriceWithNewDDRType("TTS service costs", DDRTypeCategory.TTS_SERVICE_COST.name(), null,
                                                    null, 0.01, null, null, null, null, null, null, null);
        ddrRecordAgent.createDDRPriceWithNewDDRType("TTS service costs", DDRTypeCategory.TTS_COST.name(), null, null,
                                                    0.01, null, null, null, null, null, null, null);

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        ttsInfo.setVoiceUsed("testtest");

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        String message = "How are you doing? today";
        url = ServerUtils.getURLWithQueryParams(url, "question", message);
        Response securedDialogResponse = performSecuredCall("inbound", "testuserName", "testpassword", ttsInfo,
                                                                   url, "in-progress", null);
        assertTrue(securedDialogResponse != null);
        //check if ddr is created for ttsprocessing
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        int ttsChargesAttached = 0;
        for (DDRRecord ddrRecord : ddrRecords) {
            Assert.assertFalse(ddrRecord.getDdrType().getCategory().equals(DDRTypeCategory.TTS_SERVICE_COST));
            if (ddrRecord.getDdrType().getCategory().equals(DDRTypeCategory.TTS_COST)) {
                ttsChargesAttached++;
            }
        }
        assertEquals(1, ttsChargesAttached);
    }

    /**
     * This test is to check if the outbound functionality works for a dialog
     * with language as English. But adapter is set to French, and question is
     * set to Dutch still parses TTS in English
     *
     * @throws Exception
     */
    @Test
    public void outboundPhoneCall_WithEnglishLanguageTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        ttsInfo.setVoiceUsed("testtest");
        ttsInfo.setSpeed("0");
        String ttsAccountId = UUID.randomUUID().toString();
        ttsInfo.setTtsAccountId(ttsAccountId);
        ttsInfo.setLanguage(Language.ENGLISH_UNITEDSTATES);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        Response securedDialogResponse = performSecuredCall("outbound", "testuserName", "testpassword", ttsInfo,
                                                                   url, "in-progress", null);
        assertTrue(securedDialogResponse != null);
        //make sure that the tts source generated has a service and voice
        Document doc = getXMLDocumentBuilder(securedDialogResponse.getEntity().toString());
        String ttsURL = doc.getFirstChild().getFirstChild().getTextContent();
        URIBuilder uriBuilder = new URIBuilder(URLDecoder.decode(ttsURL, "UTF-8").replace(" ", "%20"));
        for (NameValuePair queryParams : uriBuilder.getQueryParams()) {
            if (queryParams.getName().equals("text")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_MESSAGE));
                continue;
            }
            else if (queryParams.getName().equals("codec")) {
                assertThat(queryParams.getValue(), Matchers.is("WAV"));
                continue;
            }
            else if (queryParams.getName().equals("speed")) {
                assertThat(queryParams.getValue(), Matchers.is("0"));
                continue;
            }
            else if (queryParams.getName().equals("format")) {
                assertThat(queryParams.getValue(), Matchers.is("8khz_8bit_mono"));
                continue;
            }
            else if (queryParams.getName().equals("type")) {
                assertThat(queryParams.getValue(), Matchers.is(".wav"));
                continue;
            }
            else if (queryParams.getName().equals("lang")) {
                assertThat(queryParams.getValue(), Matchers.is("en-us"));
                continue;
            }
            else if (queryParams.getName().equals("voice")) {
                assertThat(queryParams.getValue(), Matchers.is("testtest"));
                continue;
            }
            else if (queryParams.getName().equals("service")) {
                assertThat(queryParams.getValue(), Matchers.is("ACAPELA"));
                continue;
            }
            else if (queryParams.getName().equals("id")) {
                assertThat(queryParams.getValue(), Matchers.is(ttsAccountId));
                continue;
            }
            else if (queryParams.getName().equals("askFastAccountId")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_ACCOUNT_ID));
                continue;
            }
            assertTrue(String.format("query not found: %s=%s", queryParams.getName(), queryParams.getValue()), false);
        }
    }

    /**
     * This test is to check if the outbound functionality works for a dialog
     * with language as French. But adapter is set to English and question
     * parsed in Dutch, parses TTS in French
     *
     * @throws Exception
     */
    @Test
    public void outboundPhoneCall_WithEnglishTTSAndDiffLanguageInQuestionTest() throws Exception {

        new DDRRecordAgent().generateDefaultDDRTypes();

        TTSInfo ttsInfo = new TTSInfo();
        ttsInfo.setProvider(TTSProvider.ACAPELA);
        ttsInfo.setVoiceUsed("testtest");
        ttsInfo.setSpeed("0");
        String ttsAccountId = UUID.randomUUID().toString();
        ttsInfo.setTtsAccountId(ttsAccountId);
        ttsInfo.setLanguage(Language.DUTCH);

        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.SIMPLE_COMMENT.name());
        url = ServerUtils.getURLWithQueryParams(url, "lang", Language.FRENCH_FRANCE.getCode());
        url = ServerUtils.getURLWithQueryParams(url, "question", TEST_MESSAGE);
        Response securedDialogResponse = performSecuredCall("outbound", "testuserName", "testpassword", ttsInfo,
                                                                   url, "in-progress", null);
        assertTrue(securedDialogResponse != null);
        //make sure that the tts source generated has a service and voice
        Document doc = getXMLDocumentBuilder(securedDialogResponse.getEntity().toString());
        String ttsURL = doc.getFirstChild().getFirstChild().getTextContent();
        URIBuilder uriBuilder = new URIBuilder(URLDecoder.decode(ttsURL, "UTF-8").replace(" ", "%20"));
        for (NameValuePair queryParams : uriBuilder.getQueryParams()) {
            if (queryParams.getName().equals("text")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_MESSAGE));
                continue;
            }
            else if (queryParams.getName().equals("codec")) {
                assertThat(queryParams.getValue(), Matchers.is("WAV"));
                continue;
            }
            else if (queryParams.getName().equals("speed")) {
                assertThat(queryParams.getValue(), Matchers.is("0"));
                continue;
            }
            else if (queryParams.getName().equals("format")) {
                assertThat(queryParams.getValue(), Matchers.is("8khz_8bit_mono"));
                continue;
            }
            else if (queryParams.getName().equals("type")) {
                assertThat(queryParams.getValue(), Matchers.is(".wav"));
                continue;
            }
            else if (queryParams.getName().equals("lang")) {
                assertThat(queryParams.getValue(), Matchers.is("fr-fr"));
                continue;
            }
            else if (queryParams.getName().equals("voice")) {
                assertThat(queryParams.getValue(), Matchers.is("testtest"));
                continue;
            }
            else if (queryParams.getName().equals("service")) {
                assertThat(queryParams.getValue(), Matchers.is("ACAPELA"));
                continue;
            }
            else if (queryParams.getName().equals("id")) {
                assertThat(queryParams.getValue(), Matchers.is(ttsAccountId));
                continue;
            }
            else if (queryParams.getName().equals("askFastAccountId")) {
                assertThat(queryParams.getValue(), Matchers.is(TEST_ACCOUNT_ID));
                continue;
            }
            assertTrue(String.format("query not found: %s=%s", queryParams.getName(), queryParams.getValue()), false);
        }
    }

    /**
     * This test is to check if the outbound functionality will create ddr
     * records for tts processing.
     *
     * @throws Exception
     */
    @Test
    public void ttsInvokesCharges() throws Exception {

        //create a ddrPrice
        createTestDDRPrice(DDRTypeCategory.TTS_COST, 0.1, "ddr price for tts", UnitType.PART, null, null);
        createTestDDRPrice(DDRTypeCategory.TTS_SERVICE_COST, 0.01, "ddr price for tts service", UnitType.PART, null,
                           null);
        outboundPhoneCall_WithEnglishTTSAndDiffLanguageInQuestionTest();
        DDRType ddrType = DDRType.getDDRType(DDRTypeCategory.TTS_SERVICE_COST);
        List<DDRRecord> ddrRecords = DDRRecord.getDDRRecords(TEST_ACCOUNT_ID, null, null, null, null,
            Arrays.asList(ddrType.getTypeId()), null, null, null, null, null, null, null, null);
        assertThat(ddrRecords.size(), Matchers.is(1));
        DDRRecord ddrRecord = ddrRecords.iterator().next();
        ddrRecord.setShouldGenerateCosts(true);
        assertThat(ddrRecord.getTotalCost(), Matchers.is(0.01));
    }

    /**
     * This test is to check if the outbound functionality does not invoke ddr
     * charges as there is no ddrPrice attached for the tts provider
     *
     * @throws Exception
     */
    @Test
    public void ttsDoesNotInvokesCharges() throws Exception {

        //create a ddrPrice for voice rss.
        DDRPrice ddrPrice = createTestDDRPrice(DDRTypeCategory.TTS_COST, 0.1, "ddr price for tts", UnitType.PART, null,
                                               null);
        ddrPrice.setKeyword(TTSProvider.VOICE_RSS.toString());
        ddrPrice.createOrUpdate();

        //invoke an outbound call with acapella tts
        outboundPhoneCall_WithEnglishTTSAndDiffLanguageInQuestionTest();
        DDRType ddrType = DDRType.getDDRType(DDRTypeCategory.TTS_COST);
        List<DDRRecord> ddrRecords = DDRRecord.getDDRRecords(TEST_PUBLIC_KEY, null, null, null, null,
            Arrays.asList(ddrType.getTypeId()), null, null, null, null, null, null, null, null);
        //make sure there is no costs involved, as the ddr price attached is for VoiceRSS tts and not acapela
        assertThat(ddrRecords.size(), Matchers.is(0));
    }

    /**
     * Test if the
     * {@link DialogAgent#outboundCallWithDialogRequest(com.askfast.commons.entity.DialogRequest)}
     * gives an error code if the question is not fetched by the dialog agent
     * @throws UnsupportedEncodingException
     */
    @Test
    public void outboundCallWithoutQuestionTest() throws Exception {

        dialogAgent = new DialogAgent();
        //setup bad question url
        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH + "wrongURL", "questionType",
                                                       QuestionInRequest.TWELVE_INPUT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", "start");

        //create mail adapter
        AdapterConfig adapterConfig = createTwilioAdapter();
        adapterConfig.update();

        //setup to generate ddrRecords
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.1, "test", UnitType.SECOND, AdapterType.CALL,
                           null);

        DialogRequest details = new DialogRequest();
        details.setAccountID(adapterConfig.getOwner());
        details.setAdapterID(adapterConfig.getConfigId());
        details.setAddress(remoteAddressVoice);
        details.setBearerToken(UUID.randomUUID().toString());
        details.setUrl(url);
        RestResponse outboundCallResponse = dialogAgent.outboundCallWithDialogRequest(details);
        assertEquals(Status.BAD_REQUEST.getStatusCode(), outboundCallResponse.getCode());
        assertThat(outboundCallResponse.getMessage(), Matchers.is(DialogAgent.getQuestionNotFetchedMessage(url)));

        //verify that the session is not saved
        assertEquals(0, Session.getAllSessions().size());
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertEquals(1, ddrRecords.size());
        assertEquals(CommunicationStatus.ERROR,
                     ddrRecords.iterator().next()
                               .getStatusForAddress(PhoneNumberUtils.formatNumber(remoteAddressVoice, null)));
        assertEquals(1, ddrRecords.iterator().next().getStatusPerAddress().size());
    }

    /**
     * Test if the
     * {@link DialogAgent#outboundCallWithDialogRequest(com.askfast.commons.entity.DialogRequest)}
     * gives an error code if the question is fetched by the dialog agent but
     * the telephone number is invalid
     *
     * @throws UnsupportedEncodingException
     */
    @Test
    public void outboundCallWithQuestionInvalidAddressTest() throws Exception {

        dialogAgent = new DialogAgent();
        //setup bad question url
        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.TWELVE_INPUT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", "start");

        //create mail adapter
        AdapterConfig adapterConfig = createTwilioAdapter();

        //setup to generate ddrRecords
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.1, "test", UnitType.SECOND, AdapterType.CALL,
                           null);

        DialogRequest details = new DialogRequest();
        details.setAccountID(adapterConfig.getOwner());
        details.setAdapterID(adapterConfig.getConfigId());
        details.setAddress("0611223"); //invalid address
        details.setBearerToken(UUID.randomUUID().toString());
        details.setMethod("outboundCall");
        details.setUrl(url);
        RestResponse outboundCallResponse = dialogAgent.outboundCallWithDialogRequest(details);
        assertEquals(Status.BAD_REQUEST.getStatusCode(), outboundCallResponse.getCode());

        //verify that the session is not saved
        assertEquals(0, Session.getAllSessions().size());
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertEquals(1, ddrRecords.size());
        assertEquals(CommunicationStatus.ERROR,
                     ddrRecords.iterator().next().getStatusForAddress(PhoneNumberUtils.formatNumber("0611223", null)));
        assertEquals(1, ddrRecords.iterator().next().getStatusPerAddress().size());
    }

    /**
     * Test if the
     * {@link DialogAgent#outboundCallWithDialogRequest(com.askfast.commons.entity.DialogRequest)}
     * gives an error code if the question is fetched by the dialog agent but
     * the telephone numbers are a mix of valid and invalid numbers
     *
     * @throws UnsupportedEncodingException
     */
    @Test
    public void outboundCallWithQuestionInvalidAndValidAddressTest() throws Exception {

        dialogAgent = new DialogAgent();
        //setup bad question url
        String url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                       QuestionInRequest.TWELVE_INPUT.name());
        url = ServerUtils.getURLWithQueryParams(url, "question", "start");

        //create mail adapter
        AdapterConfig adapterConfig = createTwilioAdapter();

        //setup to generate ddrRecords
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.1, "test", UnitType.SECOND, AdapterType.CALL,
                           null);

        DialogRequest details = new DialogRequest();
        details.setAccountID(adapterConfig.getOwner());
        details.setAdapterID(adapterConfig.getConfigId());
        details.setAddressList(new LinkedHashSet<String>(Arrays.asList("0611223", remoteAddressVoice)));
        details.setBearerToken(UUID.randomUUID().toString());
        details.setUrl(url);
        RestResponse outboundCallResponse = dialogAgent.outboundCallWithDialogRequest(details);
        assertEquals(Status.CREATED.getStatusCode(), outboundCallResponse.getCode());

        //verify that the session is not saved
        assertEquals(1, Session.getAllSessions().size());
        List<DDRRecord> ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertEquals(1, ddrRecords.size());
        DDRRecord ddrRecord = ddrRecords.iterator().next();
        assertEquals(CommunicationStatus.ERROR,
                     ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber("0611223", null)));
        assertEquals(CommunicationStatus.SENT,
                     ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber(remoteAddressVoice, null)));
        assertEquals(2, ddrRecords.iterator().next().getStatusPerAddress().size());

        //finalize the call. fetch the callSid from the session
        Session sessionForValidNumber = Session.getSessionByInternalKey(adapterConfig.getAdapterType(),
                                                                        adapterConfig.getMyAddress(),
                                                                        PhoneNumberUtils.formatNumber(remoteAddressVoice,
                                                                                null));

        //update with some answer timestamp
        sessionForValidNumber.setAnswerTimestamp(String.valueOf(TimeUtils.getServerCurrentTimeInMillis()));
        sessionForValidNumber.storeSession();

        assertNotNull(sessionForValidNumber);
        new TwilioAdapter().receiveCCMessage(sessionForValidNumber.getExternalSession(),
                                             sessionForValidNumber.getLocalAddress(),
                                             sessionForValidNumber.getRemoteAddress(),
                                             sessionForValidNumber.getDirection(), "completed");
        //validate the ddrRecords again
        ddrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertEquals(1, ddrRecords.size());
        ddrRecord = ddrRecords.iterator().next();
        assertEquals(CommunicationStatus.ERROR,
                     ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber("0611223", null)));
        assertEquals(CommunicationStatus.FINISHED,
                     ddrRecord.getStatusForAddress(PhoneNumberUtils.formatNumber(remoteAddressVoice, null)));
        assertEquals(2, ddrRecords.iterator().next().getStatusPerAddress().size());
    }

    /**
     * CHeck if an outbound call is not triggered for a number that is added to blacklist group
     * @throws Exception
     */
    @Test
    public void outboundCallNotTriggeredForBlackListNumberTest() throws Exception {

        //create mail adapter
        AdapterConfig adapterConfig = createTwilioAdapter();
        //setup to generate ddrRecords
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.1, "test", UnitType.SECOND, AdapterType.CALL,
            null);

        triggerOutboundCallForAddresses(Arrays.asList("0611223", remoteAddressVoice),
            Arrays.asList(remoteAddressVoice), adapterConfig, null);

        //validate that no sessions are created.
        assertThat(Session.getAllSessions().size(), Matchers.is(0));
        //validate ddr records for Rejected status
        List<DDRRecord> allDdrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertThat(allDdrRecords.size(), Matchers.is(1));
        assertThat(allDdrRecords.iterator().next().getStatusForAddress(
            PhoneNumberUtils.formatNumber(remoteAddressVoice, null)), Matchers.is(CommunicationStatus.REJECTED));
    }

    /**
     * CHeck if an outbound call is triggered for a number that is not added to
     * blacklist group
     *
     * @throws Exception
     */
    @Test
    public void outboundCallTriggeredForNotBlackListNumberTest() throws Exception {

        String secondAddress = "0612345678";

        //create mail adapter
        AdapterConfig adapterConfig = createTwilioAdapter();
        //setup to generate ddrRecords
        new DDRRecordAgent().generateDefaultDDRTypes();
        createTestDDRPrice(DDRTypeCategory.OUTGOING_COMMUNICATION_COST, 0.1, "test", UnitType.SECOND, AdapterType.CALL,
            null);

        triggerOutboundCallForAddresses(Arrays.asList(secondAddress, remoteAddressVoice),
            Arrays.asList(remoteAddressVoice), adapterConfig, null);

        //validate that no sessions are created.
        assertThat(Session.getAllSessions().size(), Matchers.is(1));
        //validate ddr records for Rejected status
        List<DDRRecord> allDdrRecords = getAllDdrRecords(TEST_ACCOUNT_ID);
        assertThat(allDdrRecords.size(), Matchers.is(1));
        assertThat(allDdrRecords.iterator().next().getStatusForAddress(
            PhoneNumberUtils.formatNumber(remoteAddressVoice, null)), Matchers.is(CommunicationStatus.REJECTED));
        assertThat(
            allDdrRecords.iterator().next().getStatusForAddress(PhoneNumberUtils.formatNumber(secondAddress, null)),
            Matchers.is(CommunicationStatus.SENT));
    }

    /**
     * @throws UnsupportedEncodingException
     * @throws Exception
     * @throws URISyntaxException
     */
    private Response performSecuredCall(String direction, String username, String password, TTSInfo ttsInfo,
        String url, String callStatus, Boolean isTest) throws Exception {

        if (url == null) {
            url = ServerUtils.getURLWithQueryParams(TestServlet.TEST_SERVLET_PATH, "questionType",
                                                    QuestionInRequest.OPEN_QUESION_WITHOUT_ANSWERS.name());
            url = ServerUtils.getURLWithQueryParams(url, "question", COMMENT_QUESTION_AUDIO);
            url = ServerUtils.getURLWithQueryParams(url, "secured", "true");
        }

        //create a dialog
        dialogAgent = dialogAgent != null ? dialogAgent : new DialogAgent();
        dialogAgent.createDialog(TEST_PUBLIC_KEY, "Test secured dialog", url);
        Dialog createDialog = Dialog.createDialog("Test secured dialog", url, TEST_ACCOUNT_ID);
        createDialog.setUserName(username);
        createDialog.setPassword(password);
        createDialog.setUseBasicAuth(true);
        createDialog.setTtsInfo(ttsInfo);
        createDialog.storeOrUpdate();

        //create SMS adapter
        AdapterConfig adapterConfig = createAdapterConfig(AdapterAgent.ADAPTER_TYPE_CALL, AdapterProviders.TWILIO,
                                                          TEST_ACCOUNT_ID, localAddressBroadsoft,
                                                          localAddressBroadsoft, url);
        adapterConfig.setPreferred_language(Language.ENGLISH_UNITEDSTATES.getCode());
        adapterConfig.setDialogId(createDialog.getId());
        adapterConfig.update();

        //mock the Context
        String remoteAddress = remoteAddressVoice;
        String localAddress = localAddressBroadsoft;
        UriInfo uriInfo = Mockito.mock(UriInfo.class);
        Mockito.when(uriInfo.getBaseUri()).thenReturn(new URI(TestServlet.TEST_SERVLET_PATH));
        String callSid = UUID.randomUUID().toString();
        if (direction.equals("outbound")) {
            HashMap<String, String> outboundCall = dialogAgent.outboundCall(remoteAddressVoice, "test", null,
                createDialog.getId(), null, adapterConfig.getConfigId(), TEST_ACCOUNT_ID, null,
                adapterConfig.getAccountType());
            String sessionKey = outboundCall.values().iterator().next();
            Session session = Session.getSession(sessionKey);
            callSid = session.getExternalSession();
        }
        else {
            String tmpLocalId = new String(localAddress);
            localAddress = new String(remoteAddress);
            remoteAddress = tmpLocalId;
        }
        return new TwilioAdapter().getNewDialog(callSid, UUID.randomUUID().toString(), localAddress, remoteAddress,
                                                direction, null, callStatus, isTest);
    }
}


text:
package com.microsoft.azure.iot.service.transport.amqps;

import mockit.Expectations;
import mockit.Mocked;
import mockit.integration.junit4.JMockit;
import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.Binary;
import org.apache.qpid.proton.amqp.messaging.*;
import org.apache.qpid.proton.amqp.transport.ErrorCondition;
import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
import org.apache.qpid.proton.amqp.transport.Source;
import org.apache.qpid.proton.engine.*;
import org.apache.qpid.proton.message.Message;
import org.apache.qpid.proton.message.MessageError;
import org.apache.qpid.proton.message.MessageFormat;
import org.apache.qpid.proton.messenger.impl.Address;
import org.apache.qpid.proton.reactor.Handshaker;
import org.apache.qpid.proton.reactor.Reactor;
import org.apache.qpid.proton.reactor.Selectable;
import org.apache.qpid.proton.reactor.Task;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.nio.BufferOverflowException;
import java.util.EnumSet;

import static org.junit.Assert.assertEquals;

/** Unit tests for AmqpSendHandler */
@RunWith(JMockit.class)
public class AmqpSendHandlerTest
{
    private Integer exceptionCount = 0;

    @Mocked Handshaker handshaker;
    @Mocked Proton proton;
    @Mocked Message message;
    @Mocked Message messageWithException;
    @Mocked Properties properties;
    @Mocked Binary binary;
    @Mocked Section section;
    @Mocked Data data;
    @Mocked Event event;
    @Mocked Transport transport;
    @Mocked Connection connection;
    @Mocked Address address;
    @Mocked Sasl sasl;
    @Mocked SslDomain sslDomain;
    @Mocked Session session;
    @Mocked Sender sender;
    @Mocked Link link;
    @Mocked Target target;
    @Mocked Delivery delivery;

    // Test_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall copy all input parameters to private member variables for event processing]
    // Test_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_002: [The constructor shall concatenate the host name with the port]
    // Test_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_003: [The constructor shall initialize a new Handshaker (Proton) object to handle communication handshake]
    @Test
    public void constructor_copies_params_to_members()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        new Expectations()
        {
            {
                handshaker = new Handshaker();
            }
        };
        // Act
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        String _hostName = amqpSendHandler.hostName;
        String _userName = amqpSendHandler.userName;
        String _sasToken = amqpSendHandler.sasToken;
        // Assert
        assertEquals(hostName + ":5671", _hostName);
        assertEquals(userName, _userName);
        assertEquals(sasToken, _sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_hostName_null()
    {
        // Arrange
        String hostName = null;
        String userName = "bbb";
        String sasToken = "ccc";
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_hostName_empty()
    {
        // Arrange
        String hostName = "";
        String userName = "bbb";
        String sasToken = "ccc";
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_userName_null()
    {
        // Arrange
        String hostName = "aaa";
        String userName = null;
        String sasToken = "ccc";
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_userName_empty()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "";
        String sasToken = "ccc";
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_sasToken_null()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = null;
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_001: [The constructor shall throw IllegalArgumentException if any of the input parameter is null or empty]
    // Assert
    @Test (expected = IllegalArgumentException.class)
    public void constructor_checks_if_sasToken_empty()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "";
        // Act
        AmqpSendHandler amqpSend = new AmqpSendHandler(hostName, userName, sasToken);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_004: [The function shall create a new Message (Proton) object]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_005: [The function shall set the "to" property on the Message object using the created device path]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_006: [The function shall create a Binary (Proton) object from the content string]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_007: [The function shall create a data Section (Proton) object from the Binary]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_008: [The function shall set the Message body to the created data section]
    @Test
    public void createBinaryMessage_creates_Message_and_sets_To()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String deviceId = "deviceId";
        String content = "abcdefghijklmnopqrst";
        String toProperty = "/devices/deviceId/messages/devicebound";
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        // Assert
        new Expectations()
        {
            {
                message = Proton.message();
                properties = new Properties();
                properties.setTo(toProperty);
                message.setProperties(properties);
                binary = new Binary(content.getBytes());
                section = new Data(binary);
                message.setBody(section);
            }
        };
        // Act
        amqpSendHandler.createBinaryMessage(deviceId, content);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_009: [The event handler shall set the SASL PLAIN authentication on the Transport using the given user name and sas token]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_010: [The event handler shall set ANONYMUS_PEER authentication mode on the domain of the Transport]
    @Test
    public void onConnectionBound_sets_Sasl_Plain()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String hostAddr = hostName + ":5671";
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        // Assert
        new Expectations()
        {
            {
                connection = event.getConnection();
                transport = connection.getTransport();
                sasl.plain(anyString, anyString);
                address = new Address(hostAddr);
                sslDomain = Proton.sslDomain();
                sslDomain.init(SslDomain.Mode.CLIENT);
                sslDomain.setPeerAuthentication(SslDomain.VerifyMode.ANONYMOUS_PEER);
                transport.ssl(sslDomain);
            }
        };
        // Act
        amqpSendHandler.onConnectionBound(event);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_011: [The event handler shall set the host name on the connection]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_012: [The event handler shall create a Session (Proton) object from the connection]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_013: [The event handler shall create a Sender (Proton) object and set the protocol tag on it to a predefined constant]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_014: [The event handler shall open the Connection, the Session and the Sender object]
    @Test
    public void onConnectionInit_creates_Session_and_open_Connection()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String hostAddr = hostName + ":5671";
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        // Assert
        new Expectations()
        {
            {
                connection = event.getConnection();
                connection.setHostname(hostAddr);
                session = connection.session();
                sender = session.sender(anyString);
                connection.open();
                session.open();
                sender.open();
            }
        };
        // Act
        amqpSendHandler.onConnectionInit(event);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_015: [The event handler shall create a new Target (Proton) object using the given endpoint address]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_016: [The event handler shall get the Link (Proton) object and set its target to the created Target (Proton) object]
    @Test
    public void onLinkInit_call_flow_ok()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String hostAddr = hostName + ":5671";
        String endpoint = "/messages/devicebound";
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        // Assert
        new Expectations()
        {
            {
                link = event.getLink();
                target = new Target();
                target.setAddress(endpoint);
            }
        };
        // Act
        amqpSendHandler.onLinkInit(event);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_017: [The event handler shall get the Sender (Proton) object from the link]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_018: [The event handler shall encode the message and copy to the byte buffer]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_019: [The event handler shall set the delivery tag on the Sender (Proton) object]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_020: [The event handler shall send the encoded bytes]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_021: [The event handler shall close the Sender, Session and Connection]
    @Test
    public void onLinkFlow_call_flow_ok()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String hostAddr = hostName + ":5671";
        String deviceId = "deviceId";
        String content = "abcdefghijklmnopqrst";
        String endpoint = "/messages/devicebound";
        createProtonObjects();
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        amqpSendHandler.createBinaryMessage(deviceId, content);
        // Assert
        new Expectations()
        {
            {
                link = event.getLink();
                link.getCredit();
                byte[] buffer = new byte[1024];
                message.encode(buffer, 0, 1024);
                sender.close();
                session = sender.getSession();
                connection = session.getConnection();
                connection.close();
            }
        };
        // Act
        amqpSendHandler.onLinkFlow(event);
    }

    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_017: [The event handler shall get the Sender (Proton) object from the link]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_018: [The event handler shall encode the message and copy to the byte buffer]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_019: [The event handler shall set the delivery tag on the Sender (Proton) object]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_020: [The event handler shall send the encoded bytes]
    // Tests_SRS_SERVICE_SDK_JAVA_AMQPSENDHANDLER_12_021: [The event handler shall close the Sender, Session and Connection]
    @Test
    public void onLinkFlowBufferOverflow_call_flow_ok()
    {
        // Arrange
        String hostName = "aaa";
        String userName = "bbb";
        String sasToken = "ccc";
        String hostAddr = hostName + ":5671";
        String deviceId = "deviceId";
        String content = "abcdefghijklmnopqrst";
        String endpoint = "/messages/devicebound";
        exceptionCount = 0;
        createProtonObjects();
        AmqpSendHandler amqpSendHandler = new AmqpSendHandler(hostName, userName, sasToken);
        // Assert
        new Expectations()
        {
            {
                amqpSendHandler.message = messageWithException;
                link = event.getLink();
                link.getCredit();
            }
        };
        // Act
        amqpSendHandler.onLinkFlow(event);
    }

    private void createProtonObjects()
    {
        String exceptionMessage = "Not expected function called";

        message = Proton.message();

        messageWithException = new Message()
        {
            @Override
            public boolean isDurable()
            { return false; }

            @Override
            public long getDeliveryCount()
            { return 0; }

            @Override
            public short getPriority()
            { return 0; }

            @Override
            public boolean isFirstAcquirer()
            { return false; }

            @Override
            public long getTtl()
            { return 0; }

            @Override
            public void setDurable(boolean b)
            { }

            @Override
            public void setTtl(long l)
            { }

            @Override public void setDeliveryCount(long l)
            { }

            @Override
            public void setFirstAcquirer(boolean b)
            { }

            @Override
            public void setPriority(short i)
            { }

            @Override
            public Object getMessageId()
            { return null; }

            @Override
            public long getGroupSequence()
            { return 0; }

            @Override
            public String getReplyToGroupId()
            { return null; }

            @Override
            public long getCreationTime()
            { return 0; }

            @Override
            public String getAddress()
            { return null; }

            @Override
            public byte[] getUserId()
            { return new byte[0]; }

            @Override
            public String getReplyTo()
            { return null; }

            @Override
            public String getGroupId()
            { return null; }

            @Override
            public String getContentType()
            { return null; }

            @Override
            public long getExpiryTime()
            { return 0; }

            @Override
            public Object getCorrelationId()
            { return null; }

            @Override
            public String getContentEncoding()
            { return null; }

            @Override
            public String getSubject()
            { return null; }

            @Override
            public void setGroupSequence(long l)
            { }

            @Override
            public void setUserId(byte[] bytes)
            { }

            @Override
            public void setCreationTime(long l)
            { }

            @Override
            public void setSubject(String s)
            { }

            @Override
            public void setGroupId(String s)
            { }

            @Override
            public void setAddress(String s)
            { }

            @Override
            public void setExpiryTime(long l)
            { }

            @Override
            public void setReplyToGroupId(String s)
            { }

            @Override
            public void setContentEncoding(String s)
            { }

            @Override
            public void setContentType(String s)
            { }

            @Override
            public void setReplyTo(String s)
            { }

            @Override
            public void setCorrelationId(Object o)
            { }

            @Override
            public void setMessageId(Object o)
            { }

            @Override
            public Header getHeader()
            { return null; }

            @Override
            public DeliveryAnnotations getDeliveryAnnotations()
            { return null; }

            @Override
            public MessageAnnotations getMessageAnnotations()
            { return null; }

            @Override
            public Properties getProperties()
            { return null; }

            @Override
            public ApplicationProperties getApplicationProperties()
            { return null; }

            @Override
            public Section getBody()
            { return null; }

            @Override
            public Footer getFooter()
            { return null; }

            @Override
            public void setHeader(Header header)
            { }

            @Override
            public void setDeliveryAnnotations(DeliveryAnnotations deliveryAnnotations)
            { }

            @Override
            public void setMessageAnnotations(MessageAnnotations messageAnnotations)
            { }

            @Override
            public void setProperties(Properties properties)
            { }

            @Override
            public void setApplicationProperties(ApplicationProperties applicationProperties)
            { }

            @Override
            public void setBody(Section section)
            { }

            @Override
            public void setFooter(Footer footer)
            { }

            @Override
            public int decode(byte[] bytes, int i, int i1)
            { return 0; }

            @Override
            public int encode(byte[] bytes, int i, int i1)
            {
                if (exceptionCount == 0)
                {
                    exceptionCount++;
                    throw new BufferOverflowException();
                }
                else
                {
                    return 0;
                }
            }

            @Override
            public void load(Object o)
            { }

            @Override
            public Object save()
            { return null; }

            @Override
            public String toAMQPFormat(Object o)
            { return null; }

            @Override
            public Object parseAMQPFormat(String s)
            { return null; }

            @Override
            public void setMessageFormat(MessageFormat messageFormat)
            { } @Override
            public MessageFormat getMessageFormat()
            { return null; }

            @Override
            public void clear()
            { }

            @Override
            public MessageError getError()
            { return null; }
        };

        sender = new Sender()
        {
            @Override
            public Record attachments()
            { return null; }

            @Override
            public EndpointState getLocalState()
            { return null; }

            @Override
            public EndpointState getRemoteState()
            { return null; }

            @Override
            public ErrorCondition getCondition()
            { return null; }

            @Override
            public void setCondition(ErrorCondition errorCondition)
            { }

            @Override
            public ErrorCondition getRemoteCondition()
            { return null; }

            @Override
            public void free()
            { }

            @Override
            public void open()
            { }

            @Override
            public void close()
            { }

            @Override
            public void setContext(Object o)
            { }

            @Override
            public Object getContext()
            { return null; }

            @Override
            public void offer(int i)
            { }

            @Override
            public int send(byte[] bytes, int i, int i1)
            { return 0; }

            @Override
            public void abort()
            { }

            @Override
            public String getName()
            { return null; }

            @Override
            public Delivery delivery(byte[] bytes)
            { return delivery; }

            @Override
            public Delivery delivery(byte[] bytes, int i, int i1)
            { return null; }

            @Override
            public Delivery head()
            { return null; }

            @Override
            public Delivery current()
            { return null; }

            @Override
            public boolean advance()
            { return false; }

            @Override
            public Source getSource()
            { return null; }

            @Override
            public org.apache.qpid.proton.amqp.transport.Target getTarget()
            { return null; }

            @Override
            public void setSource(Source source)
            { }

            @Override
            public void setTarget(org.apache.qpid.proton.amqp.transport.Target target)
            { }

            @Override
            public Source getRemoteSource()
            { return null; }

            @Override
            public org.apache.qpid.proton.amqp.transport.Target getRemoteTarget()
            { return null; }

            @Override
            public Link next(EnumSet<EndpointState> enumSet, EnumSet<EndpointState> enumSet1)
            { return null; }

            @Override
            public int getCredit()
            { return 1; }

            @Override
            public int getQueued()
            { return 0; }

            @Override
            public int getUnsettled()
            { return 0; }

            @Override
            public Session getSession()
            { return session; }

            @Override
            public SenderSettleMode getSenderSettleMode()
            { return null; }

            @Override
            public void setSenderSettleMode(SenderSettleMode senderSettleMode)
            { }

            @Override
            public SenderSettleMode getRemoteSenderSettleMode()
            { return null; }

            @Override
            public ReceiverSettleMode getReceiverSettleMode()
            { return null; }

            @Override
            public void setReceiverSettleMode(ReceiverSettleMode receiverSettleMode)
            { }

            @Override
            public ReceiverSettleMode getRemoteReceiverSettleMode()
            { return null; }

            @Override
            public void setRemoteSenderSettleMode(SenderSettleMode senderSettleMode)
            { }

            @Override
            public int drained()
            { return 0; }

            @Override
            public int getRemoteCredit()
            { return 0; }

            @Override
            public boolean getDrain()
            { return false; }

            @Override
            public void detach()
            { }

            @Override
            public boolean detached()
            { return false; }
        };

        event = new Event()
        {

            @Override public Event.Type getType()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override public Object getContext()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override public void dispatch(Handler hndlr) throws HandlerException
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override public Connection getConnection()
            { return connection; }

            @Override public Session getSession()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Link getLink()
            { return sender; }

            @Override
            public Delivery getDelivery()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Transport getTransport()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Reactor getReactor()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Selectable getSelectable()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Task getTask()
            { throw new UnsupportedOperationException(exceptionMessage);}

            @Override
            public Event copy()
            { throw new UnsupportedOperationException(exceptionMessage); }

            @Override
            public Record attachments()
            { throw new UnsupportedOperationException(exceptionMessage); }
        };
    }
}

redpajama_set_name: RedPajamaGithub


text:
package com.erdemorman.mdx.ui.icons;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class IconGroupDividerItemDecoration extends RecyclerView.ItemDecoration {
    private Drawable mDivider;

    public IconGroupDividerItemDecoration(Context context, int resId) {
        mDivider = ContextCompat.getDrawable(context, resId);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        int left = parent.getPaddingLeft();
        int right = parent.getWidth() - parent.getPaddingRight();

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);

            if (shouldDrawDivider(parent, child)) {
                RecyclerView.LayoutParams params =
                        (RecyclerView.LayoutParams) child.getLayoutParams();

                int bottom = child.getTop() - params.topMargin;
                int top = bottom - mDivider.getIntrinsicHeight();

                mDivider.setBounds(left, top, right, bottom);
                mDivider.draw(c);
            }
        }
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
                               RecyclerView.State state) {
        if (shouldDrawDivider(parent, view)) {
            outRect.top = mDivider.getIntrinsicHeight();
        }
    }

    private boolean shouldDrawDivider(RecyclerView parent, View child) {
        boolean shouldDraw = false;
        int adapterPosition = parent.getChildAdapterPosition(child);

        if (adapterPosition != 0) {
            // TODO: remove access to adapter, use view holder
            IconsAdapter iconsAdapter = (IconsAdapter) parent.getAdapter();
            shouldDraw = iconsAdapter.isGroupHeader(adapterPosition);
        }

        return shouldDraw;
    }
}


text:
layout: post
status: publish
published: true
title: wiki updated
author:
  display_name: void
  login: admin
  email: void@lessvoid.com
  url: http://nifty-gui.lessvoid.com/
author_login: admin
author_email: void@lessvoid.com
author_url: http://nifty-gui.lessvoid.com/
wordpress_id: 76
wordpress_url: http://nifty-gui.lessvoid.com/?p=76
date: '2009-03-14 11:22:19 +0100'
date_gmt: '2009-03-14 10:22:19 +0100'
categories:
- docs
tags: []
comments: []
---

Adding Documentation on how and where to "svn checkout" Nifty and how to build it with Maven:

Building Nifty from Source Wiki Page

</a>

:D


text:
/**
 * \file constantes.h
 * \brief Définition de constantes et énumérations afin de faciliter la lecture et l'utilisation du code source, ainsi que regrouper certains paramètres clés.
 * \author Steinhausser Maxime, Jean Burellier, Fleury Dorian.
 */

#ifndef CONSTANTES_H_INCLUDED
#define CONSTANTES_H_INCLUDED

/////////////////////////////////PARAMETRES/////////////////////////////////
#define VITESSE_MARIO_BASE 1 //0=>Vitesse Minimum (initialisée à 1 + VITESSE_MARIO_BASE dans le jeu)
#define VITESSE_TONNEAU 0 //initialisé à 1 + VITESSE_TONNEAU dans le jeu
#define VITESSE_CARAPACE 0 //initialisé à 1 + VITESSE_CARAPACE dans le jeu
#define PENTE 40 //Plus la pente est forte, plus la valeur est faible
#define GRAVITE 45 //Définie la hauteur de saut de Mario
#define PORTEE_SAUT 1 //Définie la portée de saut de Mario
#define FREQUENCE_ATTAQUE 8 //Def.la proba qu'un projectile soit lancé par DK (Minimum dépent du nombre de projectiles codés, 6 actuellement, 3 carapaces et 3 tonneaux à la fois)
#define FREQUENCE_HELP 3 //Définie la probabilité que Peach crie Help.
#define PROBAS_CHAMPI_UP 2//Definie la probas qu'un champi UP apparaisse à coté de Donkey Kong lors de la génération du niveau. Plus le nombre est grand, plus faible est la chance. Actuel = 1 chance sur 3.
#define PROBAS_POW 2 //Définie de la même manière que précédement l'apparition du Pow
#define DUREE_POW 600 //Définie la durée de l'effet du Pow (100= environ 1 seconde)
#define PROBAS_BLOC_METAL 2//Définie de la même manière que précédement l'apparition du Bloc Metal
///////////////////////////////FIN PARAMETRES///////////////////////////////

    enum {STATIC, SAUT_G, SAUT_D, SAUT_S, G1, G2, G3, G4, G5, G6, G7, G8, G9, G10, G11, G12, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, CLIMBING};  //Posture Mario
    enum {ETAGE_UN, ECHELLE_UNE, ETAGE_DEUX, ECHELLE_DEUX, ECHELLE_TROIS, ETAGE_TROIS, ECHELLE_QUATRE, ECHELLE_CINQ, ETAGE_QUATRE, ECHELLE_SIX, ETAGE_CINQ};//Gestion étages et echelles
    enum {DK_NORMAL, DK_CARAPACE, DK_TONNEAU, DK_POW}; //Posture Donkey Kong
    enum {TYPE_1, TYPE_2, TYPE_3}; //Type de pente
    enum {ZERO_VIE, UNE_VIE, DEUX_VIES, TROIS_VIES}; //Nombre de vie à afficher
    enum {PEACH1, PEACH_HELP}; //Posture Peach

////////////////////////////PARAMETRES ECHELLES/////////////////////////////
//La définition de la taille des echelles définie la zone d'interaction du personnage avec celles-ci.
//TAILLE ECHELLE 1
#define Y_MIN_SCALE_ONE 547
#define Y_MAX_SCALE_ONE 440
#define X_MIN_SCALE_ONE 720
#define X_MAX_SCALE_ONE 760
#define X_MARIO_ONE 740
//TAILLE ECHELLE 2
#define Y_MIN_SCALE_TWO 433
#define Y_MAX_SCALE_TWO 313
#define X_MIN_SCALE_TWO 415
#define X_MAX_SCALE_TWO 455//prec+40
#define X_MARIO_TWO 436//prec-20
//TAILLE ECHELLE 3
#define Y_MIN_SCALE_THREE 425
#define Y_MAX_SCALE_THREE 316
#define X_MIN_SCALE_THREE 100
#define X_MAX_SCALE_THREE 140//prec+40
#define X_MARIO_THREE 120//prec-20
//TAILLE ECHELLE 4
#define Y_MIN_SCALE_FOUR 310
#define Y_MAX_SCALE_FOUR 182
#define X_MIN_SCALE_FOUR 275
#define X_MAX_SCALE_FOUR 315//prec+40
#define X_MARIO_FOUR 295//prec-20
//TAILLE ECHELLE 5
#define Y_MIN_SCALE_FIVE 300
#define Y_MAX_SCALE_FIVE 190
#define X_MIN_SCALE_FIVE 840
#define X_MAX_SCALE_FIVE 880//prec+40
#define X_MARIO_FIVE 860//prec-20
//TAILLE ECHELLE 6
#define Y_MIN_SCALE_SIX 190
#define Y_MAX_SCALE_SIX 70
#define X_MIN_SCALE_SIX 770
#define X_MAX_SCALE_SIX 810//prec+40
#define X_MARIO_SIX 800//prec-20
//////////////////////////FIN PARAMETRES ECHELLES///////////////////////////

#endif // CONSTANTES_H_INCLUDED