Skip to content

Commit 8359a44

Browse files
committed
bool support, unit tests
1 parent 15a101d commit 8359a44

File tree

17 files changed

+262
-20
lines changed

17 files changed

+262
-20
lines changed

azure_functions_worker/bindings/datumdef.py

+3-12
Original file line numberDiff line numberDiff line change
@@ -211,18 +211,9 @@ def datum_as_proto(datum: Datum) -> protos.TypedData:
211211
return protos.TypedData(int=datum.value)
212212
elif datum.type == 'double':
213213
return protos.TypedData(double=datum.value)
214-
elif datum.type == 'http_response':
215-
return protos.TypedData(http=protos.RpcHttp(
216-
status_code=str(datum.value.status_code),
217-
headers={
218-
k: v.value
219-
for k, v in datum.value.headers.items()
220-
},
221-
cookies=parse_to_rpc_http_cookie_list(None),
222-
enable_content_negotiation=False,
223-
body=datum_as_proto(Datum(type="string",
224-
value=datum.value.get_body())),
225-
))
214+
elif datum.type == 'bool':
215+
# TypedData doesn't support bool, so we return it as an int
216+
return protos.TypedData(int=int(datum.value))
226217
else:
227218
raise NotImplementedError(
228219
'unexpected Datum type: {!r}'.format(datum.type)

azure_functions_worker/bindings/generic.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,10 @@ def encode(cls, obj: Any, *,
3838
return datumdef.Datum(type='int', value=obj)
3939
elif isinstance(obj, float):
4040
return datumdef.Datum(type='double', value=obj)
41+
elif isinstance(obj, bool):
42+
return datumdef.Datum(type='bool', value=obj)
4143
else:
42-
# This isn't a common case so we do it last
43-
from azure.functions import HttpResponse
44-
if isinstance(obj, HttpResponse):
45-
return datumdef.Datum(type='http_response', value=obj)
46-
else:
47-
raise NotImplementedError
44+
raise NotImplementedError
4845

4946
@classmethod
5047
def decode(cls, data: datumdef.Datum, *, trigger_metadata) -> typing.Any:

tests/endtoend/generic_functions/generic_functions_stein/function_app.py

+28
Original file line numberDiff line numberDiff line change
@@ -114,3 +114,31 @@ def return_list(mytimer: func.TimerRequest, testEntity):
114114
def return_int(mytimer: func.TimerRequest, testEntity):
115115
logging.info("Return int")
116116
return 12
117+
118+
119+
@app.function_name(name="return_double")
120+
@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer",
121+
run_on_startup=False,
122+
use_monitor=False)
123+
@app.generic_input_binding(
124+
arg_name="testEntity",
125+
type="table",
126+
connection="AzureWebJobsStorage",
127+
table_name="EventHubBatchTest")
128+
def return_double(mytimer: func.TimerRequest, testEntity):
129+
logging.info("Return double")
130+
return 12.34
131+
132+
133+
@app.function_name(name="return_bool")
134+
@app.schedule(schedule="*/1 * * * * *", arg_name="mytimer",
135+
run_on_startup=False,
136+
use_monitor=False)
137+
@app.generic_input_binding(
138+
arg_name="testEntity",
139+
type="table",
140+
connection="AzureWebJobsStorage",
141+
table_name="EventHubBatchTest")
142+
def return_bool(mytimer: func.TimerRequest, testEntity):
143+
logging.info("Return bool")
144+
return True

tests/endtoend/generic_functions/return_http/main.py renamed to tests/endtoend/generic_functions/return_bool/main.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@
77

88

99
def main(mytimer: func.TimerRequest, testEntity):
10-
logging.info("Return HttpResponse")
11-
return func.HttpResponse("Hello world")
10+
logging.info("Return bool")
11+
return True

tests/endtoend/test_generic_functions.py

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def check_log_return_types(self, host_out: typing.List[str]):
6262
self.assertIn("Return list", host_out)
6363
self.assertIn("Return int", host_out)
6464
self.assertIn("Return double", host_out)
65+
self.assertIn("Return bool", host_out)
6566

6667
# Checks for failed executions (TypeErrors, etc.)
6768
errors_found = False
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"type": "foobar",
6+
"name": "input",
7+
"direction": "in",
8+
"dataType": "string"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
def main(input):
6+
return True
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"type": "foobar",
6+
"name": "input",
7+
"direction": "in",
8+
"dataType": "string"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
def main(input):
6+
return {"hello": "world"}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"type": "foobar",
6+
"name": "input",
7+
"direction": "in",
8+
"dataType": "string"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
def main(input):
6+
return 12.34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"type": "foobar",
6+
"name": "input",
7+
"direction": "in",
8+
"dataType": "string"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
def main(input):
6+
return 12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"scriptFile": "main.py",
3+
"bindings": [
4+
{
5+
"type": "foobar",
6+
"name": "input",
7+
"direction": "in",
8+
"dataType": "string"
9+
}
10+
]
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
4+
5+
def main(input):
6+
return [1, 2, 3]

tests/unittests/test_mock_generic_functions.py

+140
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,143 @@ async def test_mock_generic_as_none(self):
247247
self.assertEqual(
248248
r.response.return_value,
249249
protos.TypedData(string="hello"))
250+
251+
async def test_mock_generic_return_dict(self):
252+
async with testutils.start_mockhost(
253+
script_root=self.generic_funcs_dir) as host:
254+
255+
await host.init_worker("4.17.1")
256+
func_id, r = await host.load_function('foobar_return_dict')
257+
258+
self.assertEqual(r.response.function_id, func_id)
259+
self.assertEqual(r.response.result.status,
260+
protos.StatusResult.Success)
261+
262+
_, r = await host.invoke_function(
263+
'foobar_return_dict', [
264+
protos.ParameterBinding(
265+
name='input',
266+
data=protos.TypedData(
267+
string='test'
268+
)
269+
)
270+
]
271+
)
272+
self.assertEqual(r.response.result.status,
273+
protos.StatusResult.Success)
274+
self.assertEqual(
275+
r.response.return_value,
276+
protos.TypedData(json="{\"hello\": \"world\"}")
277+
)
278+
279+
async def test_mock_generic_return_list(self):
280+
async with testutils.start_mockhost(
281+
script_root=self.generic_funcs_dir) as host:
282+
283+
await host.init_worker("4.17.1")
284+
func_id, r = await host.load_function('foobar_return_list')
285+
286+
self.assertEqual(r.response.function_id, func_id)
287+
self.assertEqual(r.response.result.status,
288+
protos.StatusResult.Success)
289+
290+
_, r = await host.invoke_function(
291+
'foobar_return_list', [
292+
protos.ParameterBinding(
293+
name='input',
294+
data=protos.TypedData(
295+
string='test'
296+
)
297+
)
298+
]
299+
)
300+
self.assertEqual(r.response.result.status,
301+
protos.StatusResult.Success)
302+
self.assertEqual(
303+
r.response.return_value,
304+
protos.TypedData(json="[1, 2, 3]")
305+
)
306+
307+
async def test_mock_generic_return_int(self):
308+
async with testutils.start_mockhost(
309+
script_root=self.generic_funcs_dir) as host:
310+
311+
await host.init_worker("4.17.1")
312+
func_id, r = await host.load_function('foobar_return_int')
313+
314+
self.assertEqual(r.response.function_id, func_id)
315+
self.assertEqual(r.response.result.status,
316+
protos.StatusResult.Success)
317+
318+
_, r = await host.invoke_function(
319+
'foobar_return_int', [
320+
protos.ParameterBinding(
321+
name='input',
322+
data=protos.TypedData(
323+
string='test'
324+
)
325+
)
326+
]
327+
)
328+
self.assertEqual(r.response.result.status,
329+
protos.StatusResult.Success)
330+
self.assertEqual(
331+
r.response.return_value,
332+
protos.TypedData(int=12)
333+
)
334+
335+
async def test_mock_generic_return_double(self):
336+
async with testutils.start_mockhost(
337+
script_root=self.generic_funcs_dir) as host:
338+
339+
await host.init_worker("4.17.1")
340+
func_id, r = await host.load_function('foobar_return_double')
341+
342+
self.assertEqual(r.response.function_id, func_id)
343+
self.assertEqual(r.response.result.status,
344+
protos.StatusResult.Success)
345+
346+
_, r = await host.invoke_function(
347+
'foobar_return_double', [
348+
protos.ParameterBinding(
349+
name='input',
350+
data=protos.TypedData(
351+
string='test'
352+
)
353+
)
354+
]
355+
)
356+
self.assertEqual(r.response.result.status,
357+
protos.StatusResult.Success)
358+
self.assertEqual(
359+
r.response.return_value,
360+
protos.TypedData(double=12.34)
361+
)
362+
363+
async def test_mock_generic_return_bool(self):
364+
async with testutils.start_mockhost(
365+
script_root=self.generic_funcs_dir) as host:
366+
367+
await host.init_worker("4.17.1")
368+
func_id, r = await host.load_function('foobar_return_bool')
369+
370+
self.assertEqual(r.response.function_id, func_id)
371+
self.assertEqual(r.response.result.status,
372+
protos.StatusResult.Success)
373+
374+
_, r = await host.invoke_function(
375+
'foobar_return_bool', [
376+
protos.ParameterBinding(
377+
name='input',
378+
data=protos.TypedData(
379+
string='test'
380+
)
381+
)
382+
]
383+
)
384+
self.assertEqual(r.response.result.status,
385+
protos.StatusResult.Success)
386+
self.assertEqual(
387+
r.response.return_value,
388+
protos.TypedData(int=1)
389+
)

0 commit comments

Comments
 (0)