diff --git a/ci/build-examples.yaml b/ci/build-examples.yaml index 06577562..b01ead98 100644 --- a/ci/build-examples.yaml +++ b/ci/build-examples.yaml @@ -202,7 +202,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-env_vars' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=env_vars', '--path', 'examples/site/env_vars', 'site-env_vars', @@ -211,7 +210,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-hello_world_error' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=hello_world_error', '--path', 'examples/site/hello_world_error', 'site-hello_world_error', @@ -220,7 +218,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-hello_world_get' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=hello_world_get', '--path', 'examples/site/hello_world_get', 'site-hello_world_get', @@ -253,7 +250,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_content' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_content', '--path', 'examples/site/http_content', 'site-http_content', @@ -262,7 +258,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_cors' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_cors', '--path', 'examples/site/http_cors', 'site-http_cors', @@ -271,7 +266,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_cors_auth' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_cors_auth', '--path', 'examples/site/http_cors_auth', 'site-http_cors_auth', @@ -280,7 +274,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_form_data' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_form_data', '--path', 'examples/site/http_form_data', 'site-http_form_data', @@ -289,7 +282,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_method' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_method', '--path', 'examples/site/http_method', 'site-http_method', @@ -298,7 +290,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-http_xml' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=http_xml', '--path', 'examples/site/http_xml', 'site-http_xml', @@ -307,7 +298,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-log_helloworld' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=log_helloworld', '--path', 'examples/site/log_helloworld', 'site-log_helloworld', diff --git a/examples/site/env_vars/env_vars.cc b/examples/site/env_vars/env_vars.cc index 6f40bce7..571f7381 100644 --- a/examples/site/env_vars/env_vars.cc +++ b/examples/site/env_vars/env_vars.cc @@ -13,15 +13,16 @@ // limitations under the License. // [START functions_env_vars] -#include -#include +#include #include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse env_vars(gcf::HttpRequest /*request*/) { // NOLINT - char const* value = std::getenv("FOO"); - if (value == nullptr) value = "FOO environment variable is not set"; - return gcf::HttpResponse{}.set_payload(value); +gcf::Function env_vars() { + return gcf::MakeFunction([](gcf::HttpRequest const& /*request*/) { + char const* value = std::getenv("FOO"); + if (value == nullptr) value = "FOO environment variable is not set"; + return gcf::HttpResponse{}.set_payload(value); + }); } // [END functions_env_vars] diff --git a/examples/site/hello_world_error/hello_world_error.cc b/examples/site/hello_world_error/hello_world_error.cc index 0bf7cb70..39838d4b 100644 --- a/examples/site/hello_world_error/hello_world_error.cc +++ b/examples/site/hello_world_error/hello_world_error.cc @@ -13,46 +13,45 @@ // limitations under the License. // [START functions_helloworld_error] -#include -#include +#include #include #include namespace gcf = ::google::cloud::functions; -// Though not used in this example, the request is passed by value to support -// applications that move-out its data. -gcf::HttpResponse hello_world_error(gcf::HttpRequest request) { // NOLINT - if (request.target() == "/return500") { - // An error response code does NOT create entries in Error Reporting - return gcf::HttpResponse{}.set_result( - gcf::HttpResponse::kInternalServerError); - } - // Unstructured logs to stdout and/or stderr do NOT create entries in Error - // Reporting - std::cout << "An error occurred (stdout)\n"; - std::cerr << "An error occurred (stderr)\n"; +gcf::Function hello_world_error() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + if (request.target() == "/return500") { + // An error response code does NOT create entries in Error Reporting + return gcf::HttpResponse{}.set_result( + gcf::HttpResponse::kInternalServerError); + } + // Unstructured logs to stdout and/or stderr do NOT create entries in Error + // Reporting + std::cout << "An error occurred (stdout)\n"; + std::cerr << "An error occurred (stderr)\n"; - if (request.target() == "/throw/exception") { - // Throwing an exception WILL create new entries in Error Reporting - throw std::runtime_error("I failed you"); - } + if (request.target() == "/throw/exception") { + // Throwing an exception WILL create new entries in Error Reporting + throw std::runtime_error("I failed you"); + } - // Structured logs MAY create entries in Error Reporting depending on their - // severity. You can create structured logs manually (as shown here), or using - // your favorite logging library with suitable formatting. - std::cerr << nlohmann::json{{"severity", "info"}, - {"message", "informational message"}} - .dump() - << std::endl; + // Structured logs MAY create entries in Error Reporting depending on their + // severity. You can create structured logs manually (as shown here), or + // using your favorite logging library with suitable formatting. + std::cerr << nlohmann::json{{"severity", "info"}, + {"message", "informational message"}} + .dump() + << std::endl; - std::cerr << nlohmann::json{{"severity", "error"}, - {"message", "an error message"}} - .dump() - << std::endl; + std::cerr << nlohmann::json{{"severity", "error"}, + {"message", "an error message"}} + .dump() + << std::endl; - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello World!"); + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello World!"); + }); } // [END functions_helloworld_error] diff --git a/examples/site/hello_world_get/hello_world_get.cc b/examples/site/hello_world_get/hello_world_get.cc index 973c731e..ac508186 100644 --- a/examples/site/hello_world_get/hello_world_get.cc +++ b/examples/site/hello_world_get/hello_world_get.cc @@ -13,16 +13,15 @@ // limitations under the License. // [START functions_helloworld_get] -#include -#include +#include namespace gcf = ::google::cloud::functions; -// Though not used in this example, the request is passed by value to support -// applications that move-out its data. -gcf::HttpResponse hello_world_get(gcf::HttpRequest) { // NOLINT - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello World!"); +gcf::Function hello_world_get() { + return gcf::MakeFunction([](gcf::HttpRequest const&) { + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello World!"); + }); } // [END functions_helloworld_get] diff --git a/examples/site/http_content/http_content.cc b/examples/site/http_content/http_content.cc index 2e59fe00..e52b107a 100644 --- a/examples/site/http_content/http_content.cc +++ b/examples/site/http_content/http_content.cc @@ -13,8 +13,7 @@ // limitations under the License. // [START functions_http_content] -#include -#include +#include #include #include #include @@ -29,25 +28,27 @@ std::map parse_www_form_urlencoded( std::string const& text); } // namespace -gcf::HttpResponse http_content(gcf::HttpRequest request) { // NOLINT - std::string name; - auto const& headers = request.headers(); - if (auto f = headers.find("content-type"); f != headers.end()) { - if (f->second == "application/json") { - name = nlohmann::json::parse(request.payload()).value("name", ""); - } else if (f->second == "application/octet-stream" || - f->second == "text/plain") { - name = request.payload(); // treat contents as a string - } else if (f->second == "application/x-www-form-urlencoded") { - // Use your preferred parser, here we use some custom code. - auto form = parse_www_form_urlencoded(request.payload()); - name = form["name"]; +gcf::Function http_content() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + std::string name; + auto const& headers = request.headers(); + if (auto f = headers.find("content-type"); f != headers.end()) { + if (f->second == "application/json") { + name = nlohmann::json::parse(request.payload()).value("name", ""); + } else if (f->second == "application/octet-stream" || + f->second == "text/plain") { + name = request.payload(); // treat contents as a string + } else if (f->second == "application/x-www-form-urlencoded") { + // Use your preferred parser, here we use some custom code. + auto form = parse_www_form_urlencoded(request.payload()); + name = form["name"]; + } } - } - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello " + name); + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello " + name); + }); } // [END functions_http_content] diff --git a/examples/site/http_cors/http_cors.cc b/examples/site/http_cors/http_cors.cc index ac998ced..46647dc9 100644 --- a/examples/site/http_cors/http_cors.cc +++ b/examples/site/http_cors/http_cors.cc @@ -13,27 +13,28 @@ // limitations under the License. // [START functions_http_cors] -#include -#include +#include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse http_cors(gcf::HttpRequest request) { // NOLINT - // Set CORS headers for preflight request - if (request.verb() == "OPTIONS") { - // Allows GET requests from any origin with the Content-Type header and - // caches preflight response for an 3600s +gcf::Function http_cors() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + // Set CORS headers for preflight request + if (request.verb() == "OPTIONS") { + // Allows GET requests from any origin with the Content-Type header and + // caches preflight response for an 3600s + return gcf::HttpResponse{} + .set_result(gcf::HttpResponse::kNoContent) + .set_header("Access-Control-Allow-Origin", "*") + .set_header("Access-Control-Allow-Methods", "GET") + .set_header("Access-Control-Allow-Headers", "Content-Type") + .set_header("Access-Control-Max-Age", "3600"); + } + return gcf::HttpResponse{} - .set_result(gcf::HttpResponse::kNoContent) .set_header("Access-Control-Allow-Origin", "*") - .set_header("Access-Control-Allow-Methods", "GET") - .set_header("Access-Control-Allow-Headers", "Content-Type") - .set_header("Access-Control-Max-Age", "3600"); - } - - return gcf::HttpResponse{} - .set_header("Access-Control-Allow-Origin", "*") - .set_header("content-type", "text/plain") - .set_payload("Hello World!"); + .set_header("content-type", "text/plain") + .set_payload("Hello World!"); + }); } // [END functions_http_cors] diff --git a/examples/site/http_cors_auth/http_cors_auth.cc b/examples/site/http_cors_auth/http_cors_auth.cc index 6ace8302..155d5600 100644 --- a/examples/site/http_cors_auth/http_cors_auth.cc +++ b/examples/site/http_cors_auth/http_cors_auth.cc @@ -13,29 +13,30 @@ // limitations under the License. // [START functions_http_cors_auth] -#include -#include +#include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse http_cors_auth(gcf::HttpRequest request) { // NOLINT - // Set CORS headers for preflight request - if (request.verb() == "OPTIONS") { - // Allows GET requests from any origin with the Content-Type header and - // caches preflight response for an 3600s +gcf::Function http_cors_auth() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + // Set CORS headers for preflight request + if (request.verb() == "OPTIONS") { + // Allows GET requests from any origin with the Content-Type header and + // caches preflight response for an 3600s + return gcf::HttpResponse{} + .set_result(gcf::HttpResponse::kNoContent) + .set_header("Access-Control-Allow-Origin", "https://mydomain.com") + .set_header("Access-Control-Allow-Methods", "GET") + .set_header("Access-Control-Allow-Headers", "Authorization") + .set_header("Access-Control-Max-Age", "3600") + .set_header("Access-Control-Allow-Credentials", "true"); + } + return gcf::HttpResponse{} - .set_result(gcf::HttpResponse::kNoContent) .set_header("Access-Control-Allow-Origin", "https://mydomain.com") - .set_header("Access-Control-Allow-Methods", "GET") - .set_header("Access-Control-Allow-Headers", "Authorization") - .set_header("Access-Control-Max-Age", "3600") - .set_header("Access-Control-Allow-Credentials", "true"); - } - - return gcf::HttpResponse{} - .set_header("Access-Control-Allow-Origin", "https://mydomain.com") - .set_header("Access-Control-Allow-Credentials", "true") - .set_header("content-type", "text/plain") - .set_payload("Hello World!"); + .set_header("Access-Control-Allow-Credentials", "true") + .set_header("content-type", "text/plain") + .set_payload("Hello World!"); + }); } // [END functions_http_cors_auth] diff --git a/examples/site/http_form_data/http_form_data.cc b/examples/site/http_form_data/http_form_data.cc index 2bd058bf..06f4aee5 100644 --- a/examples/site/http_form_data/http_form_data.cc +++ b/examples/site/http_form_data/http_form_data.cc @@ -13,8 +13,7 @@ // limitations under the License. // [START functions_http_form_data] -#include -#include +#include #include #include #include @@ -59,7 +58,7 @@ class FormDataDelimiter { } // namespace -gcf::HttpResponse http_form_data(gcf::HttpRequest request) { +gcf::HttpResponse http_form_data_impl(gcf::HttpRequest request) { if (request.verb() != "POST") { return gcf::HttpResponse{}.set_result(gcf::HttpResponse::kMethodNotAllowed); } @@ -118,6 +117,10 @@ gcf::HttpResponse http_form_data(gcf::HttpRequest request) { .set_header("content-type", "application/json") .set_payload(result.dump()); } + +gcf::Function http_form_data() { + return gcf::MakeFunction(http_form_data_impl); +} // [END functions_http_form_data] namespace { diff --git a/examples/site/http_method/http_method.cc b/examples/site/http_method/http_method.cc index 13e17f91..c5a15aae 100644 --- a/examples/site/http_method/http_method.cc +++ b/examples/site/http_method/http_method.cc @@ -13,20 +13,21 @@ // limitations under the License. // [START functions_http_method] -#include -#include +#include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse http_method(gcf::HttpRequest request) { // NOLINT - if (request.verb() == "GET") { - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello World!"); - } +gcf::Function http_method() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + if (request.verb() == "GET") { + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello World!"); + } - return gcf::HttpResponse{}.set_result( - request.verb() == "POST" ? gcf::HttpResponse::kForbidden - : gcf::HttpResponse::kMethodNotAllowed); + return gcf::HttpResponse{}.set_result( + request.verb() == "POST" ? gcf::HttpResponse::kForbidden + : gcf::HttpResponse::kMethodNotAllowed); + }); } // [END functions_http_method] diff --git a/examples/site/http_xml/http_xml.cc b/examples/site/http_xml/http_xml.cc index bf15227f..ac1062aa 100644 --- a/examples/site/http_xml/http_xml.cc +++ b/examples/site/http_xml/http_xml.cc @@ -13,25 +13,26 @@ // limitations under the License. // [START functions_http_xml] -#include -#include +#include #include #include #include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse http_xml(gcf::HttpRequest request) { // NOLINT - std::istringstream is(request.payload()); - // Use the Boost.PropertyTree XML parser, this is adequate for a small - // example, but application developers may want to consider a more robust - // parser for production code. - boost::property_tree::ptree data; - boost::property_tree::read_xml(is, data); +gcf::Function http_xml() { + return gcf::MakeFunction([](gcf::HttpRequest const& request) { + std::istringstream is(request.payload()); + // Use the Boost.PropertyTree XML parser, as this is adequate for a small + // example. Application developers may want to consider a more robust + // parser for production code. + boost::property_tree::ptree data; + boost::property_tree::read_xml(is, data); - auto name = data.get("name", "World"); - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello " + name); + auto name = data.get("name", "World"); + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello " + name); + }); } // [END functions_http_xml] diff --git a/examples/site/log_helloworld/log_helloworld.cc b/examples/site/log_helloworld/log_helloworld.cc index 71309f15..9b1abb33 100644 --- a/examples/site/log_helloworld/log_helloworld.cc +++ b/examples/site/log_helloworld/log_helloworld.cc @@ -13,23 +13,24 @@ // limitations under the License. // [START functions_log_helloworld] -#include -#include +#include #include #include namespace gcf = ::google::cloud::functions; -gcf::HttpResponse log_helloworld(gcf::HttpRequest /*request*/) { // NOLINT - std::cout << "This is stdout\n"; - std::cerr << "This is stderr\n"; +gcf::Function log_helloworld() { + return gcf::MakeFunction([](gcf::HttpRequest const& /*request*/) { + std::cout << "This is stdout\n"; + std::cerr << "This is stderr\n"; - std::cerr << nlohmann::json{{"message", "This has ERROR severity"}, - {"severity", "error"}} - .dump() - << "\n"; - return gcf::HttpResponse{} - .set_header("content-type", "text/plain") - .set_payload("Hello Logging!"); + std::cerr << nlohmann::json{{"message", "This has ERROR severity"}, + {"severity", "error"}} + .dump() + << "\n"; + return gcf::HttpResponse{} + .set_header("content-type", "text/plain") + .set_payload("Hello Logging!"); + }); } // [END functions_log_helloworld] diff --git a/examples/site_test.cc b/examples/site_test.cc index 42641aff..b37a6759 100644 --- a/examples/site_test.cc +++ b/examples/site_test.cc @@ -37,19 +37,19 @@ extern gcf::Function concepts_after_timeout(); extern gcf::Function concepts_filesystem(); extern gcf::Function concepts_request(); extern gcf::Function concepts_stateless(); -extern gcf::HttpResponse env_vars(gcf::HttpRequest request); -extern gcf::HttpResponse hello_world_error(gcf::HttpRequest request); -extern gcf::HttpResponse hello_world_get(gcf::HttpRequest request); +extern gcf::Function env_vars(); +extern gcf::Function hello_world_error(); +extern gcf::Function hello_world_get(); extern gcf::Function hello_world_http(); extern gcf::Function hello_world_pubsub(); extern gcf::Function hello_world_storage(); -extern gcf::HttpResponse http_content(gcf::HttpRequest request); -extern gcf::HttpResponse http_cors(gcf::HttpRequest request); -extern gcf::HttpResponse http_cors_auth(gcf::HttpRequest request); -extern gcf::HttpResponse http_form_data(gcf::HttpRequest request); -extern gcf::HttpResponse http_method(gcf::HttpRequest request); -extern gcf::HttpResponse http_xml(gcf::HttpRequest request); -extern gcf::HttpResponse log_helloworld(gcf::HttpRequest request); +extern gcf::Function http_content(); +extern gcf::Function http_cors(); +extern gcf::Function http_cors_auth(); +extern gcf::Function http_form_data(); +extern gcf::Function http_method(); +extern gcf::Function http_xml(); +extern gcf::Function log_helloworld(); extern void log_stackdriver(gcf::CloudEvent event); extern void pubsub_subscribe(gcf::CloudEvent event); extern gcf::HttpResponse tips_gcp_apis(gcf::HttpRequest request); @@ -67,6 +67,7 @@ using ::testing::IsEmpty; auto TriggerFunctionHttp(gcf::Function const& function, gcf::HttpRequest const& r) { gcf_internal::BeastRequest request; + request.method_string(r.verb()); request.target(r.target()); request.body() = r.payload(); for (auto const& [k, v] : r.headers()) request.insert(k, v); @@ -188,28 +189,32 @@ TEST(ExamplesSiteTest, ConceptsStateless) { TEST(ExamplesSiteTest, EnvVars) { google::cloud::functions_internal::SetEnv("FOO", std::nullopt); - auto actual = env_vars(gcf::HttpRequest{}); - EXPECT_THAT(actual.payload(), AllOf(HasSubstr("FOO"), HasSubstr("not set"))); + auto function = env_vars(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_THAT(actual.body(), AllOf(HasSubstr("FOO"), HasSubstr("not set"))); google::cloud::functions_internal::SetEnv("FOO", "test-value"); - actual = env_vars(gcf::HttpRequest{}); - EXPECT_THAT(actual.payload(), HasSubstr("test-value")); + actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_THAT(actual.body(), HasSubstr("test-value")); } TEST(ExamplesSiteTest, HelloWorldError) { - auto actual = hello_world_error(gcf::HttpRequest{}); - EXPECT_EQ(actual.payload(), "Hello World!"); + auto function = hello_world_error(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_EQ(actual.body(), "Hello World!"); - EXPECT_THROW( - hello_world_error(gcf::HttpRequest{}.set_target("/throw/exception")), - std::exception); - auto error = hello_world_error(gcf::HttpRequest{}.set_target("/return500")); - EXPECT_EQ(error.result(), gcf::HttpResponse::kInternalServerError); + actual = TriggerFunctionHttp( + function, gcf::HttpRequest{}.set_target("/throw/exception")); + EXPECT_EQ(actual.result_int(), gcf::HttpResponse::kInternalServerError); + auto error = TriggerFunctionHttp(function, + gcf::HttpRequest{}.set_target("/return500")); + EXPECT_EQ(error.result_int(), gcf::HttpResponse::kInternalServerError); } TEST(ExamplesSiteTest, HelloWorldGet) { - auto actual = hello_world_get(gcf::HttpRequest{}); - EXPECT_EQ(actual.payload(), "Hello World!"); + auto function = hello_world_get(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_EQ(actual.body(), "Hello World!"); } TEST(ExamplesSiteTest, HelloWorlHttp) { @@ -287,7 +292,7 @@ TEST(ExamplesSiteTest, HelloWorldPubSub) { struct TestCase { std::string name; std::string body; - } cases[] = { + } const cases[] = { {"text", kBodyDataText}, {"json", kBodyDataJson}, }; @@ -359,7 +364,7 @@ TEST(ExamplesSiteTest, HelloWorldStorage) { struct TestCase { std::string name; std::string body; - } cases[] = { + } const cases[] = { {"base", base.dump()}, {"text", kBodyDataText}, {"json", kBodyDataJson}, @@ -385,41 +390,47 @@ TEST(ExamplesSiteTest, HttpContent) { .set_payload(std::move(payload)); }; - auto actual = http_content( - make_request("application/json", R"js({ "name": "Foo" })js")); - EXPECT_THAT(actual.payload(), "Hello Foo"); + auto function = http_content(); + auto actual = TriggerFunctionHttp( + function, make_request("application/json", R"js({ "name": "Foo" })js")); + EXPECT_THAT(actual.body(), "Hello Foo"); - actual = http_content(make_request("text/plain", "Bar")); - EXPECT_THAT(actual.payload(), "Hello Bar"); + actual = TriggerFunctionHttp(function, make_request("text/plain", "Bar")); + EXPECT_THAT(actual.body(), "Hello Bar"); - actual = http_content(make_request("application/x-www-form-urlencoded", - "id=1&name=Baz%20Qux&value=x")); - EXPECT_THAT(actual.payload(), "Hello Baz Qux"); + actual = TriggerFunctionHttp(function, + make_request("application/x-www-form-urlencoded", + "id=1&name=Baz%20Qux&value=x")); + EXPECT_THAT(actual.body(), "Hello Baz Qux"); - actual = http_content(make_request("application/x-www-form-urlencoded", - "id=1&name=Baz%Qux&value=x")); - EXPECT_THAT(actual.payload(), "Hello Baz%Qux"); + actual = TriggerFunctionHttp(function, + make_request("application/x-www-form-urlencoded", + "id=1&name=Baz%Qux&value=x")); + EXPECT_THAT(actual.body(), "Hello Baz%Qux"); } TEST(ExamplesSiteTest, HttpCors) { - auto actual = http_cors(gcf::HttpRequest{}.set_verb("OPTIONS")); - EXPECT_EQ(actual.headers().at("Access-Control-Allow-Methods"), "GET"); - - actual = http_cors(gcf::HttpRequest{}.set_verb("GET")); - EXPECT_EQ(actual.headers().at("Access-Control-Allow-Origin"), "*"); - EXPECT_EQ(actual.payload(), "Hello World!"); + auto function = http_cors(); + auto actual = + TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb("OPTIONS")); + std::cout << "DEBUG DEBUG " << actual << std::endl; + EXPECT_EQ(actual.at("Access-Control-Allow-Methods"), "GET"); + + actual = TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb("GET")); + EXPECT_EQ(actual.at("Access-Control-Allow-Origin"), "*"); + EXPECT_EQ(actual.body(), "Hello World!"); } TEST(ExamplesSiteTest, HttpCorsAuth) { - auto actual = http_cors_auth(gcf::HttpRequest{}.set_verb("OPTIONS")); - EXPECT_EQ(actual.headers().at("Access-Control-Allow-Headers"), - "Authorization"); - - actual = http_cors_auth(gcf::HttpRequest{}.set_verb("GET")); - EXPECT_EQ(actual.headers().at("Access-Control-Allow-Origin"), - "https://mydomain.com"); - EXPECT_EQ(actual.headers().at("Access-Control-Allow-Credentials"), "true"); - EXPECT_EQ(actual.payload(), "Hello World!"); + auto function = http_cors_auth(); + auto actual = + TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb("OPTIONS")); + EXPECT_EQ(actual.at("Access-Control-Allow-Headers"), "Authorization"); + + actual = TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb("GET")); + EXPECT_EQ(actual.at("Access-Control-Allow-Origin"), "https://mydomain.com"); + EXPECT_EQ(actual.at("Access-Control-Allow-Credentials"), "true"); + EXPECT_EQ(actual.body(), "Hello World!"); } TEST(ExamplesSiteTest, HttpFormData) { @@ -438,16 +449,18 @@ TEST(ExamplesSiteTest, HttpFormData) { ; // Test with both quoted and unquoted boundaries. + auto function = http_form_data(); for (auto const* content_type : {R"""(multipart/form-data;boundary="boundary")""", R"""(multipart/form-data;boundary=boundary)"""}) { SCOPED_TRACE("Testing with content_type = " + std::string(content_type)); - auto actual = http_form_data(gcf::HttpRequest{} - .add_header("content-type", content_type) - .set_payload(kPayload) - .set_verb("POST")); - ASSERT_EQ(actual.result(), gcf::HttpResponse::kOkay); - auto const actual_payload = nlohmann::json::parse(actual.payload()); + auto actual = TriggerFunctionHttp( + function, gcf::HttpRequest{} + .add_header("content-type", content_type) + .set_payload(kPayload) + .set_verb("POST")); + ASSERT_EQ(actual.result_int(), gcf::HttpResponse::kOkay); + auto const actual_payload = nlohmann::json::parse(actual.body()); auto const expected_payload = nlohmann::json{ {"parts", { @@ -460,34 +473,39 @@ TEST(ExamplesSiteTest, HttpFormData) { EXPECT_EQ(actual_payload, expected_payload); } - EXPECT_EQ(http_form_data(gcf::HttpRequest{}).result(), + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), gcf::HttpResponse::kMethodNotAllowed); - EXPECT_EQ(http_form_data(gcf::HttpRequest{}.set_verb("POST")).result(), + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb("POST")) + .result_int(), gcf::HttpResponse::kBadRequest); - EXPECT_EQ(http_form_data(gcf::HttpRequest{}.set_verb("POST").add_header( - "content-type", "application/json")) - .result(), + EXPECT_EQ(TriggerFunctionHttp(function, + gcf::HttpRequest{}.set_verb("POST").add_header( + "content-type", "application/json")) + .result_int(), gcf::HttpResponse::kBadRequest); - EXPECT_THROW( - http_form_data(gcf::HttpRequest{} - .add_header("content-type", "multipart/form-data") - .set_verb("POST")), - std::exception); + EXPECT_EQ(TriggerFunctionHttp( + function, gcf::HttpRequest{} + .add_header("content-type", "multipart/form-data") + .set_verb("POST")) + .result_int(), + gcf::HttpResponse::kInternalServerError); } TEST(ExamplesSiteTest, HttpMethod) { struct Test { std::string verb; int result; - } tests[] = { + } const tests[] = { {"GET", gcf::HttpResponse::kOkay}, {"POST", gcf::HttpResponse::kForbidden}, {"PUT", gcf::HttpResponse::kMethodNotAllowed}, }; + auto function = http_method(); for (auto const& test : tests) { - auto actual = http_method(gcf::HttpRequest{}.set_verb(test.verb)); - EXPECT_EQ(actual.result(), test.result); + auto actual = + TriggerFunctionHttp(function, gcf::HttpRequest{}.set_verb(test.verb)); + EXPECT_EQ(actual.result_int(), test.result); } } @@ -496,24 +514,26 @@ TEST(ExamplesSiteTest, HttpXml) { return gcf::HttpRequest{}.set_payload(std::move(payload)); }; - auto actual = http_xml(make_request(R"xml( + auto function = http_xml(); + auto actual = TriggerFunctionHttp(function, make_request(R"xml( Foo Bar Baz )xml")); - EXPECT_EQ(actual.payload(), "Hello Foo"); + EXPECT_EQ(actual.body(), "Hello Foo"); - actual = http_xml(make_request(R"xml( + actual = TriggerFunctionHttp(function, make_request(R"xml( Foo Bar Baz )xml")); - EXPECT_EQ(actual.payload(), "Hello World"); + EXPECT_EQ(actual.body(), "Hello World"); } TEST(ExamplesSiteTest, LogHelloWorld) { - auto actual = log_helloworld(gcf::HttpRequest{}); - EXPECT_EQ(actual.payload(), "Hello Logging!"); + auto function = log_helloworld(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_EQ(actual.body(), "Hello Logging!"); } TEST(ExamplesSiteTest, LogStackdriver) {