From 7b26f7b8310b97cd290a1f83d9c34ded89eebf1a Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Tue, 4 Jul 2023 21:26:40 +0000 Subject: [PATCH 1/3] doc: examples use declarative configuration 5/N --- ci/build-examples.yaml | 8 - examples/site/bearer_token/bearer_token.cc | 7 +- .../site/log_stackdriver/log_stackdriver.cc | 24 +-- .../site/pubsub_subscribe/pubsub_subscribe.cc | 12 +- examples/site/tips_gcp_apis/tips_gcp_apis.cc | 7 +- .../tips_infinite_retries.cc | 26 +-- .../tips_lazy_globals/tips_lazy_globals.cc | 11 +- examples/site/tips_retry/tips_retry.cc | 22 ++- examples/site/tips_scopes/tips_scopes.cc | 11 +- examples/site_test.cc | 173 ++++++++++++------ 10 files changed, 184 insertions(+), 117 deletions(-) diff --git a/ci/build-examples.yaml b/ci/build-examples.yaml index 90c1c148..5715083f 100644 --- a/ci/build-examples.yaml +++ b/ci/build-examples.yaml @@ -153,7 +153,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-bearer_token' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=bearer_token', '--path', 'examples/site/bearer_token', 'site-bearer_token', @@ -306,7 +305,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-log_stackdriver' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent', '--env', 'GOOGLE_FUNCTION_TARGET=log_stackdriver', '--path', 'examples/site/log_stackdriver', 'site-log_stackdriver', @@ -315,7 +313,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-pubsub_subscribe' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent', '--env', 'GOOGLE_FUNCTION_TARGET=pubsub_subscribe', '--path', 'examples/site/pubsub_subscribe', 'site-pubsub_subscribe', @@ -324,7 +321,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-tips_gcp_apis' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=tips_gcp_apis', '--path', 'examples/site/tips_gcp_apis', 'site-tips_gcp_apis', @@ -333,7 +329,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-tips_infinite_retries' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent', '--env', 'GOOGLE_FUNCTION_TARGET=tips_infinite_retries', '--path', 'examples/site/tips_infinite_retries', 'site-tips_infinite_retries', @@ -342,7 +337,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-tips_lazy_globals' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=tips_lazy_globals', '--path', 'examples/site/tips_lazy_globals', 'site-tips_lazy_globals', @@ -351,7 +345,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-tips_retry' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=cloudevent', '--env', 'GOOGLE_FUNCTION_TARGET=tips_retry', '--path', 'examples/site/tips_retry', 'site-tips_retry', @@ -360,7 +353,6 @@ steps: waitFor: ['gcf-builder-ready'] id: 'site-tips_scopes' args: ['build', - '--env', 'GOOGLE_FUNCTION_SIGNATURE_TYPE=http', '--env', 'GOOGLE_FUNCTION_TARGET=tips_scopes', '--path', 'examples/site/tips_scopes', 'site-tips_scopes', diff --git a/examples/site/bearer_token/bearer_token.cc b/examples/site/bearer_token/bearer_token.cc index fad8408b..8e2238d7 100644 --- a/examples/site/bearer_token/bearer_token.cc +++ b/examples/site/bearer_token/bearer_token.cc @@ -13,8 +13,7 @@ // limitations under the License. // [START functions_bearer_token] -#include -#include +#include #include #include #include @@ -31,7 +30,7 @@ gcf::HttpResponse HttpGet(std::string const& url, std::string const& authorization_header); } // namespace -gcf::HttpResponse bearer_token(gcf::HttpRequest request) { // NOLINT +gcf::HttpResponse bearer_token_impl(gcf::HttpRequest const& request) { static auto const kTargetUrl = [] { auto const* target_url = std::getenv("TARGET_URL"); if (target_url != nullptr) return std::string(target_url); @@ -61,6 +60,8 @@ gcf::HttpResponse bearer_token(gcf::HttpRequest request) { // NOLINT os << "Error creating authorization header: " << std::move(header).status(); throw std::runtime_error(std::move(os).str()); } + +gcf::Function bearer_token() { return gcf::MakeFunction(bearer_token_impl); } // [END functions_bearer_token] namespace { diff --git a/examples/site/log_stackdriver/log_stackdriver.cc b/examples/site/log_stackdriver/log_stackdriver.cc index 7997a1c7..219d8bcb 100644 --- a/examples/site/log_stackdriver/log_stackdriver.cc +++ b/examples/site/log_stackdriver/log_stackdriver.cc @@ -13,22 +13,24 @@ // limitations under the License. // [START functions_log_stackdriver] -#include +#include #include #include #include namespace gcf = ::google::cloud::functions; -void log_stackdriver(gcf::CloudEvent event) { // NOLINT - if (event.data_content_type().value_or("") != "application/json") { - std::cerr << "expected application/json data"; - return; - } - auto const payload = nlohmann::json::parse(event.data().value_or("{}")); - auto const data = cppcodec::base64_rfc4648::decode( - payload["message"]["data"].get()); - auto const log_entry = nlohmann::json::parse(data); - std::cout << "Log entry data: " << log_entry.dump(/*indent=*/2) << "\n"; +gcf::Function log_stackdriver() { + return gcf::MakeFunction([](gcf::CloudEvent const& event) { + if (event.data_content_type().value_or("") != "application/json") { + std::cerr << "expected application/json data\n"; + return; + } + auto const payload = nlohmann::json::parse(event.data().value_or("{}")); + auto const data = cppcodec::base64_rfc4648::decode( + payload["message"]["data"].get()); + auto const log_entry = nlohmann::json::parse(data); + std::cout << "Log entry data: " << log_entry.dump(/*indent=*/2) << "\n"; + }); } // [END functions_log_stackdriver] diff --git a/examples/site/pubsub_subscribe/pubsub_subscribe.cc b/examples/site/pubsub_subscribe/pubsub_subscribe.cc index 76c2771a..952e82a6 100644 --- a/examples/site/pubsub_subscribe/pubsub_subscribe.cc +++ b/examples/site/pubsub_subscribe/pubsub_subscribe.cc @@ -13,11 +13,15 @@ // limitations under the License. // [START functions_pubsub_subscribe] -#include +#include #include -void pubsub_subscribe(google::cloud::functions::CloudEvent event) { // NOLINT - // The framework converts the data from base64 if needed. - std::cout << event.data().value_or("") << "\n"; +namespace gcf = ::google::cloud::functions; + +gcf::Function pubsub_subscribe() { + return gcf::MakeFunction([](gcf::CloudEvent const& event) { + // The framework converts the data from base64 if needed. + std::cout << event.data().value_or("") << "\n"; + }); } // [END functions_pubsub_subscribe] diff --git a/examples/site/tips_gcp_apis/tips_gcp_apis.cc b/examples/site/tips_gcp_apis/tips_gcp_apis.cc index 2fbfdebc..5ce1843c 100644 --- a/examples/site/tips_gcp_apis/tips_gcp_apis.cc +++ b/examples/site/tips_gcp_apis/tips_gcp_apis.cc @@ -14,8 +14,7 @@ // [START functions_pubsub_publish] // [START functions_tips_gcp_apis] -#include -#include +#include #include #include #include @@ -44,7 +43,7 @@ pubsub::Publisher GetPublisher(pubsub::Topic topic) { } } // namespace -gcf::HttpResponse tips_gcp_apis(gcf::HttpRequest request) { // NOLINT +gcf::HttpResponse tips_gcp_apis_impl(gcf::HttpRequest const& request) { auto const* project = std::getenv("GCP_PROJECT"); if (project == nullptr) throw std::runtime_error("GCP_PROJECT is not set"); @@ -65,5 +64,7 @@ gcf::HttpResponse tips_gcp_apis(gcf::HttpRequest request) { // NOLINT } return response; } + +gcf::Function tips_gcp_apis() { return gcf::MakeFunction(tips_gcp_apis_impl); } // [END functions_tips_gcp_apis] // [END functions_pubsub_publish] diff --git a/examples/site/tips_infinite_retries/tips_infinite_retries.cc b/examples/site/tips_infinite_retries/tips_infinite_retries.cc index d5f64acd..6cc6f296 100644 --- a/examples/site/tips_infinite_retries/tips_infinite_retries.cc +++ b/examples/site/tips_infinite_retries/tips_infinite_retries.cc @@ -13,7 +13,7 @@ // limitations under the License. // [START functions_tips_infinite_retries] -#include +#include #include #include @@ -23,17 +23,19 @@ namespace { auto constexpr kMaxAge = std::chrono::seconds(10); } // namespace -void tips_infinite_retries(gcf::CloudEvent event) { // NOLINT - using std::chrono::system_clock; - auto const age = - system_clock::now() - event.time().value_or(system_clock::time_point()); - auto const seconds = - std::chrono::duration_cast(age).count(); +gcf::Function tips_infinite_retries() { + return gcf::MakeFunction([](gcf::CloudEvent const& event) { + using std::chrono::system_clock; + auto const age = + system_clock::now() - event.time().value_or(system_clock::time_point()); + auto const seconds = + std::chrono::duration_cast(age).count(); - if (age >= kMaxAge) { - std::cout << "Dropped " << event.id() << " (age " << seconds << "s)\n"; - return; - } - std::cout << "Processed " << event.id() << " (age " << seconds << "s)\n"; + if (age >= kMaxAge) { + std::cout << "Dropped " << event.id() << " (age " << seconds << "s)\n"; + return; + } + std::cout << "Processed " << event.id() << " (age " << seconds << "s)\n"; + }); } // [END functions_tips_infinite_retries] diff --git a/examples/site/tips_lazy_globals/tips_lazy_globals.cc b/examples/site/tips_lazy_globals/tips_lazy_globals.cc index e6f0898d..76db078a 100644 --- a/examples/site/tips_lazy_globals/tips_lazy_globals.cc +++ b/examples/site/tips_lazy_globals/tips_lazy_globals.cc @@ -13,8 +13,7 @@ // limitations under the License. // [START functions_tips_lazy_globals] -#include -#include +#include #include #include @@ -27,8 +26,10 @@ std::string h; void h_init() { h = "heavy computation"; } } // namespace -gcf::HttpResponse tips_lazy_globals(gcf::HttpRequest /*request*/) { // NOLINT - std::call_once(h_init_flag, h_init); - return gcf::HttpResponse{}.set_payload("Global: " + h); +gcf::Function tips_lazy_globals() { + return gcf::MakeFunction([](gcf::HttpRequest const& /*request*/) { + std::call_once(h_init_flag, h_init); + return gcf::HttpResponse{}.set_payload("Global: " + h); + }); } // [END functions_tips_lazy_globals] diff --git a/examples/site/tips_retry/tips_retry.cc b/examples/site/tips_retry/tips_retry.cc index a70e557e..3c71beae 100644 --- a/examples/site/tips_retry/tips_retry.cc +++ b/examples/site/tips_retry/tips_retry.cc @@ -13,20 +13,22 @@ // limitations under the License. // [START functions_tips_retry] -#include +#include #include #include namespace gcf = ::google::cloud::functions; -void tips_retry(gcf::CloudEvent event) { // NOLINT - if (event.data_content_type().value_or("") != "application/json") { - std::cerr << "Error: expected application/json data\n"; - return; - } - auto const payload = nlohmann::json::parse(event.data().value_or("{}")); - auto const retry = payload.value("retry", false); - if (retry) throw std::runtime_error("Throwing exception to force retry"); - // Normal processing goes here. +gcf::Function tips_retry() { + return gcf::MakeFunction([](gcf::CloudEvent const& event) { + if (event.data_content_type().value_or("") != "application/json") { + std::cerr << "Error: expected application/json data\n"; + return; + } + auto const payload = nlohmann::json::parse(event.data().value_or("{}")); + auto const retry = payload.value("retry", false); + if (retry) throw std::runtime_error("Throwing exception to force retry"); + // Normal processing goes here. + }); } // [END functions_tips_retry] diff --git a/examples/site/tips_scopes/tips_scopes.cc b/examples/site/tips_scopes/tips_scopes.cc index 4f5a1184..fcff43aa 100644 --- a/examples/site/tips_scopes/tips_scopes.cc +++ b/examples/site/tips_scopes/tips_scopes.cc @@ -13,8 +13,7 @@ // limitations under the License. // [START functions_tips_scopes] -#include -#include +#include #include namespace gcf = ::google::cloud::functions; @@ -27,9 +26,11 @@ std::string light_computation(); std::string h = heavy_computation(); } // namespace -gcf::HttpResponse tips_scopes(gcf::HttpRequest /*request*/) { // NOLINT - auto l = light_computation(); - return gcf::HttpResponse{}.set_payload("Global: " + h + ", Local: " + l); +gcf::Function tips_scopes() { + return gcf::MakeFunction([](gcf::HttpRequest const& /*request*/) { + auto l = light_computation(); + return gcf::HttpResponse{}.set_payload("Global: " + h + ", Local: " + l); + }); } // [END functions_tips_scopes] diff --git a/examples/site_test.cc b/examples/site_test.cc index b37a6759..b17c22c3 100644 --- a/examples/site_test.cc +++ b/examples/site_test.cc @@ -31,7 +31,7 @@ namespace gcf = ::google::cloud::functions; namespace gcf_internal = ::google::cloud::functions_internal; -extern gcf::HttpResponse bearer_token(gcf::HttpRequest request); +extern gcf::Function bearer_token(); extern gcf::Function concepts_after_response(); extern gcf::Function concepts_after_timeout(); extern gcf::Function concepts_filesystem(); @@ -50,13 +50,13 @@ 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); -extern void tips_infinite_retries(gcf::CloudEvent event); -extern gcf::HttpResponse tips_lazy_globals(gcf::HttpRequest request); -extern gcf::HttpResponse tips_scopes(gcf::HttpRequest request); -extern void tips_retry(gcf::CloudEvent event); +extern gcf::Function log_stackdriver(); +extern gcf::Function pubsub_subscribe(); +extern gcf::Function tips_gcp_apis(); +extern gcf::Function tips_infinite_retries(); +extern gcf::Function tips_lazy_globals(); +extern gcf::Function tips_scopes(); +extern gcf::Function tips_retry(); namespace { @@ -77,18 +77,51 @@ auto TriggerFunctionHttp(gcf::Function const& function, return handler(std::move(request)); } +auto TriggerFunctionCloudEvent(gcf::Function const& function, + gcf::CloudEvent const& e) { + auto payload = nlohmann::json{ + {"specversion", e.spec_version()}, + {"id", e.id()}, + {"source", e.source()}, + {"type", e.type()}, + }; + auto if_set = [&payload](std::string_view name, + std::optional const& v) { + if (v.has_value()) payload[name] = *v; + }; + if_set("datacontenttype", e.data_content_type()); + if_set("dataschema", e.data_schema()); + if_set("subject", e.subject()); + if (e.data_content_type().value_or("") == "application/json") { + payload["data"] = nlohmann::json::parse(e.data().value_or("{}")); + } else if (auto const& d = e.data(); d.has_value()) { + payload["data"] = *d; + } + + gcf_internal::BeastRequest request; + request.insert("content-type", "application/cloudevents+json"); + request.body() = payload.dump(); + + auto handler = + gcf_internal::FunctionImpl::GetImpl(function)->GetHandler("unused"); + return handler(std::move(request)); +} + TEST(ExamplesSiteTest, BearerToken) { google::cloud::functions_internal::SetEnv("TARGET_URL", std::nullopt); google::cloud::functions_internal::SetEnv("GOOGLE_APPLICATION_CREDENTIALS", "/dev/null"); - EXPECT_THROW(bearer_token(gcf::HttpRequest{}), std::exception); + auto function = bearer_token(); + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), + gcf::HttpResponse::kInternalServerError); google::cloud::functions_internal::SetEnv( "TARGET_URL", "https://storage.googleapis.com/storage/v1/" "b?project=invalid-project-name---"); - EXPECT_THROW(bearer_token(gcf::HttpRequest{}), std::exception); + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), + gcf::HttpResponse::kInternalServerError); // This is a syntactically valid JSON key file, but the key has been // invalidated and therefore presents no security risks. @@ -148,10 +181,14 @@ lUtj+/nH3HDQjM4ltYfTPUg= google::cloud::functions_internal::SetEnv("GOOGLE_APPLICATION_CREDENTIALS", filename.string()); - EXPECT_THROW(bearer_token(gcf::HttpRequest{}), std::exception); + // We get different errors in the CI builds vs. development workstations. + EXPECT_NE(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), + gcf::HttpResponse::kOkay); - EXPECT_NO_THROW( - bearer_token(gcf::HttpRequest{}.set_target("/no-auth-header"))); + EXPECT_EQ(TriggerFunctionHttp( + function, gcf::HttpRequest{}.set_target("/no-auth-header")) + .result_int(), + gcf::HttpResponse::kBadRequest); std::filesystem::remove(filename); } @@ -257,13 +294,14 @@ TEST(ExamplesSiteTest, HelloWorldPubSub) { for (auto const* data : {"dGVzdCBtZXNzYWdlIDM=", "YWJjZA==", ""}) { auto json = base; json["data"]["message"]["data"] = data; - auto response = - TriggerFunctionHttp(hello_world_pubsub(), - gcf::HttpRequest{} - .set_payload(json.dump()) - .add_header("ce-type", "com.example.someevent") - .add_header("ce-source", "/mycontext") - .add_header("ce-id", "A234-1234-1234")); + auto response = TriggerFunctionHttp( + hello_world_pubsub(), + gcf::HttpRequest{} + .set_payload(json.dump()) + .add_header("content-type", "application/cloudevents+json") + .add_header("ce-type", "com.example.someevent") + .add_header("ce-source", "/mycontext") + .add_header("ce-id", "A234-1234-1234")); EXPECT_EQ(response.result_int(), 200); } @@ -299,13 +337,13 @@ TEST(ExamplesSiteTest, HelloWorldPubSub) { for (auto const& [name, body] : cases) { SCOPED_TRACE("Testing for " + name); - auto response = - TriggerFunctionHttp(hello_world_storage(), - gcf::HttpRequest{} - .set_payload(body) - .add_header("ce-type", "com.example.someevent") - .add_header("ce-source", "/mycontext") - .add_header("ce-id", "A234-1234-1234")); + auto response = TriggerFunctionHttp( + hello_world_pubsub(), + gcf::HttpRequest{} + .set_payload(body) + .add_header("ce-type", "com.example.someevent") + .add_header("ce-source", "/mycontext") + .add_header("ce-id", "A234-1234-1234")); EXPECT_EQ(response.result_int(), 200); } } @@ -364,18 +402,20 @@ TEST(ExamplesSiteTest, HelloWorldStorage) { struct TestCase { std::string name; std::string body; + std::string content_type; } const cases[] = { - {"base", base.dump()}, - {"text", kBodyDataText}, - {"json", kBodyDataJson}, + {"base", base.dump(), "application/cloudevents+json"}, + {"text", kBodyDataText, "text/plain"}, + {"json", kBodyDataJson, "application/cloudevents+json"}, }; - for (auto const& [name, body] : cases) { + for (auto const& [name, body, content_type] : cases) { SCOPED_TRACE("Testing for " + name); auto response = TriggerFunctionHttp(hello_world_storage(), gcf::HttpRequest{} .set_payload(body) + .add_header("content-type", content_type) .add_header("ce-type", "com.example.someevent") .add_header("ce-source", "/mycontext") .add_header("ce-id", "A234-1234-1234")); @@ -413,7 +453,6 @@ TEST(ExamplesSiteTest, HttpCors) { 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")); @@ -572,13 +611,18 @@ TEST(ExamplesSiteTest, LogStackdriver) { }}, }; - EXPECT_NO_THROW(log_stackdriver( - google::cloud::functions_internal::ParseCloudEventJson(envelope.dump()))); + auto const event = + google::cloud::functions_internal::ParseCloudEventJson(envelope.dump()); + auto function = log_stackdriver(); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); // This is just to fix the code coverage nit. envelope.erase("datacontenttype"); - EXPECT_NO_THROW(log_stackdriver( - google::cloud::functions_internal::ParseCloudEventJson(envelope.dump()))); + auto const bad = + google::cloud::functions_internal::ParseCloudEventJson(envelope.dump()); + EXPECT_EQ(TriggerFunctionCloudEvent(function, bad).result_int(), + gcf::HttpResponse::kOkay); } TEST(ExamplesSiteTest, PubsubSubscribe) { @@ -604,19 +648,23 @@ TEST(ExamplesSiteTest, PubsubSubscribe) { })js"); // Test with different values for data.message.data + auto function = pubsub_subscribe(); for (auto const* data : {"dGVzdCBtZXNzYWdlIDM=", "YWJjZA==", ""}) { auto json = base; json["data"]["message"]["data"] = data; - EXPECT_NO_THROW(pubsub_subscribe( - google::cloud::functions_internal::ParseCloudEventJson(json.dump()))); + auto const event = + google::cloud::functions_internal::ParseCloudEventJson(json.dump()); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); } } TEST(ExamplesSiteTest, TipsLazyGlobals) { - auto actual = tips_lazy_globals(gcf::HttpRequest{}); - EXPECT_THAT(actual.payload(), HasSubstr("heavy computation")); - actual = tips_lazy_globals(gcf::HttpRequest{}); - EXPECT_THAT(actual.payload(), HasSubstr("heavy computation")); + auto function = tips_lazy_globals(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_THAT(actual.body(), HasSubstr("heavy computation")); + actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_THAT(actual.body(), HasSubstr("heavy computation")); } TEST(ExamplesSiteTest, TipsGcpApis) { @@ -627,37 +675,50 @@ TEST(ExamplesSiteTest, TipsGcpApis) { #endif // __has_feature(thread_sanitizer) #endif // defined(__has_feature) google::cloud::functions_internal::SetEnv("GCP_PROJECT", std::nullopt); - EXPECT_THROW(tips_gcp_apis(gcf::HttpRequest{}), std::runtime_error); + auto function = tips_gcp_apis(); + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), + gcf::HttpResponse::kInternalServerError); google::cloud::functions_internal::SetEnv("GCP_PROJECT", "test-unused"); - EXPECT_THROW(tips_gcp_apis(gcf::HttpRequest{}), std::exception); - EXPECT_THROW( - tips_gcp_apis(gcf::HttpRequest{}.set_payload(nlohmann::json({}).dump())), - std::runtime_error); + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}).result_int(), + gcf::HttpResponse::kInternalServerError); + EXPECT_EQ(TriggerFunctionHttp(function, gcf::HttpRequest{}.set_payload( + nlohmann::json({}).dump())) + .result_int(), + gcf::HttpResponse::kInternalServerError); } TEST(ExamplesSiteTest, TipsInfiniteRetries) { + auto function = tips_infinite_retries(); gcf::CloudEvent event("test-id", "test-source", "test-type"); - EXPECT_NO_THROW(tips_infinite_retries(event)); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); event.set_time(std::chrono::system_clock::now()); - EXPECT_NO_THROW(tips_infinite_retries(event)); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); } TEST(ExamplesSiteTest, TipsScopes) { - auto actual = tips_scopes(gcf::HttpRequest{}); - EXPECT_THAT(actual.payload(), HasSubstr("Global: ")); - EXPECT_THAT(actual.payload(), HasSubstr("Local: ")); + auto function = tips_scopes(); + auto actual = TriggerFunctionHttp(function, gcf::HttpRequest{}); + EXPECT_THAT(actual.body(), HasSubstr("Global: ")); + EXPECT_THAT(actual.body(), HasSubstr("Local: ")); } TEST(ExamplesSiteTest, TipsRetry) { + auto function = tips_retry(); gcf::CloudEvent event("test-id", "test-source", "test-type"); - EXPECT_NO_THROW(tips_retry(event)); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); event.set_data_content_type("application/json"); - EXPECT_NO_THROW(tips_retry(event)); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); event.set_data(nlohmann::json({{"retry", false}}).dump()); - EXPECT_NO_THROW(tips_retry(event)); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kOkay); event.set_data(nlohmann::json({{"retry", true}}).dump()); - EXPECT_THROW(tips_retry(event), std::exception); + EXPECT_EQ(TriggerFunctionCloudEvent(function, event).result_int(), + gcf::HttpResponse::kInternalServerError); } } // namespace From 0dc88ad09f65898c313370a9b2d5ec3c1b91c000 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Wed, 5 Jul 2023 17:30:53 +0000 Subject: [PATCH 2/3] Fix formatting --- examples/site_test.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/site_test.cc b/examples/site_test.cc index b17c22c3..9f832435 100644 --- a/examples/site_test.cc +++ b/examples/site_test.cc @@ -337,13 +337,13 @@ TEST(ExamplesSiteTest, HelloWorldPubSub) { for (auto const& [name, body] : cases) { SCOPED_TRACE("Testing for " + name); - auto response = TriggerFunctionHttp( - hello_world_pubsub(), - gcf::HttpRequest{} - .set_payload(body) - .add_header("ce-type", "com.example.someevent") - .add_header("ce-source", "/mycontext") - .add_header("ce-id", "A234-1234-1234")); + auto response = + TriggerFunctionHttp(hello_world_pubsub(), + gcf::HttpRequest{} + .set_payload(body) + .add_header("ce-type", "com.example.someevent") + .add_header("ce-source", "/mycontext") + .add_header("ce-id", "A234-1234-1234")); EXPECT_EQ(response.result_int(), 200); } } From 58864fd9364b3a84d4c35f6d40f707a20bdca8e2 Mon Sep 17 00:00:00 2001 From: Carlos O'Ryan Date: Wed, 5 Jul 2023 17:39:45 +0000 Subject: [PATCH 3/3] Work with older nlohmann::json --- examples/site_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/site_test.cc b/examples/site_test.cc index 9f832435..1d91e000 100644 --- a/examples/site_test.cc +++ b/examples/site_test.cc @@ -85,7 +85,7 @@ auto TriggerFunctionCloudEvent(gcf::Function const& function, {"source", e.source()}, {"type", e.type()}, }; - auto if_set = [&payload](std::string_view name, + auto if_set = [&payload](std::string const& name, std::optional const& v) { if (v.has_value()) payload[name] = *v; };