Skip to content

Commit 692aba1

Browse files
hallvictoriaVictoria Hall
and
Victoria Hall
authored
test: refactoring deferred bindings tests (#1555)
* refactoring db tests * test fixes * condition fix * specific build id * skip unit tests for sdk releases * added comments, retries for flaky tests --------- Co-authored-by: Victoria Hall <victoria.hall@microsoft.com>
1 parent 64cef47 commit 692aba1

File tree

12 files changed

+194
-91
lines changed

12 files changed

+194
-91
lines changed

eng/templates/jobs/build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ jobs:
1919
.env\Scripts\Activate.ps1
2020
python -m pip install --upgrade pip
2121
python -m pip install .
22-
displayName: 'Build python worker'
22+
displayName: 'Build python worker'
23+
# Skip the build stage for SDK and Extensions release branches. This stage will fail because pyproject.toml contains the updated (and unreleased) library version
24+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))

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

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -33,43 +33,9 @@ jobs:
3333
eng/scripts/test-setup.sh
3434
displayName: 'Install dependencies'
3535
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
36-
- task: DownloadPipelineArtifact@2
37-
displayName: 'Download Python SDK Artifact'
38-
inputs:
39-
buildType: specific
40-
artifactName: 'azure-functions'
41-
project: 'internal'
42-
definition: 679
43-
buildVersionToDownload: latest
44-
targetPath: '$(Pipeline.Workspace)/PythonSdkArtifact'
45-
condition: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
46-
- bash: |
47-
chmod +x eng/scripts/test-sdk.sh
48-
chmod +x eng/scripts/test-setup.sh
49-
50-
eng/scripts/test-sdk.sh $(Pipeline.Workspace) $(PYTHON_VERSION)
51-
eng/scripts/test-setup.sh
52-
displayName: 'Install test python sdk, dependencies and the worker'
53-
condition: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
54-
- task: DownloadPipelineArtifact@2
55-
displayName: 'Download Python Extension Artifact'
56-
inputs:
57-
buildType: specific
58-
artifactName: $(PYTHONEXTENSIONNAME)
59-
project: 'internal'
60-
definition: 798
61-
buildVersionToDownload: latest
62-
targetPath: '$(Pipeline.Workspace)/PythonExtensionArtifact'
63-
condition: or(eq(variables.isExtensionsRelease, true), eq(variables['USETESTPYTHONEXTENSIONS'], true))
64-
- bash: |
65-
chmod +x eng/scripts/test-setup.sh
66-
chmod +x eng/scripts/test-extensions.sh
67-
68-
eng/scripts/test-extensions.sh $(Pipeline.Workspace) $(PYTHON_VERSION)
69-
eng/scripts/test-setup.sh
70-
displayName: 'Install test python extension, dependencies and the worker'
71-
condition: or(eq(variables.isExtensionsRelease, true), eq(variables['USETESTPYTHONEXTENSIONS'], true))
7236
- bash: |
7337
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests
7438
displayName: "Running $(PYTHON_VERSION) Unit Tests"
39+
# Skip running tests for SDK and Extensions release branches. Public pipeline doesn't have permissions to download artifact.
40+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
7541

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,5 @@ jobs:
125125
AzureWebJobsSqlConnectionString: $(SQL_CONNECTION)
126126
AzureWebJobsEventGridTopicUri: $(EVENTGRID_URI)
127127
AzureWebJobsEventGridConnectionKey: $(EVENTGRID_CONNECTION)
128-
USETESTPYTHONSDK: eq(variables.isSdkRelease, true)
128+
USETESTPYTHONSDK: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
129129
displayName: "Running $(PYTHON_VERSION) Python E2E Tests"

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ jobs:
3131
cd tests
3232
python -m invoke -c test_setup build-protos
3333
displayName: 'Install dependencies and the worker'
34+
# Skip the installation stage for SDK and Extensions release branches. This stage will fail because pyproject.toml contains the updated (and unreleased) library version
35+
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
3436
- bash: |
3537
python -m pytest -n auto --dist loadfile -vv --reruns 4 --instafail tests/consumption_tests
3638
env:

tests/extension_tests/deferred_bindings_tests/deferred_bindings_functions/deferred_bindings_disabled/function_app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
88

99

10-
@app.function_name(name="blob_trigger")
10+
@app.function_name(name="blob_trigger_only")
1111
@app.blob_trigger(arg_name="file",
1212
path="python-worker-tests/test-blob-trigger.txt",
1313
connection="AzureWebJobsStorage")
1414
@app.blob_output(arg_name="$return",
1515
path="python-worker-tests/test-blob-triggered.txt",
1616
connection="AzureWebJobsStorage")
17-
def blob_trigger(file: func.InputStream) -> str:
17+
def blob_trigger_only(file: func.InputStream) -> str:
1818
return json.dumps({
1919
'name': file.name,
2020
'length': file.length,

tests/extension_tests/deferred_bindings_tests/deferred_bindings_functions/deferred_bindings_enabled/function_app.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)
77

88

9-
@app.function_name(name="get_bc_blob_triggered")
9+
@app.function_name(name="blob_input_only")
1010
@app.blob_input(arg_name="client",
1111
path="python-worker-tests/test-blobclient-triggered.txt",
1212
connection="AzureWebJobsStorage")
13-
@app.route(route="get_bc_blob_triggered")
14-
def get_bc_blob_triggered(req: func.HttpRequest,
15-
client: blob.BlobClient) -> str:
13+
@app.route(route="blob_input_only")
14+
def blob_input_only(req: func.HttpRequest,
15+
client: blob.BlobClient) -> str:
1616
return client.download_blob(encoding='utf-8').readall()
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
import sys
4+
import unittest
5+
6+
import azure.functions as func
7+
from tests.utils import testutils
8+
9+
from azure_functions_worker import protos
10+
from azure_functions_worker.bindings import meta
11+
12+
13+
DEFERRED_BINDINGS_DISABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
14+
'deferred_bindings_tests' / \
15+
'deferred_bindings_functions' / \
16+
'deferred_bindings_disabled'
17+
18+
19+
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
20+
"is only supported for 3.9+.")
21+
class TestDeferredBindingsDisabled(testutils.AsyncTestCase):
22+
23+
async def test_deferred_bindings_disabled_metadata(self):
24+
async with testutils.start_mockhost(
25+
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
26+
await host.init_worker()
27+
r = await host.get_functions_metadata()
28+
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
29+
self.assertEqual(r.response.result.status,
30+
protos.StatusResult.Success)
31+
32+
@testutils.retryable_test(3, 5)
33+
async def test_deferred_bindings_disabled_log(self):
34+
async with testutils.start_mockhost(
35+
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
36+
await host.init_worker()
37+
r = await host.get_functions_metadata()
38+
disabled_log_present = False
39+
for log in r.logs:
40+
message = log.message
41+
if "Deferred bindings enabled: False" in message:
42+
disabled_log_present = True
43+
break
44+
self.assertTrue(disabled_log_present)
45+
46+
47+
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
48+
"is only supported for 3.9+.")
49+
class TestDeferredBindingsDisabledHelpers(testutils.AsyncTestCase):
50+
51+
async def test_check_deferred_bindings_disabled(self):
52+
"""
53+
check_deferred_bindings_enabled checks if deferred bindings is enabled at fx
54+
and single binding level.
55+
56+
The first bool represents if deferred bindings is enabled at a fx level. This
57+
means that at least one binding in the function is a deferred binding type.
58+
59+
The second represents if the current binding is deferred binding. If this is
60+
True, then deferred bindings must also be enabled at the function level.
61+
62+
Test: type is not supported, deferred_bindings_enabled is not yet set
63+
"""
64+
async with testutils.start_mockhost(
65+
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
66+
await host.init_worker()
67+
self.assertEqual(meta.check_deferred_bindings_enabled(
68+
func.InputStream, False), (False, False))

tests/extension_tests/deferred_bindings_tests/test_deferred_bindings.py renamed to tests/extension_tests/deferred_bindings_tests/test_deferred_bindings_enabled.py

Lines changed: 29 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import sys
44
import unittest
55

6-
import azure.functions as func
76
from tests.utils import testutils
87

98
from azure_functions_worker import protos
@@ -12,21 +11,15 @@
1211
# Even if the tests are skipped for <=3.8, the library is still imported as
1312
# it is used for these tests.
1413
if sys.version_info.minor >= 9:
15-
from azurefunctions.extensions.bindings.blob import BlobClient, BlobClientConverter
14+
from azurefunctions.extensions.bindings.blob import (BlobClient,
15+
BlobClientConverter,
16+
ContainerClient,
17+
StorageStreamDownloader)
1618

1719
DEFERRED_BINDINGS_ENABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
1820
'deferred_bindings_tests' / \
1921
'deferred_bindings_functions' / \
2022
'deferred_bindings_enabled'
21-
DEFERRED_BINDINGS_DISABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
22-
'deferred_bindings_tests' / \
23-
'deferred_bindings_functions' / \
24-
'deferred_bindings_disabled'
25-
26-
DEFERRED_BINDINGS_ENABLED_DUAL_DIR = testutils.EXTENSION_TESTS_FOLDER / \
27-
'deferred_bindings_tests' / \
28-
'deferred_bindings_functions' / \
29-
'deferred_bindings_enabled_dual'
3023

3124

3225
class MockMBD:
@@ -42,7 +35,7 @@ def __init__(self, version: str, source: str,
4235
"is only supported for 3.9+.")
4336
class TestDeferredBindingsEnabled(testutils.AsyncTestCase):
4437

45-
async def test_deferred_bindings_metadata(self):
38+
async def test_deferred_bindings_enabled_metadata(self):
4639
async with testutils.start_mockhost(
4740
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
4841
await host.init_worker()
@@ -51,40 +44,25 @@ async def test_deferred_bindings_metadata(self):
5144
self.assertEqual(r.response.result.status,
5245
protos.StatusResult.Success)
5346

54-
55-
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
56-
"is only supported for 3.9+.")
57-
class TestDeferredBindingsEnabledDual(testutils.AsyncTestCase):
58-
59-
async def test_deferred_bindings_dual_metadata(self):
47+
async def test_deferred_bindings_enabled_log(self):
6048
async with testutils.start_mockhost(
61-
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
62-
await host.init_worker()
63-
r = await host.get_functions_metadata()
64-
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
65-
self.assertEqual(r.response.result.status,
66-
protos.StatusResult.Success)
67-
68-
69-
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
70-
"is only supported for 3.9+.")
71-
class TestDeferredBindingsDisabled(testutils.AsyncTestCase):
72-
73-
async def test_non_deferred_bindings_metadata(self):
74-
async with testutils.start_mockhost(
75-
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
49+
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
7650
await host.init_worker()
7751
r = await host.get_functions_metadata()
78-
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
79-
self.assertEqual(r.response.result.status,
80-
protos.StatusResult.Success)
52+
enabled_log_present = False
53+
for log in r.logs:
54+
message = log.message
55+
if "Deferred bindings enabled: True" in message:
56+
enabled_log_present = True
57+
break
58+
self.assertTrue(enabled_log_present)
8159

8260

8361
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
8462
"is only supported for 3.9+.")
85-
class TestDeferredBindingsHelpers(testutils.AsyncTestCase):
63+
class TestDeferredBindingsEnabledHelpers(testutils.AsyncTestCase):
8664

87-
def test_deferred_bindings_decode(self):
65+
def test_deferred_bindings_enabled_decode(self):
8866
binding = BlobClientConverter
8967
pb = protos.ParameterBinding(name='test',
9068
data=protos.TypedData(
@@ -114,19 +92,27 @@ async def test_check_deferred_bindings_enabled(self):
11492
11593
The second represents if the current binding is deferred binding. If this is
11694
True, then deferred bindings must also be enabled at the function level.
95+
96+
Test type 1: type is supported, deferred_bindings_enabled is not yet set
97+
Test type 2: type is supported, deferred_bindings_enabled is already set
11798
"""
11899
async with testutils.start_mockhost(
119-
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
100+
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
120101
await host.init_worker()
102+
self.assertEqual(meta.check_deferred_bindings_enabled(
103+
BlobClient, False), (True, True))
104+
105+
self.assertEqual(meta.check_deferred_bindings_enabled(
106+
BlobClient, True), (True, True))
121107

122108
self.assertEqual(meta.check_deferred_bindings_enabled(
123-
func.InputStream, False), (False, False))
109+
ContainerClient, False), (True, True))
124110

125111
self.assertEqual(meta.check_deferred_bindings_enabled(
126-
func.InputStream, True), (True, False))
112+
ContainerClient, True), (True, True))
127113

128114
self.assertEqual(meta.check_deferred_bindings_enabled(
129-
BlobClient, False), (True, True))
115+
StorageStreamDownloader, False), (True, True))
130116

131117
self.assertEqual(meta.check_deferred_bindings_enabled(
132-
BlobClient, True), (True, True))
118+
StorageStreamDownloader, True), (True, True))
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Copyright (c) Microsoft Corporation. All rights reserved.
2+
# Licensed under the MIT License.
3+
import sys
4+
import unittest
5+
6+
import azure.functions as func
7+
from tests.utils import testutils
8+
9+
from azure_functions_worker import protos
10+
from azure_functions_worker.bindings import meta
11+
12+
DEFERRED_BINDINGS_ENABLED_DUAL_DIR = testutils.EXTENSION_TESTS_FOLDER / \
13+
'deferred_bindings_tests' / \
14+
'deferred_bindings_functions' / \
15+
'deferred_bindings_enabled_dual'
16+
17+
18+
class MockMBD:
19+
def __init__(self, version: str, source: str,
20+
content_type: str, content: str):
21+
self.version = version
22+
self.source = source
23+
self.content_type = content_type
24+
self.content = content
25+
26+
27+
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
28+
"is only supported for 3.9+.")
29+
class TestDeferredBindingsEnabledDual(testutils.AsyncTestCase):
30+
31+
async def test_deferred_bindings_dual_metadata(self):
32+
async with testutils.start_mockhost(
33+
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
34+
await host.init_worker()
35+
r = await host.get_functions_metadata()
36+
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
37+
self.assertEqual(r.response.result.status,
38+
protos.StatusResult.Success)
39+
40+
async def test_deferred_bindings_dual_enabled_log(self):
41+
async with testutils.start_mockhost(
42+
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
43+
await host.init_worker()
44+
r = await host.get_functions_metadata()
45+
enabled_log_present = False
46+
for log in r.logs:
47+
message = log.message
48+
if "Deferred bindings enabled: True" in message:
49+
enabled_log_present = True
50+
break
51+
self.assertTrue(enabled_log_present)
52+
53+
54+
@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
55+
"is only supported for 3.9+.")
56+
class TestDeferredBindingsDualHelpers(testutils.AsyncTestCase):
57+
58+
async def test_check_deferred_bindings_dual_enabled(self):
59+
"""
60+
check_deferred_bindings_enabled checks if deferred bindings is enabled at fx
61+
and single binding level.
62+
63+
The first bool represents if deferred bindings is enabled at a fx level. This
64+
means that at least one binding in the function is a deferred binding type.
65+
66+
The second represents if the current binding is deferred binding. If this is
67+
True, then deferred bindings must also be enabled at the function level.
68+
69+
Test: type is not supported, deferred_bindings_enabled already set
70+
"""
71+
async with testutils.start_mockhost(
72+
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
73+
await host.init_worker()
74+
self.assertEqual(meta.check_deferred_bindings_enabled(
75+
func.InputStream, True), (True, False))

tests/unittests/test_dispatcher.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@
3030
DISPATCHER_STEIN_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
3131
'dispatcher_functions' / \
3232
'dispatcher_functions_stein'
33-
DISPATCHER_HTTP_V2_FASTAPI_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
34-
'dispatcher_functions' / \
35-
'http_v2' / \
36-
'fastapi'
3733
FUNCTION_APP_DIRECTORY = UNIT_TESTS_ROOT / 'dispatcher_functions' / \
3834
'dispatcher_functions_stein'
3935

0 commit comments

Comments
 (0)