// Copyright 2018 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. #include "google/cloud/future.h" #include "google/cloud/internal/throw_delegate.h" #include "google/cloud/testing_util/chrono_literals.h" #include "google/cloud/testing_util/expect_future_error.h" #include #include namespace google { namespace cloud { inline namespace GOOGLE_CLOUD_CPP_NS { namespace { using ::testing::HasSubstr; using testing_util::chrono_literals::operator"" _ms; using testing_util::ExpectFutureError; TEST(FutureTestInt, ThenSimple) { promise p; future fut = p.get_future(); EXPECT_TRUE(fut.valid()); bool called = false; future next = fut.then([&called](future r) { called = true; return 2 * r.get(); }); EXPECT_FALSE(fut.valid()); EXPECT_TRUE(next.valid()); EXPECT_FALSE(called); p.set_value(42); EXPECT_TRUE(called); EXPECT_TRUE(next.valid()); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_EQ(84, next.get()); EXPECT_FALSE(next.valid()); } TEST(FutureTestInt, ThenException) { promise p; future fut = p.get_future(); EXPECT_TRUE(fut.valid()); bool called = false; future next = fut.then([&called](future r) { called = true; int value = r.get(); if (value == 42) { internal::ThrowRuntimeError("test message"); } return 2 * value; }); EXPECT_FALSE(fut.valid()); EXPECT_TRUE(next.valid()); EXPECT_FALSE(called); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS p.set_value(42); EXPECT_TRUE(called); EXPECT_TRUE(next.valid()); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_THROW( try { next.get(); } catch (std::runtime_error const& ex) { EXPECT_THAT(ex.what(), HasSubstr("test message")); throw; }, std::runtime_error); EXPECT_FALSE(next.valid()); #else EXPECT_DEATH_IF_SUPPORTED(p.set_value(42), "test message"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } TEST(FutureTestInt, ThenUnwrap) { promise p; future fut = p.get_future(); EXPECT_TRUE(fut.valid()); promise pp; bool called = false; auto cont = [&pp, &called](future) { called = true; return pp.get_future(); }; future next = fut.then(std::move(cont)); EXPECT_FALSE(fut.valid()); EXPECT_TRUE(next.valid()); EXPECT_FALSE(next.is_ready()); p.set_value(42); EXPECT_TRUE(called); EXPECT_FALSE(next.is_ready()); pp.set_value("value=42"); EXPECT_TRUE(next.is_ready()); EXPECT_EQ("value=42", next.get()); EXPECT_FALSE(next.valid()); } TEST(FutureTestInt, ThenMoveOnlyCallable) { class MoveOnlyDoubler { public: explicit MoveOnlyDoubler(bool& called) : called_(&called) {} MoveOnlyDoubler(MoveOnlyDoubler&&) = default; MoveOnlyDoubler& operator=(MoveOnlyDoubler&&) = default; MoveOnlyDoubler(MoveOnlyDoubler const&) = delete; MoveOnlyDoubler& operator=(MoveOnlyDoubler const&) = delete; int operator()(future f) { *called_ = true; return 2 * f.get(); } private: bool* called_; }; promise p; future fut = p.get_future(); EXPECT_TRUE(fut.valid()); bool called = false; MoveOnlyDoubler cb{called}; future next = fut.then(std::move(cb)); EXPECT_FALSE(fut.valid()); EXPECT_TRUE(next.valid()); EXPECT_FALSE(called); p.set_value(42); EXPECT_TRUE(called); EXPECT_TRUE(next.valid()); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_EQ(2 * 42, next.get()); EXPECT_FALSE(next.valid()); } TEST(FutureTestInt, ThenByCopy) { promise p; future fut = p.get_future(); EXPECT_TRUE(fut.valid()); bool called = false; auto doubler = [&called](future r) { called = true; return 2 * r.get(); }; future next = fut.then(doubler); EXPECT_FALSE(fut.valid()); EXPECT_TRUE(next.valid()); EXPECT_FALSE(called); p.set_value(42); EXPECT_TRUE(called); EXPECT_TRUE(next.valid()); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_EQ(2 * 42, next.get()); EXPECT_FALSE(next.valid()); } /// @test Verify the behavior around cancellation. TEST(FutureTestInt, CancelThroughContinuation) { bool cancelled = false; promise p0([&cancelled] { cancelled = true; }); auto f0 = p0.get_future(); auto f1 = f0.then([](future f) { return f.get() * 2; }); EXPECT_TRUE(f1.cancel()); EXPECT_TRUE(cancelled); p0.set_value(42); EXPECT_EQ(84, f1.get()); } // The following tests reference the technical specification: // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html // The test names match the section and paragraph from the TS. /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_2_a) { // future should have an unwrapping constructor. promise> p; future> f = p.get_future(); future unwrapped(std::move(f)); EXPECT_FALSE(noexcept(future(p.get_future()))); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_3_a) { // A future created via the unwrapping constructor becomes satisfied // when both become satisfied. promise> p; future unwrapped(p.get_future()); EXPECT_TRUE(unwrapped.valid()); EXPECT_FALSE(unwrapped.is_ready()); promise p2; p.set_value(p2.get_future()); EXPECT_FALSE(unwrapped.is_ready()); p2.set_value(42); EXPECT_TRUE(unwrapped.is_ready()); EXPECT_EQ(42, unwrapped.get()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_3_b) { // A future created via the unwrapping constructor becomes satisfied // when the wrapped future is satisfied by an exception. promise> p; future unwrapped(p.get_future()); EXPECT_TRUE(unwrapped.valid()); EXPECT_FALSE(unwrapped.is_ready()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS p.set_exception(std::make_exception_ptr(std::runtime_error("test message"))); EXPECT_TRUE(unwrapped.is_ready()); EXPECT_THROW( try { unwrapped.get(); } catch (std::runtime_error const& ex) { EXPECT_THAT(ex.what(), HasSubstr("test message")); throw; }, std::runtime_error); #else EXPECT_DEATH_IF_SUPPORTED( p.set_exception( std::make_exception_ptr(std::runtime_error("test message"))), "future::get\\(\\) had an exception but exceptions are disabled"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_3_c) { // A future created via the unwrapping constructor becomes satisfied // when the inner future is satisfied by an exception. promise> p; future unwrapped(p.get_future()); EXPECT_TRUE(unwrapped.valid()); EXPECT_FALSE(unwrapped.is_ready()); promise p2; p.set_value(p2.get_future()); EXPECT_FALSE(unwrapped.is_ready()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS p2.set_exception(std::make_exception_ptr(std::runtime_error("test message"))); EXPECT_TRUE(unwrapped.is_ready()); EXPECT_THROW( try { unwrapped.get(); } catch (std::runtime_error const& ex) { EXPECT_THAT(ex.what(), HasSubstr("test message")); throw; }, std::runtime_error); #else EXPECT_DEATH_IF_SUPPORTED( p2.set_exception( std::make_exception_ptr(std::runtime_error("test message"))), "future::get\\(\\) had an exception but exceptions are disabled"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_3_d) { // A future created via the unwrapping constructor becomes satisfied // when the inner future is invalid. promise> p; future unwrapped(p.get_future()); EXPECT_TRUE(unwrapped.valid()); EXPECT_FALSE(unwrapped.is_ready()); promise p2; p.set_value(future{}); EXPECT_TRUE(unwrapped.is_ready()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS EXPECT_THROW( try { unwrapped.get(); } catch (std::future_error const& ex) { EXPECT_EQ(std::future_errc::broken_promise, ex.code()); throw; }, std::future_error); #else EXPECT_DEATH_IF_SUPPORTED( unwrapped.get(), "future::get\\(\\) had an exception but exceptions are disabled"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_4) { // future should leaves the source invalid. promise> p; future> f = p.get_future(); future unwrapped(std::move(f)); EXPECT_TRUE(unwrapped.valid()); EXPECT_FALSE(f.valid()); // NOLINT(bugprone-use-after-move) } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_5) { // future::then() is a template member function that takes callables. future f; auto callable = [](future f) -> int { return 2 * f.get(); }; EXPECT_TRUE((std::is_same, decltype(f.then(callable))>::value)); auto void_callable = [](future f) { f.get(); }; EXPECT_TRUE( (std::is_same, decltype(f.then(void_callable))>::value)); auto long_callable = [](future f) -> long { // NOLINT(google-runtime-int) return 2 * f.get(); }; EXPECT_TRUE( (std::is_same, decltype(f.then(long_callable))>::value)); auto string_callable = [](future) -> std::string { return "42"; }; EXPECT_TRUE((std::is_same, decltype(f.then(string_callable))>::value)); } // Use SFINAE to test if future::then() accepts a T parameter. template auto test_then(int) -> decltype(std::declval>().then(T()), std::true_type{}) { return std::true_type{}; } template auto test_then(long) -> std::false_type { // NOLINT(google-runtime-int) return std::false_type{}; } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_7) { // future::then() requires callables that take future as a // parameter. future f; using valid_callable_type = std::function)>; using invalid_callable_type = std::function; EXPECT_TRUE(decltype(test_then(0))::value); EXPECT_FALSE(decltype(test_then(0))::value); EXPECT_TRUE(decltype(test_then)>>(0))::value); EXPECT_FALSE(decltype(test_then>(0))::value); EXPECT_TRUE( decltype(test_then)>>(0))::value); EXPECT_FALSE(decltype(test_then>(0))::value); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_8_a) { // future::then() creates a future with a valid shared state. promise p; future f = p.get_future(); future next = f.then([&](future) {}); EXPECT_TRUE(next.valid()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_8_b) { // future::then() calls the functor when the future becomes ready. promise p; future f = p.get_future(); bool called = false; future next = f.then([&](future) { called = true; }); EXPECT_TRUE(next.valid()); EXPECT_FALSE(called); p.set_value(42); EXPECT_TRUE(called); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_8_c) { // future::then() calls the functor if the future was ready. promise p; future f = p.get_future(); p.set_value(42); bool called = false; future next = f.then([&](future) { called = true; }); EXPECT_TRUE(next.valid()); EXPECT_TRUE(called); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_8_d) { // future::then() propagates the value from the functor to the returned // future. promise p; future f = p.get_future(); future next = f.then([&](future r) { return 2 * r.get(); }); EXPECT_TRUE(next.valid()); p.set_value(42); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_EQ(84, next.get()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_8_e) { // future::then() propagates exceptions raised by the functort to the // returned future. promise p; future f = p.get_future(); future next = f.then([&](future) { internal::ThrowRuntimeError("test exception in functor"); }); EXPECT_TRUE(next.valid()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS p.set_value(42); ASSERT_EQ(std::future_status::ready, next.wait_for(0_ms)); EXPECT_THROW( try { next.get(); } catch (std::runtime_error const& ex) { EXPECT_THAT(ex.what(), HasSubstr("test exception in functor")); throw; }, std::runtime_error); EXPECT_FALSE(next.valid()); #else EXPECT_DEATH_IF_SUPPORTED(p.set_value(42), "test exception in functor"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_9_a) { // future::then() returns a functor containing the type of the value // returned by the functor. promise p; future f = p.get_future(); auto returns_void = [](future) -> void {}; EXPECT_TRUE( (std::is_same, decltype(f.then(returns_void))>::value)); auto returns_int = [](future) -> int { return 42; }; EXPECT_TRUE( (std::is_same, decltype(f.then(returns_int))>::value)); auto returns_string = [](future) -> std::string { return "42"; }; EXPECT_TRUE((std::is_same, decltype(f.then(returns_string))>::value)); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_9_b) { // future::then() implicitly unwraps the future type when a functor // returns a future<>. promise p; future f = p.get_future(); auto returns_void = [](future) -> future { return promise().get_future(); }; EXPECT_TRUE( (std::is_same, decltype(f.then(returns_void))>::value)); auto returns_int = [](future) -> future { return promise().get_future(); }; EXPECT_TRUE( (std::is_same, decltype(f.then(returns_int))>::value)); // The spec says the returned type must be future *exactly*, references do // not count. promise p_int; future f_int = p_int.get_future(); auto returns_int_ref = [&f_int](future) -> future& { return f_int; }; EXPECT_FALSE( (std::is_same, decltype(f.then(returns_int_ref))>::value)); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_9_c) { // future::then() implicitly unwrapping captures the returned value. promise p; future f = p.get_future(); promise p2; bool called = false; future r = f.then([&p2, &called](future f) { called = true; EXPECT_EQ(7, f.get()); return p2.get_future(); }); EXPECT_TRUE(r.valid()); EXPECT_FALSE(r.is_ready()); EXPECT_FALSE(f.valid()); p.set_value(7); EXPECT_TRUE(called); EXPECT_FALSE(r.is_ready()); p2.set_value(42); EXPECT_TRUE(r.is_ready()); EXPECT_EQ(42, r.get()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_9_d) { // future::then() implicitly unwrapping captures exceptions. promise p; future f = p.get_future(); promise p2; bool called = false; future r = f.then([&p2, &called](future f) { called = true; f.get(); return p2.get_future(); }); EXPECT_TRUE(r.valid()); EXPECT_FALSE(r.is_ready()); EXPECT_FALSE(f.valid()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS p.set_exception(std::make_exception_ptr(std::runtime_error("test message"))); EXPECT_TRUE(called); EXPECT_TRUE(r.is_ready()); EXPECT_THROW( try { r.get(); } catch (std::runtime_error const& ex) { EXPECT_THAT(ex.what(), HasSubstr("test message")); throw; }, std::runtime_error); #else // With exceptions disabled the program terminates as soon as the exception is // set. EXPECT_DEATH_IF_SUPPORTED( p.set_exception( std::make_exception_ptr(std::runtime_error("test message"))), "future::get\\(\\) had an exception but exceptions are disabled"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_9_e) { // future::then() implicitly unwrapping raises on invalid future // returned by continuation. promise p; future f = p.get_future(); bool called = false; future r = f.then([&called](future f) { called = true; f.get(); return future{}; }); EXPECT_TRUE(r.valid()); EXPECT_FALSE(r.is_ready()); EXPECT_FALSE(f.valid()); p.set_value(7); EXPECT_TRUE(called); EXPECT_TRUE(r.is_ready()); #if GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS EXPECT_THROW( try { r.get(); } catch (std::future_error const& ex) { EXPECT_EQ(std::future_errc::broken_promise, ex.code()); throw; }, std::future_error); #else EXPECT_DEATH_IF_SUPPORTED( r.get(), "future::get\\(\\) had an exception but exceptions are disabled"); #endif // GOOGLE_CLOUD_CPP_HAVE_EXCEPTIONS } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_10) { // future::then() invalidates the source future. promise p; future f = p.get_future(); future r = f.then([](future f) { return 2 * f.get(); }); EXPECT_TRUE(r.valid()); EXPECT_FALSE(r.is_ready()); EXPECT_FALSE(f.valid()); p.set_value(42); EXPECT_TRUE(r.is_ready()); EXPECT_EQ(2 * 42, r.get()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_11_a) { // future::is_ready() returns false for futures that are not ready. promise p; future const f = p.get_future(); EXPECT_FALSE(f.is_ready()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_11_b) { // future::is_ready() returns true for futures that are ready. promise p; future const f = p.get_future(); p.set_value(42); EXPECT_TRUE(f.is_ready()); } /// @test Verify conformance with section 2.3 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestInt, conform_2_3_11_c) { // future::is_ready() raises for futures that are not valid. future const f; ExpectFutureError([&] { f.is_ready(); }, std::future_errc::no_state); } /// @test Verify conformance with section 2.10 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestString, conform_2_10_4_2_a) { // When T is a simple value type we get back T. future f = make_ready_future(std::string("42")); EXPECT_TRUE(f.valid()); ASSERT_EQ(std::future_status::ready, f.wait_for(0_ms)); EXPECT_EQ("42", f.get()); } /// @test Verify conformance with section 2.10 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestString, conform_2_10_4_2_b) { // When T is a reference we get std::decay::type. std::string value("42"); std::string& sref = value; future f = make_ready_future(sref); EXPECT_TRUE(f.valid()); ASSERT_EQ(std::future_status::ready, f.wait_for(0_ms)); EXPECT_EQ("42", f.get()); } //// @test Verify conformance with section 2.10 of the Concurrency TS. // NOLINTNEXTLINE(google-readability-avoid-underscore-in-googletest-name) TEST(FutureTestString, conform_2_10_4_2_c) { #if 1 using V = internal::make_ready_return>::type; static_assert(std::is_same::value, "Expected std::string&"); #else // TODO(#1410) - Implement future specialization. // When T is a reference wrapper get R&. std::string value("42"); future f = make_ready_future(std::ref(value)); EXPECT_TRUE(f.valid()); ASSERT_EQ(std::future_status::ready, f.wait_for(0_ms)); EXPECT_EQ("42", f.get()); #endif // 1 } class MockFunctor { public: MockFunctor() = default; MockFunctor(MockFunctor&& other) noexcept : moved_from_(other.moved_from_) { other.moved_from_ = true; } MockFunctor(MockFunctor const& other) = default; void operator()(future) {} bool moved_from_{false}; }; TEST(FutureTestInt, RValueThenFunctorIsMoved) { promise promise; future fut = promise.get_future(); MockFunctor fun; fut.then(std::move(fun)); promise.set_value(1); EXPECT_TRUE(fun.moved_from_); // NOLINT(bugprone-use-after-move) } TEST(FutureTestInt, LValueThenFunctorIsCopied) { promise promise; future fut = promise.get_future(); MockFunctor fun; fut.then(fun); promise.set_value(1); EXPECT_FALSE(fun.moved_from_); } class MockUnwrapFunctor { public: MockUnwrapFunctor() = default; MockUnwrapFunctor(MockUnwrapFunctor&& other) noexcept : moved_from_(other.moved_from_) { other.moved_from_ = true; } MockUnwrapFunctor(MockUnwrapFunctor const& other) = default; future operator()(future) { return make_ready_future(); } bool moved_from_{false}; }; TEST(FutureTestInt, RValueThenUnwrapFunctorIsMoved) { promise promise; future fut = promise.get_future(); MockUnwrapFunctor fun; fut.then(std::move(fun)); promise.set_value(1); EXPECT_TRUE(fun.moved_from_); // NOLINT(bugprone-use-after-move) } TEST(FutureTestInt, LValueThenUnwrapFunctorIsCopied) { promise promise; future fut = promise.get_future(); MockUnwrapFunctor fun; fut.then(fun); promise.set_value(1); EXPECT_FALSE(fun.moved_from_); } } // namespace } // namespace GOOGLE_CLOUD_CPP_NS } // namespace cloud } // namespace google