Skip to content

Commit 14d3f4e

Browse files
fix: Consumption tests fixes (#1717)
* Consumption tests fix * Updated blob name * Uncommenting LC tests * Updated imports * Updated tests to run on an emulator * Added sas token * Fixed syntax error * upload one zip, verify, run one test * logging variables * change base url * run all tests * only run 3.13, test with loader.install() * Removed protobuf tests * Removing debugging changes * Updating pipeline to run tests on all versions * Skipping 3.13 tests * Flake8 fixes --------- Co-authored-by: Victoria Hall <[email protected]>
1 parent 8a42602 commit 14d3f4e

File tree

11 files changed

+234
-178
lines changed

11 files changed

+234
-178
lines changed

eng/ci/integration-tests.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ extends:
4747
dependsOn: []
4848
jobs:
4949
- template: /eng/templates/official/jobs/ci-e2e-tests.yml@self
50-
# Skipping consumption tests till pipeline is fixed
51-
# - stage: RunLCTests
52-
# dependsOn: []
53-
# jobs:
54-
# - template: /eng/templates/official/jobs/ci-lc-tests.yml@self
50+
- stage: RunLCTests
51+
dependsOn: []
52+
jobs:
53+
- template: /eng/templates/official/jobs/ci-lc-tests.yml@self

eng/templates/official/jobs/ci-lc-tests.yml

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,34 @@ jobs:
1212

1313
strategy:
1414
matrix:
15-
Python37:
16-
PYTHON_VERSION: '3.7'
17-
Python38:
18-
PYTHON_VERSION: '3.8'
19-
Python39:
20-
PYTHON_VERSION: '3.9'
21-
Python310:
22-
PYTHON_VERSION: '3.10'
23-
Python311:
24-
PYTHON_VERSION: '3.11'
25-
15+
Python39:
16+
PYTHON_VERSION: '3.9'
17+
Python310:
18+
PYTHON_VERSION: '3.10'
19+
Python311:
20+
PYTHON_VERSION: '3.11'
21+
Python312:
22+
PYTHON_VERSION: '3.12'
2623
steps:
2724
- task: UsePythonVersion@0
2825
inputs:
2926
versionSpec: $(PYTHON_VERSION)
27+
28+
- bash: |
29+
# Start Azurite storage emulator in the background
30+
docker run -d -p 10000:10000 -p 10001:10001 -p 10002:10002 \
31+
--name azurite-storage \
32+
mcr.microsoft.com/azure-storage/azurite:latest \
33+
azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0
34+
35+
# Wait for Azurite to be ready
36+
sleep 5
37+
38+
# Verify Azurite is running
39+
docker ps | grep azurite-storage
40+
displayName: 'Start Azurite Storage Emulator'
41+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
42+
3043
- bash: |
3144
python -m pip install --upgrade pip
3245
python -m pip install -U -e ${{ parameters.PROJECT_DIRECTORY }}/[dev]
@@ -36,11 +49,69 @@ jobs:
3649
displayName: 'Install dependencies and the worker'
3750
# Skip the installation stage for SDK and Extensions release branches. This stage will fail because pyproject.toml contains the updated (and unreleased) library version
3851
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
52+
53+
- bash: |
54+
# Install Azure CLI (if not already present)
55+
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
56+
57+
# Create the apps container in Azurite
58+
az storage container create \
59+
--name apps \
60+
--connection-string "$(AZURE_STORAGE_CONNECTION_STRING)"
61+
62+
# Upload all function app packages to the container
63+
FUNCTION_APPS_DIR="$(Build.SourcesDirectory)/${{ parameters.PROJECT_DIRECTORY }}/tests/consumption_tests/function_app_zips"
64+
for zipfile in "$FUNCTION_APPS_DIR"/*.zip; do
65+
filename=$(basename "$zipfile")
66+
echo "Uploading $filename..."
67+
az storage blob upload \
68+
--container-name apps \
69+
--name "$filename" \
70+
--file "$zipfile" \
71+
--connection-string "$(AZURE_STORAGE_CONNECTION_STRING)" \
72+
--overwrite
73+
done
74+
75+
# Generate a container-level SAS token valid for 1 day
76+
SAS_TOKEN=$(az storage container generate-sas \
77+
--name apps \
78+
--permissions r \
79+
--expiry $(date -u -d '+1 day' +%Y-%m-%dT%H:%M:%SZ) \
80+
--connection-string "$(AZURE_STORAGE_CONNECTION_STRING)" \
81+
--output tsv)
82+
83+
echo "##vso[task.setvariable variable=CONTAINER_SAS_TOKEN]$SAS_TOKEN"
84+
85+
# List blobs in the container to verify uploads
86+
echo "Verifying uploaded blobs in 'apps' container..."
87+
az storage blob list \
88+
--container-name apps \
89+
--connection-string "$(AZURE_STORAGE_CONNECTION_STRING)" \
90+
--output table
91+
92+
env:
93+
AZURE_STORAGE_CONNECTION_STRING: $(AZURE_STORAGE_CONNECTION_STRING)
94+
95+
displayName: 'Setup Function App Packages in Azurite'
96+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
97+
98+
- powershell: |
99+
Write-Host "CONTAINER_SAS_TOKEN: $(CONTAINER_SAS_TOKEN)"
100+
displayName: 'Display CONTAINER_SAS_TOKEN variable'
101+
39102
- bash: |
40-
python -m pytest -n auto --dist loadfile -vv --reruns 4 --instafail tests/consumption_tests
103+
python -m pytest -n auto --dist loadfile -vv --instafail tests/consumption_tests
41104
env:
42-
AzureWebJobsStorage: $(LinuxStorageConnectionString312)
105+
AzureWebJobsStorage: $(AZURE_STORAGE_CONNECTION_STRING)
43106
_DUMMY_CONT_KEY: $(_DUMMY_CONT_KEY)
107+
CONTAINER_SAS_TOKEN: $(CONTAINER_SAS_TOKEN)
44108
displayName: "Running $(PYTHON_VERSION) Linux Consumption tests"
45109
workingDirectory: $(Build.SourcesDirectory)/${{ parameters.PROJECT_DIRECTORY }}
46-
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
110+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
111+
112+
- bash: |
113+
# Cleanup: Stop and remove Azurite container
114+
docker stop azurite-storage || true
115+
docker rm azurite-storage || true
116+
displayName: 'Cleanup Azurite Storage Emulator'
117+
condition: always()
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

workers/tests/consumption_tests/test_linux_consumption.py

Lines changed: 13 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,21 @@
33
import os
44
import sys
55
from time import sleep
6-
from unittest import TestCase, skipIf
7-
8-
from requests import Request
9-
from tests.utils.testutils_lc import LinuxConsumptionWebHostController
6+
from unittest import TestCase, skip, skipIf
107

118
from azure_functions_worker.constants import (
129
PYTHON_ENABLE_DEBUG_LOGGING,
1310
PYTHON_ENABLE_INIT_INDEXING,
1411
PYTHON_ENABLE_WORKER_EXTENSIONS,
1512
PYTHON_ISOLATE_WORKER_DEPENDENCIES,
1613
)
14+
from requests import Request
15+
from tests.utils.testutils_lc import LinuxConsumptionWebHostController
1716

1817
_DEFAULT_HOST_VERSION = "4"
1918

2019

2120
class TestLinuxConsumption(TestCase):
22-
"""Test worker behaviors on specific scenarios.
23-
24-
SCM_RUN_FROM_PACKAGE: built function apps are acquired from
25-
-> "Simple Batch" Subscription
26-
-> "AzureFunctionsPythonWorkerCILinuxDevOps" Resource Group
27-
-> "pythonworker<python_major><python_minor>sa" Storage Account
28-
-> "python-worker-lc-apps" Blob Container
29-
30-
For a list of scenario names:
31-
https://pythonworker39sa.blob.core.windows.net/python-worker-lc-apps?restype=container&comp=list
32-
"""
3321

3422
@classmethod
3523
def setUpClass(cls):
@@ -65,6 +53,8 @@ def test_http_no_auth(self):
6553
resp = ctrl.send_request(req)
6654
self.assertEqual(resp.status_code, 200)
6755

56+
@skipIf(sys.version_info.minor != 11,
57+
"Uploaded common libraries are only supported for Python 3.11")
6858
def test_common_libraries(self):
6959
"""A function app with the following requirements.txt:
7060
@@ -95,66 +85,6 @@ def test_common_libraries(self):
9585
self.assertIn('pyodbc', content)
9686
self.assertIn('requests', content)
9787

98-
@skipIf(sys.version_info.minor in (10, 11),
99-
"Protobuf pinning fails during remote build")
100-
def test_new_protobuf(self):
101-
"""A function app with the following requirements.txt:
102-
103-
azure-functions==1.7.0
104-
protobuf==3.15.8
105-
grpcio==1.33.2
106-
107-
should return 200 after importing all libraries.
108-
"""
109-
with LinuxConsumptionWebHostController(_DEFAULT_HOST_VERSION,
110-
self._py_version) as ctrl:
111-
ctrl.assign_container(env={
112-
"AzureWebJobsStorage": self._storage,
113-
"SCM_RUN_FROM_PACKAGE": self._get_blob_url("NewProtobuf"),
114-
PYTHON_ISOLATE_WORKER_DEPENDENCIES: "1"
115-
})
116-
req = Request('GET', f'{ctrl.url}/api/HttpTrigger')
117-
resp = ctrl.send_request(req)
118-
self.assertEqual(resp.status_code, 200)
119-
120-
content = resp.json()
121-
122-
# Worker always picks up the SDK version bundled with the image
123-
# Version of the packages are inconsistent due to isolation's bug
124-
self.assertEqual(content['azure.functions'], '1.7.0')
125-
self.assertEqual(content['google.protobuf'], '3.15.8')
126-
self.assertEqual(content['grpc'], '1.33.2')
127-
128-
@skipIf(sys.version_info.minor in (10, 11),
129-
"Protobuf pinning fails during remote build")
130-
def test_old_protobuf(self):
131-
"""A function app with the following requirements.txt:
132-
133-
azure-functions==1.5.0
134-
protobuf==3.8.0
135-
grpcio==1.27.1
136-
137-
should return 200 after importing all libraries.
138-
"""
139-
with LinuxConsumptionWebHostController(_DEFAULT_HOST_VERSION,
140-
self._py_version) as ctrl:
141-
ctrl.assign_container(env={
142-
"AzureWebJobsStorage": self._storage,
143-
"SCM_RUN_FROM_PACKAGE": self._get_blob_url("OldProtobuf"),
144-
PYTHON_ISOLATE_WORKER_DEPENDENCIES: "1"
145-
})
146-
req = Request('GET', f'{ctrl.url}/api/HttpTrigger')
147-
resp = ctrl.send_request(req)
148-
self.assertEqual(resp.status_code, 200)
149-
150-
content = resp.json()
151-
152-
# Worker always picks up the SDK version bundled with the image
153-
# Version of the packages are inconsistent due to isolation's bug
154-
self.assertIn(content['azure.functions'], '1.5.0')
155-
self.assertIn(content['google.protobuf'], '3.8.0')
156-
self.assertIn(content['grpc'], '1.27.1')
157-
15888
def test_debug_logging_disabled(self):
15989
"""An HttpTrigger function app with 'azure-functions' library
16090
should return 200 and by default customer debug logging should be
@@ -230,8 +160,6 @@ def test_pinning_functions_to_older_version(self):
230160
self.assertEqual(resp.status_code, 200)
231161
self.assertIn("Func Version: 1.11.1", resp.text)
232162

233-
@skipIf(sys.version_info.minor != 10,
234-
"This is testing only for python310")
235163
def test_opencensus_with_extensions_enabled(self):
236164
"""A function app with extensions enabled containing the
237165
following libraries:
@@ -251,8 +179,6 @@ def test_opencensus_with_extensions_enabled(self):
251179
resp = ctrl.send_request(req)
252180
self.assertEqual(resp.status_code, 200)
253181

254-
@skipIf(sys.version_info.minor != 10,
255-
"This is testing only for python310")
256182
def test_opencensus_with_extensions_enabled_init_indexing(self):
257183
"""
258184
A function app with init indexing enabled
@@ -269,43 +195,6 @@ def test_opencensus_with_extensions_enabled_init_indexing(self):
269195
resp = ctrl.send_request(req)
270196
self.assertEqual(resp.status_code, 200)
271197

272-
@skipIf(sys.version_info.minor != 9,
273-
"This is testing only for python39 where extensions"
274-
"enabled by default")
275-
def test_reload_variables_after_timeout_error(self):
276-
"""
277-
A function app with HTTPtrigger which has a function timeout of
278-
20s. The app as a sleep of 30s which should trigger a timeout
279-
"""
280-
with LinuxConsumptionWebHostController(_DEFAULT_HOST_VERSION,
281-
self._py_version) as ctrl:
282-
ctrl.assign_container(env={
283-
"AzureWebJobsStorage": self._storage,
284-
"SCM_RUN_FROM_PACKAGE": self._get_blob_url(
285-
"TimeoutError"),
286-
PYTHON_ISOLATE_WORKER_DEPENDENCIES: "1"
287-
})
288-
req = Request('GET', f'{ctrl.url}/api/hello')
289-
resp = ctrl.send_request(req)
290-
self.assertEqual(resp.status_code, 500)
291-
292-
sleep(2)
293-
logs = ctrl.get_container_logs()
294-
self.assertRegex(
295-
logs,
296-
r"Applying prioritize_customer_dependencies: "
297-
r"worker_dependencies_path: \/azure-functions-host\/"
298-
r"workers\/python\/.*?\/LINUX\/X64,"
299-
r" customer_dependencies_path: \/home\/site\/wwwroot\/"
300-
r"\.python_packages\/lib\/site-packages, working_directory:"
301-
r" \/home\/site\/wwwroot, Linux Consumption: True,"
302-
r" Placeholder: False")
303-
self.assertNotIn("Failure Exception: ModuleNotFoundError",
304-
logs)
305-
306-
@skipIf(sys.version_info.minor != 9,
307-
"This is testing only for python39 where extensions"
308-
"enabled by default")
309198
def test_reload_variables_after_oom_error(self):
310199
"""
311200
A function app with HTTPtrigger mocking error code 137
@@ -337,8 +226,7 @@ def test_reload_variables_after_oom_error(self):
337226
self.assertNotIn("Failure Exception: ModuleNotFoundError",
338227
logs)
339228

340-
@skipIf(sys.version_info.minor != 10,
341-
"This is testing only for python310")
229+
@skip("Flaky test.")
342230
def test_http_v2_fastapi_streaming_upload_download(self):
343231
"""
344232
A function app using http v2 fastapi extension with streaming upload and
@@ -377,7 +265,10 @@ def generate_random_bytes_stream():
377265
streamed_data, b'streamingtestingresponseisreturned')
378266

379267
def _get_blob_url(self, scenario_name: str) -> str:
380-
return (
381-
f'https://pythonworker{self._py_shortform}sa.blob.core.windows.net/'
382-
f'python-worker-lc-apps/{scenario_name}{self._py_shortform}.zip'
383-
)
268+
base_url = "http://172.17.0.1:10000/devstoreaccount1/apps"
269+
270+
container_sas_token = os.getenv('CONTAINER_SAS_TOKEN')
271+
if not container_sas_token:
272+
raise RuntimeError('Environment variable CONTAINER_SAS_TOKEN is '
273+
'required before running Linux Consumption test')
274+
return f"{base_url}/{scenario_name}.zip?{container_sas_token}"

0 commit comments

Comments
 (0)