This repository has been archived by the owner on Dec 4, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Event Factory for handoff protocol (#1118)
* Added Event Factory for handoff protocol * Added additional unit test. Co-authored-by: tracyboehrer <[email protected]>
- Loading branch information
1 parent
42edeb3
commit 45130e6
Showing
3 changed files
with
297 additions
and
0 deletions.
There are no files selected for viewing
134 changes: 134 additions & 0 deletions
134
libraries/bot-builder/src/main/java/com/microsoft/bot/builder/EventFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MT License. | ||
|
||
package com.microsoft.bot.builder; | ||
|
||
import java.time.OffsetDateTime; | ||
import java.time.ZoneId; | ||
import java.util.ArrayList; | ||
import java.util.UUID; | ||
|
||
import com.fasterxml.jackson.databind.node.JsonNodeFactory; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
import com.microsoft.bot.schema.Activity; | ||
import com.microsoft.bot.schema.Attachment; | ||
import com.microsoft.bot.schema.ConversationAccount; | ||
import com.microsoft.bot.schema.Entity; | ||
import com.microsoft.bot.schema.HandoffEventNames; | ||
import com.microsoft.bot.schema.Transcript; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
|
||
/** | ||
* Contains utility methods for creating various event types. | ||
*/ | ||
public final class EventFactory { | ||
|
||
private EventFactory() { | ||
|
||
} | ||
|
||
/** | ||
* Create handoff initiation event. | ||
* | ||
* @param turnContext turn context. | ||
* @param handoffContext agent hub-specific context. | ||
* | ||
* @return handoff event. | ||
*/ | ||
public static Activity createHandoffInitiation(TurnContext turnContext, Object handoffContext) { | ||
return createHandoffInitiation(turnContext, handoffContext, null); | ||
} | ||
|
||
|
||
/** | ||
* Create handoff initiation event. | ||
* | ||
* @param turnContext turn context. | ||
* @param handoffContext agent hub-specific context. | ||
* @param transcript transcript of the conversation. | ||
* | ||
* @return handoff event. | ||
*/ | ||
public static Activity createHandoffInitiation(TurnContext turnContext, Object handoffContext, | ||
Transcript transcript) { | ||
if (turnContext == null) { | ||
throw new IllegalArgumentException("turnContext cannot be null."); | ||
} | ||
|
||
Activity handoffEvent = createHandoffEvent(HandoffEventNames.INITIATEHANDOFF, handoffContext, | ||
turnContext.getActivity().getConversation()); | ||
|
||
handoffEvent.setFrom(turnContext.getActivity().getFrom()); | ||
handoffEvent.setRelatesTo(turnContext.getActivity().getConversationReference()); | ||
handoffEvent.setReplyToId(turnContext.getActivity().getId()); | ||
handoffEvent.setServiceUrl(turnContext.getActivity().getServiceUrl()); | ||
handoffEvent.setChannelId(turnContext.getActivity().getChannelId()); | ||
|
||
if (transcript != null) { | ||
Attachment attachment = new Attachment(); | ||
attachment.setContent(transcript); | ||
attachment.setContentType("application/json"); | ||
attachment.setName("Transcript"); | ||
handoffEvent.getAttachments().add(attachment); | ||
} | ||
|
||
return handoffEvent; | ||
} | ||
|
||
|
||
/** | ||
* Create handoff status event. | ||
* | ||
* @param conversation Conversation being handed over. | ||
* @param state State, possible values are: "accepted", "failed", | ||
* "completed". | ||
* | ||
* @return handoff event. | ||
*/ | ||
public static Activity createHandoffStatus(ConversationAccount conversation, String state) { | ||
return createHandoffStatus(conversation, state, null); | ||
} | ||
|
||
/** | ||
* Create handoff status event. | ||
* | ||
* @param conversation Conversation being handed over. | ||
* @param state State, possible values are: "accepted", "failed", | ||
* "completed". | ||
* @param message Additional message for failed handoff. | ||
* | ||
* @return handoff event. | ||
*/ | ||
public static Activity createHandoffStatus(ConversationAccount conversation, String state, String message) { | ||
if (conversation == null) { | ||
throw new IllegalArgumentException("conversation cannot be null."); | ||
} | ||
|
||
if (state == null) { | ||
throw new IllegalArgumentException("state cannot be null."); | ||
} | ||
|
||
ObjectNode handoffContext = JsonNodeFactory.instance.objectNode(); | ||
handoffContext.set("state", JsonNodeFactory.instance.textNode(state)); | ||
if (StringUtils.isNotBlank(message)) { | ||
handoffContext.set("message", JsonNodeFactory.instance.textNode(message)); | ||
} | ||
|
||
Activity handoffEvent = createHandoffEvent(HandoffEventNames.HANDOFFSTATUS, handoffContext, conversation); | ||
return handoffEvent; | ||
} | ||
|
||
private static Activity createHandoffEvent(String name, Object value, ConversationAccount conversation) { | ||
Activity handoffEvent = Activity.createEventActivity(); | ||
|
||
handoffEvent.setName(name); | ||
handoffEvent.setValue(value); | ||
handoffEvent.setId(UUID.randomUUID().toString()); | ||
handoffEvent.setTimestamp(OffsetDateTime.now(ZoneId.of("UTC"))); | ||
handoffEvent.setConversation(conversation); | ||
handoffEvent.setAttachments(new ArrayList<Attachment>()); | ||
handoffEvent.setEntities(new ArrayList<Entity>()); | ||
return handoffEvent; | ||
} | ||
} |
138 changes: 138 additions & 0 deletions
138
libraries/bot-builder/src/test/java/com/microsoft/bot/builder/EventFactoryTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MT License. | ||
|
||
package com.microsoft.bot.builder; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.JsonNode; | ||
import com.fasterxml.jackson.databind.node.JsonNodeFactory; | ||
import com.fasterxml.jackson.databind.node.ObjectNode; | ||
import com.microsoft.bot.builder.adapters.TestAdapter; | ||
import com.microsoft.bot.schema.Activity; | ||
import com.microsoft.bot.schema.ActivityTypes; | ||
import com.microsoft.bot.schema.ChannelAccount; | ||
import com.microsoft.bot.schema.ConversationAccount; | ||
import com.microsoft.bot.schema.HandoffEventNames; | ||
import com.microsoft.bot.schema.Serialization; | ||
import com.microsoft.bot.schema.Transcript; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
public class EventFactoryTests { | ||
|
||
@Test | ||
public void HandoffInitiationNullTurnContext() { | ||
Assert.assertThrows(IllegalArgumentException.class, | ||
() -> EventFactory.createHandoffInitiation(null, "some text")); | ||
} | ||
|
||
@Test | ||
public void HandoffStatusNullConversation() { | ||
Assert.assertThrows(IllegalArgumentException.class, () -> EventFactory.createHandoffStatus(null, "accepted")); | ||
} | ||
|
||
@Test | ||
public void HandoffStatusNullStatus() { | ||
Assert.assertThrows(IllegalArgumentException.class, | ||
() -> EventFactory.createHandoffStatus(new ConversationAccount(), null)); | ||
} | ||
|
||
@Test | ||
public void TestCreateHandoffInitiation() { | ||
TestAdapter adapter = new TestAdapter( | ||
TestAdapter.createConversationReference("TestCreateHandoffInitiation", "User1", "Bot")); | ||
String fromD = "test"; | ||
Activity activity = new Activity(ActivityTypes.MESSAGE); | ||
activity.setText(""); | ||
activity.setConversation(new ConversationAccount()); | ||
activity.setRecipient(new ChannelAccount()); | ||
activity.setFrom(new ChannelAccount(fromD)); | ||
activity.setChannelId("testchannel"); | ||
activity.setServiceUrl("http://myservice"); | ||
TurnContext context = new TurnContextImpl(adapter, activity); | ||
List<Activity> activities = new ArrayList<Activity>(); | ||
activities.add(MessageFactory.text("hello")); | ||
Transcript transcript = new Transcript(); | ||
transcript.setActivities(activities); | ||
|
||
Assert.assertNull(transcript.getActivities().get(0).getChannelId()); | ||
Assert.assertNull(transcript.getActivities().get(0).getServiceUrl()); | ||
Assert.assertNull(transcript.getActivities().get(0).getConversation()); | ||
|
||
ObjectNode handoffContext = JsonNodeFactory.instance.objectNode(); | ||
handoffContext.set("Skill", JsonNodeFactory.instance.textNode("any")); | ||
|
||
Activity handoffEvent = EventFactory.createHandoffInitiation(context, handoffContext, transcript); | ||
Assert.assertEquals(handoffEvent.getName(), HandoffEventNames.INITIATEHANDOFF); | ||
ObjectNode node = (ObjectNode) handoffEvent.getValue(); | ||
String skill = node.get("Skill").asText(); | ||
Assert.assertEquals("any", skill); | ||
Assert.assertEquals(handoffEvent.getFrom().getId(), fromD); | ||
} | ||
|
||
@Test | ||
public void TestCreateHandoffInitiationNoTranscript() { | ||
TestAdapter adapter = new TestAdapter( | ||
TestAdapter.createConversationReference("TestCreateHandoffInitiation", "User1", "Bot")); | ||
String fromD = "test"; | ||
Activity activity = new Activity(ActivityTypes.MESSAGE); | ||
activity.setText(""); | ||
activity.setConversation(new ConversationAccount()); | ||
activity.setRecipient(new ChannelAccount()); | ||
activity.setFrom(new ChannelAccount(fromD)); | ||
activity.setChannelId("testchannel"); | ||
activity.setServiceUrl("http://myservice"); | ||
TurnContext context = new TurnContextImpl(adapter, activity); | ||
List<Activity> activities = new ArrayList<Activity>(); | ||
activities.add(MessageFactory.text("hello")); | ||
|
||
ObjectNode handoffContext = JsonNodeFactory.instance.objectNode(); | ||
handoffContext.set("Skill", JsonNodeFactory.instance.textNode("any")); | ||
|
||
Activity handoffEvent = EventFactory.createHandoffInitiation(context, handoffContext); | ||
Assert.assertEquals(handoffEvent.getName(), HandoffEventNames.INITIATEHANDOFF); | ||
ObjectNode node = (ObjectNode) handoffEvent.getValue(); | ||
String skill = node.get("Skill").asText(); | ||
Assert.assertEquals("any", skill); | ||
Assert.assertEquals(handoffEvent.getFrom().getId(), fromD); | ||
} | ||
|
||
@Test | ||
public void TestCreateHandoffStatus() throws JsonProcessingException { | ||
String state = "failed"; | ||
String message = "timed out"; | ||
Activity handoffEvent = EventFactory.createHandoffStatus(new ConversationAccount(), state, message); | ||
Assert.assertEquals(handoffEvent.getName(), HandoffEventNames.HANDOFFSTATUS); | ||
|
||
ObjectNode node = (ObjectNode) handoffEvent.getValue(); | ||
|
||
String stateFormEvent = node.get("state").asText(); | ||
Assert.assertEquals(stateFormEvent, state); | ||
|
||
String messageFormEvent = node.get("message").asText(); | ||
Assert.assertEquals(messageFormEvent, message); | ||
|
||
String status = Serialization.toString(node); | ||
Assert.assertEquals(status, String.format("{\"state\":\"%s\",\"message\":\"%s\"}", state, message)); | ||
Assert.assertNotNull(handoffEvent.getAttachments()); | ||
Assert.assertNotNull(handoffEvent.getId()); | ||
} | ||
|
||
@Test | ||
public void TestCreateHandoffStatusNoMessage() { | ||
String state = "failed"; | ||
Activity handoffEvent = EventFactory.createHandoffStatus(new ConversationAccount(), state); | ||
|
||
ObjectNode node = (ObjectNode) handoffEvent.getValue(); | ||
|
||
String stateFormEvent = node.get("state").asText(); | ||
Assert.assertEquals(stateFormEvent, state); | ||
|
||
JsonNode messageFormEvent = node.get("message"); | ||
Assert.assertNull(messageFormEvent); | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
libraries/bot-schema/src/main/java/com/microsoft/bot/schema/HandoffEventNames.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
package com.microsoft.bot.schema; | ||
|
||
/** | ||
* Defines values for handoff event names. | ||
*/ | ||
public final class HandoffEventNames { | ||
|
||
private HandoffEventNames() { | ||
|
||
} | ||
|
||
/** | ||
* The value of handoff events for initiate handoff. | ||
*/ | ||
public static final String INITIATEHANDOFF = "handoff.initiate"; | ||
|
||
/** | ||
* The value of handoff events for handoff status. | ||
*/ | ||
public static final String HANDOFFSTATUS = "handoff.status"; | ||
} |