Repository: opsdroid/opsdroid

Issue:
Upgrade Dialogflow to V2 API
There is now a V2 API for Dialogflow.

We should look at the parser and skill and upgrade the API if applicable.

https://dialogflow.com/docs/reference/v2-agent-setup


Discussion:
I had a look at what changed on the V2 of the API and it seems a lot did change.  The major things that will need to be addressed are:

- Use OAuth instead of token to make api calls
- endpoint `/query` stops works and should know be `detectIntent` [documentation reference](https://cloud.google.com/dialogflow-enterprise/docs/reference/rest/v2beta1/projects.agent.sessions/detectIntent)
- webhooks are available now

The [migration reference](https://dialogflow.com/docs/reference/v1-v2-migration-guide-api) might be useful. We can use V1 of the API until 23rd of October 2019, so we should work on this in order to keep dialogflow working with opsdroid.
Just had a reminder email that this needs to be done by October 23rd. 
I'll try to address this issue on my days off 👍 

Resolving patch:
diff --git a/opsdroid/core.py b/opsdroid/core.py
--- a/opsdroid/core.py
+++ b/opsdroid/core.py
@@ -367,22 +367,7 @@ async def get_ranked_skills(self, skills, message):
             _LOGGER.debug(_("Processing parsers..."))
             parsers = self.config["parsers"] or []
 
-            dialogflow = [
-                p for p in parsers if p["name"] == "dialogflow" or p["name"] == "apiai"
-            ]
-
-            # Show deprecation message but  parse message
-            # Once it stops working remove this bit
-            apiai = [p for p in parsers if p["name"] == "apiai"]
-            if apiai:
-                _LOGGER.warning(
-                    _(
-                        "Api.ai is now called Dialogflow. This "
-                        "parser will stop working in the future "
-                        "please swap: 'name: apiai' for "
-                        "'name: dialogflow' in configuration.yaml"
-                    )
-                )
+            dialogflow = [p for p in parsers if p["name"] == "dialogflow"]
 
             if len(dialogflow) == 1 and (
                 "enabled" not in dialogflow[0] or dialogflow[0]["enabled"] is not False
diff --git a/opsdroid/matchers.py b/opsdroid/matchers.py
--- a/opsdroid/matchers.py
+++ b/opsdroid/matchers.py
@@ -66,44 +66,6 @@ def matcher(func):
     return matcher
 
 
-def match_apiai_action(action):
-    """Return Dialogflow action match decorator."""
-
-    def matcher(func):
-        """Add decorated function to skills list for Dialogflow matching."""
-        func = add_skill_attributes(func)
-        func.matchers.append({"dialogflow_action": action})
-        return func
-
-    _LOGGER.warning(
-        _(
-            "Api.ai is now called Dialogflow, this matcher "
-            "will stop working in the future. "
-            "Use match_dialogflow_action instead."
-        )
-    )
-    return matcher
-
-
-def match_apiai_intent(intent):
-    """Return Dialogflow intent match decorator."""
-
-    def matcher(func):
-        """Add decorated function to skills list for Dialogflow matching."""
-        func = add_skill_attributes(func)
-        func.matchers.append({"dialogflow_intent": intent})
-        return func
-
-    _LOGGER.warning(
-        _(
-            "Api.ai is now called Dialogflow, this matcher "
-            "will stop working in the future. "
-            "Use match_dialogflow_intent instead."
-        )
-    )
-    return matcher
-
-
 def match_dialogflow_action(action):
     """Return Dialogflowi action match decorator."""
 
diff --git a/opsdroid/parsers/dialogflow.py b/opsdroid/parsers/dialogflow.py
--- a/opsdroid/parsers/dialogflow.py
+++ b/opsdroid/parsers/dialogflow.py
@@ -1,96 +1,131 @@
 """A helper function for parsing and executing Dialogflow skills."""
-
+import os
 import logging
-import json
-
-import aiohttp
 
-from opsdroid.const import (
-    DEFAULT_LANGUAGE,
-    DIALOGFLOW_API_VERSION,
-    DIALOGFLOW_API_ENDPOINT,
-)
+from opsdroid.const import DEFAULT_LANGUAGE
 
 
 _LOGGER = logging.getLogger(__name__)
 
 
-async def call_dialogflow(message, config, lang=DEFAULT_LANGUAGE):
-    """Call the Dialogflow api and return the response."""
-    async with aiohttp.ClientSession() as session:
-        payload = {
-            "v": DIALOGFLOW_API_VERSION,
-            "lang": lang,
-            "sessionId": message.connector.name,
-            "query": message.text,
-        }
-        headers = {
-            "Authorization": "Bearer " + config["access-token"],
-            "Content-Type": "application/json",
-        }
-        resp = await session.post(
-            DIALOGFLOW_API_ENDPOINT, data=json.dumps(payload), headers=headers
-        )
-        result = await resp.json()
-        _LOGGER.info(_("Dialogflow response - %s"), json.dumps(result))
+async def call_dialogflow(text, opsdroid, config):
+    """Call Dialogflow to get intent from text.
 
-        return result
+    Dialogflow will return an object with a few restrictions, you can't
+    iterate it and the only way to access each element is by using dot
+    notation.
 
+    Args:
+        text (string): message.text this is the text obtained from the user.
+        opsdroid (OpsDroid): An instance of opsdroid.core.
+        config (dict): configuration settings from the file config.yaml.
 
-async def parse_dialogflow(opsdroid, skills, message, config):
-    """Parse a message against all Dialogflow skills."""
-    matched_skills = []
-    if "access-token" in config:
-        try:
-            result = await call_dialogflow(
-                message, config, opsdroid.config.get("lang", DEFAULT_LANGUAGE)
+    Return:
+        A 'google.cloud.dialogflow_v2.types.DetectIntentResponse' object.
+
+    Raises:
+        Warning: if Google credentials are not found in environmental
+        variables or 'project-id' is not in config.
+
+    """
+    try:
+        import dialogflow
+
+        if os.environ.get("GOOGLE_APPLICATION_CREDENTIALS") and config.get(
+            "project-id"
+        ):
+            session_client = dialogflow.SessionsClient()
+            project_id = config.get("project-id")
+            language = config.get("lang") or opsdroid.config.get(
+                "lang", DEFAULT_LANGUAGE
             )
-        except aiohttp.ClientOSError:
-            _LOGGER.error(_("No response from Dialogflow, " "check your network."))
-            return matched_skills
 
-        if result["status"]["code"] >= 300:
-            _LOGGER.error(
-                _("Dialogflow error - %s  - %s"),
-                str(result["status"]["code"]),
-                result["status"]["errorType"],
+            session = session_client.session_path(project_id, "opsdroid")
+            text_input = dialogflow.types.TextInput(text=text, language_code=language)
+            query_input = dialogflow.types.QueryInput(text=text_input)
+
+            response = session_client.detect_intent(
+                session=session, query_input=query_input
             )
-            return matched_skills
 
-        if "min-score" in config and result["result"]["score"] < config["min-score"]:
-            _LOGGER.debug(_("Dialogflow score lower than min-score"))
+            return response
+        else:
+            raise Warning(
+                _(
+                    "Authentication file not found or 'project-id' not in configuration, dialogflow parser will not be available"
+                )
+            )
+    except ImportError:
+        _LOGGER.error(
+            _(
+                "Unable to find dialogflow dependency. Please install dialogflow with the command pip install dialogflow if you want to use this parser."
+            )
+        )
+        opsdroid.config["parsers"][0]["enabled"] = False
+
+
+async def parse_dialogflow(opsdroid, skills, message, config):
+    """Parse a message against all Dialogflow skills.
+
+    This function does a few things, first it will check if the
+    intent confidence is higher than the minimum score set on config,
+    then it will try to match an action or an intent to a matcher and
+    add the proper skills to the skills list.
+
+    At the moment a broad exception is being used due to the fact that
+    dialogflow library doesn't have the best documentation yet and it's
+    not possible to know what sort of exceptions the library will return.
+
+    Args:
+        opsdroid (OpsDroid): An instance of opsdroid.core.
+        skills (list): A list containing all skills available.
+        message(object): An instance of events.message.
+        config (dict): configuration settings from the
+            file config.yaml.
+
+    Return:
+        Either empty list or a list containing all matched skills.
+
+    """
+    try:
+        result = await call_dialogflow(message.text, opsdroid, config)
+        matched_skills = []
+        if (
+            "min-score" in config
+            and result.query_result.intent_detection_confidence < config["min-score"]
+        ):
+            _LOGGER.debug(_("Dialogflow confidence lower than min-score"))
             return matched_skills
 
         if result:
-
             for skill in skills:
                 for matcher in skill.matchers:
-
                     if "dialogflow_action" in matcher or "dialogflow_intent" in matcher:
                         if (
-                            "action" in result["result"]
-                            and matcher["dialogflow_action"]
-                            in result["result"]["action"]
+                            matcher.get("dialogflow_action")
+                            == result.query_result.action
                         ) or (
-                            "intentName" in result["result"]
-                            and matcher["dialogflow_intent"]
-                            in result["result"]["intentName"]
+                            matcher.get("dialogflow_intent")
+                            == result.query_result.intent.display_name
                         ):
-                            message.dialogflow = result
-                            message.apiai = message.dialogflow
-                            for key, entity in (
-                                result["result"].get("parameters", {}).items()
-                            ):
-                                await message.update_entity(key, entity, None)
+
+                            message.dialogflow = result.query_result
+
                             _LOGGER.debug(
                                 _("Matched against skill %s"), skill.config["name"]
                             )
                             matched_skills.append(
                                 {
-                                    "score": result["result"]["score"],
+                                    "score": result.query_result.intent_detection_confidence,
                                     "skill": skill,
                                     "config": skill.config,
                                     "message": message,
                                 }
                             )
-    return matched_skills
+        return matched_skills
+
+    except Exception as error:
+        # TODO: Refactor broad exception
+        _LOGGER.error(
+            _("There was an error while parsing to dialogflow - {}".format(error))
+        )


Test patch:
diff --git a/requirements_test.txt b/requirements_test.txt
--- a/requirements_test.txt
+++ b/requirements_test.txt
@@ -1,6 +1,7 @@
 black==19.3b0
 flake8==3.7.8
 coveralls==1.8.2
+dialogflow==0.6.0
 astroid==2.3.1
 pytest==5.2.0
 pytest-cov==2.7.1
diff --git a/tests/test_core.py b/tests/test_core.py
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -1,3 +1,4 @@
+import os
 import asyncio
 import unittest
 import unittest.mock as mock
@@ -306,19 +307,20 @@ async def test_parse_regex_insensitive(self):
             self.assertTrue(mock_connector.send.called)
 
     async def test_parse_dialogflow(self):
+        os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/test.json"
         with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [{"name": "dialogflow"}]
-            dialogflow_action = ""
+            opsdroid.config["parsers"] = [{"name": "dialogflow", "project-id": "test"}]
+            dialogflow_action = "smalltalk.greetings.whatsup"
             skill = amock.CoroutineMock()
             mock_connector = Connector({}, opsdroid=opsdroid)
             match_dialogflow_action(dialogflow_action)(skill)
             message = Message("Hello world", "user", "default", mock_connector)
-            with amock.patch("opsdroid.parsers.dialogflow.parse_dialogflow"):
+            with amock.patch(
+                "opsdroid.parsers.dialogflow.parse_dialogflow"
+            ), amock.patch("opsdroid.parsers.dialogflow.call_dialogflow"):
                 tasks = await opsdroid.parse(message)
                 self.assertEqual(len(tasks), 1)
 
-                # Once apiai parser stops working, remove this test!
-                opsdroid.config["parsers"] = [{"name": "apiai"}]
                 tasks = await opsdroid.parse(message)
                 self.assertLogs("_LOGGER", "warning")
 
diff --git a/tests/test_matchers.py b/tests/test_matchers.py
--- a/tests/test_matchers.py
+++ b/tests/test_matchers.py
@@ -39,28 +39,6 @@ async def test_match_regex(self):
             )
             self.assertTrue(asyncio.iscoroutinefunction(opsdroid.skills[0]))
 
-    async def test_match_apiai(self):
-        with OpsDroid() as opsdroid:
-            action = "myaction"
-            decorator = matchers.match_apiai_action(action)
-            opsdroid.skills.append(decorator(await self.getMockSkill()))
-            self.assertEqual(len(opsdroid.skills), 1)
-            self.assertEqual(
-                opsdroid.skills[0].matchers[0]["dialogflow_action"], action
-            )
-            self.assertTrue(asyncio.iscoroutinefunction(opsdroid.skills[0]))
-            intent = "myIntent"
-            decorator = matchers.match_apiai_intent(intent)
-            opsdroid.skills.append(decorator(await self.getMockSkill()))
-            self.assertEqual(len(opsdroid.skills), 2)
-            self.assertEqual(
-                opsdroid.skills[1].matchers[0]["dialogflow_intent"], intent
-            )
-            self.assertTrue(asyncio.iscoroutinefunction(opsdroid.skills[1]))
-            decorator = matchers.match_apiai_intent(intent)
-            opsdroid.skills.append(decorator(await self.getMockSkill()))
-            self.assertLogs("_LOGGER", "warning")
-
     async def test_match_dialogflow(self):
         with OpsDroid() as opsdroid:
             action = "myaction"
diff --git a/tests/test_parser_dialogflow.py b/tests/test_parser_dialogflow.py
--- a/tests/test_parser_dialogflow.py
+++ b/tests/test_parser_dialogflow.py
@@ -1,8 +1,9 @@
+import os
 import asyncio
 import asynctest
 import asynctest.mock as amock
 
-from aiohttp import ClientOSError
+from types import SimpleNamespace
 
 from opsdroid.cli.start import configure_lang
 from opsdroid.core import OpsDroid
@@ -12,6 +13,16 @@
 from opsdroid.connector import Connector
 
 
+class NestedNamespace(SimpleNamespace):
+    def __init__(self, dictionary, **kwargs):
+        super().__init__(**kwargs)
+        for key, value in dictionary.items():
+            if isinstance(value, dict):
+                self.__setattr__(key, NestedNamespace(value))
+            else:
+                self.__setattr__(key, value)
+
+
 class TestParserDialogflow(asynctest.TestCase):
     """Test the opsdroid Dialogflow parser."""
 
@@ -33,137 +44,123 @@ async def mockedskill(opsdroid, config, message):
         return mockedskill
 
     async def test_call_dialogflow(self):
+        os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/test.json"
+        config = {"name": "dialogflow", "project-id": "test"}
         opsdroid = amock.CoroutineMock()
         mock_connector = Connector({}, opsdroid=opsdroid)
         message = Message("Hello world", "user", "default", mock_connector)
-        config = {"name": "dialogflow", "access-token": "test"}
+
         result = amock.Mock()
         result.json = amock.CoroutineMock()
         result.json.return_value = {
-            "result": {"action": "myaction", "score": 0.7},
-            "status": {"code": 200, "errorType": "success"},
+            "query_result": {
+                "query_text": "what is up",
+                "action": "smalltalk.greetings.whatsup",
+                "parameters": {},
+                "all_required_params_present": True,
+                "fulfillment_text": "Not much. What's new with you?",
+                "fulfillment_messages": {
+                    "text": {"text": "Not much. What's new with you?"}
+                },
+                "intent": {},
+                "intent_detection_confidence": 1.0,
+                "language_code": "en",
+            }
         }
-        with amock.patch("aiohttp.ClientSession.post") as patched_request:
-            patched_request.return_value = asyncio.Future()
+        with amock.patch("dialogflow.SessionsClient") as patched_request, amock.patch(
+            "dialogflow.types.TextInput"
+        ) as mocked_input, amock.patch(
+            "dialogflow.types.QueryInput"
+        ) as mocked_response:
+            patched_request.session_path.return_value = (
+                "projects/test/agent/sessions/opsdroid"
+            )
+            mocked_input.return_value = 'text: "hi"'
+
+            mocked_response.return_value = asyncio.Future()
             patched_request.return_value.set_result(result)
 
-            await dialogflow.call_dialogflow(message, config)
+            await dialogflow.call_dialogflow(message, opsdroid, config)
             self.assertTrue(patched_request.called)
 
-    async def test_parse_dialogflow(self):
-        with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test"}
-            ]
-            mock_skill = await self.getMockSkill()
-            mock_skill.config = {"name": "greetings"}
-            opsdroid.skills.append(match_dialogflow_action("myaction")(mock_skill))
+    async def test_call_dialogflow_failure(self):
+        config = {"name": "dialogflow"}
+        opsdroid = amock.CoroutineMock()
+        mock_connector = Connector({}, opsdroid=opsdroid)
+        message = Message("Hello world", "user", "default", mock_connector)
 
-            mock_connector = amock.CoroutineMock()
+        with self.assertRaises(Warning):
+            await dialogflow.call_dialogflow(message, opsdroid, config)
+            self.assertLogs("_LOGGER", "error")
+
+    async def test_call_dialogflow_import_failure(self):
+        with OpsDroid() as opsdroid, amock.patch(
+            "dialogflow.SessionsClient"
+        ) as patched_request, amock.patch.object(dialogflow, "parse_dialogflow"):
+            config = {"name": "dialogflow", "project-id": "test"}
+            mock_connector = Connector({}, opsdroid=opsdroid)
             message = Message("Hello world", "user", "default", mock_connector)
+            patched_request.side_effect = ImportError()
+            opsdroid.config["parsers"] = [config]
 
-            with amock.patch.object(
-                dialogflow, "call_dialogflow"
-            ) as mocked_call_dialogflow:
-                mocked_call_dialogflow.return_value = {
-                    "result": {"action": "myaction", "score": 0.7},
-                    "status": {"code": 200, "errorType": "success"},
+            await dialogflow.call_dialogflow(message, opsdroid, config)
+
+            self.assertLogs("_LOGGER", "error")
+            self.assertIn("enabled", opsdroid.config["parsers"][0])
+            self.assertEqual(opsdroid.config["parsers"][0]["enabled"], False)
+
+    async def test_parse_dialogflow(self):
+        os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/test.json"
+        dialogflow_response = NestedNamespace(
+            {
+                "query_result": {
+                    "query_text": "what is up",
+                    "action": "smalltalk.greetings.whatsup",
+                    "parameters": {},
+                    "all_required_params_present": True,
+                    "fulfillment_text": "Not much. What's new with you?",
+                    "fulfillment_messages": {
+                        "text": {"text": "Not much. What's new with you?"}
+                    },
+                    "intent": {},
+                    "intent_detection_confidence": 1.0,
+                    "language_code": "en",
                 }
-                skills = await dialogflow.parse_dialogflow(
-                    opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
-                )
-                self.assertEqual(mock_skill, skills[0]["skill"])
+            }
+        )
 
-    async def test_parse_dialogflow_entities(self):
         with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test"}
-            ]
+            opsdroid.config["parsers"] = [{"name": "dialogflow", "project-id": "test"}]
             mock_skill = await self.getMockSkill()
             mock_skill.config = {"name": "greetings"}
             opsdroid.skills.append(
-                match_dialogflow_action("restaurant.search")(mock_skill)
+                match_dialogflow_action("smalltalk.greetings.whatsup")(mock_skill)
             )
 
             mock_connector = amock.CoroutineMock()
-            message = Message(
-                "I want some good French food", "user", "default", mock_connector
-            )
-
-            with amock.patch.object(
-                dialogflow, "call_dialogflow"
-            ) as mocked_call_dialogflow:
-                mocked_call_dialogflow.return_value = {
-                    "id": "aab19d9e-3a85-4d44-95ac-2eda162c9663",
-                    "timestamp": "2019-05-24T16:44:06.972Z",
-                    "lang": "en",
-                    "result": {
-                        "source": "agent",
-                        "resolvedQuery": "I want some good French food",
-                        "action": "restaurant.search",
-                        "actionIncomplete": False,
-                        "parameters": {"Cuisine": "French"},
-                        "contexts": [],
-                        "metadata": {
-                            "intentId": "4e6ce594-6be3-461d-8d5b-418343cfbda6",
-                            "webhookUsed": "false",
-                            "webhookForSlotFillingUsed": "false",
-                            "isFallbackIntent": "false",
-                            "intentName": "restaurant.search",
-                        },
-                        "fulfillment": {
-                            "speech": "",
-                            "messages": [{"type": 0, "speech": ""}],
-                        },
-                        "score": 0.8299999833106995,
-                    },
-                    "status": {"code": 200, "errorType": "success"},
-                    "sessionId": "30ad1a2f-e760-d62f-5a21-e8aafc1eaa35",
-                }
-                [skill] = await dialogflow.parse_dialogflow(
-                    opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
-                )
-                self.assertEqual(len(skill["message"].entities.keys()), 1)
-                self.assertTrue("Cuisine" in skill["message"].entities.keys())
-                self.assertEqual(
-                    skill["message"].entities["Cuisine"]["value"], "French"
-                )
-
-    async def test_parse_dialogflow_raises(self):
-        with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test"}
-            ]
-            mock_skill = await self.getRaisingMockSkill()
-            mock_skill.config = {"name": "greetings"}
-            opsdroid.skills.append(match_dialogflow_action("myaction")(mock_skill))
-
-            mock_connector = amock.MagicMock()
-            mock_connector.send = amock.CoroutineMock()
             message = Message("Hello world", "user", "default", mock_connector)
 
             with amock.patch.object(
                 dialogflow, "call_dialogflow"
             ) as mocked_call_dialogflow:
-                mocked_call_dialogflow.return_value = {
-                    "result": {"action": "myaction", "score": 0.7},
-                    "status": {"code": 200, "errorType": "success"},
-                }
+                mocked_call_dialogflow.return_value = dialogflow_response
+
                 skills = await dialogflow.parse_dialogflow(
                     opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
                 )
                 self.assertEqual(mock_skill, skills[0]["skill"])
-
-            await opsdroid.run_skill(skills[0]["skill"], skills[0]["config"], message)
-            self.assertLogs("_LOGGER", "exception")
+                self.assertLogs("_LOGGERS", "debug")
 
     async def test_parse_dialogflow_failure(self):
+        os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/test.json"
+
         with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test"}
-            ]
-            mock_skill = amock.CoroutineMock()
-            match_dialogflow_action("myaction")(mock_skill)
+            opsdroid.config["parsers"] = [{"name": "dialogflow", "project-id": "test"}]
+            mock_skill = await self.getMockSkill()
+            mock_skill.config = {"name": "greetings"}
+            opsdroid.skills.append(
+                match_dialogflow_action("smalltalk.greetings.whatsup")(mock_skill)
+            )
 
             mock_connector = amock.CoroutineMock()
             message = Message("Hello world", "user", "default", mock_connector)
@@ -171,19 +168,36 @@ async def test_parse_dialogflow_failure(self):
             with amock.patch.object(
                 dialogflow, "call_dialogflow"
             ) as mocked_call_dialogflow:
-                mocked_call_dialogflow.return_value = {
-                    "result": {"action": "myaction", "score": 0.7},
-                    "status": {"code": 404, "errorType": "not found"},
-                }
+                mocked_call_dialogflow.side_effect = Exception()
+
                 skills = await dialogflow.parse_dialogflow(
                     opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
                 )
-                self.assertFalse(skills)
+                self.assertEqual(skills, None)
+                self.assertLogs("_LOGGERS", "debug")
 
     async def test_parse_dialogflow_low_score(self):
+        os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "path/test.json"
+        dialogflow_response = NestedNamespace(
+            {
+                "query_result": {
+                    "query_text": "what is up",
+                    "action": "smalltalk.greetings.whatsup",
+                    "parameters": {},
+                    "all_required_params_present": True,
+                    "fulfillment_text": "Not much. What's new with you?",
+                    "fulfillment_messages": {
+                        "text": {"text": "Not much. What's new with you?"}
+                    },
+                    "intent": {},
+                    "intent_detection_confidence": 0.3,
+                    "language_code": "en",
+                }
+            }
+        )
         with OpsDroid() as opsdroid:
             opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test", "min-score": 0.8}
+                {"name": "dialogflow", "project-id": "test", "min-score": 0.8}
             ]
             mock_skill = amock.CoroutineMock()
             match_dialogflow_action("myaction")(mock_skill)
@@ -194,32 +208,10 @@ async def test_parse_dialogflow_low_score(self):
             with amock.patch.object(
                 dialogflow, "call_dialogflow"
             ) as mocked_call_dialogflow:
-                mocked_call_dialogflow.return_value = {
-                    "result": {"action": "myaction", "score": 0.7},
-                    "status": {"code": 200, "errorType": "success"},
-                }
-                await dialogflow.parse_dialogflow(
-                    opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
-                )
-
-            self.assertFalse(mock_skill.called)
-
-    async def test_parse_dialogflow_raise_ClientOSError(self):
-        with OpsDroid() as opsdroid:
-            opsdroid.config["parsers"] = [
-                {"name": "dialogflow", "access-token": "test", "min-score": 0.8}
-            ]
-            mock_skill = amock.CoroutineMock()
-            match_dialogflow_action("myaction")(mock_skill)
-
-            mock_connector = amock.CoroutineMock()
-            message = Message("Hello world", "user", "default", mock_connector)
-
-            with amock.patch.object(dialogflow, "call_dialogflow") as mocked_call:
-                mocked_call.side_effect = ClientOSError()
+                mocked_call_dialogflow.return_value = dialogflow_response
                 await dialogflow.parse_dialogflow(
                     opsdroid, opsdroid.skills, message, opsdroid.config["parsers"][0]
                 )
 
             self.assertFalse(mock_skill.called)
-            self.assertTrue(mocked_call.called)
+            self.assertLogs("_LOGGERS", "debug")