Skip to content

Commit af1f2fb

Browse files
committed
small test fixes
give up on coverage support for things that are tested in different processes, or in gthread, because it looks like pytest-cov gave up on support for these, where as coverage has out-of-the-box support
1 parent 1821445 commit af1f2fb

File tree

3 files changed

+26
-24
lines changed

3 files changed

+26
-24
lines changed

src/functions_framework/_http/gunicorn.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,16 @@ def __init__(self, app, host, port, debug, **options):
4040
"limit_request_line": 0,
4141
}
4242

43-
if TIMEOUT_SECONDS > 0:
44-
if threads > 1 and _is_truthy(
45-
os.environ.get("THREADED_TIMEOUT_ENABLED", "False")
46-
):
47-
self.options["worker_class"] = (
48-
"functions_framework._http.gunicorn.GThreadWorkerWithTimeoutSupport"
49-
)
50-
else:
51-
self.options["timeout"] = TIMEOUT_SECONDS
43+
if (
44+
TIMEOUT_SECONDS > 0
45+
and threads > 1
46+
and _is_truthy(os.environ.get("THREADED_TIMEOUT_ENABLED", "False"))
47+
): # pragma: no cover
48+
self.options["worker_class"] = (
49+
"functions_framework._http.gunicorn.GThreadWorkerWithTimeoutSupport"
50+
)
51+
else:
52+
self.options["timeout"] = TIMEOUT_SECONDS
5253

5354
self.options.update(options)
5455
self.app = app
@@ -63,11 +64,11 @@ def load(self):
6364
return self.app
6465

6566

66-
class GThreadWorkerWithTimeoutSupport(ThreadWorker):
67+
class GThreadWorkerWithTimeoutSupport(ThreadWorker): # pragma: no cover
6768
def handle_request(self, req, conn):
68-
with ThreadingTimeout(TIMEOUT_SECONDS, swallow_exc=False):
69+
with ThreadingTimeout(TIMEOUT_SECONDS):
6970
super(GThreadWorkerWithTimeoutSupport, self).handle_request(req, conn)
7071

7172

72-
def _is_truthy(s):
73+
def _is_truthy(s): # pragma: no cover
7374
return str(s).lower() in ("yes", "y", "1", "yeah", "true", "t")

src/functions_framework/request_timeout.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
logger = logging.getLogger(__name__)
99

1010

11-
class ThreadingTimeout(object):
12-
def __init__(self, seconds, swallow_exc=True):
11+
class ThreadingTimeout(object): # pragma: no cover
12+
def __init__(self, seconds):
1313
self.seconds = seconds
14-
self.swallow_exc = swallow_exc
1514
self.target_tid = threading.current_thread().ident
1615
self.timer = None
1716

tests/test_timeouts.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
import os
1514
import pathlib
1615
import pytest
1716
import requests
@@ -30,10 +29,14 @@
3029

3130
@pytest.fixture(autouse=True)
3231
def run_around_tests():
32+
# the test samples test also listens on 8080, so let's be good stewards of
33+
# the port and make sure it's free
3334
_wait_for_no_listen(TEST_HOST, TEST_PORT)
3435
yield
36+
_wait_for_no_listen(TEST_HOST, TEST_PORT)
3537

3638

39+
@pytest.mark.slow_integration_test
3740
def test_no_timeout_allows_request_processing_to_finish():
3841
source = TEST_FUNCTIONS_DIR / "timeout" / "main.py"
3942
target = "function"
@@ -53,12 +56,13 @@ def test_no_timeout_allows_request_processing_to_finish():
5356

5457
result = requests.get("http://{}:{}/".format(TEST_HOST, TEST_PORT))
5558

56-
gunicorn_p.kill()
59+
gunicorn_p.terminate()
5760
gunicorn_p.join()
5861

5962
assert result.status_code == 200
6063

6164

65+
@pytest.mark.slow_integration_test
6266
def test_timeout_but_not_threaded_timeout_enabled_does_not_kill(monkeypatch):
6367
monkeypatch.setenv("CLOUD_RUN_TIMEOUT_SECONDS", "1")
6468
monkeypatch.setenv("THREADED_TIMEOUT_ENABLED", "false")
@@ -73,23 +77,20 @@ def test_timeout_but_not_threaded_timeout_enabled_does_not_kill(monkeypatch):
7377
app, TEST_HOST, TEST_PORT, False, **options
7478
)
7579

76-
os.environ.clear()
77-
os.environ["CLOUD_RUN_TIMEOUT_SECONDS"] = "1"
78-
os.environ["THREADED_TIMEOUT_ENABLED"] = "false"
79-
8080
gunicorn_p = Process(target=gunicorn_app.run)
8181
gunicorn_p.start()
8282

8383
_wait_for_listen(TEST_HOST, TEST_PORT)
8484

8585
result = requests.get("http://{}:{}/".format(TEST_HOST, TEST_PORT))
8686

87-
gunicorn_p.kill()
87+
gunicorn_p.terminate()
8888
gunicorn_p.join()
8989

9090
assert result.status_code == 200
9191

9292

93+
@pytest.mark.slow_integration_test
9394
def test_timeout_and_threaded_timeout_enabled_kills(monkeypatch):
9495
monkeypatch.setenv("CLOUD_RUN_TIMEOUT_SECONDS", "1")
9596
monkeypatch.setenv("THREADED_TIMEOUT_ENABLED", "true")
@@ -111,7 +112,7 @@ def test_timeout_and_threaded_timeout_enabled_kills(monkeypatch):
111112

112113
result = requests.get("http://{}:{}/".format(TEST_HOST, TEST_PORT))
113114

114-
gunicorn_p.kill()
115+
gunicorn_p.terminate()
115116
gunicorn_p.join()
116117

117118
# Any exception raised in execution is a 500 error. Cloud Functions 1st gen and
@@ -121,6 +122,7 @@ def test_timeout_and_threaded_timeout_enabled_kills(monkeypatch):
121122
assert result.status_code == 500
122123

123124

125+
@pytest.mark.slow_integration_test
124126
def test_timeout_and_threaded_timeout_enabled_but_timeout_not_exceeded_doesnt_kill(
125127
monkeypatch,
126128
):
@@ -144,7 +146,7 @@ def test_timeout_and_threaded_timeout_enabled_but_timeout_not_exceeded_doesnt_ki
144146

145147
result = requests.get("http://{}:{}/".format(TEST_HOST, TEST_PORT))
146148

147-
gunicorn_p.kill()
149+
gunicorn_p.terminate()
148150
gunicorn_p.join()
149151

150152
assert result.status_code == 200

0 commit comments

Comments
 (0)