Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: refactoring deferred bindings tests #1555

Merged
merged 6 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion eng/templates/jobs/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ jobs:
.env\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install .
displayName: 'Build python worker'
displayName: 'Build python worker'
# Skip the build stage for SDK and Extensions release branches. This stage will fail because pyproject.toml contains the updated (and unreleased) library version
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
38 changes: 2 additions & 36 deletions eng/templates/jobs/ci-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,43 +33,9 @@ jobs:
eng/scripts/test-setup.sh
displayName: 'Install dependencies'
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
- task: DownloadPipelineArtifact@2
displayName: 'Download Python SDK Artifact'
inputs:
buildType: specific
artifactName: 'azure-functions'
project: 'internal'
definition: 679
buildVersionToDownload: latest
targetPath: '$(Pipeline.Workspace)/PythonSdkArtifact'
condition: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
- bash: |
chmod +x eng/scripts/test-sdk.sh
chmod +x eng/scripts/test-setup.sh

eng/scripts/test-sdk.sh $(Pipeline.Workspace) $(PYTHON_VERSION)
eng/scripts/test-setup.sh
displayName: 'Install test python sdk, dependencies and the worker'
condition: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
- task: DownloadPipelineArtifact@2
displayName: 'Download Python Extension Artifact'
inputs:
buildType: specific
artifactName: $(PYTHONEXTENSIONNAME)
project: 'internal'
definition: 798
buildVersionToDownload: latest
targetPath: '$(Pipeline.Workspace)/PythonExtensionArtifact'
condition: or(eq(variables.isExtensionsRelease, true), eq(variables['USETESTPYTHONEXTENSIONS'], true))
- bash: |
chmod +x eng/scripts/test-setup.sh
chmod +x eng/scripts/test-extensions.sh

eng/scripts/test-extensions.sh $(Pipeline.Workspace) $(PYTHON_VERSION)
eng/scripts/test-setup.sh
displayName: 'Install test python extension, dependencies and the worker'
condition: or(eq(variables.isExtensionsRelease, true), eq(variables['USETESTPYTHONEXTENSIONS'], true))
- bash: |
python -m pytest -q -n auto --dist loadfile --reruns 4 --instafail --cov=./azure_functions_worker --cov-report xml --cov-branch tests/unittests
displayName: "Running $(PYTHON_VERSION) Unit Tests"
# Skip running tests for SDK and Extensions release branches. Public pipeline doesn't have permissions to download artifact.
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))

2 changes: 1 addition & 1 deletion eng/templates/official/jobs/ci-e2e-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,5 @@ jobs:
AzureWebJobsSqlConnectionString: $(SQL_CONNECTION)
AzureWebJobsEventGridTopicUri: $(EVENTGRID_URI)
AzureWebJobsEventGridConnectionKey: $(EVENTGRID_CONNECTION)
USETESTPYTHONSDK: eq(variables.isSdkRelease, true)
USETESTPYTHONSDK: or(eq(variables.isSdkRelease, true), eq(variables['USETESTPYTHONSDK'], true))
displayName: "Running $(PYTHON_VERSION) Python E2E Tests"
2 changes: 2 additions & 0 deletions eng/templates/official/jobs/ci-lc-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ jobs:
cd tests
python -m invoke -c test_setup build-protos
displayName: 'Install dependencies and the worker'
# Skip the installation stage for SDK and Extensions release branches. This stage will fail because pyproject.toml contains the updated (and unreleased) library version
condition: and(eq(variables.isSdkRelease, false), eq(variables.isExtensionsRelease, false), eq(variables['USETESTPYTHONSDK'], false), eq(variables['USETESTPYTHONEXTENSIONS'], false))
- bash: |
python -m pytest -n auto --dist loadfile -vv --reruns 4 --instafail tests/consumption_tests
env:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)


@app.function_name(name="blob_trigger")
@app.function_name(name="blob_trigger_only")
@app.blob_trigger(arg_name="file",
path="python-worker-tests/test-blob-trigger.txt",
connection="AzureWebJobsStorage")
@app.blob_output(arg_name="$return",
path="python-worker-tests/test-blob-triggered.txt",
connection="AzureWebJobsStorage")
def blob_trigger(file: func.InputStream) -> str:
def blob_trigger_only(file: func.InputStream) -> str:
return json.dumps({
'name': file.name,
'length': file.length,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
app = func.FunctionApp(http_auth_level=func.AuthLevel.ANONYMOUS)


@app.function_name(name="get_bc_blob_triggered")
@app.function_name(name="blob_input_only")
@app.blob_input(arg_name="client",
path="python-worker-tests/test-blobclient-triggered.txt",
connection="AzureWebJobsStorage")
@app.route(route="get_bc_blob_triggered")
def get_bc_blob_triggered(req: func.HttpRequest,
client: blob.BlobClient) -> str:
@app.route(route="blob_input_only")
def blob_input_only(req: func.HttpRequest,
client: blob.BlobClient) -> str:
return client.download_blob(encoding='utf-8').readall()
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import sys
import unittest

import azure.functions as func
from tests.utils import testutils

from azure_functions_worker import protos
from azure_functions_worker.bindings import meta


DEFERRED_BINDINGS_DISABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
'deferred_bindings_tests' / \
'deferred_bindings_functions' / \
'deferred_bindings_disabled'


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsDisabled(testutils.AsyncTestCase):

async def test_deferred_bindings_disabled_metadata(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
self.assertEqual(r.response.result.status,
protos.StatusResult.Success)

@testutils.retryable_test(3, 5)
async def test_deferred_bindings_disabled_log(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
disabled_log_present = False
for log in r.logs:
message = log.message
if "Deferred bindings enabled: False" in message:
disabled_log_present = True
break
self.assertTrue(disabled_log_present)


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsDisabledHelpers(testutils.AsyncTestCase):

async def test_check_deferred_bindings_disabled(self):
"""
check_deferred_bindings_enabled checks if deferred bindings is enabled at fx
and single binding level.

The first bool represents if deferred bindings is enabled at a fx level. This
means that at least one binding in the function is a deferred binding type.

The second represents if the current binding is deferred binding. If this is
True, then deferred bindings must also be enabled at the function level.

Test: type is not supported, deferred_bindings_enabled is not yet set
"""
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
await host.init_worker()
self.assertEqual(meta.check_deferred_bindings_enabled(
func.InputStream, False), (False, False))
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import sys
import unittest

import azure.functions as func
from tests.utils import testutils

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

DEFERRED_BINDINGS_ENABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
'deferred_bindings_tests' / \
'deferred_bindings_functions' / \
'deferred_bindings_enabled'
DEFERRED_BINDINGS_DISABLED_DIR = testutils.EXTENSION_TESTS_FOLDER / \
'deferred_bindings_tests' / \
'deferred_bindings_functions' / \
'deferred_bindings_disabled'

DEFERRED_BINDINGS_ENABLED_DUAL_DIR = testutils.EXTENSION_TESTS_FOLDER / \
'deferred_bindings_tests' / \
'deferred_bindings_functions' / \
'deferred_bindings_enabled_dual'


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

async def test_deferred_bindings_metadata(self):
async def test_deferred_bindings_enabled_metadata(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
await host.init_worker()
Expand All @@ -51,40 +44,25 @@ async def test_deferred_bindings_metadata(self):
self.assertEqual(r.response.result.status,
protos.StatusResult.Success)


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsEnabledDual(testutils.AsyncTestCase):

async def test_deferred_bindings_dual_metadata(self):
async def test_deferred_bindings_enabled_log(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
self.assertEqual(r.response.result.status,
protos.StatusResult.Success)


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsDisabled(testutils.AsyncTestCase):

async def test_non_deferred_bindings_metadata(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
self.assertEqual(r.response.result.status,
protos.StatusResult.Success)
enabled_log_present = False
for log in r.logs:
message = log.message
if "Deferred bindings enabled: True" in message:
enabled_log_present = True
break
self.assertTrue(enabled_log_present)


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

def test_deferred_bindings_decode(self):
def test_deferred_bindings_enabled_decode(self):
binding = BlobClientConverter
pb = protos.ParameterBinding(name='test',
data=protos.TypedData(
Expand Down Expand Up @@ -114,19 +92,27 @@ async def test_check_deferred_bindings_enabled(self):

The second represents if the current binding is deferred binding. If this is
True, then deferred bindings must also be enabled at the function level.

Test type 1: type is supported, deferred_bindings_enabled is not yet set
Test type 2: type is supported, deferred_bindings_enabled is already set
"""
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_DISABLED_DIR) as host:
script_root=DEFERRED_BINDINGS_ENABLED_DIR) as host:
await host.init_worker()
self.assertEqual(meta.check_deferred_bindings_enabled(
BlobClient, False), (True, True))

self.assertEqual(meta.check_deferred_bindings_enabled(
BlobClient, True), (True, True))

self.assertEqual(meta.check_deferred_bindings_enabled(
func.InputStream, False), (False, False))
ContainerClient, False), (True, True))

self.assertEqual(meta.check_deferred_bindings_enabled(
func.InputStream, True), (True, False))
ContainerClient, True), (True, True))

self.assertEqual(meta.check_deferred_bindings_enabled(
BlobClient, False), (True, True))
StorageStreamDownloader, False), (True, True))

self.assertEqual(meta.check_deferred_bindings_enabled(
BlobClient, True), (True, True))
StorageStreamDownloader, True), (True, True))
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import sys
import unittest

import azure.functions as func
from tests.utils import testutils

from azure_functions_worker import protos
from azure_functions_worker.bindings import meta

DEFERRED_BINDINGS_ENABLED_DUAL_DIR = testutils.EXTENSION_TESTS_FOLDER / \
'deferred_bindings_tests' / \
'deferred_bindings_functions' / \
'deferred_bindings_enabled_dual'


class MockMBD:
def __init__(self, version: str, source: str,
content_type: str, content: str):
self.version = version
self.source = source
self.content_type = content_type
self.content = content


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsEnabledDual(testutils.AsyncTestCase):

async def test_deferred_bindings_dual_metadata(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
self.assertIsInstance(r.response, protos.FunctionMetadataResponse)
self.assertEqual(r.response.result.status,
protos.StatusResult.Success)

async def test_deferred_bindings_dual_enabled_log(self):
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
await host.init_worker()
r = await host.get_functions_metadata()
enabled_log_present = False
for log in r.logs:
message = log.message
if "Deferred bindings enabled: True" in message:
enabled_log_present = True
break
self.assertTrue(enabled_log_present)


@unittest.skipIf(sys.version_info.minor <= 8, "The base extension"
"is only supported for 3.9+.")
class TestDeferredBindingsDualHelpers(testutils.AsyncTestCase):

async def test_check_deferred_bindings_dual_enabled(self):
"""
check_deferred_bindings_enabled checks if deferred bindings is enabled at fx
and single binding level.

The first bool represents if deferred bindings is enabled at a fx level. This
means that at least one binding in the function is a deferred binding type.

The second represents if the current binding is deferred binding. If this is
True, then deferred bindings must also be enabled at the function level.

Test: type is not supported, deferred_bindings_enabled already set
"""
async with testutils.start_mockhost(
script_root=DEFERRED_BINDINGS_ENABLED_DUAL_DIR) as host:
await host.init_worker()
self.assertEqual(meta.check_deferred_bindings_enabled(
func.InputStream, True), (True, False))
4 changes: 0 additions & 4 deletions tests/unittests/test_dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@
DISPATCHER_STEIN_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
'dispatcher_functions' / \
'dispatcher_functions_stein'
DISPATCHER_HTTP_V2_FASTAPI_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \
'dispatcher_functions' / \
'http_v2' / \
'fastapi'
FUNCTION_APP_DIRECTORY = UNIT_TESTS_ROOT / 'dispatcher_functions' / \
'dispatcher_functions_stein'

Expand Down
Loading
Loading