diff --git a/src/functions_framework/__init__.py b/src/functions_framework/__init__.py index b7f38290..594551d3 100644 --- a/src/functions_framework/__init__.py +++ b/src/functions_framework/__init__.py @@ -174,6 +174,19 @@ def create_app(target=None, source=None, signature_type=None): app = flask.Flask(target, template_folder=template_folder) app.config["MAX_CONTENT_LENGTH"] = MAX_CONTENT_LENGTH + # 6. Handle legacy GCF Python 3.7 behavior + if os.environ.get("ENTRY_POINT"): + os.environ["FUNCTION_TRIGGER_TYPE"] = signature_type + os.environ["FUNCTION_NAME"] = os.environ.get("K_SERVICE", target) + app.make_response_original = app.make_response + + def handle_none(rv): + if rv is None: + rv = "OK" + return app.make_response_original(rv) + + app.make_response = handle_none + # Extract the target function from the source file try: function = getattr(source_module, target) diff --git a/tests/test_functions.py b/tests/test_functions.py index c6eccb91..4698049e 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import pathlib import re import time @@ -455,3 +456,42 @@ def test_class_in_main_is_in_right_module(): resp = client.get("/") assert resp.status_code == 200 + + +def test_function_returns_none(): + source = TEST_FUNCTIONS_DIR / "returns_none" / "main.py" + target = "function" + + client = create_app(target, source).test_client() + resp = client.get("/") + + assert resp.status_code == 500 + + +def test_legacy_function_check_env(monkeypatch): + source = TEST_FUNCTIONS_DIR / "http_check_env" / "main.py" + target = "function" + + monkeypatch.setenv("ENTRY_POINT", target) + + client = create_app(target, source).test_client() + resp = client.post("/", json={"mode": "FUNCTION_TRIGGER_TYPE"}) + assert resp.status_code == 200 + assert resp.data == b"http" + + resp = client.post("/", json={"mode": "FUNCTION_NAME"}) + assert resp.status_code == 200 + assert resp.data.decode("utf-8") == target + + +def test_legacy_function_returns_none(monkeypatch): + source = TEST_FUNCTIONS_DIR / "returns_none" / "main.py" + target = "function" + + monkeypatch.setenv("ENTRY_POINT", target) + + client = create_app(target, source).test_client() + resp = client.get("/") + + assert resp.status_code == 200 + assert resp.data == b"OK" diff --git a/tests/test_functions/returns_none/main.py b/tests/test_functions/returns_none/main.py new file mode 100644 index 00000000..f6a4acaa --- /dev/null +++ b/tests/test_functions/returns_none/main.py @@ -0,0 +1,27 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def function(request): + """Test HTTP function when using legacy GCF behavior. + + The function returns None, which should be a 200 response. + + Args: + request: The HTTP request which triggered this function. + + Returns: + None. + """ + return None