Added BotAdapterBracketingTest, BotAdapterTests, BotStateSetTests, and renamed BotFrameworkAdaterTests.
This commit is contained in:
Родитель
13a3e99c1f
Коммит
f148cafff2
|
@ -15,28 +15,31 @@ import java.util.function.Function;
|
|||
/**
|
||||
* Represents a bot adapter that can connect a bot to a service endpoint.
|
||||
* This class is abstract.
|
||||
* The bot adapter encapsulates authentication processes and sends
|
||||
* <p>The bot adapter encapsulates authentication processes and sends
|
||||
* activities to and receives activities from the Bot Connector Service. When your
|
||||
* bot receives an activity, the adapter creates a context object, passes it to your
|
||||
* bot's application logic, and sends responses back to the user's channel.
|
||||
* bot's application logic, and sends responses back to the user's channel.</p>
|
||||
* <p>Use {@link #use(Middleware)} to add {@link Middleware} objects
|
||||
* to your adapter’s middleware collection. The adapter processes and directs
|
||||
* incoming activities in through the bot middleware pipeline to your bot’s logic
|
||||
* and then back out again. As each activity flows in and out of the bot, each piece
|
||||
* of middleware can inspect or act upon the activity, both before and after the bot
|
||||
* logic runs.</p>
|
||||
* <p>
|
||||
* {@linkalso TurnContext}
|
||||
* {@linkalso Activity}
|
||||
* {@linkalso Bot}
|
||||
* {@linkalso Middleware}
|
||||
*
|
||||
* {@link TurnContext}
|
||||
* {@link Activity}
|
||||
* {@link Bot}
|
||||
* {@link Middleware}
|
||||
*/
|
||||
public abstract class BotAdapter {
|
||||
/**
|
||||
* The collection of middleware in the adapter's pipeline.
|
||||
*/
|
||||
protected final MiddlewareSet _middlewareSet = new MiddlewareSet();
|
||||
protected final MiddlewareSet middlewareSet = new MiddlewareSet();
|
||||
|
||||
/**
|
||||
* Error handler that can catch exceptions in the middleware or application.
|
||||
*/
|
||||
private OnTurnErrorHandler onTurnError;
|
||||
|
||||
/**
|
||||
|
@ -63,7 +66,7 @@ public abstract class BotAdapter {
|
|||
* For each turn, the adapter calls middleware in the order in which you added it.
|
||||
*/
|
||||
public BotAdapter use(Middleware middleware) {
|
||||
_middlewareSet.use(middleware);
|
||||
middlewareSet.use(middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,7 @@ public abstract class BotAdapter {
|
|||
* If the activities are successfully sent, the task result contains
|
||||
* an array of {@link ResourceResponse} objects containing the IDs that
|
||||
* the receiving channel assigned to the activities.
|
||||
* {@linkalso TurnContext.OnSendActivities(SendActivitiesHandler)}
|
||||
* {@link TurnContext#onSendActivities(SendActivitiesHandler)}
|
||||
*/
|
||||
public abstract CompletableFuture<ResourceResponse[]> sendActivities(TurnContext context, Activity[] activities);
|
||||
|
||||
|
@ -92,7 +95,7 @@ public abstract class BotAdapter {
|
|||
* channel assigned to the activity.
|
||||
* <p>Before calling this, set the ID of the replacement activity to the ID
|
||||
* of the activity to replace.</p>
|
||||
* {@linkalso TurnContext.OnUpdateActivity(UpdateActivityHandler)}
|
||||
* {@link TurnContext#onUpdateActivity(UpdateActivityHandler)}
|
||||
*/
|
||||
public abstract CompletableFuture<ResourceResponse> updateActivity(TurnContext context, Activity activity);
|
||||
|
||||
|
@ -105,7 +108,7 @@ public abstract class BotAdapter {
|
|||
* @return A task that represents the work queued to execute.
|
||||
* The {@link ConversationReference#getActivityId} of the conversation
|
||||
* reference identifies the activity to delete.
|
||||
* {@linkalso TurnContext.OnDeleteActivity(DeleteActivityHandler)}
|
||||
* {@link TurnContext#onDeleteActivity(DeleteActivityHandler)}
|
||||
*/
|
||||
public abstract CompletableFuture<Void> deleteActivity(TurnContext context, ConversationReference reference);
|
||||
|
||||
|
@ -113,30 +116,32 @@ public abstract class BotAdapter {
|
|||
/**
|
||||
* Starts activity processing for the current bot turn.
|
||||
*
|
||||
* The adapter calls middleware in the order in which you added it.
|
||||
* The adapter passes in the context object for the turn and a next delegate,
|
||||
* and the middleware calls the delegate to pass control to the next middleware
|
||||
* in the pipeline. Once control reaches the end of the pipeline, the adapter calls
|
||||
* the {@code callback} method. If a middleware component doesn’t call
|
||||
* the next delegate, the adapter does not call any of the subsequent middleware’s
|
||||
* {@link Middleware#onTurn(TurnContext, NextDelegate)}
|
||||
* methods or the callback method, and the pipeline short circuits.
|
||||
*
|
||||
* <p>When the turn is initiated by a user activity (reactive messaging), the
|
||||
* callback method will be a reference to the bot's
|
||||
* {@link Bot#onTurn(TurnContext)} method. When the turn is
|
||||
* initiated by a call to {@link #continueConversation(String, ConversationReference, BotCallbackHandler)}
|
||||
* (proactive messaging), the callback method is the callback method that was provided in the call.</p>
|
||||
*
|
||||
* @param context The turn's context object.
|
||||
* @param callback A callback method to run at the end of the pipeline.
|
||||
* @return A task that represents the work queued to execute.
|
||||
* @throws NullPointerException {@code context} is null.
|
||||
* The adapter calls middleware in the order in which you added it.
|
||||
* The adapter passes in the context object for the turn and a next delegate,
|
||||
* and the middleware calls the delegate to pass control to the next middleware
|
||||
* in the pipeline. Once control reaches the end of the pipeline, the adapter calls
|
||||
* the {@code callback} method. If a middleware component doesn’t call
|
||||
* the next delegate, the adapter does not call any of the subsequent middleware’s
|
||||
* {@link Middleware#onTurn(TurnContext, NextDelegate)}
|
||||
* methods or the callback method, and the pipeline short circuits.
|
||||
* <p>When the turn is initiated by a user activity (reactive messaging), the
|
||||
* callback method will be a reference to the bot's
|
||||
* {@link Bot#onTurn(TurnContext)} method. When the turn is
|
||||
* initiated by a call to {@link #continueConversation(String, ConversationReference, BotCallbackHandler)}
|
||||
* (proactive messaging), the callback method is the callback method that was provided in the call.</p>
|
||||
*/
|
||||
protected CompletableFuture<Void> runPipeline(TurnContext context, BotCallbackHandler callback) {
|
||||
BotAssert.contextNotNull(context);
|
||||
|
||||
// Call any registered Middleware Components looking for ReceiveActivity()
|
||||
if (context.getActivity() != null) {
|
||||
return _middlewareSet.receiveActivityWithStatus(context, callback)
|
||||
return middlewareSet.receiveActivityWithStatus(context, callback)
|
||||
.exceptionally(exception -> {
|
||||
if (onTurnError != null) {
|
||||
return onTurnError.invoke(context, exception);
|
||||
|
|
|
@ -192,7 +192,7 @@ public class BotFrameworkAdapter extends BotAdapter {
|
|||
* @return The updated adapter object.
|
||||
*/
|
||||
public BotFrameworkAdapter use(Middleware middleware) {
|
||||
super._middlewareSet.use(middleware);
|
||||
super.middlewareSet.use(middleware);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ public class BotFrameworkAdapter extends BotAdapter {
|
|||
|
||||
// For all non-invoke scenarios, the HTTP layers above don't have to mess
|
||||
// with the Body and return codes.
|
||||
return null;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
package com.microsoft.bot.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -14,6 +16,10 @@ import java.util.stream.Collectors;
|
|||
public class BotStateSet {
|
||||
private List<BotState> botStates = new ArrayList<>();
|
||||
|
||||
public BotStateSet(BotState... withBotStates) {
|
||||
this(Arrays.asList(withBotStates));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the BotStateSet class.
|
||||
*
|
||||
|
|
|
@ -22,9 +22,9 @@ import java.util.stream.Collectors;
|
|||
|
||||
/**
|
||||
* The memory transcript store stores transcripts in volatile memory in a Dictionary.
|
||||
* <p>
|
||||
* <p>
|
||||
* Because this uses an unbounded volitile dictionary this should only be used for unit tests or non-production environments.
|
||||
*
|
||||
* Because this uses an unbounded volatile dictionary this should only be used for unit tests or
|
||||
* non-production environments.
|
||||
*/
|
||||
public class MemoryTranscriptStore implements TranscriptStore {
|
||||
private HashMap<String, HashMap<String, ArrayList<Activity>>> channels = new HashMap<String, HashMap<String, ArrayList<Activity>>>();
|
||||
|
|
|
@ -19,6 +19,6 @@ public class InspectionState extends BotState {
|
|||
|
||||
@Override
|
||||
public String getStorageKey(TurnContext turnContext) {
|
||||
return InspectionState.class.getName();
|
||||
return InspectionState.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.builder;
|
||||
|
||||
import com.microsoft.bot.builder.adapters.TestAdapter;
|
||||
import com.microsoft.bot.builder.adapters.TestFlow;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BotAdapterBracketingTest {
|
||||
@Test
|
||||
public void Middleware_BracketingValidation() {
|
||||
TestAdapter adapter = new TestAdapter()
|
||||
.use(new BeforeAfterMiddleware());
|
||||
|
||||
BotCallbackHandler echo = (turnContext -> {
|
||||
String toEcho = "ECHO:" + turnContext.getActivity().getText();
|
||||
return turnContext.sendActivity(turnContext.getActivity().createReply(toEcho))
|
||||
.thenApply(resourceResponse -> null);
|
||||
});
|
||||
|
||||
new TestFlow(adapter, echo)
|
||||
.send("test")
|
||||
.assertReply("BEFORE")
|
||||
.assertReply("ECHO:test")
|
||||
.assertReply("AFTER")
|
||||
.startTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void Middleware_ThrowException() {
|
||||
String uniqueId = UUID.randomUUID().toString();
|
||||
|
||||
TestAdapter adapter = new TestAdapter()
|
||||
.use(new CatchExceptionMiddleware());
|
||||
|
||||
BotCallbackHandler echoWithException = (turnContext -> {
|
||||
String toEcho = "ECHO:" + turnContext.getActivity().getText();
|
||||
return turnContext.sendActivity(turnContext.getActivity().createReply(toEcho))
|
||||
.thenApply(resourceResponse -> {
|
||||
throw new RuntimeException(uniqueId);
|
||||
});
|
||||
});
|
||||
|
||||
new TestFlow(adapter, echoWithException)
|
||||
.send("test")
|
||||
.assertReply("BEFORE")
|
||||
.assertReply("ECHO:test")
|
||||
.assertReply("CAUGHT:" + uniqueId)
|
||||
.assertReply("AFTER")
|
||||
.startTest();
|
||||
}
|
||||
|
||||
private static class CatchExceptionMiddleware implements Middleware {
|
||||
@Override
|
||||
public CompletableFuture<Void> onTurn(TurnContext turnContext, NextDelegate next) {
|
||||
return turnContext.sendActivity(turnContext.getActivity().createReply("BEFORE"))
|
||||
.thenCompose(resourceResponse -> next.next())
|
||||
.exceptionally(exception -> {
|
||||
turnContext.sendActivity(turnContext.getActivity().createReply("CAUGHT:" + exception.getMessage())).join();
|
||||
return null;
|
||||
})
|
||||
.thenCompose(result -> turnContext.sendActivity(turnContext.getActivity().createReply("AFTER"))
|
||||
.thenApply(resourceResponse -> null));
|
||||
}
|
||||
}
|
||||
|
||||
private static class BeforeAfterMiddleware implements Middleware {
|
||||
@Override
|
||||
public CompletableFuture<Void> onTurn(TurnContext turnContext, NextDelegate next) {
|
||||
return turnContext.sendActivity(turnContext.getActivity().createReply("BEFORE"))
|
||||
.thenCompose(result -> next.next())
|
||||
.thenCompose(result -> turnContext.sendActivity(turnContext.getActivity().createReply("AFTER"))
|
||||
.thenApply(resourceResponse -> null));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.builder;
|
||||
|
||||
import com.microsoft.bot.builder.adapters.TestAdapter;
|
||||
import com.microsoft.bot.schema.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BotAdapterTests {
|
||||
@Test
|
||||
public void AdapterSingleUse() {
|
||||
SimpleAdapter a = new SimpleAdapter();
|
||||
a.use(new CallCountingMiddleware());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void AdapterUseChaining() {
|
||||
SimpleAdapter a = new SimpleAdapter();
|
||||
a.use(new CallCountingMiddleware()).use(new CallCountingMiddleware());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void PassResourceResponsesThrough() {
|
||||
Consumer<Activity[]> validateResponse = (activities) -> {
|
||||
// no need to do anything.
|
||||
};
|
||||
|
||||
SimpleAdapter a = new SimpleAdapter(validateResponse);
|
||||
TurnContextImpl c = new TurnContextImpl(a, new Activity(ActivityTypes.MESSAGE));
|
||||
|
||||
String activityId = UUID.randomUUID().toString();
|
||||
Activity activity = TestMessage.Message();
|
||||
activity.setId(activityId);
|
||||
|
||||
ResourceResponse resourceResponse = c.sendActivity(activity).join();
|
||||
Assert.assertTrue("Incorrect response Id returned", StringUtils.equals(resourceResponse.getId(), activityId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ContinueConversation_DirectMsgAsync() {
|
||||
boolean[] callbackInvoked = new boolean[] { false };
|
||||
|
||||
TestAdapter adapter = new TestAdapter();
|
||||
ConversationReference cr = new ConversationReference(){{
|
||||
setActivityId("activityId");
|
||||
setBot(new ChannelAccount(){{
|
||||
setId("channelId");
|
||||
setName("testChannelAccount");
|
||||
setRole(RoleTypes.BOT);
|
||||
}});
|
||||
setChannelId("testChannel");
|
||||
setServiceUrl("testUrl");
|
||||
setConversation(new ConversationAccount() {{
|
||||
setConversationType("");
|
||||
setId("testConversationId");
|
||||
setIsGroup(false);
|
||||
setName("testConversationName");
|
||||
setRole(RoleTypes.USER);
|
||||
}});
|
||||
setUser(new ChannelAccount() {{
|
||||
setId("channelId");
|
||||
setName("testChannelAccount");
|
||||
setRole(RoleTypes.BOT);
|
||||
}});
|
||||
}};
|
||||
|
||||
BotCallbackHandler callback = (turnContext) -> {
|
||||
callbackInvoked[0] = true;
|
||||
return CompletableFuture.completedFuture(null);
|
||||
};
|
||||
|
||||
adapter.continueConversation("MyBot", cr, callback).join();
|
||||
Assert.assertTrue(callbackInvoked[0]);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.builder;
|
||||
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import com.microsoft.bot.schema.ActivityTypes;
|
||||
import com.microsoft.bot.schema.ResourceResponse;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BotFrameworkAdapterTest {
|
||||
@Test
|
||||
public void AdapterSingleUse() {
|
||||
SimpleAdapter a = new SimpleAdapter();
|
||||
a.use(new CallCountingMiddleware());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void AdapterUseChaining() {
|
||||
SimpleAdapter a = new SimpleAdapter();
|
||||
a.use(new CallCountingMiddleware()).use(new CallCountingMiddleware());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void PassResourceResponsesThrough() throws Exception {
|
||||
Consumer<Activity[]> validateResponse = (activities) -> {
|
||||
// no need to do anything.
|
||||
};
|
||||
|
||||
SimpleAdapter a = new SimpleAdapter(validateResponse);
|
||||
TurnContextImpl c = new TurnContextImpl(a, new Activity(ActivityTypes.MESSAGE));
|
||||
|
||||
String activityId = UUID.randomUUID().toString();
|
||||
Activity activity = TestMessage.Message();
|
||||
activity.setId(activityId);
|
||||
|
||||
ResourceResponse resourceResponse = c.sendActivity(activity).join();
|
||||
Assert.assertTrue("Incorrect response Id returned", StringUtils.equals(resourceResponse.getId(), activityId));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.microsoft.bot.builder;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.microsoft.bot.connector.Channels;
|
||||
import com.microsoft.bot.connector.authentication.ClaimsIdentity;
|
||||
import com.microsoft.bot.connector.authentication.CredentialProvider;
|
||||
import com.microsoft.bot.connector.authentication.SimpleCredentialProvider;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import com.microsoft.bot.schema.ConversationAccount;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BotFrameworkAdapterTests {
|
||||
@Test
|
||||
public void TenantIdShouldBeSetInConversationForTeams() {
|
||||
Activity activity = processActivity(Channels.MSTEAMS, "theTenantId", null);
|
||||
Assert.assertEquals("theTenantId", activity.getConversation().getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TenantIdShouldNotChangeInConversationForTeamsIfPresent() {
|
||||
Activity activity = processActivity(Channels.MSTEAMS, "theTenantId", "shouldNotBeReplaced");
|
||||
Assert.assertEquals("shouldNotBeReplaced", activity.getConversation().getTenantId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void TenantIdShouldNotBeSetInConversationIfNotTeams() {
|
||||
Activity activity = processActivity(Channels.DIRECTLINE, "theTenantId", null);
|
||||
Assert.assertNull(activity.getConversation().getTenantId());
|
||||
}
|
||||
|
||||
private Activity processActivity(String channelId, String channelDataTenantId, String conversationTenantId) {
|
||||
ClaimsIdentity mockClaims = new ClaimsIdentity("anonymous");
|
||||
CredentialProvider mockCredentials = new SimpleCredentialProvider();
|
||||
|
||||
BotFrameworkAdapter sut = new BotFrameworkAdapter(mockCredentials);
|
||||
|
||||
ObjectNode channelData = new ObjectMapper().createObjectNode();
|
||||
ObjectNode tenantId = new ObjectMapper().createObjectNode();
|
||||
tenantId.put("id", channelDataTenantId);
|
||||
channelData.set("tenant", tenantId);
|
||||
|
||||
Activity[] activity = new Activity[] { null };
|
||||
sut.processActivity(
|
||||
mockClaims,
|
||||
new Activity("test") {{
|
||||
setChannelId(channelId);
|
||||
setServiceUrl("https://smba.trafficmanager.net/amer/");
|
||||
setChannelData(channelData);
|
||||
setConversation(new ConversationAccount() {{
|
||||
setTenantId(conversationTenantId);
|
||||
}});
|
||||
}},
|
||||
(context) -> {
|
||||
activity[0] = context.getActivity();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}).join();
|
||||
|
||||
return activity[0];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
package com.microsoft.bot.builder;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BotStateSetTests {
|
||||
@Test
|
||||
public void BotStateSet_Properties() {
|
||||
Storage storage = new MemoryStorage();
|
||||
|
||||
UserState userState = new UserState(storage);
|
||||
ConversationState conversationState = new ConversationState(storage);
|
||||
BotStateSet stateSet = new BotStateSet(userState, conversationState);
|
||||
|
||||
Assert.assertEquals(2, stateSet.getBotStates().size());
|
||||
Assert.assertTrue(stateSet.getBotStates().get(0) instanceof UserState);
|
||||
Assert.assertTrue(stateSet.getBotStates().get(1) instanceof ConversationState);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BotStateSet_LoadAsync() {
|
||||
Storage storage = new MemoryStorage();
|
||||
|
||||
TurnContext turnContext = TestUtilities.createEmptyContext();
|
||||
|
||||
{
|
||||
UserState userState = new UserState(storage);
|
||||
StatePropertyAccessor<Integer> userProperty = userState.createProperty("userCount");
|
||||
|
||||
ConversationState convState = new ConversationState(storage);
|
||||
StatePropertyAccessor<Integer> convProperty = convState.createProperty("convCount");
|
||||
|
||||
BotStateSet stateSet = new BotStateSet(userState, convState);
|
||||
|
||||
Assert.assertEquals(2, stateSet.getBotStates().size());
|
||||
|
||||
Integer userCount = userProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(0, userCount.intValue());
|
||||
Integer convCount = convProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(0, convCount.intValue());
|
||||
|
||||
userProperty.set(turnContext, 10).join();
|
||||
convProperty.set(turnContext, 20).join();
|
||||
|
||||
stateSet.saveAllChanges(turnContext).join();
|
||||
}
|
||||
|
||||
{
|
||||
UserState userState = new UserState(storage);
|
||||
StatePropertyAccessor<Integer> userProperty = userState.createProperty("userCount");
|
||||
|
||||
ConversationState convState = new ConversationState(storage);
|
||||
StatePropertyAccessor<Integer> convProperty = convState.createProperty("convCount");
|
||||
|
||||
BotStateSet stateSet = new BotStateSet(userState, convState);
|
||||
|
||||
stateSet.loadAll(turnContext).join();
|
||||
|
||||
Integer userCount = userProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(10, userCount.intValue());
|
||||
Integer convCount = convProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(20, convCount.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void BotStateSet_SaveAsync() {
|
||||
Storage storage = new MemoryStorage();
|
||||
|
||||
UserState userState = new UserState(storage);
|
||||
StatePropertyAccessor<Integer> userProperty = userState.createProperty("userCount");
|
||||
|
||||
ConversationState convState = new ConversationState(storage);
|
||||
StatePropertyAccessor<Integer> convProperty = convState.createProperty("convCount");
|
||||
|
||||
BotStateSet stateSet = new BotStateSet(userState, convState);
|
||||
|
||||
Assert.assertEquals(2, stateSet.getBotStates().size());
|
||||
|
||||
TurnContext turnContext = TestUtilities.createEmptyContext();
|
||||
stateSet.loadAll(turnContext).join();
|
||||
|
||||
Integer userCount = userProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(0, userCount.intValue());
|
||||
Integer convCount = convProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(0, convCount.intValue());
|
||||
|
||||
userProperty.set(turnContext, 10).join();
|
||||
convProperty.set(turnContext, 20).join();
|
||||
|
||||
stateSet.saveAllChanges(turnContext).join();
|
||||
|
||||
userCount = userProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(10, userCount.intValue());
|
||||
convCount = convProperty.get(turnContext, () -> 0).join();
|
||||
Assert.assertEquals(20, convCount.intValue());
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ import java.util.UUID;
|
|||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
|
||||
public class BotStateTest {
|
||||
public class BotStateTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void State_EmptyName() {
|
|
@ -5,6 +5,7 @@ package com.microsoft.bot.builder;
|
|||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface CallOnException {
|
||||
<T> CompletableFuture<Void> apply(TurnContext context, T t);
|
||||
<T> CompletableFuture<Void> invoke(TurnContext context, T t);
|
||||
}
|
||||
|
|
|
@ -14,26 +14,26 @@ import java.util.concurrent.CompletionException;
|
|||
* multiple times to allow you to handle different exception types in different ways.
|
||||
*/
|
||||
public class CatchExceptionMiddleware<T extends Exception> implements Middleware {
|
||||
private final CallOnException _handler;
|
||||
private final Class<T> _exceptionType;
|
||||
private CallOnException handler;
|
||||
private Class<T> exceptionType;
|
||||
|
||||
public CatchExceptionMiddleware(CallOnException callOnException, Class<T> exceptionType) {
|
||||
_handler = callOnException;
|
||||
_exceptionType = exceptionType;
|
||||
public CatchExceptionMiddleware(CallOnException withCallOnException, Class<T> withExceptionType) {
|
||||
handler = withCallOnException;
|
||||
exceptionType = withExceptionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> onTurn(TurnContext context, NextDelegate next) {
|
||||
|
||||
Class c = _exceptionType.getDeclaringClass();
|
||||
Class c = exceptionType.getDeclaringClass();
|
||||
|
||||
// Continue to route the activity through the pipeline
|
||||
// any errors further down the pipeline will be caught by
|
||||
// this try / catch
|
||||
return next.next()
|
||||
.exceptionally(exception -> {
|
||||
if (_exceptionType.isInstance(exception)) {
|
||||
_handler.apply(context, (T) exception);
|
||||
if (exceptionType.isInstance(exception)) {
|
||||
handler.invoke(context, exception);
|
||||
} else {
|
||||
throw new CompletionException(exception);
|
||||
}
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
package com.microsoft.bot.builder;
|
||||
|
||||
import com.microsoft.bot.builder.adapters.TestAdapter;
|
||||
import com.microsoft.bot.builder.adapters.TestFlow;
|
||||
import com.microsoft.bot.connector.ExecutorFactory;
|
||||
import com.microsoft.bot.schema.Activity;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class CatchException_MiddlewareTest {
|
||||
|
||||
@Test
|
||||
public void CatchException_TestMiddleware_TestStackedErrorMiddleware() throws ExecutionException, InterruptedException {
|
||||
|
||||
TestAdapter adapter = new TestAdapter()
|
||||
.use(new CatchExceptionMiddleware<Exception>(new CallOnException() {
|
||||
@Override
|
||||
public <T> CompletableFuture apply(TurnContext context, T t) {
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
Activity activity = context.getActivity();
|
||||
if (activity instanceof Activity) {
|
||||
try {
|
||||
context.sendActivity(activity.createReply(t.toString())).join();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(String.format("CatchException_TestMiddleware_TestStackedErrorMiddleware:SendActivity failed %s", e.toString()));
|
||||
}
|
||||
} else
|
||||
Assert.assertTrue("Test was built for ActivityImpl", false);
|
||||
|
||||
}, ExecutorFactory.getExecutor());
|
||||
|
||||
}
|
||||
}, Exception.class))
|
||||
// Add middleware to catch NullReferenceExceptions before throwing up to the general exception instance
|
||||
.use(new CatchExceptionMiddleware<NullPointerException>(new CallOnException() {
|
||||
@Override
|
||||
public <T> CompletableFuture apply(TurnContext context, T t) {
|
||||
context.sendActivity("Sorry - Null Reference Exception").join();
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}, NullPointerException.class));
|
||||
|
||||
|
||||
new TestFlow(adapter, (context) -> {
|
||||
if (StringUtils.equals(context.getActivity().getText(), "foo")) {
|
||||
try {
|
||||
context.sendActivity(context.getActivity().getText()).join();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (StringUtils.equals(context.getActivity().getText(), "UnsupportedOperationException")) {
|
||||
throw new UnsupportedOperationException("Test");
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
.send("foo")
|
||||
.assertReply("foo", "passthrough")
|
||||
.send("UnsupportedOperationException")
|
||||
.assertReply("Test")
|
||||
.startTest();
|
||||
|
||||
}
|
||||
|
||||
/* @Test
|
||||
// [TestCategory("Middleware")]
|
||||
public void CatchException_TestMiddleware_SpecificExceptionType()
|
||||
{
|
||||
TestAdapter adapter = new TestAdapter()
|
||||
.Use(new CatchExceptionMiddleware<Exception>((context, exception) =>
|
||||
{
|
||||
context.SendActivity("Generic Exception Caught");
|
||||
return CompletableFuture.CompletedTask;
|
||||
}))
|
||||
.Use(new CatchExceptionMiddleware<NullReferenceException>((context, exception) =>
|
||||
{
|
||||
context.SendActivity(exception.Message);
|
||||
return CompletableFuture.CompletedTask;
|
||||
}));
|
||||
|
||||
|
||||
await new TestFlow(adapter, (context) =>
|
||||
{
|
||||
if (context.Activity.AsMessageActivity().Text == "foo")
|
||||
{
|
||||
context.SendActivity(context.Activity.AsMessageActivity().Text);
|
||||
}
|
||||
|
||||
if (context.Activity.AsMessageActivity().Text == "NullReferenceException")
|
||||
{
|
||||
throw new NullReferenceException("Test");
|
||||
}
|
||||
|
||||
return CompletableFuture.CompletedTask;
|
||||
})
|
||||
.Send("foo")
|
||||
.AssertReply("foo", "passthrough")
|
||||
.Send("NullReferenceException")
|
||||
.AssertReply("Test")
|
||||
.StartTest();
|
||||
}*/
|
||||
}
|
Загрузка…
Ссылка в новой задаче