From 64b5fae49f17fb9617e4eaf4a1213d0bca191bef Mon Sep 17 00:00:00 2001 From: Axel Suarez Date: Fri, 9 Aug 2019 15:27:40 -0700 Subject: [PATCH] PrivateConversationState implemented with basic unit test, more testing pending. --- .../botbuilder/core/__init__.py | 2 ++ .../core/private_conversation_state.py | 36 +++++++++++++++++++ .../tests/test_private_conversation_state.py | 36 +++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 libraries/botbuilder-core/botbuilder/core/private_conversation_state.py create mode 100644 libraries/botbuilder-core/tests/test_private_conversation_state.py diff --git a/libraries/botbuilder-core/botbuilder/core/__init__.py b/libraries/botbuilder-core/botbuilder/core/__init__.py index f34eec933..c25ab14d7 100644 --- a/libraries/botbuilder-core/botbuilder/core/__init__.py +++ b/libraries/botbuilder-core/botbuilder/core/__init__.py @@ -23,6 +23,7 @@ from .message_factory import MessageFactory from .middleware_set import AnonymousReceiveMiddleware, Middleware, MiddlewareSet from .null_telemetry_client import NullTelemetryClient +from .private_conversation_state import PrivateConversationState from .recognizer import Recognizer from .recognizer_result import RecognizerResult, TopIntent from .state_property_accessor import StatePropertyAccessor @@ -54,6 +55,7 @@ "Middleware", "MiddlewareSet", "NullTelemetryClient", + "PrivateConversationState", "Recognizer", "RecognizerResult", "StatePropertyAccessor", diff --git a/libraries/botbuilder-core/botbuilder/core/private_conversation_state.py b/libraries/botbuilder-core/botbuilder/core/private_conversation_state.py new file mode 100644 index 000000000..6b13bc5f5 --- /dev/null +++ b/libraries/botbuilder-core/botbuilder/core/private_conversation_state.py @@ -0,0 +1,36 @@ +from .bot_state import BotState +from .turn_context import TurnContext +from .storage import Storage + + +class PrivateConversationState(BotState): + def __init__(self, storage: Storage, namespace: str = ""): + async def aux_func(context: TurnContext) -> str: + nonlocal self + return await self.get_storage_key(context) + + self.namespace = namespace + super().__init__(storage, aux_func) + + def get_storage_key(self, turn_context: TurnContext) -> str: + activity = turn_context.activity + channel_id = activity.channel_id if activity is not None else None + + if not channel_id: + raise Exception("missing activity.channel_id") + + if activity and activity.conversation and activity.conversation.id is not None: + conversation_id = activity.conversation.id + else: + raise Exception("missing activity.conversation.id") + + if ( + activity + and activity.from_property + and activity.from_property.id is not None + ): + user_id = activity.from_property.id + else: + raise Exception("missing activity.from_property.id") + + return f"{channel_id}/conversations/{ conversation_id }/users/{ user_id }/{ self.namespace }" diff --git a/libraries/botbuilder-core/tests/test_private_conversation_state.py b/libraries/botbuilder-core/tests/test_private_conversation_state.py new file mode 100644 index 000000000..fe477a72b --- /dev/null +++ b/libraries/botbuilder-core/tests/test_private_conversation_state.py @@ -0,0 +1,36 @@ +import aiounittest + +from botbuilder.core import MemoryStorage, TurnContext, PrivateConversationState +from botbuilder.core.adapters import TestAdapter +from botbuilder.schema import Activity, ChannelAccount, ConversationAccount + +RECEIVED_MESSAGE = Activity( + text="received", + type="message", + channel_id="test", + conversation=ConversationAccount(id="convo"), + from_property=ChannelAccount(id="user"), +) + + +class TestPrivateConversationState(aiounittest.AsyncTestCase): + async def test_should_load_and_save_state_from_storage(self): + storage = MemoryStorage() + adapter = TestAdapter() + context = TurnContext(adapter, RECEIVED_MESSAGE) + private_conversation_state = PrivateConversationState(storage) + + # Simulate a "Turn" in a conversation by loading the state, + # changing it and then saving the changes to state. + await private_conversation_state.load(context) + key = private_conversation_state.get_storage_key(context) + state = private_conversation_state.get(context) + assert state == {}, "State not loaded" + assert key, "Key not found" + state["test"] = "foo" + await private_conversation_state.save_changes(context) + + # Check the storage to see if the changes to state were saved. + items = await storage.read([key]) + assert key in items, "Saved state not found in storage." + assert items[key]["test"] == "foo", "Missing test value in stored state."