Skip to content

Commit c681591

Browse files
authored
Enhance test Webhost logs and fix 503s (#1411)
* add sanity check for testwebhost and refactor webhost log after test * reduce ut pipeline passing log * format * format * update github action versions * codecov * fix ut ppl * fix deprecated output flag * Revert "fix deprecated output flag" This reverts commit af04661. * fix output 2 * Revert "fix output 2" This reverts commit 5b03b6f. * len check * enable host console log for ut pipeline * suppress passed ut log * reduce log * reduce log for e2e ppl * upload webhost log to artifact * fix * archive logs for e2e ppl * revert format * add lang version to log filename * fix * always publish archive * revert * upgrade eg ext version * revert gitignore * only publish log if failure * feedback * feedback * fix * fback * flake
1 parent eef7628 commit c681591

File tree

6 files changed

+91
-40
lines changed

6 files changed

+91
-40
lines changed

.github/Scripts/e2e-tests.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
#!/usr/bin/env bash
2-
python -m pytest -n auto --dist loadfile --reruns 4 -vv --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch --cov-append tests/endtoend/test_worker_process_count_functions.py tests/endtoend/test_threadpool_thread_count_functions.py
3-
python -m pytest -n auto --dist loadfile --reruns 4 -vv --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch --cov-append --ignore=tests/endtoend/test_worker_process_count_functions.py --ignore=tests/endtoend/test_threadpool_thread_count_functions.py tests/endtoend
2+
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch --cov-append tests/endtoend/test_worker_process_count_functions.py tests/endtoend/test_threadpool_thread_count_functions.py
3+
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch --cov-append --ignore=tests/endtoend/test_worker_process_count_functions.py --ignore=tests/endtoend/test_threadpool_thread_count_functions.py tests/endtoend

.github/workflows/ci_e2e_workflow.yml

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@ name: CI E2E tests
55

66
on:
77
workflow_dispatch:
8+
inputs:
9+
archive_webhost_logging:
10+
description: "For debugging purposes, archive test webhost logs"
11+
required: false
12+
default: "false"
813
push:
9-
branches: [ dev, master, main, release/* ]
14+
branches: [dev, master, main, release/*]
1015
pull_request:
11-
branches: [ dev, master, main, release/* ]
16+
branches: [dev, master, main, release/*]
1217
schedule:
1318
# Monday to Thursday 1 AM PDT build
1419
# * is a special character in YAML so you have to quote this string
@@ -21,27 +26,23 @@ jobs:
2126
strategy:
2227
fail-fast: false
2328
matrix:
24-
python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ]
29+
python-version: [3.7, 3.8, 3.9, "3.10", "3.11"]
2530
permissions: read-all
2631
steps:
2732
- name: Checkout code.
28-
uses: actions/checkout@v2
33+
uses: actions/checkout@v4
2934
- name: Set up Python ${{ matrix.python-version }}
30-
uses: actions/setup-python@v2
35+
uses: actions/setup-python@v5
3136
with:
3237
python-version: ${{ matrix.python-version }}
33-
- name: Set up Dotnet 3.1.x
34-
uses: actions/setup-dotnet@v1
35-
with:
36-
dotnet-version: '3.1.x'
3738
- name: Set up Dotnet 6.x
38-
uses: actions/setup-dotnet@v1
39+
uses: actions/setup-dotnet@v4
3940
with:
40-
dotnet-version: '6.x'
41+
dotnet-version: "6.x"
4142
- name: Set up Dotnet 8.0.x
42-
uses: actions/setup-dotnet@v1
43+
uses: actions/setup-dotnet@v4
4344
with:
44-
dotnet-version: '8.0.x'
45+
dotnet-version: "8.0.x"
4546
- name: Install dependencies and the worker
4647
run: |
4748
retry() {
@@ -64,11 +65,12 @@ jobs:
6465
python -m pip install --upgrade pip
6566
python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple -U azure-functions --pre
6667
python -m pip install -U -e .[dev]
67-
68+
6869
# Retry a couple times to avoid certificate issue
6970
retry 5 python setup.py build
7071
retry 5 python setup.py webhost --branch-name=dev
7172
retry 5 python setup.py extension
73+
mkdir logs
7274
- name: Grant execute permission
7375
run: chmod +x .github/Scripts/e2e-tests.sh
7476
- name: Running 3.7 Tests
@@ -81,6 +83,7 @@ jobs:
8183
AzureWebJobsSqlConnectionString: ${{ secrets.LinuxSqlConnectionString37 }}
8284
AzureWebJobsEventGridTopicUri: ${{ secrets.LinuxEventGridTopicUriString37 }}
8385
AzureWebJobsEventGridConnectionKey: ${{ secrets.LinuxEventGridConnectionKeyString37 }}
86+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
8487
run: .github/Scripts/e2e-tests.sh
8588
- name: Running 3.8 Tests
8689
if: matrix.python-version == 3.8
@@ -92,6 +95,7 @@ jobs:
9295
AzureWebJobsSqlConnectionString: ${{ secrets.LinuxSqlConnectionString38 }}
9396
AzureWebJobsEventGridTopicUri: ${{ secrets.LinuxEventGridTopicUriString38 }}
9497
AzureWebJobsEventGridConnectionKey: ${{ secrets.LinuxEventGridConnectionKeyString38 }}
98+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
9599
run: .github/Scripts/e2e-tests.sh
96100
- name: Running 3.9 Tests
97101
if: matrix.python-version == 3.9
@@ -103,6 +107,7 @@ jobs:
103107
AzureWebJobsSqlConnectionString: ${{ secrets.LinuxSqlConnectionString39 }}
104108
AzureWebJobsEventGridTopicUri: ${{ secrets.LinuxEventGridTopicUriString39 }}
105109
AzureWebJobsEventGridConnectionKey: ${{ secrets.LinuxEventGridConnectionKeyString39 }}
110+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
106111
run: .github/Scripts/e2e-tests.sh
107112
- name: Running 3.10 Tests
108113
if: matrix.python-version == 3.10
@@ -114,6 +119,7 @@ jobs:
114119
AzureWebJobsSqlConnectionString: ${{ secrets.LinuxSqlConnectionString310 }}
115120
AzureWebJobsEventGridTopicUri: ${{ secrets.LinuxEventGridTopicUriString310 }}
116121
AzureWebJobsEventGridConnectionKey: ${{ secrets.LinuxEventGridConnectionKeyString310 }}
122+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
117123
run: .github/Scripts/e2e-tests.sh
118124
- name: Running 3.11 Tests
119125
if: matrix.python-version == 3.11
@@ -125,11 +131,19 @@ jobs:
125131
AzureWebJobsSqlConnectionString: ${{ secrets.LinuxSqlConnectionString311 }}
126132
AzureWebJobsEventGridTopicUri: ${{ secrets.LinuxEventGridTopicUriString311 }}
127133
AzureWebJobsEventGridConnectionKey: ${{ secrets.LinuxEventGridConnectionKeyString311 }}
134+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
128135
run: .github/Scripts/e2e-tests.sh
129136
- name: Codecov
130-
uses: codecov/codecov-action@v1.0.13
137+
uses: codecov/codecov-action@v3
131138
with:
132139
file: ./coverage.xml # optional
133140
flags: unittests # optional
134141
name: codecov # optional
135142
fail_ci_if_error: false # optional (default = false)
143+
- name: Publish Logs to Artifact
144+
if: failure()
145+
uses: actions/upload-artifact@v4
146+
with:
147+
name: Test WebHost Logs ${{ github.run_id }} ${{ matrix.python-version }}
148+
path: logs/*.log
149+
if-no-files-found: ignore

.github/workflows/ci_ut_workflow.yml

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ name: CI Unit tests
55

66
on:
77
workflow_dispatch:
8+
inputs:
9+
archive_webhost_logging:
10+
description: "For debugging purposes, archive test webhost logs"
11+
required: false
12+
default: "false"
813
schedule:
914
# Monday to Thursday 1 AM PDT build
1015
# * is a special character in YAML so you have to quote this string
@@ -23,21 +28,13 @@ jobs:
2328
python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ]
2429
permissions: read-all
2530
steps:
26-
- uses: actions/checkout@v2
31+
- uses: actions/checkout@v4
2732
- name: Set up Python ${{ matrix.python-version }}
28-
uses: actions/setup-python@v2
33+
uses: actions/setup-python@v5
2934
with:
3035
python-version: ${{ matrix.python-version }}
31-
- name: Set up Dotnet 3.1.x
32-
uses: actions/setup-dotnet@v1
33-
with:
34-
dotnet-version: '3.1.x'
35-
- name: Set up Dotnet 6.x
36-
uses: actions/setup-dotnet@v1
37-
with:
38-
dotnet-version: '6.x'
3936
- name: Set up Dotnet 8.0.x
40-
uses: actions/setup-dotnet@v1
37+
uses: actions/setup-dotnet@v4
4138
with:
4239
dotnet-version: "8.0.x"
4340
- name: Install dependencies and the worker
@@ -67,15 +64,24 @@ jobs:
6764
retry 5 python setup.py build
6865
retry 5 python setup.py webhost --branch-name=dev
6966
retry 5 python setup.py extension
67+
mkdir logs
7068
- name: Test with pytest
7169
env:
7270
AzureWebJobsStorage: ${{ secrets.LinuxStorageConnectionString310 }} # needed for installing azure-functions-durable while running setup.py
71+
ARCHIVE_WEBHOST_LOGS: ${{ github.event.inputs.archive_webhost_logging }}
7372
run: |
74-
python -m pytest -n auto --dist loadfile --reruns 4 -vv --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests
73+
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests
7574
- name: Codecov
7675
uses: codecov/codecov-action@v3
7776
with:
7877
file: ./coverage.xml # optional
7978
flags: unittests # optional
8079
name: codecov # optional
8180
fail_ci_if_error: false # optional (default = false)
81+
- name: Publish Logs to Artifact
82+
if: failure()
83+
uses: actions/upload-artifact@v4
84+
with:
85+
name: Test WebHost Logs ${{ github.run_id }} ${{ matrix.python-version }}
86+
path: logs/*.log
87+
if-no-files-found: ignore

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.EventHubs"
4646
Version="5.0.0" />
4747
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.EventGrid"
48-
Version="3.1.0" />
48+
Version="3.3.1" />
4949
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage"
5050
Version="4.0.5" />
5151
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.ServiceBus"

tests/utils/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
# Debug Flags
1616
PYAZURE_WEBHOST_DEBUG = "PYAZURE_WEBHOST_DEBUG"
17+
ARCHIVE_WEBHOST_LOGS = "ARCHIVE_WEBHOST_LOGS"
1718

1819
# CI test constants
1920
CONSUMPTION_DOCKER_TEST = "CONSUMPTION_DOCKER_TEST"

tests/utils/testutils.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@
4848
from azure_functions_worker.utils.common import is_envvar_true, get_app_setting
4949
from tests.utils.constants import PYAZURE_WORKER_DIR, \
5050
PYAZURE_INTEGRATION_TEST, PROJECT_ROOT, WORKER_CONFIG, \
51-
CONSUMPTION_DOCKER_TEST, DEDICATED_DOCKER_TEST, PYAZURE_WEBHOST_DEBUG
51+
CONSUMPTION_DOCKER_TEST, DEDICATED_DOCKER_TEST, PYAZURE_WEBHOST_DEBUG, \
52+
ARCHIVE_WEBHOST_LOGS
5253
from tests.utils.testutils_docker import WebHostConsumption, WebHostDedicated, \
5354
DockerConfigs
5455

@@ -257,6 +258,14 @@ def setUpClass(cls):
257258
_setup_func_app(TESTS_ROOT / script_dir)
258259
cls.webhost = start_webhost(script_dir=script_dir,
259260
stdout=cls.host_stdout)
261+
if not cls.webhost.is_healthy():
262+
cls.host_out = cls.host_stdout.read()
263+
if cls.host_out is not None and len(cls.host_out) > 0:
264+
error_message = 'WebHost is not started correctly. '
265+
f'{cls.host_stdout.name}: {cls.host_out}'
266+
cls.host_stdout_logger.error(error_message)
267+
raise RuntimeError(error_message)
268+
260269
except Exception:
261270
_teardown_func_app(TESTS_ROOT / script_dir)
262271
raise
@@ -267,6 +276,21 @@ def tearDownClass(cls):
267276
cls.webhost = None
268277

269278
if cls.host_stdout is not None:
279+
if is_envvar_true(ARCHIVE_WEBHOST_LOGS):
280+
cls.host_stdout.seek(0)
281+
content = cls.host_stdout.read()
282+
if content is not None and len(content) > 0:
283+
version_info = sys.version_info
284+
log_file = (
285+
"logs/"
286+
f"{cls.__module__}_{cls.__name__}"
287+
f"{version_info.minor}_webhost.log"
288+
)
289+
with open(log_file, 'w+') as file:
290+
file.write(content)
291+
cls.host_stdout_logger.info("WebHost log is archived to"
292+
f"{log_file} in the artifact")
293+
270294
cls.host_stdout.close()
271295
cls.host_stdout = None
272296

@@ -287,16 +311,18 @@ def _run_test(self, test, *args, **kwargs):
287311
test(self, *args, **kwargs)
288312
except Exception as e:
289313
test_exception = e
290-
291-
try:
292-
self.host_stdout.seek(last_pos)
293-
self.host_out = self.host_stdout.read()
294-
self.host_stdout_logger.error(
295-
'Captured WebHost stdout from %s :\n%s',
296-
self.host_stdout.name, self.host_out)
297314
finally:
298-
if test_exception is not None:
299-
raise test_exception
315+
try:
316+
self.host_stdout.seek(last_pos)
317+
self.host_out = self.host_stdout.read()
318+
if self.host_out is not None and len(self.host_out) > 0:
319+
self.host_stdout_logger.error(
320+
'Captured WebHost log generated during test '
321+
'%s from %s :\n%s', test.__name__,
322+
self.host_stdout.name, self.host_out)
323+
finally:
324+
if test_exception is not None:
325+
raise test_exception
300326

301327

302328
class SharedMemoryTestCase(unittest.TestCase):
@@ -776,6 +802,10 @@ def __init__(self, proc, addr):
776802
self._proc = proc
777803
self._addr = addr
778804

805+
def is_healthy(self):
806+
r = self.request('GET', '', no_prefix=True)
807+
return 200 <= r.status_code < 300
808+
779809
def request(self, meth, funcname, *args, **kwargs):
780810
request_method = getattr(requests, meth.lower())
781811
params = dict(kwargs.pop('params', {}))

0 commit comments

Comments
 (0)