def test_basic_functionality(self, templates_file, version): """End-to-end test of the request handling.""" app = Flask(__name__) agent = DialogflowAgent(app, templates_file=templates_file, version=version) @agent.handle('Test') def handler(conv): conv.ask('Hello world!') return conv request = { 'queryResult': { 'intent': { 'displayName': 'Test' } }, 'originalDetectIntentRequest': { 'source': 'test' }, 'session': 'project/test/agent/sessions/foobar' } with app.test_client() as client: rv = client.post('/', json=request) resp = rv.get_json() text = resp['fulfillmentMessages'][0]['text']['text'][0] assert text == 'Hello world!'
def agent(templates_file, request): agent = DialogflowAgent(templates_file=templates_file, version=request.param) @agent.handle('Test') def handler(conv: DialogflowConversation) -> DialogflowConversation: return conv return agent
"""A minimal Hello-world agent to demonstrate the general usage of this lib.""" from flask import Flask, render_template as __ from flask_onsei.agent import DialogflowAgent from flask_onsei.conversation import V2DialogflowConversation from flask_onsei.google_apis.actions_on_google_v2 import ( BasicCard, Image, MediaResponse, MediaType, MediaObject, ) app = Flask(__name__) agent = DialogflowAgent(app, templates_file='templates/templates.yaml') @agent.handle('Default Welcome Intent') def welcome(conv: V2DialogflowConversation) -> V2DialogflowConversation: """A simple intent handler.""" # The simplest possible response for an Actions-on-Google agent. Speaks and # displays the given text and leaves the session open for further input. conv.google.ask('Hallo ONSEI! Was kann ich für dich tun?') return conv @agent.handle('GetDate') def get_date(conv: V2DialogflowConversation) -> V2DialogflowConversation: """A slightly more complex intent handler.
def test_basic_context_functionality(self, templates_file, version): """End-to-end test of the context registration and handling. This is a long test of two consecutive requests through Flask and the agent. It verifies that the registration of custom context classes works as expected. The scenario is a game state context, which is used as an example in the documentation. Note that this is obviously not meant to replace the tests of the individual parts of the context system, see TestDialogflowAgentContextAPI and the test_context module for them. """ # Setup a new Flask app and an agent app = Flask(__name__) agent = DialogflowAgent(app, templates_file=templates_file, version=version) # Schema for the custom context class class _GameStateSchema(JSONTypeSchema): questions_answered = Int() last_answer = Str() # Implement and register the custom context class. Serialization should # be completely hidden behind the scenes. @agent.context('game_state', keep_around=True) @dataclass class GameState(JSONType, schema=_GameStateSchema): questions_answered: int = 0 last_answer: Optional[str] = None # Now a handler that works with the context class @agent.handle('CorrectAnswer') def handler(conv): # Assert that the context has been properly initialized if # necessary assert 'game_state' in conv.contexts assert isinstance(conv.contexts.game_state.parameters, GameState) conv.contexts.game_state.parameters.questions_answered += 1 conv.contexts.game_state.parameters.last_answer = 'foo bar' return conv # Setup a minimal request as it would come from Dialogflow request = { 'queryResult': { 'intent': { 'displayName': 'CorrectAnswer' } }, 'originalDetectIntentRequest': { 'source': 'test' }, 'session': 'project/test/agent/sessions/foobar' } # Send it via Flasks test client to ensure that this really is # end-to-end with app.test_client() as client: rv = client.post('/', json=request) response = rv.get_json() # Now examine the response # First: The game_state ctx should be there assert any(ctx['name'].endswith('game_state') for ctx in response['outputContexts']) game_state_ctx = [ ctx for ctx in response['outputContexts'] if ctx['name'].endswith('game_state') ][0] # Next: It should have a long remaining lifespan assert game_state_ctx['lifespanCount'] == CTX_KEEP_AROUND_LIFESPAN # And: Its params should be what we set them to expected = {'questions_answered': 1, 'last_answer': 'foo bar'} assert game_state_ctx['parameters'] == expected # Now prepare a second request, were the context is already present second_request = request.copy() existing_context = game_state_ctx['parameters'].copy() del request, response, expected, game_state_ctx # To make it more realistic: Add random noise to the context existing_context.update( {'hi-im-dialogflow': 'i-add-my-own-fields-to-your-data'}) second_request['queryResult']['outputContexts'] = [{ 'name': 'game_state', 'lifespanCount': CTX_KEEP_AROUND_LIFESPAN - 1, 'parameters': existing_context }] # Second request via Flask with app.test_client() as client: rv = client.post('/', json=second_request) response = rv.get_json() # Context should still be there ... assert any(ctx['name'].endswith('game_state') for ctx in response['outputContexts']) game_state_ctx = [ ctx for ctx in response['outputContexts'] if ctx['name'].endswith('game_state') ][0] # ... should have the default lifespan again ... assert game_state_ctx['lifespanCount'] == CTX_KEEP_AROUND_LIFESPAN # ... and should have its counter increased once more expected = {'questions_answered': 2, 'last_answer': 'foo bar'} assert game_state_ctx['parameters'] == expected
def test_init_app_called_when_app_passed_to_constructor( self, app, templates_file, monkeypatch): init_app_mock = Mock() agent = DialogflowAgent(app, templates_file=templates_file) monkeypatch.setattr(agent, 'init_app', init_app_mock) init_app_mock.called_once_with(app)
def uninitialized_agent(self, templates_file): return DialogflowAgent(templates_file=templates_file)
def test_debug_mode_adds_handler(self, templates_file): agent = DialogflowAgent(debug=True) assert has_level_handler(agent.logger)
def test_debug_mode_sets_debug_logging_level(self, templates_file): agent = DialogflowAgent(debug=True) assert agent.logger.getEffectiveLevel() == logging.DEBUG