diff --git a/azure_functions_worker/bindings/datumdef.py b/azure_functions_worker/bindings/datumdef.py index 2df29da47..48136e8bd 100644 --- a/azure_functions_worker/bindings/datumdef.py +++ b/azure_functions_worker/bindings/datumdef.py @@ -201,6 +201,19 @@ def datum_as_proto(datum: Datum) -> protos.TypedData: )) elif datum.type is None: return None + elif datum.type == 'dict': + # TypedData doesn't support dict, so we return it as json + return protos.TypedData(json=json.dumps(datum.value)) + elif datum.type == 'list': + # TypedData doesn't support list, so we return it as json + return protos.TypedData(json=json.dumps(datum.value)) + elif datum.type == 'int': + return protos.TypedData(int=datum.value) + elif datum.type == 'double': + return protos.TypedData(double=datum.value) + elif datum.type == 'bool': + # TypedData doesn't support bool, so we return it as an int + return protos.TypedData(int=int(datum.value)) else: raise NotImplementedError( 'unexpected Datum type: {!r}'.format(datum.type) diff --git a/azure_functions_worker/bindings/generic.py b/azure_functions_worker/bindings/generic.py index 28db5fe78..901b15e78 100644 --- a/azure_functions_worker/bindings/generic.py +++ b/azure_functions_worker/bindings/generic.py @@ -30,6 +30,16 @@ def encode(cls, obj: Any, *, return datumdef.Datum(type='bytes', value=bytes(obj)) elif obj is None: return datumdef.Datum(type=None, value=obj) + elif isinstance(obj, dict): + return datumdef.Datum(type='dict', value=obj) + elif isinstance(obj, list): + return datumdef.Datum(type='list', value=obj) + elif isinstance(obj, int): + return datumdef.Datum(type='int', value=obj) + elif isinstance(obj, float): + return datumdef.Datum(type='double', value=obj) + elif isinstance(obj, bool): + return datumdef.Datum(type='bool', value=obj) else: raise NotImplementedError diff --git a/tests/endtoend/generic_functions/generic_functions_stein/function_app.py b/tests/endtoend/generic_functions/generic_functions_stein/function_app.py index 7eff50d3d..c77aaaf03 100644 --- a/tests/endtoend/generic_functions/generic_functions_stein/function_app.py +++ b/tests/endtoend/generic_functions/generic_functions_stein/function_app.py @@ -1,6 +1,7 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. import azure.functions as func + import logging app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS) @@ -45,7 +46,91 @@ def mytimer(mytimer: func.TimerRequest, testEntity) -> None: logging.info("This timer trigger function executed successfully") -@app.function_name(name="mytimer2") +@app.function_name(name="return_string") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_string(mytimer: func.TimerRequest, testEntity): + logging.info("Return string") + return "hi!" + + +@app.function_name(name="return_bytes") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_bytes(mytimer: func.TimerRequest, testEntity): + logging.info("Return bytes") + return "test-dată" + + +@app.function_name(name="return_dict") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_dict(mytimer: func.TimerRequest, testEntity): + logging.info("Return dict") + return {"hello": "world"} + + +@app.function_name(name="return_list") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_list(mytimer: func.TimerRequest, testEntity): + logging.info("Return list") + return [1, 2, 3] + + +@app.function_name(name="return_int") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_int(mytimer: func.TimerRequest, testEntity): + logging.info("Return int") + return 12 + + +@app.function_name(name="return_double") +@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", + run_on_startup=False, + use_monitor=False) +@app.generic_input_binding( + arg_name="testEntity", + type="table", + connection="AzureWebJobsStorage", + table_name="EventHubBatchTest") +def return_double(mytimer: func.TimerRequest, testEntity): + logging.info("Return double") + return 12.34 + + +@app.function_name(name="return_bool") @app.schedule(schedule="*/1 * * * * *", arg_name="mytimer", run_on_startup=False, use_monitor=False) @@ -54,5 +139,6 @@ def mytimer(mytimer: func.TimerRequest, testEntity) -> None: type="table", connection="AzureWebJobsStorage", table_name="EventHubBatchTest") -def mytimer2(mytimer: func.TimerRequest, testEntity): - logging.info("Timer trigger with none return and no type hint") +def return_bool(mytimer: func.TimerRequest, testEntity): + logging.info("Return bool") + return True diff --git a/tests/endtoend/generic_functions/return_bool/function.json b/tests/endtoend/generic_functions/return_bool/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_bool/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_bool/main.py b/tests/endtoend/generic_functions/return_bool/main.py new file mode 100644 index 000000000..08d693dff --- /dev/null +++ b/tests/endtoend/generic_functions/return_bool/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return bool") + return True diff --git a/tests/endtoend/generic_functions/return_bytes/function.json b/tests/endtoend/generic_functions/return_bytes/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_bytes/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_bytes/main.py b/tests/endtoend/generic_functions/return_bytes/main.py new file mode 100644 index 000000000..c02b678c0 --- /dev/null +++ b/tests/endtoend/generic_functions/return_bytes/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return bytes") + return "test-dată" diff --git a/tests/endtoend/generic_functions/return_dict/function.json b/tests/endtoend/generic_functions/return_dict/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_dict/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_dict/main.py b/tests/endtoend/generic_functions/return_dict/main.py new file mode 100644 index 000000000..27f343fcb --- /dev/null +++ b/tests/endtoend/generic_functions/return_dict/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return dict") + return {"hello": "world"} diff --git a/tests/endtoend/generic_functions/return_double/function.json b/tests/endtoend/generic_functions/return_double/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_double/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_double/main.py b/tests/endtoend/generic_functions/return_double/main.py new file mode 100644 index 000000000..6bfc4b9d7 --- /dev/null +++ b/tests/endtoend/generic_functions/return_double/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return double") + return 12.34 diff --git a/tests/endtoend/generic_functions/return_int/function.json b/tests/endtoend/generic_functions/return_int/function.json new file mode 100644 index 000000000..54c81f8f3 --- /dev/null +++ b/tests/endtoend/generic_functions/return_int/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} diff --git a/tests/endtoend/generic_functions/return_int/main.py b/tests/endtoend/generic_functions/return_int/main.py new file mode 100644 index 000000000..3a5e7175d --- /dev/null +++ b/tests/endtoend/generic_functions/return_int/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return int") + return 12 diff --git a/tests/endtoend/generic_functions/return_list/function.json b/tests/endtoend/generic_functions/return_list/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_list/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_list/main.py b/tests/endtoend/generic_functions/return_list/main.py new file mode 100644 index 000000000..feccec7e2 --- /dev/null +++ b/tests/endtoend/generic_functions/return_list/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return list") + return [1, 2, 3] diff --git a/tests/endtoend/generic_functions/return_string/function.json b/tests/endtoend/generic_functions/return_string/function.json new file mode 100644 index 000000000..4dc852e37 --- /dev/null +++ b/tests/endtoend/generic_functions/return_string/function.json @@ -0,0 +1,21 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "name": "mytimer", + "type": "timerTrigger", + "direction": "in", + "schedule": "*/1 * * * * *", + "runOnStartup": false + }, + { + "direction": "in", + "type": "table", + "name": "testEntity", + "partitionKey": "test", + "rowKey": "WillBePopulatedWithGuid", + "tableName": "BindingTestTable", + "connection": "AzureWebJobsStorage" + } + ] +} \ No newline at end of file diff --git a/tests/endtoend/generic_functions/return_string/main.py b/tests/endtoend/generic_functions/return_string/main.py new file mode 100644 index 000000000..02f7aa432 --- /dev/null +++ b/tests/endtoend/generic_functions/return_string/main.py @@ -0,0 +1,11 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import logging + +import azure.functions as func + + +def main(mytimer: func.TimerRequest, testEntity): + logging.info("Return string") + return "hi!" diff --git a/tests/endtoend/test_generic_functions.py b/tests/endtoend/test_generic_functions.py index 4f1d14461..fa983a060 100644 --- a/tests/endtoend/test_generic_functions.py +++ b/tests/endtoend/test_generic_functions.py @@ -44,25 +44,33 @@ def test_return_not_processed_last(self): r = self.webhost.request('GET', 'return_not_processed_last') self.assertEqual(r.status_code, 200) - def test_return_none(self): - time.sleep(1) + def test_return_types(self): + # Checking that the function app is okay + time.sleep(10) # Checking webhost status. r = self.webhost.request('GET', '', no_prefix=True, timeout=5) self.assertTrue(r.ok) - def test_return_none_no_type_hint(self): - time.sleep(1) - # Checking webhost status. - r = self.webhost.request('GET', '', no_prefix=True, - timeout=5) - self.assertTrue(r.ok) - - def check_log_timer(self, host_out: typing.List[str]): - self.assertEqual(host_out.count("This timer trigger function executed " - "successfully"), 1) - self.assertEqual(host_out.count("Timer trigger with none return " - "and no type hint"), 1) + def check_log_return_types(self, host_out: typing.List[str]): + # Checks that functions executed correctly + self.assertIn("This timer trigger function executed " + "successfully", host_out) + self.assertIn("Return string", host_out) + self.assertIn("Return bytes", host_out) + self.assertIn("Return dict", host_out) + self.assertIn("Return list", host_out) + self.assertIn("Return int", host_out) + self.assertIn("Return double", host_out) + self.assertIn("Return bool", host_out) + + # Checks for failed executions (TypeErrors, etc.) + errors_found = False + for log in host_out: + if "Exception" in log: + errors_found = True + break + self.assertFalse(errors_found) @skipIf(is_envvar_true(DEDICATED_DOCKER_TEST) diff --git a/tests/unittests/generic_functions/foobar_as_none/function.json b/tests/unittests/generic_functions/foobar_as_none/function.json new file mode 100644 index 000000000..7a458eb7f --- /dev/null +++ b/tests/unittests/generic_functions/foobar_as_none/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "direction": "out", + "name": "$return", + "type": "foobar", + "dataType": "binary" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_as_none/main.py b/tests/unittests/generic_functions/foobar_as_none/main.py new file mode 100644 index 000000000..b7acadcdd --- /dev/null +++ b/tests/unittests/generic_functions/foobar_as_none/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(): + return "hello" diff --git a/tests/unittests/generic_functions/foobar_return_bool/function.json b/tests/unittests/generic_functions/foobar_return_bool/function.json new file mode 100644 index 000000000..6f8a83ec0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_bool/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "type": "foobar", + "name": "input", + "direction": "in", + "dataType": "string" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_return_bool/main.py b/tests/unittests/generic_functions/foobar_return_bool/main.py new file mode 100644 index 000000000..4fadd2bff --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_bool/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(input): + return True diff --git a/tests/unittests/generic_functions/foobar_return_dict/function.json b/tests/unittests/generic_functions/foobar_return_dict/function.json new file mode 100644 index 000000000..6f8a83ec0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_dict/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "type": "foobar", + "name": "input", + "direction": "in", + "dataType": "string" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_return_dict/main.py b/tests/unittests/generic_functions/foobar_return_dict/main.py new file mode 100644 index 000000000..c8aef81a3 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_dict/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(input): + return {"hello": "world"} diff --git a/tests/unittests/generic_functions/foobar_return_double/function.json b/tests/unittests/generic_functions/foobar_return_double/function.json new file mode 100644 index 000000000..6f8a83ec0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_double/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "type": "foobar", + "name": "input", + "direction": "in", + "dataType": "string" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_return_double/main.py b/tests/unittests/generic_functions/foobar_return_double/main.py new file mode 100644 index 000000000..42aac3fc0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_double/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(input): + return 12.34 diff --git a/tests/unittests/generic_functions/foobar_return_int/function.json b/tests/unittests/generic_functions/foobar_return_int/function.json new file mode 100644 index 000000000..6f8a83ec0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_int/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "type": "foobar", + "name": "input", + "direction": "in", + "dataType": "string" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_return_int/main.py b/tests/unittests/generic_functions/foobar_return_int/main.py new file mode 100644 index 000000000..8beb85606 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_int/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(input): + return 12 diff --git a/tests/unittests/generic_functions/foobar_return_list/function.json b/tests/unittests/generic_functions/foobar_return_list/function.json new file mode 100644 index 000000000..6f8a83ec0 --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_list/function.json @@ -0,0 +1,11 @@ +{ + "scriptFile": "main.py", + "bindings": [ + { + "type": "foobar", + "name": "input", + "direction": "in", + "dataType": "string" + } + ] +} diff --git a/tests/unittests/generic_functions/foobar_return_list/main.py b/tests/unittests/generic_functions/foobar_return_list/main.py new file mode 100644 index 000000000..1d1a4a5ea --- /dev/null +++ b/tests/unittests/generic_functions/foobar_return_list/main.py @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + + +def main(input): + return [1, 2, 3] diff --git a/tests/unittests/test_mock_generic_functions.py b/tests/unittests/test_mock_generic_functions.py index 695d53110..159ec681e 100644 --- a/tests/unittests/test_mock_generic_functions.py +++ b/tests/unittests/test_mock_generic_functions.py @@ -173,6 +173,9 @@ async def test_mock_generic_should_support_without_datatype(self): # implicitly self.assertEqual(r.response.result.status, protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(bytes=b'\x00\x01')) async def test_mock_generic_implicit_output_exemption(self): async with testutils.start_mockhost( @@ -223,3 +226,164 @@ async def test_mock_generic_as_nil_data(self): self.assertEqual( r.response.return_value, protos.TypedData()) + + async def test_mock_generic_as_none(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_as_none') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_as_none', [ + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(string="hello")) + + async def test_mock_generic_return_dict(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_return_dict') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_return_dict', [ + protos.ParameterBinding( + name='input', + data=protos.TypedData( + string='test' + ) + ) + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(json="{\"hello\": \"world\"}") + ) + + async def test_mock_generic_return_list(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_return_list') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_return_list', [ + protos.ParameterBinding( + name='input', + data=protos.TypedData( + string='test' + ) + ) + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(json="[1, 2, 3]") + ) + + async def test_mock_generic_return_int(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_return_int') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_return_int', [ + protos.ParameterBinding( + name='input', + data=protos.TypedData( + string='test' + ) + ) + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(int=12) + ) + + async def test_mock_generic_return_double(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_return_double') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_return_double', [ + protos.ParameterBinding( + name='input', + data=protos.TypedData( + string='test' + ) + ) + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(double=12.34) + ) + + async def test_mock_generic_return_bool(self): + async with testutils.start_mockhost( + script_root=self.generic_funcs_dir) as host: + + await host.init_worker("4.17.1") + func_id, r = await host.load_function('foobar_return_bool') + + self.assertEqual(r.response.function_id, func_id) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + + _, r = await host.invoke_function( + 'foobar_return_bool', [ + protos.ParameterBinding( + name='input', + data=protos.TypedData( + string='test' + ) + ) + ] + ) + self.assertEqual(r.response.result.status, + protos.StatusResult.Success) + self.assertEqual( + r.response.return_value, + protos.TypedData(int=1) + )