From 71c0169b569faec12c5e3716837c61eaaa2f8d24 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Thu, 29 Feb 2024 10:57:23 -0600 Subject: [PATCH 01/10] fixed invalid stein tests --- tests/unittests/test_invalid_stein.py | 80 +++++++++++---------------- 1 file changed, 31 insertions(+), 49 deletions(-) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 5c8e04c68..2c1b1f05c 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -1,14 +1,8 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. -import collections as col -import os -from unittest.mock import patch - from azure_functions_worker import protos from tests.utils import testutils -SysVersionInfo = col.namedtuple("VersionInfo", ["major", "minor", "micro", - "releaselevel", "serial"]) STEIN_INVALID_APP_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \ 'broken_functions' / \ 'invalid_app_stein' @@ -18,52 +12,40 @@ class TestInvalidAppStein(testutils.AsyncTestCase): - - def setUp(self): - self._ctrl = testutils.start_mockhost( - script_root=STEIN_INVALID_APP_FUNCTIONS_DIR) - self._pre_env = dict(os.environ) - self.mock_version_info = patch( - 'azure_functions_worker.dispatcher.sys.version_info', - SysVersionInfo(3, 9, 0, 'final', 0)) - self.mock_version_info.start() - - def tearDown(self): - os.environ.clear() - os.environ.update(self._pre_env) - self.mock_version_info.stop() - + @testutils.retryable_test(4, 5) async def test_indexing_not_app(self): - """Test if the functions metadata response will be 0 - when an invalid app is provided - """ - async with self._ctrl as host: + """Test if the functions metadata response will be + an error when an invalid app is provided + """ + async with testutils.start_mockhost( + script_root=STEIN_INVALID_APP_FUNCTIONS_DIR) as host: + await host.init_worker() r = await host.get_functions_metadata() self.assertIsInstance(r.response, protos.FunctionMetadataResponse) - self.assertIn("Error", r.response.result.exception.message) - - -class TestInvalidStein(testutils.AsyncTestCase): - - def setUp(self): - self._ctrl = testutils.start_mockhost( - script_root=STEIN_INVALID_FUNCTIONS_DIR) - self._pre_env = dict(os.environ) - self.mock_version_info = patch( - 'azure_functions_worker.dispatcher.sys.version_info', - SysVersionInfo(3, 9, 0, 'final', 0)) - self.mock_version_info.start() - - def tearDown(self): - os.environ.clear() - os.environ.update(self._pre_env) - self.mock_version_info.stop() - + self.assertEqual(r.response.result.status, + protos.StatusResult.Failure) + self.assertIsNotNone(r.response.result.exception.message) + self.assertRegex(r.response.result.exception.message, + r"ValueError: Could not find top level " + r"function app instances in function_app.py.") + + @testutils.retryable_test(4, 5) async def test_indexing_invalid_app(self): - """Test if the functions metadata response will be 0 - when an invalid app is provided - """ - async with self._ctrl as host: + """Test if the functions metadata response will be + an error when an invalid app is provided + """ + async with testutils.start_mockhost( + script_root=STEIN_INVALID_FUNCTIONS_DIR) as host: + await host.init_worker() r = await host.get_functions_metadata() self.assertIsInstance(r.response, protos.FunctionMetadataResponse) - self.assertIn("Error", r.response.result.exception.message) + self.assertEqual(r.response.result.status, + protos.StatusResult.Failure) + self.assertIsNotNone(r.response.result.exception.message) + self.assertRegex(r.response.result.exception.message, + r"FunctionLoadError: cannot load the main " + r"function: " + r"the following parameters " + r"are declared in function.json but not in " + r"Python: " + r".*'req'.*") From 561f2037ac73d62dfa0e58a4aa9bcd105d031713 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 12:13:41 -0600 Subject: [PATCH 02/10] removed retries --- tests/unittests/test_invalid_stein.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 2c1b1f05c..4a1d1043e 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -12,7 +12,7 @@ class TestInvalidAppStein(testutils.AsyncTestCase): - @testutils.retryable_test(4, 5) + async def test_indexing_not_app(self): """Test if the functions metadata response will be an error when an invalid app is provided @@ -29,7 +29,6 @@ async def test_indexing_not_app(self): r"ValueError: Could not find top level " r"function app instances in function_app.py.") - @testutils.retryable_test(4, 5) async def test_indexing_invalid_app(self): """Test if the functions metadata response will be an error when an invalid app is provided From 2a61e9d27a74ea51cc4f2c150af1597369dd0974 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 13:26:46 -0600 Subject: [PATCH 03/10] @pytest.mark.asyncio --- tests/unittests/test_invalid_stein.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 4a1d1043e..125875839 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -2,6 +2,7 @@ # Licensed under the MIT License. from azure_functions_worker import protos from tests.utils import testutils +import pytest STEIN_INVALID_APP_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \ 'broken_functions' / \ @@ -13,6 +14,7 @@ class TestInvalidAppStein(testutils.AsyncTestCase): + @pytest.mark.asyncio async def test_indexing_not_app(self): """Test if the functions metadata response will be an error when an invalid app is provided @@ -29,6 +31,7 @@ async def test_indexing_not_app(self): r"ValueError: Could not find top level " r"function app instances in function_app.py.") + @pytest.mark.asyncio async def test_indexing_invalid_app(self): """Test if the functions metadata response will be an error when an invalid app is provided From 39794e41649a7941454246c8cf4292483c709328 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 14:02:24 -0600 Subject: [PATCH 04/10] pytest-asyncio in setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 403cd7d20..c590102e3 100644 --- a/setup.py +++ b/setup.py @@ -93,6 +93,7 @@ "flake8~=4.0.1", "mypy", "pytest", + "pytest-asyncio", "requests==2.*", "coverage", "pytest-sugar", From defb4fea6023f2892afa3b33dde1309b512761a2 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 14:13:29 -0600 Subject: [PATCH 05/10] class scope --- tests/unittests/test_invalid_stein.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 125875839..3ab1ab307 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -12,9 +12,9 @@ 'invalid_stein' +@pytest.mark.asyncio(scope="class") class TestInvalidAppStein(testutils.AsyncTestCase): - @pytest.mark.asyncio async def test_indexing_not_app(self): """Test if the functions metadata response will be an error when an invalid app is provided @@ -31,7 +31,6 @@ async def test_indexing_not_app(self): r"ValueError: Could not find top level " r"function app instances in function_app.py.") - @pytest.mark.asyncio async def test_indexing_invalid_app(self): """Test if the functions metadata response will be an error when an invalid app is provided From dca5c3148c8d83d307d23c461a0255b552ecef46 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 14:35:54 -0600 Subject: [PATCH 06/10] event loop policy --- tests/unittests/test_invalid_stein.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 3ab1ab307..9b0fd5bd2 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -3,6 +3,7 @@ from azure_functions_worker import protos from tests.utils import testutils import pytest +import asyncio STEIN_INVALID_APP_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \ 'broken_functions' / \ @@ -14,6 +15,7 @@ @pytest.mark.asyncio(scope="class") class TestInvalidAppStein(testutils.AsyncTestCase): + loop = asyncio.get_event_loop_policy().new_event_loop() async def test_indexing_not_app(self): """Test if the functions metadata response will be From 7035c58ba8debb6929d9ba60f5b8203c9edcad74 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 15:01:12 -0600 Subject: [PATCH 07/10] def event_loop --- tests/unittests/test_invalid_stein.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 9b0fd5bd2..4ab16c377 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -15,7 +15,11 @@ @pytest.mark.asyncio(scope="class") class TestInvalidAppStein(testutils.AsyncTestCase): - loop = asyncio.get_event_loop_policy().new_event_loop() + def event_loop(self): + policy = asyncio.get_event_loop_policy() + loop = policy.new_event_loop() + yield loop + loop.close() async def test_indexing_not_app(self): """Test if the functions metadata response will be From 4bbb2482e68abea129450a091807577fbb9b5ad3 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Fri, 1 Mar 2024 15:30:57 -0600 Subject: [PATCH 08/10] check status --- setup.py | 1 - tests/unittests/test_invalid_stein.py | 26 ++++---------------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/setup.py b/setup.py index c590102e3..403cd7d20 100644 --- a/setup.py +++ b/setup.py @@ -93,7 +93,6 @@ "flake8~=4.0.1", "mypy", "pytest", - "pytest-asyncio", "requests==2.*", "coverage", "pytest-sugar", diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 4ab16c377..6083c6dff 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -2,8 +2,6 @@ # Licensed under the MIT License. from azure_functions_worker import protos from tests.utils import testutils -import pytest -import asyncio STEIN_INVALID_APP_FUNCTIONS_DIR = testutils.UNIT_TESTS_FOLDER / \ 'broken_functions' / \ @@ -13,17 +11,11 @@ 'invalid_stein' -@pytest.mark.asyncio(scope="class") class TestInvalidAppStein(testutils.AsyncTestCase): - def event_loop(self): - policy = asyncio.get_event_loop_policy() - loop = policy.new_event_loop() - yield loop - loop.close() async def test_indexing_not_app(self): - """Test if the functions metadata response will be - an error when an invalid app is provided + """Test if the functions metadata status will be + Failure when an invalid app is provided """ async with testutils.start_mockhost( script_root=STEIN_INVALID_APP_FUNCTIONS_DIR) as host: @@ -33,13 +25,10 @@ async def test_indexing_not_app(self): self.assertEqual(r.response.result.status, protos.StatusResult.Failure) self.assertIsNotNone(r.response.result.exception.message) - self.assertRegex(r.response.result.exception.message, - r"ValueError: Could not find top level " - r"function app instances in function_app.py.") async def test_indexing_invalid_app(self): - """Test if the functions metadata response will be - an error when an invalid app is provided + """Test if the functions metadata status will be + Failure when an invalid app is provided """ async with testutils.start_mockhost( script_root=STEIN_INVALID_FUNCTIONS_DIR) as host: @@ -49,10 +38,3 @@ async def test_indexing_invalid_app(self): self.assertEqual(r.response.result.status, protos.StatusResult.Failure) self.assertIsNotNone(r.response.result.exception.message) - self.assertRegex(r.response.result.exception.message, - r"FunctionLoadError: cannot load the main " - r"function: " - r"the following parameters " - r"are declared in function.json but not in " - r"Python: " - r".*'req'.*") From a1e1610efe50b06720a541db5055b687a5a289d0 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Tue, 5 Mar 2024 11:12:03 -0600 Subject: [PATCH 09/10] fixing filename docker tests --- .github/workflows/ci_docker_con_workflow.yml | 2 +- tests/endtoend/test_file_name_functions.py | 6 +++++- tests/unittests/test_dispatcher.py | 8 ++++---- tests/unittests/test_enable_debug_logging_functions.py | 3 +++ tests/unittests/test_invalid_stein.py | 2 ++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci_docker_con_workflow.yml b/.github/workflows/ci_docker_con_workflow.yml index bd8b649b4..4845af83a 100644 --- a/.github/workflows/ci_docker_con_workflow.yml +++ b/.github/workflows/ci_docker_con_workflow.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [ 3.7, 3.8, 3.9, "3.10" ] + python-version: [ 3.7, 3.8, 3.9, "3.10", "3.11" ] permissions: read-all env: CONSUMPTION_DOCKER_TEST: "true" diff --git a/tests/endtoend/test_file_name_functions.py b/tests/endtoend/test_file_name_functions.py index 27ee9058c..29b3ff2f8 100644 --- a/tests/endtoend/test_file_name_functions.py +++ b/tests/endtoend/test_file_name_functions.py @@ -28,7 +28,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): - # Remove the WEBSITE_HOSTNAME environment variable + # Remove the PYTHON_SCRIPT_FILE_NAME environment variable os.environ.pop('PYTHON_SCRIPT_FILE_NAME') super().tearDownClass() @@ -38,6 +38,10 @@ def get_script_dir(cls): 'http_functions_stein' / \ 'file_name' + @classmethod + def get_environment_variables(cls): + return {"PYTHON_SCRIPT_FILE_NAME": "main.py"} + @testutils.retryable_test(3, 5) def test_index_page_should_return_ok(self): """The index page of Azure Functions should return OK in any diff --git a/tests/unittests/test_dispatcher.py b/tests/unittests/test_dispatcher.py index 1f183c6d3..e069e640f 100644 --- a/tests/unittests/test_dispatcher.py +++ b/tests/unittests/test_dispatcher.py @@ -335,9 +335,9 @@ async def test_async_invocation_request_log(self): ) async def test_sync_invocation_request_log_threads(self): - os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '5'}) - with patch('azure_functions_worker.dispatcher.logger') as mock_logger: + os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '5'}) + async with self._ctrl as host: request_id: str = self._ctrl._worker._request_id func_id, invoke_id, func_name = ( @@ -359,9 +359,9 @@ async def test_sync_invocation_request_log_threads(self): ) async def test_async_invocation_request_log_threads(self): - os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '4'}) - with patch('azure_functions_worker.dispatcher.logger') as mock_logger: + os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '4'}) + async with self._ctrl as host: request_id: str = self._ctrl._worker._request_id func_id, invoke_id, func_name = ( diff --git a/tests/unittests/test_enable_debug_logging_functions.py b/tests/unittests/test_enable_debug_logging_functions.py index 8ac0bc1d9..120d54dfe 100644 --- a/tests/unittests/test_enable_debug_logging_functions.py +++ b/tests/unittests/test_enable_debug_logging_functions.py @@ -35,6 +35,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): + os.environ.pop(PYTHON_ENABLE_DEBUG_LOGGING) super().tearDownClass() cls._patch_environ.stop() @@ -72,6 +73,7 @@ def setUpClass(cls): @classmethod def tearDownClass(cls): + os.environ.pop(PYTHON_ENABLE_DEBUG_LOGGING) super().tearDownClass() cls._patch_environ.stop() @@ -118,6 +120,7 @@ def tearDownClass(cls): host_json = TESTS_ROOT / cls.get_script_dir() / 'host.json' remove_path(host_json) + os.environ.pop(PYTHON_ENABLE_DEBUG_LOGGING) super().tearDownClass() cls._patch_environ.stop() diff --git a/tests/unittests/test_invalid_stein.py b/tests/unittests/test_invalid_stein.py index 6083c6dff..e1e0e6417 100644 --- a/tests/unittests/test_invalid_stein.py +++ b/tests/unittests/test_invalid_stein.py @@ -13,6 +13,7 @@ class TestInvalidAppStein(testutils.AsyncTestCase): + @testutils.retryable_test(4, 5) async def test_indexing_not_app(self): """Test if the functions metadata status will be Failure when an invalid app is provided @@ -26,6 +27,7 @@ async def test_indexing_not_app(self): protos.StatusResult.Failure) self.assertIsNotNone(r.response.result.exception.message) + @testutils.retryable_test(4, 5) async def test_indexing_invalid_app(self): """Test if the functions metadata status will be Failure when an invalid app is provided From a6528ce4bfa935ce405fa75b682c27b8056a2377 Mon Sep 17 00:00:00 2001 From: hallvictoria Date: Tue, 5 Mar 2024 11:47:49 -0600 Subject: [PATCH 10/10] fixing dispatcher tests --- tests/endtoend/test_file_name_functions.py | 3 ++- tests/unittests/test_dispatcher.py | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/endtoend/test_file_name_functions.py b/tests/endtoend/test_file_name_functions.py index 29b3ff2f8..0e74851b2 100644 --- a/tests/endtoend/test_file_name_functions.py +++ b/tests/endtoend/test_file_name_functions.py @@ -24,6 +24,7 @@ class TestHttpFunctionsFileName(testutils.WebHostTestCase): @classmethod def setUpClass(cls): os.environ["PYTHON_SCRIPT_FILE_NAME"] = "main.py" + cls.env_variables['PYTHON_SCRIPT_FILE_NAME'] = 'main.py' super().setUpClass() @classmethod @@ -40,7 +41,7 @@ def get_script_dir(cls): @classmethod def get_environment_variables(cls): - return {"PYTHON_SCRIPT_FILE_NAME": "main.py"} + return cls.env_variables @testutils.retryable_test(3, 5) def test_index_page_should_return_ok(self): diff --git a/tests/unittests/test_dispatcher.py b/tests/unittests/test_dispatcher.py index e069e640f..5c8ad015d 100644 --- a/tests/unittests/test_dispatcher.py +++ b/tests/unittests/test_dispatcher.py @@ -143,7 +143,8 @@ async def test_dispatcher_sync_threadpool_default_worker(self): correct default value """ async with self._ctrl as host: - # await self._check_if_function_is_ok(host) + await host.init_worker() + await self._check_if_function_is_ok(host) await self._assert_workers_threadpool(self._ctrl, host, self._default_workers) @@ -154,6 +155,7 @@ async def test_dispatcher_sync_threadpool_set_worker(self): os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: f'{self._allowed_max_workers}'}) async with self._ctrl as host: + await host.init_worker() await self._check_if_function_is_ok(host) await self._assert_workers_threadpool(self._ctrl, host, self._allowed_max_workers) @@ -339,6 +341,7 @@ async def test_sync_invocation_request_log_threads(self): os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '5'}) async with self._ctrl as host: + await host.init_worker() request_id: str = self._ctrl._worker._request_id func_id, invoke_id, func_name = ( await self._check_if_function_is_ok(host) @@ -363,6 +366,7 @@ async def test_async_invocation_request_log_threads(self): os.environ.update({PYTHON_THREADPOOL_THREAD_COUNT: '4'}) async with self._ctrl as host: + await host.init_worker() request_id: str = self._ctrl._worker._request_id func_id, invoke_id, func_name = ( await self._check_if_async_function_is_ok(host)