We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
An exception is raised when calling MockDatastoreService.set_value() with a ttl
## SUMMARY

When using `MockDatastoreService.set_value()` for unit testing (e.g. via `BaseActionTestCase`), a `ValueError` exception will be raised if `ttl` argument is specified.


### STACKSTORM VERSION

`st2 3.1.0, on Python 3.6.8`

### OS, environment, install method

Custom install, but not relevant to this case, see below.

## Steps to reproduce the problem

See [code](https://github.com/StackStorm/st2/blob/6d1809a4bb577e117baa00f249757284db9c6e76/st2tests/st2tests/mocks/datastore.py#L108) for `MockDatastoreService.set_value()`. If `ttl` argument is specified, `ValueError` will explicitly be raised.

```python
class MockDatastoreService(BaseDatastoreService):
    # ...
    def set_value(self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False):
        """
        Store a value in a dictionary which is local to this class.
        """
        if ttl:
            raise ValueError('MockDatastoreService.set_value doesn\'t support "ttl" argument')
        # ...
```


## Expected Results

Both `action_service.set_value()` and  `sensor_service.set_value()` support `ttl` argument. Although I understand that this argument cannot be honored in a mock situation, `MockDatastoreService`  should be consistent with the behavior of the class it is mocking - perhaps fire a warning instead of an Exception?

## Actual Results

An exception is returned while running tests:
```python
ValueError: MockDatastoreService.set_value doesn't support "ttl" argument
```
It is not possible to test actions or sensors that use `xxx.set_value()` with a `ttl` argument.



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `st2tests/st2tests/mocks/datastore.py`
Content:
```
1 # Copyright 2020 The StackStorm Authors.
2 # Copyright 2019 Extreme Networks, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15 
16 """
17 Mock classes for use in pack testing.
18 """
19 
20 from __future__ import absolute_import
21 from st2common.constants.keyvalue import SYSTEM_SCOPE
22 from st2common.services.datastore import BaseDatastoreService
23 from st2client.models.keyvalue import KeyValuePair
24 
25 __all__ = ["MockDatastoreService"]
26 
27 
28 class MockDatastoreService(BaseDatastoreService):
29     """
30     Mock DatastoreService for use in testing.
31     """
32 
33     def __init__(self, logger, pack_name, class_name, api_username=None):
34         self._pack_name = pack_name
35         self._class_name = class_name
36         self._username = api_username or "admin"
37 
38         # Holds mock KeyValuePair objects
39         # Key is a KeyValuePair name and value is the KeyValuePair object
40         self._datastore_items = {}
41 
42     ##################################
43     # General methods
44     ##################################
45 
46     def get_user_info(self):
47         """
48         Retrieve information about the current user which is authenticated against StackStorm and
49         used to perform other datastore operations via the API.
50 
51         :rtype: ``dict``
52         """
53         result = {
54             "username": self._username,
55             "rbac": {"is_admin": True, "enabled": True, "roles": ["admin"]},
56             "authentication": {"method": "authentication token", "location": "header"},
57         }
58 
59         return result
60 
61     ##################################
62     # Methods for datastore management
63     ##################################
64 
65     def list_values(self, local=True, prefix=None):
66         """
67         Return a list of all values stored in a dictionary which is local to this class.
68         """
69         key_prefix = self._get_full_key_prefix(local=local, prefix=prefix)
70 
71         if not key_prefix:
72             return list(self._datastore_items.values())
73 
74         result = []
75         for name, kvp in self._datastore_items.items():
76             if name.startswith(key_prefix):
77                 result.append(kvp)
78 
79         return result
80 
81     def get_value(self, name, local=True, scope=SYSTEM_SCOPE, decrypt=False):
82         """
83         Return a particular value stored in a dictionary which is local to this class.
84         """
85         name = self._get_full_key_name(name=name, local=local)
86 
87         if name not in self._datastore_items:
88             return None
89 
90         kvp = self._datastore_items[name]
91         return kvp.value
92 
93     def set_value(
94         self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False
95     ):
96         """
97         Store a value in a dictionary which is local to this class.
98         """
99         if ttl:
100             raise ValueError(
101                 'MockDatastoreService.set_value doesn\'t support "ttl" argument'
102             )
103 
104         name = self._get_full_key_name(name=name, local=local)
105 
106         instance = KeyValuePair()
107         instance.id = name
108         instance.name = name
109         instance.value = value
110 
111         self._datastore_items[name] = instance
112         return True
113 
114     def delete_value(self, name, local=True, scope=SYSTEM_SCOPE):
115         """
116         Delete a value from a dictionary which is local to this class.
117         """
118         name = self._get_full_key_name(name=name, local=local)
119 
120         if name not in self._datastore_items:
121             return False
122 
123         del self._datastore_items[name]
124         return True
125
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/st2tests/st2tests/mocks/datastore.py b/st2tests/st2tests/mocks/datastore.py
--- a/st2tests/st2tests/mocks/datastore.py
+++ b/st2tests/st2tests/mocks/datastore.py
@@ -34,6 +34,7 @@
         self._pack_name = pack_name
         self._class_name = class_name
         self._username = api_username or "admin"
+        self._logger = logger
 
         # Holds mock KeyValuePair objects
         # Key is a KeyValuePair name and value is the KeyValuePair object
@@ -96,10 +97,6 @@
         """
         Store a value in a dictionary which is local to this class.
         """
-        if ttl:
-            raise ValueError(
-                'MockDatastoreService.set_value doesn\'t support "ttl" argument'
-            )
 
         name = self._get_full_key_name(name=name, local=local)
 
@@ -107,6 +104,11 @@
         instance.id = name
         instance.name = name
         instance.value = value
+        if ttl:
+            self._logger.warning(
+                "MockDatastoreService is not able to expire keys based on ttl."
+            )
+            instance.ttl = ttl
 
         self._datastore_items[name] = instance
         return True

{"golden_diff": "diff --git a/st2tests/st2tests/mocks/datastore.py b/st2tests/st2tests/mocks/datastore.py\n--- a/st2tests/st2tests/mocks/datastore.py\n+++ b/st2tests/st2tests/mocks/datastore.py\n@@ -34,6 +34,7 @@\n         self._pack_name = pack_name\n         self._class_name = class_name\n         self._username = api_username or \"admin\"\n+        self._logger = logger\n \n         # Holds mock KeyValuePair objects\n         # Key is a KeyValuePair name and value is the KeyValuePair object\n@@ -96,10 +97,6 @@\n         \"\"\"\n         Store a value in a dictionary which is local to this class.\n         \"\"\"\n-        if ttl:\n-            raise ValueError(\n-                'MockDatastoreService.set_value doesn\\'t support \"ttl\" argument'\n-            )\n \n         name = self._get_full_key_name(name=name, local=local)\n \n@@ -107,6 +104,11 @@\n         instance.id = name\n         instance.name = name\n         instance.value = value\n+        if ttl:\n+            self._logger.warning(\n+                \"MockDatastoreService is not able to expire keys based on ttl.\"\n+            )\n+            instance.ttl = ttl\n \n         self._datastore_items[name] = instance\n         return True\n", "issue": "An exception is raised when calling MockDatastoreService.set_value() with a ttl\n## SUMMARY\r\n\r\nWhen using `MockDatastoreService.set_value()` for unit testing (e.g. via `BaseActionTestCase`), a `ValueError` exception will be raised if `ttl` argument is specified.\r\n\r\n\r\n### STACKSTORM VERSION\r\n\r\n`st2 3.1.0, on Python 3.6.8`\r\n\r\n### OS, environment, install method\r\n\r\nCustom install, but not relevant to this case, see below.\r\n\r\n## Steps to reproduce the problem\r\n\r\nSee [code](https://github.com/StackStorm/st2/blob/6d1809a4bb577e117baa00f249757284db9c6e76/st2tests/st2tests/mocks/datastore.py#L108) for `MockDatastoreService.set_value()`. If `ttl` argument is specified, `ValueError` will explicitly be raised.\r\n\r\n```python\r\nclass MockDatastoreService(BaseDatastoreService):\r\n    # ...\r\n    def set_value(self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False):\r\n        \"\"\"\r\n        Store a value in a dictionary which is local to this class.\r\n        \"\"\"\r\n        if ttl:\r\n            raise ValueError('MockDatastoreService.set_value doesn\\'t support \"ttl\" argument')\r\n        # ...\r\n```\r\n\r\n\r\n## Expected Results\r\n\r\nBoth `action_service.set_value()` and  `sensor_service.set_value()` support `ttl` argument. Although I understand that this argument cannot be honored in a mock situation, `MockDatastoreService`  should be consistent with the behavior of the class it is mocking - perhaps fire a warning instead of an Exception?\r\n\r\n## Actual Results\r\n\r\nAn exception is returned while running tests:\r\n```python\r\nValueError: MockDatastoreService.set_value doesn't support \"ttl\" argument\r\n```\r\nIt is not possible to test actions or sensors that use `xxx.set_value()` with a `ttl` argument.\r\n\r\n\n", "before_files": [{"content": "# Copyright 2020 The StackStorm Authors.\n# Copyright 2019 Extreme Networks, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nMock classes for use in pack testing.\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom st2common.constants.keyvalue import SYSTEM_SCOPE\nfrom st2common.services.datastore import BaseDatastoreService\nfrom st2client.models.keyvalue import KeyValuePair\n\n__all__ = [\"MockDatastoreService\"]\n\n\nclass MockDatastoreService(BaseDatastoreService):\n    \"\"\"\n    Mock DatastoreService for use in testing.\n    \"\"\"\n\n    def __init__(self, logger, pack_name, class_name, api_username=None):\n        self._pack_name = pack_name\n        self._class_name = class_name\n        self._username = api_username or \"admin\"\n\n        # Holds mock KeyValuePair objects\n        # Key is a KeyValuePair name and value is the KeyValuePair object\n        self._datastore_items = {}\n\n    ##################################\n    # General methods\n    ##################################\n\n    def get_user_info(self):\n        \"\"\"\n        Retrieve information about the current user which is authenticated against StackStorm and\n        used to perform other datastore operations via the API.\n\n        :rtype: ``dict``\n        \"\"\"\n        result = {\n            \"username\": self._username,\n            \"rbac\": {\"is_admin\": True, \"enabled\": True, \"roles\": [\"admin\"]},\n            \"authentication\": {\"method\": \"authentication token\", \"location\": \"header\"},\n        }\n\n        return result\n\n    ##################################\n    # Methods for datastore management\n    ##################################\n\n    def list_values(self, local=True, prefix=None):\n        \"\"\"\n        Return a list of all values stored in a dictionary which is local to this class.\n        \"\"\"\n        key_prefix = self._get_full_key_prefix(local=local, prefix=prefix)\n\n        if not key_prefix:\n            return list(self._datastore_items.values())\n\n        result = []\n        for name, kvp in self._datastore_items.items():\n            if name.startswith(key_prefix):\n                result.append(kvp)\n\n        return result\n\n    def get_value(self, name, local=True, scope=SYSTEM_SCOPE, decrypt=False):\n        \"\"\"\n        Return a particular value stored in a dictionary which is local to this class.\n        \"\"\"\n        name = self._get_full_key_name(name=name, local=local)\n\n        if name not in self._datastore_items:\n            return None\n\n        kvp = self._datastore_items[name]\n        return kvp.value\n\n    def set_value(\n        self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False\n    ):\n        \"\"\"\n        Store a value in a dictionary which is local to this class.\n        \"\"\"\n        if ttl:\n            raise ValueError(\n                'MockDatastoreService.set_value doesn\\'t support \"ttl\" argument'\n            )\n\n        name = self._get_full_key_name(name=name, local=local)\n\n        instance = KeyValuePair()\n        instance.id = name\n        instance.name = name\n        instance.value = value\n\n        self._datastore_items[name] = instance\n        return True\n\n    def delete_value(self, name, local=True, scope=SYSTEM_SCOPE):\n        \"\"\"\n        Delete a value from a dictionary which is local to this class.\n        \"\"\"\n        name = self._get_full_key_name(name=name, local=local)\n\n        if name not in self._datastore_items:\n            return False\n\n        del self._datastore_items[name]\n        return True\n", "path": "st2tests/st2tests/mocks/datastore.py"}], "after_files": [{"content": "# Copyright 2020 The StackStorm Authors.\n# Copyright 2019 Extreme Networks, Inc.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\n\"\"\"\nMock classes for use in pack testing.\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom st2common.constants.keyvalue import SYSTEM_SCOPE\nfrom st2common.services.datastore import BaseDatastoreService\nfrom st2client.models.keyvalue import KeyValuePair\n\n__all__ = [\"MockDatastoreService\"]\n\n\nclass MockDatastoreService(BaseDatastoreService):\n    \"\"\"\n    Mock DatastoreService for use in testing.\n    \"\"\"\n\n    def __init__(self, logger, pack_name, class_name, api_username=None):\n        self._pack_name = pack_name\n        self._class_name = class_name\n        self._username = api_username or \"admin\"\n        self._logger = logger\n\n        # Holds mock KeyValuePair objects\n        # Key is a KeyValuePair name and value is the KeyValuePair object\n        self._datastore_items = {}\n\n    ##################################\n    # General methods\n    ##################################\n\n    def get_user_info(self):\n        \"\"\"\n        Retrieve information about the current user which is authenticated against StackStorm and\n        used to perform other datastore operations via the API.\n\n        :rtype: ``dict``\n        \"\"\"\n        result = {\n            \"username\": self._username,\n            \"rbac\": {\"is_admin\": True, \"enabled\": True, \"roles\": [\"admin\"]},\n            \"authentication\": {\"method\": \"authentication token\", \"location\": \"header\"},\n        }\n\n        return result\n\n    ##################################\n    # Methods for datastore management\n    ##################################\n\n    def list_values(self, local=True, prefix=None):\n        \"\"\"\n        Return a list of all values stored in a dictionary which is local to this class.\n        \"\"\"\n        key_prefix = self._get_full_key_prefix(local=local, prefix=prefix)\n\n        if not key_prefix:\n            return list(self._datastore_items.values())\n\n        result = []\n        for name, kvp in self._datastore_items.items():\n            if name.startswith(key_prefix):\n                result.append(kvp)\n\n        return result\n\n    def get_value(self, name, local=True, scope=SYSTEM_SCOPE, decrypt=False):\n        \"\"\"\n        Return a particular value stored in a dictionary which is local to this class.\n        \"\"\"\n        name = self._get_full_key_name(name=name, local=local)\n\n        if name not in self._datastore_items:\n            return None\n\n        kvp = self._datastore_items[name]\n        return kvp.value\n\n    def set_value(\n        self, name, value, ttl=None, local=True, scope=SYSTEM_SCOPE, encrypt=False\n    ):\n        \"\"\"\n        Store a value in a dictionary which is local to this class.\n        \"\"\"\n\n        name = self._get_full_key_name(name=name, local=local)\n\n        instance = KeyValuePair()\n        instance.id = name\n        instance.name = name\n        instance.value = value\n        if ttl:\n            self._logger.warning(\n                \"MockDatastoreService is not able to expire keys based on ttl.\"\n            )\n            instance.ttl = ttl\n\n        self._datastore_items[name] = instance\n        return True\n\n    def delete_value(self, name, local=True, scope=SYSTEM_SCOPE):\n        \"\"\"\n        Delete a value from a dictionary which is local to this class.\n        \"\"\"\n        name = self._get_full_key_name(name=name, local=local)\n\n        if name not in self._datastore_items:\n            return False\n\n        del self._datastore_items[name]\n        return True\n", "path": "st2tests/st2tests/mocks/datastore.py"}]}