Skip to content

Commit be5e361

Browse files
committed
tests!
1 parent 2f125d9 commit be5e361

19 files changed

+1394
-44
lines changed

azure_functions_worker_v2/bindings/meta.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def from_incoming_proto(
171171
val = pb.data
172172
datum = Datum.from_typed_data(val)
173173
else:
174-
raise TypeError('Unknown ParameterBindingType: %s', pb_type)
174+
raise TypeError('Unknown ParameterBindingType: %s' % pb_type)
175175

176176
try:
177177
# if the binding is an sdk type binding
@@ -189,7 +189,7 @@ def from_incoming_proto(
189189
raise TypeError(
190190
'unable to decode incoming TypedData: '
191191
'unsupported combination of TypedData field %s '
192-
'and expected binding type %s', repr(dt), binding_obj)
192+
'and expected binding type %s' % (repr(dt), binding_obj))
193193

194194

195195
def get_datum(binding: str, obj: Any,
@@ -205,7 +205,7 @@ def get_datum(binding: str, obj: Any,
205205
raise TypeError(
206206
'unable to encode outgoing TypedData: '
207207
'unsupported type "%s" for '
208-
'Python type "%s"', binding, type(obj).__name__)
208+
'Python type "%s"' % (binding, type(obj).__name__))
209209
return datum
210210

211211

azure_functions_worker_v2/bindings/nullable_converters.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def to_nullable_string(nullable: Optional[str], property_name: str, protos):
2222
if nullable is not None:
2323
raise TypeError(
2424
"A 'str' type was expected instead of a '%s' "
25-
"type. Cannot parse value %s of '%s'.",
26-
type(nullable), nullable, property_name)
25+
"type. Cannot parse value %s of '%s'."
26+
% (type(nullable), nullable, property_name))
2727

2828
return None
2929

@@ -45,8 +45,8 @@ def to_nullable_bool(nullable: Optional[bool], property_name: str, protos):
4545
if nullable is not None:
4646
raise TypeError(
4747
"A 'bool' type was expected instead of a '%s' "
48-
"type. Cannot parse value %s of '%s'.",
49-
type(nullable), nullable, property_name)
48+
"type. Cannot parse value %s of '%s'."
49+
% (type(nullable), nullable, property_name))
5050

5151
return None
5252

@@ -74,14 +74,14 @@ def to_nullable_double(nullable: Optional[Union[str, int, float]],
7474
except Exception:
7575
raise TypeError(
7676
"Cannot parse value %s of '%s' to "
77-
"float.", nullable, property_name)
77+
"float." % (nullable, property_name))
7878

7979
if nullable is not None:
8080
raise TypeError(
8181
"A 'int' or 'float'"
8282
" type was expected instead of a '%s' "
83-
"type. Cannot parse value %s of '%s'.",
84-
type(nullable), nullable, property_name)
83+
"type. Cannot parse value %s of '%s'."
84+
% (type(nullable), nullable, property_name))
8585

8686
return None
8787

@@ -110,6 +110,6 @@ def to_nullable_timestamp(date_time: Optional[Union[datetime, int]],
110110
raise TypeError(
111111
"A 'datetime' or 'int'"
112112
" type was expected instead of a '%s' "
113-
"type. Cannot parse value %s of '%s'.",
114-
type(date_time), date_time, property_name)
113+
"type. Cannot parse value %s of '%s'."
114+
% (type(date_time), date_time, property_name))
115115
return None

azure_functions_worker_v2/handle_event.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Copyright (c) Microsoft Corporation. All rights reserved.
22
# Licensed under the MIT License.
3-
43
import json
54
import logging
65
import os

azure_functions_worker_v2/loader.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from datetime import timedelta
1212
from typing import Dict, Optional, Union
1313

14-
1514
from .functions import Registry
1615
from .logging import logger
1716

@@ -168,14 +167,15 @@ def index_function_app(function_path: str):
168167
else:
169168
raise ValueError(
170169
"More than one %s or other top "
171-
"level function app instances are defined.", app.__class__.__name__)
170+
"level function app instances are defined."
171+
% app.__class__.__name__)
172172

173173
if not app:
174174
script_file_name = get_app_setting(
175175
setting=PYTHON_SCRIPT_FILE_NAME,
176176
default_value=PYTHON_SCRIPT_FILE_NAME_DEFAULT)
177-
raise ValueError("Could not find top level function app instances in %s.",
178-
script_file_name)
177+
raise ValueError("Could not find top level function app instances in %s."
178+
% script_file_name)
179179

180180
return app.get_functions()
181181

azure_functions_worker_v2/otel.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ def update_opentelemetry_status():
5353
TraceContextTextMapPropagator,
5454
)
5555

56-
OTelManager.set_context_api(context_api)
57-
OTelManager.set_trace_context_propagator(TraceContextTextMapPropagator())
56+
otel_manager.set_context_api(context_api)
57+
otel_manager.set_trace_context_propagator(TraceContextTextMapPropagator())
5858

5959
except ImportError:
6060
logger.exception(
@@ -88,26 +88,26 @@ def initialize_azure_monitor():
8888
default_value=PYTHON_APPLICATIONINSIGHTS_LOGGER_NAME_DEFAULT
8989
),
9090
)
91-
OTelManager.set_azure_monitor_available(True)
91+
otel_manager.set_azure_monitor_available(azure_monitor_available=True)
9292

9393
logger.info("Successfully configured Azure monitor distro.")
9494
except ImportError:
9595
logger.exception(
9696
"Cannot import Azure Monitor distro."
9797
)
98-
OTelManager.set_azure_monitor_available(False)
98+
otel_manager.set_azure_monitor_available(False)
9999
except Exception:
100100
logger.exception(
101101
"Error initializing Azure monitor distro."
102102
)
103-
OTelManager.set_azure_monitor_available(False)
103+
otel_manager.set_azure_monitor_available(False)
104104

105105

106106
def configure_opentelemetry(invocation_context):
107107
carrier = {TRACEPARENT: invocation_context.trace_context.trace_parent,
108108
TRACESTATE: invocation_context.trace_context.trace_state}
109-
ctx = OTelManager.get_trace_context_propagator().extract(carrier)
110-
OTelManager.get_context_api().attach(ctx)
109+
ctx = otel_manager.get_trace_context_propagator().extract(carrier)
110+
otel_manager.get_context_api().attach(ctx)
111111

112112

113113
otel_manager = OTelManager()

eng/templates/jobs/ci-unit-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,5 @@ jobs:
2222
- bash: |
2323
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker_v2 --cov-report xml --cov-branch tests/unittests
2424
displayName: "Running $(PYTHON_VERSION) Unit Tests"
25+
env:
26+
AzureWebJobsStorage: $(AzureWebJobsStorage)

tests/unittests/basic_function/function_app.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
# Licensed under the MIT License.
33

44
import logging
5-
import time
6-
from datetime import datetime
75

86
import azure.functions as func
97

tests/unittests/test_app_setting_manager.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
# Licensed under the MIT License.
33
import os
44

5-
from azure_functions_worker_v2.utils.app_setting_manager import get_python_appsetting_state
5+
from azure_functions_worker_v2.utils.app_setting_manager import (
6+
get_python_appsetting_state)
67
from azure_functions_worker_v2.utils.constants import (
78
PYTHON_ENABLE_DEBUG_LOGGING,
89
PYTHON_THREADPOOL_THREAD_COUNT,
@@ -17,7 +18,7 @@ class TestDefaultAppSettingsLogs(testutils.AsyncTestCase):
1718
def test_get_python_appsetting_state(self):
1819
app_setting_state = get_python_appsetting_state()
1920
expected_string = ""
20-
self.assertEquals(expected_string, app_setting_state)
21+
self.assertEqual(expected_string, app_setting_state)
2122

2223

2324
class TestNonDefaultAppSettingsLogs(testutils.AsyncTestCase):

tests/unittests/test_datumdef.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
import unittest
4+
5+
import tests.protos as protos
6+
7+
from datetime import datetime
8+
from http.cookies import SimpleCookie
9+
10+
from azure_functions_worker_v2.bindings.datumdef import (
11+
Datum,
12+
parse_cookie_attr_expires,
13+
parse_cookie_attr_same_site,
14+
parse_to_rpc_http_cookie_list,
15+
)
16+
from azure_functions_worker_v2.bindings.nullable_converters import (
17+
to_nullable_bool,
18+
to_nullable_double,
19+
to_nullable_string,
20+
to_nullable_timestamp,
21+
)
22+
23+
24+
class TestDatumDef(unittest.TestCase):
25+
def test_parse_cookie_attr_expires_none(self):
26+
self.assertEqual(parse_cookie_attr_expires({"expires": None}), None)
27+
28+
def test_parse_cookie_attr_expires_zero_length(self):
29+
self.assertEqual(parse_cookie_attr_expires({"expires": ""}), None)
30+
31+
def test_parse_cookie_attr_expires_valid(self):
32+
self.assertEqual(parse_cookie_attr_expires(
33+
{"expires": "Thu, 12 Jan 2017 13:55:08 GMT"}),
34+
datetime.strptime("Thu, 12 Jan 2017 13:55:08 GMT",
35+
"%a, %d %b %Y %H:%M:%S GMT"))
36+
37+
def test_parse_cookie_attr_expires_value_error(self):
38+
with self.assertRaises(ValueError):
39+
parse_cookie_attr_expires(
40+
{"expires": "Thu, 12 Jan 2017 13:550:08 GMT"})
41+
42+
def test_parse_cookie_attr_expires_overflow_error(self):
43+
with self.assertRaises(ValueError):
44+
parse_cookie_attr_expires(
45+
{"expires": "Thu, 12 Jan 9999999999999999 13:55:08 GMT"})
46+
47+
def test_parse_cookie_attr_same_site_default(self):
48+
self.assertEqual(parse_cookie_attr_same_site(
49+
{}, protos),
50+
getattr(protos.RpcHttpCookie.SameSite, "None"))
51+
52+
def test_parse_cookie_attr_same_site_lax(self):
53+
self.assertEqual(parse_cookie_attr_same_site(
54+
{'samesite': 'lax'}, protos),
55+
getattr(protos.RpcHttpCookie.SameSite, "Lax"))
56+
57+
def test_parse_cookie_attr_same_site_strict(self):
58+
self.assertEqual(parse_cookie_attr_same_site(
59+
{'samesite': 'strict'}, protos),
60+
getattr(protos.RpcHttpCookie.SameSite, "Strict"))
61+
62+
def test_parse_cookie_attr_same_site_explicit_none(self):
63+
self.assertEqual(parse_cookie_attr_same_site(
64+
{'samesite': 'none'}, protos),
65+
getattr(protos.RpcHttpCookie.SameSite, "ExplicitNone"))
66+
67+
def test_parse_to_rpc_http_cookie_list_none(self):
68+
self.assertEqual(parse_to_rpc_http_cookie_list(None, protos), None)
69+
70+
@unittest.skip("TODO: fix this test. Figure out what to do with Timestamp")
71+
def test_parse_to_rpc_http_cookie_list_valid(self):
72+
headers = [
73+
'foo=bar; Path=/some/path; Secure; HttpOnly; Domain=123; '
74+
'SameSite=Lax; Max-Age=12345; Expires=Thu, 12 Jan 2017 13:55:08 '
75+
'GMT;',
76+
'foo2=bar; Path=/some/path2; Secure; HttpOnly; Domain=123; '
77+
'SameSite=Lax; Max-Age=12345; Expires=Thu, 12 Jan 2017 13:55:08 '
78+
'GMT;']
79+
80+
cookies = SimpleCookie('\r\n'.join(headers))
81+
82+
cookie1 = protos.RpcHttpCookie(name="foo",
83+
value="bar",
84+
domain=to_nullable_string("123",
85+
"cookie.domain",
86+
protos),
87+
path=to_nullable_string("/some/path",
88+
"cookie.path",
89+
protos),
90+
expires=to_nullable_timestamp(
91+
parse_cookie_attr_expires(
92+
{
93+
"expires": "Thu, "
94+
"12 Jan 2017 13:55:08"
95+
" GMT"}),
96+
'cookie.expires',
97+
protos),
98+
secure=to_nullable_bool(
99+
bool("True"),
100+
'cookie.secure',
101+
protos),
102+
http_only=to_nullable_bool(
103+
bool("True"),
104+
'cookie.httpOnly',
105+
protos),
106+
same_site=parse_cookie_attr_same_site(
107+
{"samesite": "Lax"},
108+
protos),
109+
max_age=to_nullable_double(
110+
12345,
111+
'cookie.maxAge',
112+
protos))
113+
114+
cookie2 = protos.RpcHttpCookie(name="foo2",
115+
value="bar",
116+
domain=to_nullable_string("123",
117+
"cookie.domain",
118+
protos),
119+
path=to_nullable_string("/some/path2",
120+
"cookie.path",
121+
protos),
122+
expires=to_nullable_timestamp(
123+
parse_cookie_attr_expires(
124+
{
125+
"expires": "Thu, "
126+
"12 Jan 2017 13:55:08"
127+
" GMT"}),
128+
'cookie.expires',
129+
protos),
130+
secure=to_nullable_bool(
131+
bool("True"),
132+
'cookie.secure',
133+
protos),
134+
http_only=to_nullable_bool(
135+
bool("True"),
136+
'cookie.httpOnly',
137+
protos),
138+
same_site=parse_cookie_attr_same_site(
139+
{"samesite": "Lax"},
140+
protos),
141+
max_age=to_nullable_double(
142+
12345,
143+
'cookie.maxAge',
144+
protos))
145+
146+
rpc_cookies = parse_to_rpc_http_cookie_list([cookies], protos)
147+
self.assertEqual(cookie1, rpc_cookies[0])
148+
self.assertEqual(cookie2, rpc_cookies[1])
149+
150+
def test_parse_to_rpc_http_cookie_list_no_cookie(self):
151+
datum = Datum(
152+
type='http',
153+
value=dict(
154+
status_code=None,
155+
headers=None,
156+
body=None,
157+
)
158+
)
159+
160+
self.assertIsNone(
161+
parse_to_rpc_http_cookie_list(datum.value.get('cookies'), protos))

tests/unittests/test_deferred_bindings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
EVENTHUB_SAMPLE_CONTENT = b"\x00Sr\xc1\x8e\x08\xa3\x1bx-opt-sequence-number-epochT\xff\xa3\x15x-opt-sequence-numberU\x04\xa3\x0cx-opt-offset\x81\x00\x00\x00\x01\x00\x00\x010\xa3\x13x-opt-enqueued-time\x00\xa3\x1dcom.microsoft:datetime-offset\x81\x08\xddW\x05\xc3Q\xcf\x10\x00St\xc1I\x02\xa1\rDiagnostic-Id\xa1700-bdc3fde4889b4e907e0c9dcb46ff8d92-21f637af293ef13b-00\x00Su\xa0\x08message1" # noqa: E501
1919

20+
2021
class TestDeferredBindingsEnabled(testutils.AsyncTestCase):
2122

2223
def test_mbd_deferred_bindings_enabled_decode(self):
@@ -93,4 +94,4 @@ async def test_check_deferred_bindings_enabled(self):
9394
self.assertEqual(meta.check_deferred_bindings_enabled(
9495
ContainerClient, True), (True, True))
9596
self.assertEqual(meta.check_deferred_bindings_enabled(
96-
StorageStreamDownloader, True), (True, True))
97+
StorageStreamDownloader, True), (True, True))

tests/unittests/test_handle_event.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,23 +114,19 @@ async def test_worker_init_request_with_exception(self):
114114
self.assertIsNotNone(result.worker_metadata.worker_bitness)
115115
self.assertEqual(result.result.status, 1)
116116

117-
async def test_functions_metadata_request(self):
117+
@patch("azure_functions_worker_v2.loader.index_function_app",
118+
return_value=True)
119+
async def test_functions_metadata_request(self, mock_index_function_app):
118120
handle_event.protos = test_protos
119121
metadata_result = await functions_metadata_request(None)
120122
self.assertEqual(metadata_result.result.status, 1)
121123

122-
123-
def test_functions_metadata_request_with_exception(self):
124-
pass
125-
126-
def test_invocation_request_sync(self):
127-
pass
128-
129-
def test_invocation_request_async(self):
130-
pass
131-
132-
def test_invocation_request_with_exception(self):
133-
pass
124+
@patch("azure_functions_worker_v2.metadata_exception",
125+
return_value=Exception)
126+
async def test_functions_metadata_request_with_exception(self):
127+
handle_event.protos = test_protos
128+
metadata_result = await functions_metadata_request(None)
129+
self.assertEqual(metadata_result.result.status, 0)
134130

135131
@patch("azure_functions_worker_v2.loader.index_function_app",
136132
return_value=True)

0 commit comments

Comments
 (0)