Skip to content

add e2e tests for PYTHON_THREADPOOL_THREAD_COUNT and FUNCTIONS_WORKER_PROCESS_COUNT #1136

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

Merged
merged 14 commits into from
Mar 15, 2023
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
13 changes: 13 additions & 0 deletions tests/endtoend/http_functions/http_func/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
from datetime import datetime
# flake8: noqa
import azure.functions as func
import time


def main(req: func.HttpRequest) -> func.HttpResponse:
time.sleep(1)

current_time = datetime.now().strftime("%H:%M:%S")
return func.HttpResponse(f"{current_time}")
20 changes: 20 additions & 0 deletions tests/endtoend/http_functions/http_func/function.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"scriptFile": "__init__.py",
"bindings": [
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "req",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "$return"
}
]
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from datetime import datetime
import logging
import time

import azure.functions as func

Expand Down Expand Up @@ -32,3 +34,11 @@ def default_template(req: func.HttpRequest) -> func.HttpResponse:
" personalized response.",
status_code=200
)


@app.route(route="http_func")
def http_func(req: func.HttpRequest) -> func.HttpResponse:
time.sleep(1)

current_time = datetime.now().strftime("%H:%M:%S")
return func.HttpResponse(f"{current_time}")
43 changes: 0 additions & 43 deletions tests/endtoend/test_multi_worker_functions.py

This file was deleted.

63 changes: 63 additions & 0 deletions tests/endtoend/test_threadpool_thread__count_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import os
from threading import Thread
from unittest.mock import patch
from datetime import datetime
from tests.utils import testutils


class TestPythonThreadpoolThreadCount(testutils.WebHostTestCase):
""" Test the Http Trigger with setting up the python threadpool thread
count to 2. this test will check if both requests should be processed
at the same time. this file is more focus on testing the E2E flow
scenarios.
"""

@classmethod
def setUpClass(cls):
os_environ = os.environ.copy()
os_environ['PYTHON_THREADPOOL_THREAD_COUNT'] = '2'
cls._patch_environ = patch.dict('os.environ', os_environ)
cls._patch_environ.start()
super().setUpClass()

def tearDown(self):
super().tearDown()
self._patch_environ.stop()

@classmethod
def get_script_dir(cls):
return testutils.E2E_TESTS_FOLDER / 'http_functions'

@testutils.retryable_test(3, 5)
def test_http_func_with_thread_count(self):
response = [None, None]

def http_req(res_num):
r = self.webhost.request('GET', 'http_func')
self.assertTrue(r.ok)
response[res_num] = datetime.strptime(
r.content.decode("utf-8"), "%H:%M:%S")

# creating 2 different threads to send HTTP request
thread1 = Thread(target=http_req, args=(0,))
thread2 = Thread(target=http_req, args=(1,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
"""function execution time difference between both HTTP request
should be less than 1 since both the request should be processed at
the same time because PYTHON_THREADPOOL_THREAD_COUNT is 2.
"""
time_diff_in_seconds = abs((response[0] - response[1]).total_seconds())
self.assertTrue(time_diff_in_seconds < 1)


class TestPythonThreadpoolThreadCountStein(TestPythonThreadpoolThreadCount):

@classmethod
def get_script_dir(cls):
return testutils.E2E_TESTS_FOLDER / 'http_functions' / \
'http_functions_stein'
64 changes: 64 additions & 0 deletions tests/endtoend/test_worker_proccess_count_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.
import os
from threading import Thread
from unittest.mock import patch
from datetime import datetime
from tests.utils import testutils


class TestWorkerProcessCount(testutils.WebHostTestCase):
"""Test the Http Trigger with setting up the python worker process count
to 2. this test will check if both requests should be processed at the
same time. this file is more focused on testing the E2E flow scenario for
FUNCTIONS_WORKER_PROCESS_COUNT feature.
"""

@classmethod
def setUpClass(cls):
os_environ = os.environ.copy()
os_environ['PYTHON_THREADPOOL_THREAD_COUNT'] = '1'
os_environ['FUNCTIONS_WORKER_PROCESS_COUNT'] = '2'
cls._patch_environ = patch.dict('os.environ', os_environ)
cls._patch_environ.start()
super().setUpClass()

def tearDown(self):
super().tearDown()
self._patch_environ.stop()

@classmethod
def get_script_dir(cls):
return testutils.E2E_TESTS_FOLDER / 'http_functions'

@testutils.retryable_test(3, 5)
def test_http_func_with_worker_process_count_2(self):
response = [None, None]

def http_req(res_num):
r = self.webhost.request('GET', 'http_func')
self.assertTrue(r.ok)
response[res_num] = datetime.strptime(
r.content.decode("utf-8"), "%H:%M:%S")

# creating 2 different threads to send HTTP request
thread1 = Thread(target=http_req, args=(0,))
thread2 = Thread(target=http_req, args=(1,))
thread1.start()
thread2.start()
thread1.join()
thread2.join()
'''function execution time difference between both HTTP request
should be less than 1 since both request should be processed at the
same time because FUNCTIONS_WORKER_PROCESS_COUNT is 2.
'''
time_diff_in_seconds = abs((response[0] - response[1]).total_seconds())
self.assertTrue(time_diff_in_seconds < 1)


class TestWorkerProcessCountStein(TestWorkerProcessCount):

@classmethod
def get_script_dir(cls):
return testutils.E2E_TESTS_FOLDER / 'http_functions' /\
'http_functions_stein'