Skip to content

Commit b7bcd98

Browse files
authored
Minor improvements in testing, builds and pipeline (#707)
* Doing nit fixes - Adding flake8 description - Adding typing info for parameters - fixing minor flake8 issues. - Using pytest's plugins to improve static testing, and using it to do coverage. - Adding schedule for running tests on branches
1 parent 4bcdc5a commit b7bcd98

9 files changed

+53
-37
lines changed

.ci/linux_devops_code_coverage_generate.sh

Lines changed: 0 additions & 7 deletions
This file was deleted.

.ci/linux_devops_e2e_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ export AzureWebJobsCosmosDBConnectionString=$LINUXCOSMOSDBCONNECTIONSTRING
66
export AzureWebJobsEventHubConnectionString=$LINUXEVENTHUBCONNECTIONSTRING
77
export AzureWebJobsServiceBusConnectionString=$LINUXSERVICEBUSCONNECTIONSTRING
88

9-
coverage run -p --branch -m pytest tests/endtoend
9+
pytest --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch --cov-append tests/endtoend

.ci/linux_devops_unit_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
#!/bin/bash
22

33
set -e -x
4-
coverage run -p --branch -m pytest tests/unittests
4+
pytest --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests

.flake8

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
[flake8]
2+
# it's not a bug that we aren't using all of hacking, ignore:
3+
# H402: Module level import not at top of file
4+
# W503: Line break occurred before a binary operator
5+
# E731: Do not assign a lambda expression, use a def
26
ignore = W503,E402,E731
3-
exclude =
4-
.git, __pycache__, build, dist, .eggs, .github, .local, docs/,
5-
Samples, azure_functions_worker/protos/,
6-
azure_functions_worker/_thirdparty/typing_inspect.py,
7-
tests/unittests/test_typing_inspect.py,
8-
.venv*, .env*, .vscode, venv
7+
8+
exclude = .git, __pycache__, build, dist, .eggs, .github, .local, docs/,
9+
Samples, azure_functions_worker/protos/,
10+
azure_functions_worker/_thirdparty/typing_inspect.py,
11+
tests/unittests/test_typing_inspect.py, .venv*, .env*, .vscode, venv
12+
13+
max-line-length = 80

azure-pipelines.yml

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ trigger:
88
variables:
99
DOTNET_VERSION: '2.2.207'
1010

11+
schedules:
12+
- cron: "0 0 * * *"
13+
displayName: Daily midnight build
14+
branches:
15+
include:
16+
- dev
17+
- master
18+
- release/*
19+
exclude:
20+
- releases/ancient/*
21+
1122
jobs:
1223
- job: Tests
1324
pool:
@@ -60,10 +71,6 @@ jobs:
6071
LINUXEVENTHUBCONNECTIONSTRING: $(linuxEventHub)
6172
LINUXSERVICEBUSCONNECTIONSTRING: $(linuxServiceBus)
6273
displayName: 'E2E Tests'
63-
- bash: |
64-
chmod +x .ci/linux_devops_code_coverage_generate.sh
65-
.ci/linux_devops_code_coverage_generate.sh
66-
displayName: 'Generate Code Coverage XML file'
6774
- task: PublishCodeCoverageResults@1
6875
inputs:
6976
codeCoverageTool: cobertura

azure_functions_worker/dispatcher.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,17 @@ class Dispatcher(metaclass=DispatcherMeta):
4646

4747
_GRPC_STOP_RESPONSE = object()
4848

49-
def __init__(self, loop, host, port, worker_id, request_id,
50-
grpc_connect_timeout, grpc_max_msg_len=-1):
49+
def __init__(self, loop, host, port: int, worker_id: str, request_id: str,
50+
grpc_connect_timeout: float, grpc_max_msg_len: int = -1):
5151
self._loop = loop
5252
self._host = host
5353
self._port = port
5454
self._request_id = request_id
5555
self._worker_id = worker_id
5656
self._functions = functions.Registry()
5757

58+
self._old_task_factory = None
59+
5860
# A thread-pool for synchronous function calls. We limit
5961
# the number of threads to 1 so that one Python worker can
6062
# only run one synchronous function in parallel. This is
@@ -75,7 +77,8 @@ def __init__(self, loop, host, port, worker_id, request_id,
7577
self._grpc_thread = threading.Thread(
7678
name='grpc-thread', target=self.__poll_grpc)
7779

78-
def load_bindings(self):
80+
@staticmethod
81+
def load_bindings():
7982
"""Load out-of-tree binding implementations."""
8083
services = {}
8184

@@ -88,18 +91,17 @@ def load_bindings(self):
8891
@classmethod
8992
async def connect(cls, host, port, worker_id, request_id,
9093
connect_timeout):
91-
loop = asyncio._get_running_loop()
92-
disp = cls(loop, host, port, worker_id, request_id,
93-
connect_timeout)
94+
loop = asyncio.events.get_event_loop()
95+
disp = cls(loop, host, port, worker_id, request_id, connect_timeout)
9496
disp._grpc_thread.start()
9597
await disp._grpc_connected_fut
9698
logger.info('Successfully opened gRPC channel to %s:%s', host, port)
9799
return disp
98100

99101
async def dispatch_forever(self):
100102
if DispatcherMeta.__current_dispatcher__ is not None:
101-
raise RuntimeError(
102-
'there can be only one running dispatcher per process')
103+
raise RuntimeError('there can be only one running dispatcher per '
104+
'process')
103105

104106
self._old_task_factory = self._loop.get_task_factory()
105107

@@ -131,7 +133,7 @@ async def dispatch_forever(self):
131133
try:
132134
await forever
133135
finally:
134-
# Reenable console logging when there's an exception
136+
# Re-enable console logging when there's an exception
135137
enable_console_logging()
136138
root_logger.removeHandler(logging_handler)
137139
finally:
@@ -152,7 +154,7 @@ def stop(self):
152154
self._sync_call_tp.shutdown()
153155
self._sync_call_tp = None
154156

155-
def _on_logging(self, record: logging.LogRecord, formatted_msg: str):
157+
def on_logging(self, record: logging.LogRecord, formatted_msg: str):
156158
if record.levelno >= logging.CRITICAL:
157159
log_level = protos.RpcLog.Critical
158160
elif record.levelno >= logging.ERROR:
@@ -201,7 +203,9 @@ def request_id(self):
201203
def worker_id(self):
202204
return self._worker_id
203205

204-
def _serialize_exception(self, exc):
206+
# noinspection PyBroadException
207+
@staticmethod
208+
def _serialize_exception(exc: Exception):
205209
try:
206210
message = f'{type(exc).__name__}: {exc}'
207211
except Exception:
@@ -222,8 +226,8 @@ async def _dispatch_grpc_request(self, request):
222226
# Don't crash on unknown messages. Some of them can be ignored;
223227
# and if something goes really wrong the host can always just
224228
# kill the worker's process.
225-
logger.error(
226-
f'unknown StreamingMessage content type {content_type}')
229+
logger.error(f'unknown StreamingMessage content type '
230+
f'{content_type}')
227231
return
228232

229233
resp = await request_handler(request)
@@ -524,7 +528,7 @@ def emit(self, record):
524528
# Since we disable console log after gRPC channel is initiated
525529
# We should redirect all the messages into dispatcher
526530
msg = self.format(record)
527-
Dispatcher.current._on_logging(record, msg)
531+
Dispatcher.current.on_logging(record, msg)
528532

529533

530534
class ContextEnabledTask(asyncio.Task):

setup.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,12 @@ def run(self):
290290
'mypy',
291291
'pytest',
292292
'requests==2.*',
293-
'coverage'
293+
'coverage',
294+
'pytest-sugar',
295+
'pytest-cov',
296+
'pytest-xdist',
297+
'pytest-randomly',
298+
'pytest-instafail'
294299
]
295300
},
296301
include_package_data=True,

tests/unittests/test_loader.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ async def _runner():
9494

9595
# Trimming off carriage return charater when testing on Windows
9696
stdout_lines = [
97-
l.replace(b'\r', b'') for l in stdout.strip().split(b'\n')
97+
line.replace(b'\r', b'') for line in stdout.strip().split(b'\n')
9898
]
9999
self.assertEqual(stdout_lines, [b'True', b'True'])
100100

tests/unittests/test_mock_http_functions.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ async def test_call_sync_function_check_logs(self):
2222
self.assertEqual(r.response.result.status,
2323
protos.StatusResult.Success)
2424

25-
user_logs = [l for l in r.logs if l.category == 'my function']
25+
user_logs = [line for line in r.logs
26+
if line.category == 'my function']
2627
self.assertEqual(len(user_logs), 1)
2728

2829
log = user_logs[0]
@@ -48,7 +49,8 @@ async def test_call_async_function_check_logs(self):
4849
self.assertEqual(r.response.result.status,
4950
protos.StatusResult.Success)
5051

51-
user_logs = [l for l in r.logs if l.category == 'my function']
52+
user_logs = [line for line in r.logs if
53+
line.category == 'my function']
5254
self.assertEqual(len(user_logs), 2)
5355

5456
first_msg = user_logs[0]

0 commit comments

Comments
 (0)