├── rules_gapic └── cpp │ ├── BUILD.bazel │ └── cc_gapic.bzl ├── .gitattributes ├── .gitignore ├── generator ├── README.md ├── main.cc ├── testdata │ ├── BUILD.bazel │ └── google │ │ └── example │ │ └── library │ │ └── v1 │ │ ├── library_service_stub.gapic.h.baseline │ │ ├── library_service.gapic.h.baseline │ │ └── library_service.gapic.cc.baseline ├── standalone.h ├── internal │ ├── stub_cc_generator.h │ ├── client_cc_generator.h │ ├── stub_header_generator.h │ ├── gapic_utils_test.cc │ ├── client_header_generator.h │ ├── printer.h │ ├── gapic_utils.cc │ ├── gapic_utils.h │ ├── data_model.h │ ├── stub_header_generator.cc │ ├── client_cc_generator.cc │ └── client_header_generator.cc ├── gapic_generator.h ├── gapic_generator_test.cc ├── BUILD.bazel ├── gapic_generator.cc └── standalone.cc ├── .clang-format ├── gax ├── config.cmake.in ├── operations_client.cc ├── internal │ ├── gtest_prod.h │ └── test_clock.h ├── repositories.bzl ├── config-version.cmake.in ├── backoff_policy.cc ├── operations_stub.h ├── operations_stub.cc ├── operations_stub_test.cc ├── BUILD.bazel ├── retry_loop.h ├── call_context.cc ├── status.cc ├── status.h ├── call_context_test.cc ├── CMakeLists.txt ├── backoff_policy_test.cc ├── operations_client.h ├── operation.h ├── retry_loop_test.cc ├── pagination_test.cc ├── retry_policy.h ├── backoff_policy.h ├── status_or.h ├── status_test.cc └── retry_policy_test.cc ├── ci ├── kokoro │ ├── ubuntu │ │ ├── continuous.cfg │ │ ├── presubmit.cfg │ │ └── build.sh │ └── docker │ │ ├── e2e │ │ ├── spanner_e2e.cc │ │ ├── CMakeLists.txt │ │ └── Dockerfile │ │ └── run_e2e_test.sh ├── check-style.sh ├── install-bazel.sh └── check-include-guards.gawk ├── BUILD.bazel ├── CMakeLists.txt ├── CONTRIBUTING.md ├── cmake ├── GapicGeneratorCommon.cmake └── FindGMockWithTargets.cmake ├── WORKSPACE ├── docs ├── README.md ├── GENERATOR.md └── STATUS.md ├── CODE_OF_CONDUCT.md └── repositories.bzl /rules_gapic/cpp/BUILD.bazel: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.cc.baseline linguist-language=cpp 2 | *.h.baseline linguist-language=cpp 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Common build output directory names 2 | .build/ 3 | _build/ 4 | build-output/ 5 | 6 | # Common bazel output directories 7 | bazel-* 8 | 9 | # Common editor files 10 | *~ 11 | *.swp 12 | 13 | # Ignore IDEA / IntelliJ files 14 | .idea/ 15 | cmake-build-*/ 16 | 17 | # Tags 18 | GPATH 19 | GRTAGS 20 | GTAGS 21 | TAGS 22 | -------------------------------------------------------------------------------- /generator/README.md: -------------------------------------------------------------------------------- 1 | # API Client Generator for C++ 2 | 3 | A generator for protocol buffer described APIs for and in C++. 4 | 5 | This is a generator for API client libraries for APIs specified by protocol buffers, such as those inside Google. 6 | It takes a protocol buffer (with particular annotations) and uses it to generate a client library. 7 | 8 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Use the Google style in this project. 2 | BasedOnStyle: Google 3 | 4 | # Some folks prefer to write "int& foo" while others prefer "int &foo". The 5 | # Google Style Guide only asks for consistency within a project, we chose 6 | # "int& foo" for this project: 7 | DerivePointerAlignment: false 8 | PointerAlignment: Left 9 | 10 | IncludeCategories: 11 | - Regex: '^\"gax/' 12 | Priority: 1500 13 | - Regex: '^\"generator/' 14 | Priority: 1500 15 | - Regex: '^\"' 16 | Priority: 1000 17 | - Regex: '^' 24 | Priority: 5000 25 | -------------------------------------------------------------------------------- /gax/config.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | include(CMakeFindDependencyMacro) 16 | find_dependency(Threads) 17 | 18 | include("${CMAKE_CURRENT_LIST_DIR}/gax-targets.cmake") 19 | -------------------------------------------------------------------------------- /ci/kokoro/ubuntu/continuous.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | build_file: "gapic-generator-cpp/ci/kokoro/ubuntu/build.sh" 17 | timeout_mins: 120 18 | -------------------------------------------------------------------------------- /ci/kokoro/ubuntu/presubmit.cfg: -------------------------------------------------------------------------------- 1 | # Format: //devtools/kokoro/config/proto/build.proto 2 | # Copyright 2019 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | build_file: "gapic-generator-cpp/ci/kokoro/ubuntu/build.sh" 17 | timeout_mins: 120 18 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | package(default_visibility = ["//visibility:public"]) 16 | 17 | licenses(["notice"]) # Apache 2.0 18 | 19 | exports_files([ 20 | "LICENSE", 21 | ]) 22 | 23 | -------------------------------------------------------------------------------- /gax/operations_client.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/operations_client.h" 16 | 17 | namespace google { 18 | namespace gax { 19 | constexpr MethodInfo OperationsClient::get_operation_info; 20 | constexpr MethodInfo OperationsClient::delete_operation_info; 21 | constexpr MethodInfo OperationsClient::cancel_operation_info; 22 | } // namespace gax 23 | } // namespace google 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ~~~ 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ~~~ 16 | 17 | cmake_minimum_required(VERSION 3.5) 18 | 19 | project(gapic-generator CXX) 20 | 21 | # Configure the compiler options, we will be using C++11 features. 22 | set(CMAKE_CXX_STANDARD 11) 23 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 24 | 25 | list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 26 | 27 | include(FindGMockWithTargets) 28 | 29 | # Get the destination directories based on the GNU recommendations. 30 | include(GNUInstallDirs) 31 | 32 | add_subdirectory(gax) 33 | -------------------------------------------------------------------------------- /gax/internal/gtest_prod.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_INTERNAL_GTEST_PROD_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_INTERNAL_GTEST_PROD_H_ 17 | 18 | // Note: gtest-1.8.1 doesn't have a separate target for gtest_prod. 19 | // Rather than add an overlarge dependency on @gtest//:gtest, 20 | // just define the necessary macro ourselves. 21 | #define FRIEND_TEST(test_case_name, test_name) \ 22 | friend class test_case_name##_##test_name##_Test 23 | 24 | #endif // GAPIC_GENERATOR_CPP_GAX_INTERNAL_GTEST_PROD_H_ 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | 3 | We'd love to accept your patches and contributions to this project. There are 4 | just a few small guidelines you need to follow. 5 | 6 | ## Contributor License Agreement 7 | 8 | Contributions to this project must be accompanied by a Contributor License 9 | Agreement. You (or your employer) retain the copyright to your contribution; 10 | this simply gives us permission to use and redistribute your contributions as 11 | part of the project. Head over to to see 12 | your current agreements on file or to sign a new one. 13 | 14 | You generally only need to submit a CLA once, so if you've already submitted one 15 | (even if it was for a different project), you probably don't need to do it 16 | again. 17 | 18 | ## Code reviews 19 | 20 | All submissions, including submissions by project members, require review. We 21 | use GitHub pull requests for this purpose. Consult 22 | [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more 23 | information on using pull requests. 24 | 25 | ## Community Guidelines 26 | 27 | This project follows [Google's Open Source Community 28 | Guidelines](https://opensource.google.com/conduct/). 29 | -------------------------------------------------------------------------------- /ci/check-style.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2019 Google Inc. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | # This script assumes it is running the top-level gapic-generator-cpp directory. 20 | 21 | readonly BINDIR="$(dirname $0)" 22 | 23 | function check_style { 24 | find $1 -name '*.h' -print0 \ 25 | | xargs -0 awk -f ${BINDIR}/check-include-guards.gawk 26 | 27 | find $1 \( -name '*.cc' -o -name '*.h' \) -print0 \ 28 | | xargs -0 ${CLANG_FORMAT_BIN} -i 29 | } 30 | 31 | check_style gax 32 | check_style generator 33 | 34 | # Report any differences created by running clang-format. 35 | git diff --ignore-submodules=all --color --exit-code . 36 | -------------------------------------------------------------------------------- /cmake/GapicGeneratorCommon.cmake: -------------------------------------------------------------------------------- 1 | # ~~~ 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ~~~ 16 | 17 | function (gax_install_headers target destination) 18 | get_target_property(target_sources ${target} SOURCES) 19 | foreach (header ${target_sources}) 20 | if (NOT "${header}" MATCHES "\\.h$" AND NOT "${header}" MATCHES 21 | "\\.inc$") 22 | continue() 23 | endif () 24 | string(REPLACE "${CMAKE_CURRENT_BINARY_DIR}/" "" relative "${header}") 25 | get_filename_component(dir "${relative}" DIRECTORY) 26 | install(FILES "${header}" DESTINATION "${destination}/${dir}") 27 | endforeach () 28 | endfunction () 29 | -------------------------------------------------------------------------------- /generator/main.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | /** 20 | * Entry point for C++ GAPIC generator. 21 | * 22 | * If at least one command line argument is provided, the standalone mode is 23 | * assumed. Otherwise the generator runs as a plugin (it expects input to be 24 | * received via stdin and outputs to stdout). 25 | */ 26 | int main(int argc, char** argv) { 27 | google::api::codegen::GapicGenerator generator; 28 | if (argc > 1) { 29 | return google::api::codegen::StandaloneMain(argc, argv, &generator); 30 | } 31 | // PluginMain immediately fails if argc > 1 32 | return google::protobuf::compiler::PluginMain(argc, argv, &generator); 33 | } 34 | -------------------------------------------------------------------------------- /generator/testdata/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("//rules_gapic/cpp:cc_gapic.bzl", "cc_gapic_srcjar", "cc_gapic_library") 2 | load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") 3 | load("@com_google_api_codegen//rules_gapic:gapic.bzl", "proto_library_with_info") 4 | 5 | proto_library( 6 | name = "library_proto", 7 | srcs = ["library.proto"], 8 | visibility = ["//visibility:public"], 9 | deps = ["@com_google_googleapis//google/api:client_proto"], 10 | ) 11 | 12 | proto_library_with_info( 13 | name = "library_proto_with_info", 14 | deps = [":library_proto"], 15 | ) 16 | 17 | cc_proto_library( 18 | name = "library_cc_proto", 19 | visibility = ["//visibility:public"], 20 | deps = [":library_proto"], 21 | ) 22 | 23 | cc_grpc_library( 24 | name = "library_cc_grpc", 25 | srcs = [":library_proto"], 26 | grpc_only = True, 27 | deps = [":library_cc_proto"], 28 | ) 29 | 30 | cc_gapic_library( 31 | name = "library_cc_gapic", 32 | src = ":library_proto_with_info", 33 | package = "google.example.library.v1", 34 | visibility = ["//visibility:public"], 35 | deps = [ 36 | ":library_cc_grpc", 37 | ":library_cc_proto", 38 | ], 39 | ) 40 | 41 | filegroup( 42 | name = "library_service_baseline", 43 | srcs = glob(["google/example/library/v1/**"]), 44 | visibility = ["//visibility:public"], 45 | ) 46 | -------------------------------------------------------------------------------- /gax/repositories.bzl: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 16 | 17 | def com_google_gapic_generator_cpp_gax_repositories(): 18 | _maybe( 19 | http_archive, 20 | name = "com_github_grpc_grpc", 21 | strip_prefix = "grpc-1.21.0", 22 | urls = ["https://github.com/grpc/grpc/archive/v1.21.0.tar.gz"], 23 | ) 24 | 25 | _maybe( 26 | http_archive, 27 | name = "com_google_googleapis", 28 | strip_prefix = "googleapis-c69355435cf6ae824a21f2bba31c69697733d3d2", 29 | urls = ["https://github.com/googleapis/googleapis/archive/c69355435cf6ae824a21f2bba31c69697733d3d2.tar.gz"], 30 | ) 31 | 32 | def _maybe(repo_rule, name, **kwargs): 33 | if name not in native.existing_rules(): 34 | repo_rule(name = name, **kwargs) 35 | -------------------------------------------------------------------------------- /generator/standalone.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_STANDALONE_H_ 16 | #define GAPIC_GENERATOR_CPP_GENERATOR_STANDALONE_H_ 17 | 18 | #include 19 | #include 20 | 21 | namespace google { 22 | namespace api { 23 | namespace codegen { 24 | 25 | int StandaloneMain(int argc, const char* const argv[], 26 | google::protobuf::compiler::CodeGenerator* generator); 27 | 28 | int StandaloneMain(const std::vector& descriptors, 29 | const std::string& package, const std::string& output, 30 | google::protobuf::compiler::CodeGenerator* generator); 31 | 32 | } // namespace codegen 33 | } // namespace api 34 | } // namespace google 35 | 36 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_STANDALONE_H_ 37 | -------------------------------------------------------------------------------- /gax/config-version.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | set(PACKAGE_VERSION @GAX_VERSION@) 16 | 17 | # This package has not reached 1.0, there are no compatibility guarantees 18 | # before then. 19 | if (@GAX_VERSION_MAJOR@ EQUAL 0) 20 | if ("${PACKAGE_FIND_VERSION}" STREQUAL "") 21 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 22 | elseif ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") 23 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 24 | set(PACKAGE_VERSION_EXACT TRUE) 25 | else () 26 | set(PACKAGE_VERSION_UNSUITABLE TRUE) 27 | endif () 28 | elseif("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") 29 | set(PACKAGE_VERSION_COMPATIBLE FALSE) 30 | else() 31 | set(PACKAGE_VERSION_COMPATIBLE TRUE) 32 | if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") 33 | set(PACKAGE_VERSION_EXACT TRUE) 34 | endif() 35 | endif() 36 | -------------------------------------------------------------------------------- /ci/install-bazel.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | if [[ $# -lt 1 ]]; then 20 | echo "Usage: $0 " 21 | fi 22 | 23 | if [[ "$1" = "linux" ]]; then 24 | readonly PLATFORM="linux-x86_64" 25 | elif [[ "$1" = "macos" ]] || [[ "$1" = "osx" ]]; then 26 | readonly PLATFORM="darwin-x86_64" 27 | fi 28 | 29 | readonly BAZEL_VERSION=0.23.2 30 | readonly GITHUB_DL="https://github.com/bazelbuild/bazel/releases/download" 31 | readonly SCRIPT_NAME="bazel-${BAZEL_VERSION}-installer-${PLATFORM}.sh" 32 | wget -q "${GITHUB_DL}/${BAZEL_VERSION}/${SCRIPT_NAME}" 33 | wget -q "${GITHUB_DL}/${BAZEL_VERSION}/${SCRIPT_NAME}.sha256" 34 | 35 | # We want to protect against accidents, not malice, so downloading the checksum 36 | # and the file from the same source is Okay. 37 | sha256sum --check "${SCRIPT_NAME}.sha256" 38 | 39 | chmod +x "${SCRIPT_NAME}" 40 | "./${SCRIPT_NAME}" --user 41 | -------------------------------------------------------------------------------- /generator/internal/stub_cc_generator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_CC_GENERATOR_H_ 16 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_CC_GENERATOR_H_ 17 | 18 | #include "generator/internal/printer.h" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace pb = google::protobuf; 24 | 25 | namespace google { 26 | namespace api { 27 | namespace codegen { 28 | namespace internal { 29 | 30 | bool GenerateClientStubCC(pb::ServiceDescriptor const* service, 31 | std::map const& vars, 32 | Printer& p, std::string* /* error */); 33 | 34 | } // namespace internal 35 | } // namespace codegen 36 | } // namespace api 37 | } // namespace google 38 | 39 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_CC_GENERATOR_H_ 40 | -------------------------------------------------------------------------------- /generator/internal/client_cc_generator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_CC_GENERATOR_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_CC_GENERATOR_H_ 16 | 17 | #include "generator/internal/printer.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace pb = google::protobuf; 24 | 25 | namespace google { 26 | namespace api { 27 | namespace codegen { 28 | namespace internal { 29 | 30 | bool GenerateClientCC(pb::ServiceDescriptor const* service, 31 | std::map const& vars, 32 | Printer& p, std::string* /* error */); 33 | 34 | } // namespace internal 35 | } // namespace codegen 36 | } // namespace api 37 | } // namespace google 38 | 39 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_CC_GENERATOR_H_ 40 | -------------------------------------------------------------------------------- /generator/internal/stub_header_generator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_HEADER_GENERATOR_H_ 16 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_HEADER_GENERATOR_H_ 17 | 18 | #include "generator/internal/printer.h" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace pb = google::protobuf; 24 | 25 | namespace google { 26 | namespace api { 27 | namespace codegen { 28 | namespace internal { 29 | 30 | bool GenerateClientStubHeader(pb::ServiceDescriptor const* service, 31 | std::map const& vars, 32 | Printer& p, std::string* /* error */); 33 | 34 | } // namespace internal 35 | } // namespace codegen 36 | } // namespace api 37 | } // namespace google 38 | 39 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_STUB_HEADER_GENERATOR_H_ 40 | -------------------------------------------------------------------------------- /generator/gapic_generator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_GAPIC_GENERATOR_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_GAPIC_GENERATOR_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | namespace google { 22 | namespace api { 23 | namespace codegen { 24 | 25 | /** 26 | * Code generator that outputs a C++ GAPIC client from proto descriptors. 27 | */ 28 | class GapicGenerator : public google::protobuf::compiler::CodeGenerator { 29 | public: 30 | bool Generate(google::protobuf::FileDescriptor const* file, 31 | std::string const& parameter, 32 | google::protobuf::compiler::GeneratorContext* generator_context, 33 | std::string* error) const override; 34 | }; 35 | 36 | } // namespace codegen 37 | } // namespace api 38 | } // namespace google 39 | 40 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_GAPIC_GENERATOR_H_ 41 | -------------------------------------------------------------------------------- /gax/backoff_policy.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/backoff_policy.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace google { 22 | namespace gax { 23 | 24 | std::chrono::microseconds ExponentialBackoffPolicy::OnCompletion() { 25 | if (!generator_) { 26 | generator_ = std::unique_ptr( 27 | new std::mt19937_64(std::random_device()())); 28 | } 29 | 30 | std::uniform_int_distribution dist( 31 | current_delay_range_.count() / 2, current_delay_range_.count()); 32 | auto delay = std::chrono::microseconds(dist(*generator_)); 33 | 34 | current_delay_range_ = std::min(maximum_delay_, current_delay_range_ * 2); 35 | return delay; 36 | } 37 | 38 | std::unique_ptr ExponentialBackoffPolicy::clone() const { 39 | return std::unique_ptr(new ExponentialBackoffPolicy(*this)); 40 | } 41 | 42 | } // namespace gax 43 | } // namespace google 44 | -------------------------------------------------------------------------------- /ci/kokoro/docker/e2e/spanner_e2e.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include "google/spanner/admin/instance/v1/instance_admin.gapic.h" 17 | 18 | using ::google::spanner::admin::instance::v1::ListInstanceConfigsRequest; 19 | 20 | int main() { 21 | InstanceAdmin client(CreateInstanceAdminStub()); 22 | ListInstanceConfigsRequest request; 23 | if (const char* project_id = std::getenv("GOOGLE_CLOUD_PROJECT")) { 24 | std::string proj = "projects/"; 25 | request.set_parent(proj + project_id); 26 | } else { 27 | throw std::runtime_error("Please set GOOGLE_CLOUD_PROJECT env"); 28 | } 29 | auto result = client.ListInstanceConfigs(request); 30 | if (!result) { 31 | throw std::runtime_error(result.status().message()); 32 | } 33 | auto& configs = *result->mutable_instance_configs(); 34 | int count = 0; 35 | for (auto const& config : configs) { 36 | ++count; 37 | std::cout << "Instance config [" << count << "]:\n" 38 | << config.DebugString() << "\n"; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /generator/internal/gapic_utils_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "generator/internal/gapic_utils.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace google { 22 | namespace api { 23 | namespace codegen { 24 | namespace internal { 25 | namespace { 26 | 27 | TEST(GapicUtils, CamelCaseToSnakeCase) { 28 | std::vector> test_cases{ 29 | {"abc", "abc"}, {"Abc", "abc"}, 30 | {"AbcDef", "abc_def"}, {"abcDef", "abc_def"}, 31 | {"ABc", "a_bc"}, {"ABcDEf", "a_bc_d_ef"}, 32 | {"Abc1De", "abc1_de"}, {"Abc1de", "abc1de"}, 33 | {"A1B", "a1_b"}, {"SNMPParse", "snmp_parse"}}; 34 | 35 | for (auto test_case : test_cases) { 36 | std::string actual = CamelCaseToSnakeCase(test_case.first); 37 | std::string expected = test_case.second; 38 | EXPECT_EQ(expected, actual); 39 | } 40 | } 41 | 42 | } // namespace 43 | } // namespace internal 44 | } // namespace codegen 45 | } // namespace api 46 | } // namespace google 47 | -------------------------------------------------------------------------------- /gax/operations_stub.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_OPERATIONS_STUB_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_OPERATIONS_STUB_H_ 17 | 18 | #include "google/longrunning/operations.pb.h" 19 | #include "gax/call_context.h" 20 | #include "gax/status.h" 21 | 22 | namespace google { 23 | namespace gax { 24 | 25 | class OperationsStub { 26 | public: 27 | virtual ~OperationsStub() = 0; 28 | 29 | virtual gax::Status GetOperation( 30 | gax::CallContext& context, 31 | google::longrunning::GetOperationRequest const& request, 32 | google::longrunning::Operation* response); 33 | 34 | virtual gax::Status DeleteOperation( 35 | gax::CallContext& context, 36 | google::longrunning::DeleteOperationRequest const& request, 37 | google::protobuf::Empty* response); 38 | 39 | virtual gax::Status CancelOperation( 40 | gax::CallContext& context, 41 | google::longrunning::CancelOperationRequest const& request, 42 | google::protobuf::Empty* response); 43 | }; 44 | 45 | } // namespace gax 46 | } // namespace google 47 | 48 | #endif // GAPIC_GENERATOR_CPP_GAX_OPERATIONS_STUB_H_ 49 | -------------------------------------------------------------------------------- /generator/internal/client_header_generator.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_HEADER_GENERATOR_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_HEADER_GENERATOR_H_ 16 | 17 | #include "generator/internal/printer.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace pb = google::protobuf; 24 | 25 | namespace google { 26 | namespace api { 27 | namespace codegen { 28 | namespace internal { 29 | 30 | std::vector BuildClientHeaderIncludes( 31 | pb::ServiceDescriptor const* /* service */); 32 | 33 | std::vector BuildClientHeaderNamespaces( 34 | pb::ServiceDescriptor const* /* service */); 35 | 36 | bool GenerateClientHeader(pb::ServiceDescriptor const* service, 37 | std::map const& vars, 38 | Printer& p, std::string* /* error */); 39 | 40 | } // namespace internal 41 | } // namespace codegen 42 | } // namespace api 43 | } // namespace google 44 | 45 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_CLIENT_HEADER_GENERATOR_H_ 46 | -------------------------------------------------------------------------------- /gax/operations_stub.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/operations_stub.h" 16 | #include "google/longrunning/operations.pb.h" 17 | #include "gax/call_context.h" 18 | #include "gax/status.h" 19 | 20 | namespace google { 21 | namespace gax { 22 | 23 | OperationsStub::~OperationsStub() {} 24 | 25 | gax::Status OperationsStub::GetOperation( 26 | gax::CallContext&, google::longrunning::GetOperationRequest const&, 27 | google::longrunning::Operation*) { 28 | return gax::Status{gax::StatusCode::kUnimplemented, 29 | "GetOperation not implemented"}; 30 | } 31 | 32 | gax::Status OperationsStub::DeleteOperation( 33 | gax::CallContext&, google::longrunning::DeleteOperationRequest const&, 34 | google::protobuf::Empty*) { 35 | return gax::Status{gax::StatusCode::kUnimplemented, 36 | "DeleteOperation not implemented"}; 37 | } 38 | 39 | gax::Status OperationsStub::CancelOperation( 40 | gax::CallContext&, google::longrunning::CancelOperationRequest const&, 41 | google::protobuf::Empty*) { 42 | return gax::Status{gax::StatusCode::kUnimplemented, 43 | "CancelOperation not implemented"}; 44 | } 45 | 46 | } // namespace gax 47 | } // namespace google 48 | -------------------------------------------------------------------------------- /gax/internal/test_clock.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_INTERNAL_TEST_CLOCK_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_INTERNAL_TEST_CLOCK_H_ 17 | 18 | #include 19 | 20 | namespace google { 21 | namespace gax { 22 | namespace internal { 23 | 24 | /* 25 | * A clock with an external user-mutable now point. 26 | * 27 | * Unit tests should be deterministic, but some features and associated tests 28 | * rely on clocks. The solution is to use a TestClock as an injected parameter, 29 | * with an automatic time_point passed into the constructor. 30 | * 31 | * E.g.: 32 | * 33 | * std::chrono::system_clock::time_point n; 34 | * ClockUser cu(TestClock(n)); 35 | * n += std::chrono::milliseconds(20); 36 | * cu.CheckElapsedTime(); 37 | */ 38 | class TestClock { 39 | public: 40 | TestClock(std::chrono::system_clock::time_point& now_point) 41 | : now_point_(now_point) {} 42 | std::chrono::system_clock::time_point now() const { return now_point_; } 43 | 44 | private: 45 | std::chrono::system_clock::time_point& now_point_; 46 | }; 47 | 48 | } // namespace internal 49 | } // namespace gax 50 | } // namespace google 51 | 52 | #endif // GAPIC_GENERATOR_CPP_GAX_INTERNAL_TEST_CLOCK_H_ 53 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | workspace(name = "com_google_gapic_generator_cpp") 16 | 17 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 18 | load( 19 | "//gax:repositories.bzl", 20 | "com_google_gapic_generator_cpp_gax_repositories", 21 | ) 22 | load( 23 | "//:repositories.bzl", 24 | "com_google_gapic_generator_cpp_repositories", 25 | ) 26 | 27 | com_google_gapic_generator_cpp_gax_repositories() 28 | 29 | load( 30 | "@com_google_googleapis//:repository_rules.bzl", 31 | "switched_rules_by_language", 32 | ) 33 | 34 | switched_rules_by_language( 35 | name = "com_google_googleapis_imports", 36 | cc = True, 37 | gapic = True, 38 | grpc = True, 39 | ) 40 | 41 | com_google_gapic_generator_cpp_repositories() 42 | 43 | load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") 44 | 45 | grpc_deps() 46 | 47 | # 48 | # gapic-generator (contains common definitions for gapic rules, see gapic.bzl 49 | # file in com_google_api_codegen) 50 | # 51 | http_archive( 52 | name = "com_google_api_codegen", 53 | strip_prefix = "gapic-generator-025ebdbb3d14609be938900a538418858b0ecfb7", 54 | urls = ["https://github.com/googleapis/gapic-generator/archive/025ebdbb3d14609be938900a538418858b0ecfb7.zip"], 55 | ) 56 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # API Client Generator for C++ 2 | 3 | ![release level](https://img.shields.io/badge/release%20level-%20alpha-red.svg) 4 | 5 | A generator and runtime for protocol buffer described APIs for and in C++. 6 | 7 | This repository contains two subprojects: 8 | - An API client library generator, implemented as a protoc plugin 9 | - A runtime library supporting the generated code (known as gax) 10 | 11 | The generator takes APIs specified by protocol buffers, such as those inside Google, 12 | and generates a client library. 13 | 14 | **Note:** this project has been shelved. See [`STATUS.md`](STATUS.md) for the current status of various features and designs. 15 | 16 | ## Versioning 17 | 18 | This library follows [Semantic Versioning](http://semver.org/). Please note it 19 | is currently under active development. Any release versioned 0.x.y is subject to 20 | backwards-incompatible changes at any time. 21 | 22 | **GA**: Libraries defined at a GA quality level are expected to be stable and 23 | all updates in the libraries are guaranteed to be backwards-compatible. Any 24 | backwards-incompatible changes will lead to the major version increment 25 | (1.x.y -> 2.0.0). 26 | 27 | **Beta**: Libraries defined at a Beta quality level are expected to be mostly 28 | stable and we're working towards their release candidate. We will address issues 29 | and requests with a higher priority. 30 | 31 | **Alpha**: Libraries defined at an Alpha quality level are still a 32 | work-in-progress and are more likely to get backwards-incompatible updates. 33 | Additionally, it's possible for Alpha libraries to get deprecated and deleted 34 | before ever being promoted to Beta or GA. 35 | 36 | ## Contributing changes 37 | 38 | See [`CONTRIBUTING.md`](CONTRIBUTING.md) for details on how to contribute to 39 | this project, including how to build and test your changes as well as how to 40 | properly format your code. 41 | 42 | ## Licensing 43 | 44 | Apache 2.0; see [`LICENSE`](LICENSE) for details. 45 | 46 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.2.0, available at https://www.contributor-covenant.org/version/1/2/0/code-of-conduct.html 23 | 24 | -------------------------------------------------------------------------------- /generator/internal/printer.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_PRINTER_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_PRINTER_H_ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace pb = google::protobuf; 23 | 24 | namespace google { 25 | namespace api { 26 | namespace codegen { 27 | namespace internal { 28 | 29 | /** 30 | * Wrapper around a google::protobuf::io::ZeroCopyOutputStream and a 31 | * google::protobuf::io::Printer object so that they can be used for 32 | * code generation. 33 | */ 34 | class Printer { 35 | public: 36 | Printer(pb::compiler::GeneratorContext* generator_context, 37 | std::string const& file_name) 38 | : output_(generator_context->Open(file_name)), 39 | printer_(output_.get(), '$', NULL) {} 40 | 41 | pb::io::Printer* operator->() & { return &printer_; } 42 | pb::io::Printer const* operator->() const& { return &printer_; } 43 | 44 | Printer(Printer const&) = delete; 45 | Printer& operator=(Printer const&) = delete; 46 | 47 | private: 48 | std::unique_ptr output_; 49 | pb::io::Printer printer_; 50 | }; 51 | 52 | } // namespace internal 53 | } // namespace codegen 54 | } // namespace api 55 | } // namespace google 56 | 57 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_PRINTER_H_ 58 | -------------------------------------------------------------------------------- /generator/testdata/google/example/library/v1/library_service_stub.gapic.h.baseline: -------------------------------------------------------------------------------- 1 | // Generated by the GAPIC C++ plugin. 2 | // If you make any local changes, they will be lost. 3 | // source: generator/testdata/library.proto 4 | #ifndef LibraryService_Stub_H_ 5 | #define LibraryService_Stub_H_ 6 | 7 | #include "generator/testdata/library.pb.h" 8 | #include "gax/call_context.h" 9 | #include "gax/status.h" 10 | #include "grpcpp/security/credentials.h" 11 | #include 12 | 13 | class LibraryServiceStub { 14 | public: 15 | virtual google::gax::Status CreateBook(google::gax::CallContext& context, 16 | ::google::example::library::v1::CreateBookRequest const& request, 17 | ::google::example::library::v1::Book* response); 18 | 19 | virtual google::gax::Status GetBook(google::gax::CallContext& context, 20 | ::google::example::library::v1::GetBookRequest const& request, 21 | ::google::example::library::v1::Book* response); 22 | 23 | virtual google::gax::Status ListBooks(google::gax::CallContext& context, 24 | ::google::example::library::v1::ListBooksRequest const& request, 25 | ::google::example::library::v1::ListBooksResponse* response); 26 | 27 | virtual google::gax::Status DeleteBook(google::gax::CallContext& context, 28 | ::google::example::library::v1::DeleteBookRequest const& request, 29 | ::google::example::library::v1::Empty* response); 30 | 31 | virtual google::gax::Status UpdateBook(google::gax::CallContext& context, 32 | ::google::example::library::v1::UpdateBookRequest const& request, 33 | ::google::example::library::v1::Book* response); 34 | 35 | virtual google::gax::Status GetBigBook(google::gax::CallContext& context, 36 | ::google::example::library::v1::GetBookRequest const& request, 37 | ::google::example::library::v1::Book* response); 38 | 39 | virtual ~LibraryServiceStub() = 0; 40 | 41 | }; // LibraryServiceStub 42 | 43 | std::unique_ptr 44 | CreateLibraryServiceStub(); 45 | 46 | std::unique_ptr 47 | CreateLibraryServiceStub(std::shared_ptr creds); 48 | 49 | #endif // LibraryService_Stub_H_ 50 | -------------------------------------------------------------------------------- /gax/operations_stub_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/operations_stub.h" 16 | #include "google/longrunning/operations.pb.h" 17 | #include "gax/call_context.h" 18 | #include "gax/operations_client.h" 19 | #include "gax/status.h" 20 | #include 21 | 22 | namespace { 23 | 24 | using namespace ::google; 25 | 26 | class DummyOperationsStub : public gax::OperationsStub { 27 | public: 28 | ~DummyOperationsStub() = default; 29 | }; 30 | 31 | TEST(OperationsStub, Basic) { 32 | DummyOperationsStub stub{}; 33 | 34 | longrunning::GetOperationRequest getOpReq; 35 | gax::CallContext getCtx(gax::OperationsClient::get_operation_info); 36 | EXPECT_EQ(stub.GetOperation(getCtx, getOpReq, nullptr), 37 | gax::Status(gax::StatusCode::kUnimplemented, 38 | "GetOperation not implemented")); 39 | 40 | longrunning::DeleteOperationRequest delOpReq; 41 | gax::CallContext delCtx(gax::OperationsClient::delete_operation_info); 42 | EXPECT_EQ(stub.DeleteOperation(delCtx, delOpReq, nullptr), 43 | gax::Status(gax::StatusCode::kUnimplemented, 44 | "DeleteOperation not implemented")); 45 | 46 | longrunning::CancelOperationRequest canOpReq; 47 | gax::CallContext cancelCtx(gax::OperationsClient::cancel_operation_info); 48 | EXPECT_EQ(stub.CancelOperation(cancelCtx, canOpReq, nullptr), 49 | gax::Status(gax::StatusCode::kUnimplemented, 50 | "CancelOperation not implemented")); 51 | } 52 | 53 | } // namespace 54 | -------------------------------------------------------------------------------- /ci/kokoro/docker/e2e/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ~~~ 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ~~~ 16 | 17 | cmake_minimum_required(VERSION 3.5) 18 | 19 | project(gapic-generator-e2e CXX) 20 | 21 | # Configure the compiler options, we will be using C++11 features. 22 | set(CMAKE_CXX_STANDARD 11) 23 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 24 | 25 | find_package(googleapis REQUIRED) 26 | find_package(gRPC REQUIRED) 27 | find_package(gax REQUIRED) 28 | 29 | add_library(google-cloud-cpp-spanner-gapic 30 | google/spanner/admin/instance/v1/instance_admin.gapic.cc 31 | google/spanner/admin/instance/v1/instance_admin.gapic.h 32 | google/spanner/admin/instance/v1/spanner_instance_admin.grpc.pb.cc 33 | google/spanner/admin/instance/v1/instance_admin_stub.gapic.h 34 | google/spanner/admin/instance/v1/spanner_instance_admin.grpc.pb.h 35 | google/spanner/admin/instance/v1/spanner_instance_admin.pb.h 36 | google/spanner/admin/instance/v1/spanner_instance_admin.pb.cc 37 | google/spanner/admin/instance/v1/instance_admin_stub.gapic.cc 38 | ) 39 | 40 | target_include_directories( 41 | google-cloud-cpp-spanner-gapic 42 | PUBLIC $) 43 | 44 | target_link_libraries(google-cloud-cpp-spanner-gapic PUBLIC 45 | gax 46 | googleapis-c++::api_annotations_protos 47 | googleapis-c++::longrunning_operations_protos 48 | googleapis-c++::rpc_status_protos 49 | googleapis-c++::iam_v1_iam_policy_protos 50 | ) 51 | 52 | add_executable(gapic-generator-e2e 53 | spanner_e2e.cc 54 | ) 55 | 56 | target_link_libraries(gapic-generator-e2e PUBLIC 57 | google-cloud-cpp-spanner-gapic) 58 | -------------------------------------------------------------------------------- /gax/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | package(default_visibility = ["//visibility:public"]) 16 | 17 | licenses(["notice"]) # Apache 2.0 18 | 19 | cc_library( 20 | name = "gax", 21 | srcs = [ 22 | "backoff_policy.cc", 23 | "call_context.cc", 24 | "internal/gtest_prod.h", 25 | "internal/invoke_result.h", 26 | "operations_client.cc", 27 | "operations_stub.cc", 28 | "status.cc", 29 | ], 30 | hdrs = [ 31 | "backoff_policy.h", 32 | "call_context.h", 33 | "retry_loop.h", 34 | "retry_policy.h", 35 | "operation.h", 36 | "operations_client.h", 37 | "operations_stub.h", 38 | "pagination.h", 39 | "status.h", 40 | "status_or.h", 41 | ], 42 | deps = [ 43 | "@com_github_grpc_grpc//:grpc++", 44 | "@com_google_googleapis//google/longrunning:longrunning_cc_proto", 45 | ], 46 | ) 47 | 48 | gax_unit_tests = [ 49 | "backoff_policy_test.cc", 50 | "call_context_test.cc", 51 | "operation_test.cc", 52 | "operations_stub_test.cc", 53 | "pagination_test.cc", 54 | "retry_loop_test.cc", 55 | "retry_policy_test.cc", 56 | "status_test.cc", 57 | "status_or_test.cc", 58 | ] 59 | 60 | cc_library( 61 | name = "gax_testlib", 62 | srcs = [], 63 | hdrs = ["internal/test_clock.h"], 64 | deps = [], 65 | ) 66 | 67 | [cc_test( 68 | name = "gax_" + test.replace(".cc", ""), 69 | size = "small", 70 | srcs = [test], 71 | deps = [ 72 | "//gax", 73 | ":gax_testlib", 74 | "@gtest//:gtest_main", 75 | ], 76 | ) for test in gax_unit_tests] 77 | -------------------------------------------------------------------------------- /gax/retry_loop.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_RETRY_LOOP_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_RETRY_LOOP_H_ 17 | 18 | #include "gax/backoff_policy.h" 19 | #include "gax/call_context.h" 20 | #include "gax/internal/invoke_result.h" 21 | #include "gax/retry_policy.h" 22 | #include "gax/status.h" 23 | #include 24 | #include 25 | 26 | namespace google { 27 | namespace gax { 28 | 29 | template ::value, 33 | int>::type = 0> 34 | gax::Status MakeRetryCall(gax::CallContext& context, RequestT const& request, 35 | ResponseT* response, FunctorT&& next_stub, 36 | std::unique_ptr retry_policy, 37 | std::unique_ptr backoff_policy) { 38 | while (true) { 39 | // The next layer stub may add metadata, so create a 40 | // fresh call context each time through the loop. 41 | gax::CallContext context_copy(context); 42 | context_copy.SetDeadline(retry_policy->OperationDeadline()); 43 | gax::Status status = next_stub(context_copy, request, response); 44 | if (status.IsOk() || !retry_policy->OnFailure(status)) { 45 | return status; 46 | } 47 | 48 | std::this_thread::sleep_for(backoff_policy->OnCompletion()); 49 | } 50 | } 51 | 52 | } // namespace gax 53 | } // namespace google 54 | 55 | #endif // GAPIC_GENERATOR_CPP_GAX_RETRY_LOOP_H_ 56 | -------------------------------------------------------------------------------- /gax/call_context.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/call_context.h" 16 | #include 17 | 18 | namespace google { 19 | namespace gax { 20 | 21 | void CallContext::SetDeadline(std::chrono::system_clock::time_point deadline) { 22 | deadline_ = std::move(deadline); 23 | } 24 | 25 | void CallContext::AddGrpcContextPolicy(GrpcContextPolicyFunc f) { 26 | context_policies_.emplace_back(std::move(f)); 27 | } 28 | 29 | void CallContext::PrepareGrpcContext(grpc::ClientContext* context) { 30 | context->set_deadline(deadline_); 31 | 32 | for (auto const& m : metadata_) { 33 | context->AddMetadata(m.first, m.second); 34 | } 35 | 36 | for (auto const& f : context_policies_) { 37 | f(context); 38 | } 39 | } 40 | 41 | void CallContext::AddMetadata(std::string key, std::string val) { 42 | metadata_.emplace(std::move(key), std::move(val)); 43 | } 44 | 45 | std::multimap const& CallContext::Metadata() 46 | const { 47 | return metadata_; 48 | } 49 | 50 | MethodInfo CallContext::Info() const { return method_info_; } 51 | 52 | std::unique_ptr CallContext::RetryPolicy() const { 53 | return retry_policy_ ? retry_policy_->clone() : nullptr; 54 | } 55 | 56 | std::unique_ptr CallContext::BackoffPolicy() const { 57 | return backoff_policy_ ? backoff_policy_->clone() : nullptr; 58 | } 59 | 60 | void CallContext::SetRetryPolicy(gax::RetryPolicy const& retry_policy) { 61 | retry_policy_ = retry_policy.clone(); 62 | } 63 | 64 | void CallContext::SetBackoffPolicy(gax::BackoffPolicy const& backoff_policy) { 65 | backoff_policy_ = backoff_policy.clone(); 66 | } 67 | 68 | std::chrono::system_clock::time_point CallContext::Deadline() const { 69 | return deadline_; 70 | } 71 | 72 | } // namespace gax 73 | } // namespace google 74 | -------------------------------------------------------------------------------- /generator/internal/gapic_utils.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "generator/internal/gapic_utils.h" 16 | #include 17 | 18 | namespace google { 19 | namespace api { 20 | namespace codegen { 21 | namespace internal { 22 | 23 | std::string LocalInclude(std::string header) { 24 | return absl::StrCat("\"", header, "\""); 25 | } 26 | 27 | std::string SystemInclude(std::string header) { 28 | return absl::StrCat("<", header, ">"); 29 | } 30 | 31 | bool NoStreamingPredicate(pb::MethodDescriptor const* m) { 32 | return !m->client_streaming() && !m->server_streaming(); 33 | } 34 | 35 | std::string CamelCaseToSnakeCase(std::string const& input) { 36 | std::string output; 37 | for (auto i = 0u; i < input.size(); ++i) { 38 | if (i + 2 < input.size()) { 39 | if (std::isupper(input[i + 1]) && std::islower(input[i + 2])) { 40 | absl::StrAppend(&output, std::string(1, std::tolower(input[i])), "_"); 41 | continue; 42 | } 43 | } 44 | if (i + 1 < input.size()) { 45 | if ((std::islower(input[i]) || std::isdigit(input[i])) && 46 | std::isupper(input[i + 1])) { 47 | absl::StrAppend(&output, std::string(1, std::tolower(input[i])), "_"); 48 | continue; 49 | } 50 | } 51 | absl::StrAppend(&output, std::string(1, std::tolower(input[i]))); 52 | } 53 | return output; 54 | } 55 | 56 | std::string ServiceNameToFilePath(std::string const& service_name) { 57 | std::vector components = absl::StrSplit(service_name, '.'); 58 | std::transform(components.begin(), components.end(), components.begin(), 59 | CamelCaseToSnakeCase); 60 | return absl::StrJoin(components, "/"); 61 | } 62 | 63 | std::string ProtoNameToCppName(std::string const& proto_name) { 64 | return "::" + absl::StrReplaceAll(proto_name, {{".", "::"}}); 65 | } 66 | 67 | } // namespace internal 68 | } // namespace codegen 69 | } // namespace api 70 | } // namespace google 71 | -------------------------------------------------------------------------------- /repositories.bzl: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 16 | 17 | def com_google_gapic_generator_cpp_repositories(): 18 | _maybe( 19 | http_archive, 20 | name = "absl", 21 | strip_prefix = "abseil-cpp-20181200", 22 | urls = ["https://github.com/abseil/abseil-cpp/archive/20181200.tar.gz"], 23 | ) 24 | 25 | _maybe( 26 | http_archive, 27 | name = "com_google_protobuf", 28 | strip_prefix = "protobuf-3.7.1", 29 | urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.7.1.tar.gz"], 30 | ) 31 | 32 | _maybe( 33 | http_archive, 34 | name = "bazel_skylib", 35 | strip_prefix = "bazel-skylib-2169ae1c374aab4a09aa90e65efe1a3aad4e279b", 36 | urls = ["https://github.com/bazelbuild/bazel-skylib/archive/2169ae1c374aab4a09aa90e65efe1a3aad4e279b.tar.gz"], 37 | ) 38 | 39 | _maybe( 40 | http_archive, 41 | name = "net_zlib", 42 | build_file = "@com_google_protobuf//:third_party/zlib.BUILD", 43 | strip_prefix = "zlib-1.2.11", 44 | urls = ["https://zlib.net/zlib-1.2.11.tar.gz"], 45 | ) 46 | 47 | _maybe( 48 | native.bind, 49 | name = "zlib", 50 | actual = "@net_zlib//:zlib", 51 | ) 52 | 53 | _maybe( 54 | http_archive, 55 | name = "com_google_googleapis", 56 | strip_prefix = "googleapis-c69355435cf6ae824a21f2bba31c69697733d3d2", 57 | urls = ["https://github.com/googleapis/googleapis/archive/c69355435cf6ae824a21f2bba31c69697733d3d2.tar.gz"], 58 | ) 59 | 60 | _maybe( 61 | http_archive, 62 | name = "gtest", 63 | strip_prefix = "googletest-release-1.8.1", 64 | urls = ["https://github.com/google/googletest/archive/release-1.8.1.tar.gz"], 65 | ) 66 | 67 | def _maybe(repo_rule, name, **kwargs): 68 | if name not in native.existing_rules(): 69 | repo_rule(name = name, **kwargs) 70 | -------------------------------------------------------------------------------- /generator/internal/gapic_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_GAPIC_UTILS_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_GAPIC_UTILS_H_ 16 | 17 | #include "absl/strings/str_cat.h" 18 | #include "absl/strings/str_join.h" 19 | #include "absl/strings/str_replace.h" 20 | #include "absl/strings/str_split.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace google { 27 | namespace api { 28 | namespace codegen { 29 | namespace internal { 30 | 31 | namespace pb = google::protobuf; 32 | 33 | bool NoStreamingPredicate(pb::MethodDescriptor const* m); 34 | 35 | // Convenience functions for wrapping include headers with the correct 36 | // delimiting characters (either <> or "") 37 | std::string LocalInclude(std::string header); 38 | std::string SystemInclude(std::string header); 39 | 40 | /** 41 | * Convert a CamelCase string to snake_case. 42 | */ 43 | std::string CamelCaseToSnakeCase(std::string const& input); 44 | 45 | /** 46 | * Convert a service name to a file path. 47 | * 48 | * service_name should consist of CamelCase pieces and "." separators. 49 | * Each component of service_name will become part of the path, except 50 | * the last component, which will become the file name. Components will 51 | * be converted from CamelCase to snake_case. 52 | * 53 | * Example: "google.LibraryService" -> "google/library_service" 54 | */ 55 | std::string ServiceNameToFilePath(std::string const& service_name); 56 | 57 | /** 58 | * Convert a protobuf name to a fully qualified C++ name. 59 | * 60 | * proto_name should be a "." separated name, which we convert to a 61 | * "::" separated C++ fully qualified name. 62 | */ 63 | std::string ProtoNameToCppName(std::string const& proto_name); 64 | 65 | } // namespace internal 66 | } // namespace codegen 67 | } // namespace api 68 | } // namespace google 69 | 70 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_GAPIC_UTILS_H_ 71 | -------------------------------------------------------------------------------- /gax/status.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | 18 | #include "gax/status.h" 19 | 20 | namespace google { 21 | namespace gax { 22 | 23 | std::string StatusCodeToString(StatusCode code) { 24 | switch (code) { 25 | case StatusCode::kOk: 26 | return "OK"; 27 | case StatusCode::kCancelled: 28 | return "CANCELLED"; 29 | case StatusCode::kUnknown: 30 | return "UNKNOWN"; 31 | case StatusCode::kInvalidArgument: 32 | return "INVALID_ARGUMENT"; 33 | case StatusCode::kDeadlineExceeded: 34 | return "DEADLINE_EXCEEDED"; 35 | case StatusCode::kNotFound: 36 | return "NOT_FOUND"; 37 | case StatusCode::kAlreadyExists: 38 | return "ALREADY_EXISTS"; 39 | case StatusCode::kPermissionDenied: 40 | return "PERMISSION_DENIED"; 41 | case StatusCode::kResourceExhausted: 42 | return "RESOURCE_EXHAUSTED"; 43 | case StatusCode::kFailedPrecondition: 44 | return "FAILED_PRECONDITION"; 45 | case StatusCode::kAborted: 46 | return "ABORTED"; 47 | case StatusCode::kOutOfRange: 48 | return "OUT_OF_RANGE"; 49 | case StatusCode::kUnimplemented: 50 | return "UNIMPLEMENTED"; 51 | case StatusCode::kInternal: 52 | return "INTERNAL"; 53 | case StatusCode::kUnavailable: 54 | return "UNAVAILABLE"; 55 | case StatusCode::kDataLoss: 56 | return "DATA_LOSS"; 57 | case StatusCode::kUnauthenticated: 58 | return "UNAUTHENTICATED"; 59 | default: 60 | return "UNEXPECTED_STATUS_CODE=" + std::to_string(static_cast(code)); 61 | } 62 | } 63 | 64 | std::ostream& operator<<(std::ostream& os, StatusCode code) { 65 | return os << StatusCodeToString(code); 66 | } 67 | 68 | std::ostream& operator<<(std::ostream& os, Status const& rhs) { 69 | return os << rhs.message() << " [" << rhs.code() << "]"; 70 | } 71 | 72 | Status GrpcStatusToGaxStatus(grpc::Status s) { 73 | return Status(static_cast(s.error_code()), s.error_message()); 74 | } 75 | 76 | } // namespace gax 77 | } // namespace google 78 | -------------------------------------------------------------------------------- /ci/kokoro/ubuntu/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Copyright 2019 Google LLC 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | set -eu 18 | 19 | echo "================================================================" 20 | echo "Running Bazel unit tests $(date)." 21 | echo "================================================================" 22 | 23 | echo "Running build and tests" 24 | cd "$(dirname $0)/../../.." 25 | readonly PROJECT_ROOT="${PWD}" 26 | 27 | echo "================================================================" 28 | echo "Install clang format $(date)." 29 | echo "================================================================" 30 | # The version of clang-format matters here - 3.9 makes slight changes 31 | # in formatting which we don't want. 32 | readonly CLANG_FORMAT_VERSION=3.8 33 | sudo apt-get install "clang-format-${CLANG_FORMAT_VERSION}" 34 | export CLANG_FORMAT_BIN="$(which clang-format-${CLANG_FORMAT_VERSION})" 35 | 36 | echo "================================================================" 37 | echo "Check style $(date)." 38 | echo "================================================================" 39 | "${PROJECT_ROOT}/ci/check-style.sh" 40 | 41 | echo "================================================================" 42 | echo "Update or Install Bazel $(date)." 43 | echo "================================================================" 44 | "${PROJECT_ROOT}/ci/install-bazel.sh" linux 45 | 46 | readonly BAZEL_BIN="$HOME/bin/bazel" 47 | echo "Using Bazel in ${BAZEL_BIN}" 48 | 49 | # Kokoro does guarantee that g++-4.9 will be installed, but the default compiler 50 | # might be g++-4.8. Set the compiler version explicitly: 51 | export CC=/usr/bin/gcc-4.9 52 | export CXX=/usr/bin/g++-4.9 53 | 54 | echo "================================================================" 55 | echo "Compiling and running unit tests $(date)" 56 | echo "================================================================" 57 | "${BAZEL_BIN}" test \ 58 | --test_output=errors \ 59 | --verbose_failures=true \ 60 | --keep_going \ 61 | -- //...:all 62 | 63 | echo "================================================================" 64 | echo "Build completed $(date)" 65 | echo "================================================================" 66 | -------------------------------------------------------------------------------- /ci/check-include-guards.gawk: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | 16 | # Exit the script with an error status if any files had bad guards. 17 | BEGIN { 18 | found_bad_include_guards = 0; 19 | } 20 | END { 21 | if (found_bad_include_guards) { 22 | exit 1; 23 | } 24 | } 25 | 26 | # Reset the state at the beginning of each file. 27 | BEGINFILE { 28 | # The guard must begin with the name of the project. 29 | guard_prefix="GAPIC_GENERATOR_CPP_" 30 | # The guard must end with "_" 31 | guard_suffix="_" 32 | # The guard name is the filename (including path from the root of the 33 | # project), with "/" and "." characters replaced with "_", and all 34 | # characters converted to uppercase: 35 | guard_body=toupper(FILENAME) 36 | gsub("[/\\.]", "_", guard_body) 37 | guard=toupper(guard_prefix guard_body guard_suffix) 38 | matches=0 39 | } 40 | 41 | # By the end of the file we expect to find 3 matches for the include guards. 42 | ENDFILE { 43 | if (matches != 3) { 44 | printf("%s has invalid include guards\n", FILENAME); 45 | found_bad_include_guards = 1; 46 | } 47 | } 48 | 49 | # Check only lines that start with #ifndef, #define, or #endif. 50 | /^#ifndef / { 51 | # Ignore lines that do not look like guards at all. 52 | if ($0 !~ "_H_$") { next; } 53 | if (index($0, guard) == 9) { 54 | matches++; 55 | } else { 56 | printf("%s:\n", FILENAME) 57 | printf("expected: #ifndef %s\n", guard) 58 | printf(" found: %s\n", $0); 59 | } 60 | } 61 | 62 | /^#define / { 63 | # Ignore lines that do not look like guards at all. 64 | if ($0 !~ "_H_$") { next; } 65 | if (index($0, guard) == 9) { 66 | matches++; 67 | } else { 68 | printf("%s:\n", FILENAME) 69 | printf("expected: #define %s\n", guard) 70 | printf(" found: %s\n", $0); 71 | } 72 | } 73 | 74 | /^#endif / { 75 | # Ignore lines that do not look like guards at all. 76 | if ($0 !~ "_H_$") { next; } 77 | if (index($0, "// " guard) == 9) { 78 | matches++; 79 | } else { 80 | printf("%s:\n", FILENAME) 81 | printf("expected: #endif // %s\n", guard) 82 | printf(" found: %s\n", $0); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ci/kokoro/docker/run_e2e_test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eu 17 | 18 | if [[ -z "${NCPU+x}" ]]; then 19 | # Mac doesn't have nproc. Run the equivalent. 20 | if [[ "$OSTYPE" == "darwin"* ]]; then 21 | NCPU=$(sysctl -n hw.physicalcpu) 22 | else 23 | NCPU=$(nproc) 24 | fi 25 | export NCPU 26 | fi 27 | 28 | if [[ -z "${PROJECT_ROOT+x}" ]]; then 29 | PROJECT_ROOT="$(cd "$(dirname "$0")/../../.."; pwd)" 30 | readonly PROJECT_ROOT 31 | fi 32 | 33 | echo "================================================================" 34 | echo "Change working directory to project root $(date)." 35 | cd "${PROJECT_ROOT}" 36 | 37 | echo "================================================================" 38 | echo "Building with ${NCPU} cores $(date) on ${PWD}." 39 | 40 | if [[ -n "${PROJECT_ID:-}" ]]; then 41 | DOCKER_IMAGE_PREFIX="gcr.io/${PROJECT_ID}/gapic-generator" 42 | else 43 | # We want a prefix that works when running interactively, so it must be a 44 | # (syntactically) valid project id, this works. 45 | DOCKER_IMAGE_PREFIX="gcr.io/cloud-cpp-reserved/gapic-generator" 46 | fi 47 | readonly DOCKER_IMAGE_PREFIX 48 | 49 | # First build the Docker image 50 | readonly IMAGE="${DOCKER_IMAGE_PREFIX}/e2e-ubuntu-18.04" 51 | 52 | build_flags=( 53 | "-t" "${IMAGE}" 54 | "--build-arg" "NCPU=${NCPU}" 55 | "-f" "${PROJECT_ROOT}/ci/kokoro/docker/e2e/Dockerfile" 56 | ) 57 | 58 | echo "================================================================" 59 | echo "Building a Docker image $(date)." 60 | 61 | docker build "${build_flags[@]}" . 62 | 63 | if [[ -n "${GOOGLE_APPLICATION_CREDENTIALS:-}" \ 64 | && -n "${GOOGLE_CLOUD_PROJECT:-}" ]]; then 65 | echo "================================================================" 66 | echo "Executing the binary $(date)." 67 | # Run the binary 68 | docker run --rm \ 69 | -v "${GOOGLE_APPLICATION_CREDENTIALS}:/credentials.json" \ 70 | -e "GOOGLE_APPLICATION_CREDENTIALS=/credentials.json" \ 71 | -e "GOOGLE_CLOUD_PROJECT=${GOOGLE_CLOUD_PROJECT}" \ 72 | "${IMAGE}" \ 73 | bash -c "cd /build/gapic-generator-cpp/ci/kokoro/docker/e2e && cmake-out/gapic-generator-e2e" 74 | else 75 | echo "================================================================" 76 | echo -n "Set GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_CLOUD_PROJECT" 77 | echo " environment variables to run the binary." 78 | echo "Skip executing binary $(date)." 79 | fi 80 | -------------------------------------------------------------------------------- /generator/gapic_generator_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace google { 25 | namespace api { 26 | namespace codegen { 27 | 28 | namespace pb = google::protobuf; 29 | 30 | inline std::string LoadContent(std::string const& f) { 31 | std::ifstream ifs(f); 32 | EXPECT_TRUE(ifs.good()) << "Could not open " << f; 33 | return std::string((std::istreambuf_iterator(ifs)), 34 | (std::istreambuf_iterator())); 35 | } 36 | 37 | TEST(GapicGeneratorBaselineTest, StandaloneTest) { 38 | std::string const input_dir("../"); 39 | std::string const output_dir("./"); 40 | std::string const data_dir("./generator/testdata/"); 41 | 42 | std::vector descriptors = { 43 | input_dir + 44 | "com_google_gapic_generator_cpp/generator/testdata/" 45 | "library_proto-descriptor-set.proto.bin", 46 | input_dir + 47 | "com_google_googleapis/google/api/" 48 | "client_proto-descriptor-set.proto.bin", 49 | input_dir + 50 | "com_google_protobuf/descriptor_proto-descriptor-set.proto.bin"}; 51 | std::string package = "google.example.library.v1"; 52 | 53 | GapicGenerator generator; 54 | 55 | int res = StandaloneMain(descriptors, package, output_dir, &generator); 56 | EXPECT_EQ(0, res) << "StandaloneMain failed"; 57 | 58 | std::vector files_to_check{ 59 | "google/example/library/v1/library_service.gapic.h", 60 | "google/example/library/v1/library_service.gapic.cc", 61 | "google/example/library/v1/library_service_stub.gapic.h", 62 | "google/example/library/v1/library_service_stub.gapic.cc", 63 | }; 64 | 65 | for (auto const& file : files_to_check) { 66 | std::string const expected_file(data_dir + file + ".baseline"); 67 | std::string const actual_file(output_dir + file); 68 | 69 | std::string const& expected_file_content = LoadContent(expected_file); 70 | std::string const& actual_file_content = LoadContent(actual_file); 71 | 72 | EXPECT_EQ(expected_file_content, actual_file_content) 73 | << "\nexpected_file: " << expected_file 74 | << "\nactual_file: " << actual_file; 75 | } 76 | } 77 | 78 | } // namespace codegen 79 | } // namespace api 80 | } // namespace google 81 | -------------------------------------------------------------------------------- /generator/BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google Inc. All rights reserved 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | licenses(["notice"]) # Apache 2.0 16 | 17 | cc_library( 18 | name = "gapic_generator", 19 | srcs = [ 20 | "gapic_generator.cc", 21 | "internal/client_cc_generator.cc", 22 | "internal/client_cc_generator.h", 23 | "internal/client_header_generator.cc", 24 | "internal/client_header_generator.h", 25 | "internal/data_model.h", 26 | "internal/gapic_utils.cc", 27 | "internal/gapic_utils.h", 28 | "internal/printer.h", 29 | "internal/stub_cc_generator.cc", 30 | "internal/stub_cc_generator.h", 31 | "internal/stub_header_generator.cc", 32 | "internal/stub_header_generator.h", 33 | "standalone.cc", 34 | "standalone.h", 35 | ], 36 | hdrs = [ 37 | "gapic_generator.h", 38 | ], 39 | includes = ["."], 40 | deps = [ 41 | "@absl//absl/base", 42 | "@absl//absl/strings", 43 | "@com_google_googleapis//google/api:client_cc_proto", 44 | "@com_google_protobuf//:protoc_lib", 45 | ], 46 | ) 47 | 48 | # The protoc plugin/standalone binary. The name (proto-gen-cpp_gapic) is ugly 49 | # but it is a naming requirement for protoc plugins. To use --cpp_gapic_out 50 | # command line argument without need to provide additional --plugin argument, 51 | # the binary must be named proto-gen-cpp_gapic and placed in a PATH. 52 | cc_binary( 53 | name = "protoc-gen-cpp_gapic", 54 | srcs = ["main.cc"], 55 | includes = ["."], 56 | visibility = ["//visibility:public"], 57 | deps = [":gapic_generator"], 58 | ) 59 | 60 | cc_test( 61 | name = "gapic_generator_test", 62 | size = "small", 63 | srcs = ["gapic_generator_test.cc"], 64 | data = [ 65 | "//generator/testdata:library_proto", 66 | "//generator/testdata:library_service_baseline", 67 | "@com_google_googleapis//google/api:client_proto", 68 | "@com_google_protobuf//:descriptor_proto", 69 | ], 70 | deps = [ 71 | ":gapic_generator", 72 | "//generator/testdata:library_cc_gapic", 73 | "@gtest//:gtest_main", 74 | ], 75 | ) 76 | 77 | [cc_test( 78 | name = "generator_" + test.replace("/", "_").replace(".cc", ""), 79 | size = "small", 80 | srcs = [test], 81 | deps = [ 82 | "//generator:gapic_generator", 83 | "@absl//absl/base", 84 | "@absl//absl/strings", 85 | "@gtest//:gtest_main", 86 | ], 87 | ) for test in [ 88 | "internal/gapic_utils_test.cc", 89 | ]] 90 | -------------------------------------------------------------------------------- /gax/status.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_STATUS_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_STATUS_H_ 17 | 18 | #include "grpcpp/impl/codegen/status.h" 19 | #include 20 | #include 21 | 22 | namespace google { 23 | namespace gax { 24 | 25 | /** 26 | * The underlying StatusCode is intended to closely resemble 27 | * grpc::StatusCode, the semantics of which are documented in: 28 | * https://grpc.io/grpc/cpp/classgrpc_1_1_status.html 29 | */ 30 | enum class StatusCode { 31 | /// Not an error; returned on success. 32 | kOk = 0, 33 | 34 | kCancelled = 1, 35 | kUnknown = 2, 36 | kInvalidArgument = 3, 37 | kDeadlineExceeded = 4, 38 | kNotFound = 5, 39 | kAlreadyExists = 6, 40 | kPermissionDenied = 7, 41 | kResourceExhausted = 8, 42 | kFailedPrecondition = 9, 43 | kAborted = 10, 44 | kOutOfRange = 11, 45 | kUnimplemented = 12, 46 | kInternal = 13, 47 | kUnavailable = 14, 48 | kDataLoss = 15, 49 | kUnauthenticated = 16, 50 | }; 51 | 52 | /** 53 | * Reports error code and details from a remote request. 54 | * 55 | * This class is modeled after `grpc::Status`. 56 | * It contains the status code and error message(if applicable) from an RPC. 57 | */ 58 | class Status { 59 | public: 60 | Status() : code_(StatusCode::kOk) {} 61 | Status(StatusCode code, std::string msg) 62 | : code_(code), msg_(std::move(msg)) {} 63 | Status(Status const& rhs) : Status(rhs.code_, rhs.msg_) {} 64 | Status(Status&& rhs) : Status(rhs.code_, std::move(rhs.msg_)) {} 65 | 66 | inline bool IsOk() const { return code_ == StatusCode::kOk; } 67 | inline bool IsTransientFailure() const { 68 | return (code_ == StatusCode::kAborted || 69 | code_ == StatusCode::kUnavailable || 70 | code_ == StatusCode::kDeadlineExceeded); 71 | } 72 | inline bool IsPermanentFailure() const { 73 | return !IsOk() && !IsTransientFailure(); 74 | } 75 | 76 | inline StatusCode code() const { return code_; } 77 | 78 | inline std::string const& message() const { return msg_; } 79 | 80 | bool operator==(Status const& rhs) const { 81 | return code_ == rhs.code_ && msg_ == rhs.msg_; 82 | } 83 | bool operator!=(Status const& rhs) const { return !(*this == rhs); } 84 | 85 | private: 86 | StatusCode const code_; 87 | std::string const msg_; 88 | }; 89 | 90 | std::string StatusCodeToString(StatusCode code); 91 | std::ostream& operator<<(std::ostream& os, StatusCode code); 92 | std::ostream& operator<<(std::ostream& os, Status const& rhs); 93 | 94 | Status GrpcStatusToGaxStatus(grpc::Status s); 95 | 96 | } // namespace gax 97 | } // namespace google 98 | 99 | #endif // GAPIC_GENERATOR_CPP_GAX_STATUS_H_ 100 | -------------------------------------------------------------------------------- /generator/internal/data_model.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_DATA_MODEL_H_ 15 | #define GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_DATA_MODEL_H_ 16 | 17 | #include "absl/strings/str_cat.h" 18 | #include "absl/strings/str_join.h" 19 | #include "absl/strings/str_replace.h" 20 | #include "absl/strings/str_split.h" 21 | #include "google/api/client.pb.h" 22 | #include "generator/internal/gapic_utils.h" 23 | #include "generator/internal/printer.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace pb = google::protobuf; 33 | 34 | namespace google { 35 | namespace api { 36 | namespace codegen { 37 | namespace internal { 38 | 39 | struct DataModel { 40 | static void SetServiceVars(pb::ServiceDescriptor const* service, 41 | std::map& vars) { 42 | vars["class_name"] = service->name(); 43 | vars["stub_class_name"] = absl::StrCat(service->name(), "Stub"); 44 | vars["proto_file_name"] = service->file()->name(); 45 | vars["header_include_guard_const"] = absl::StrCat(service->name(), "_H_"); 46 | vars["stub_header_include_guard_const"] = 47 | absl::StrCat(service->name(), "_Stub", "_H_"); 48 | vars["class_comment_block"] = "// TODO: pull in comments"; 49 | vars["grpc_stub_fqn"] = internal::ProtoNameToCppName(service->full_name()); 50 | vars["service_endpoint"] = 51 | service->options().GetExtension(google::api::default_host); 52 | } 53 | 54 | static void SetMethodVars(pb::MethodDescriptor const* method, 55 | std::map& vars) { 56 | vars["method_name"] = method->name(); 57 | vars["method_name_snake"] = CamelCaseToSnakeCase(method->name()); 58 | vars["request_object"] = 59 | internal::ProtoNameToCppName(method->input_type()->full_name()); 60 | vars["response_object"] = 61 | internal::ProtoNameToCppName(method->output_type()->full_name()); 62 | } 63 | 64 | static void PrintMethods( 65 | pb::ServiceDescriptor const* service, 66 | std::map vars, Printer& p, char const* tmplt, 67 | std::function predicate = 68 | [](pb::MethodDescriptor const*) { return true; }) { 69 | for (int i = 0; i < service->method_count(); i++) { 70 | const pb::MethodDescriptor* method = service->method(i); 71 | if (predicate(method)) { 72 | SetMethodVars(method, vars); 73 | p->Print(vars, tmplt); 74 | } 75 | } 76 | } 77 | }; 78 | 79 | } // namespace internal 80 | } // namespace codegen 81 | } // namespace api 82 | } // namespace google 83 | 84 | #endif // GAPIC_GENERATOR_CPP_GENERATOR_INTERNAL_DATA_MODEL_H_ 85 | -------------------------------------------------------------------------------- /generator/gapic_generator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "absl/strings/str_cat.h" 20 | #include "absl/strings/str_replace.h" 21 | #include "absl/strings/string_view.h" 22 | #include "generator/gapic_generator.h" 23 | #include "generator/internal/client_cc_generator.h" 24 | #include "generator/internal/client_header_generator.h" 25 | #include "generator/internal/data_model.h" 26 | #include "generator/internal/gapic_utils.h" 27 | #include "generator/internal/printer.h" 28 | #include "generator/internal/stub_cc_generator.h" 29 | #include "generator/internal/stub_header_generator.h" 30 | 31 | #include "google/api/client.pb.h" 32 | 33 | namespace pb = google::protobuf; 34 | 35 | namespace google { 36 | namespace api { 37 | namespace codegen { 38 | 39 | bool GapicGenerator::Generate(pb::FileDescriptor const* file, 40 | std::string const& /* parameter */, 41 | pb::compiler::GeneratorContext* generator_context, 42 | std::string* error) const { 43 | if (file->options().cc_generic_services()) { 44 | *error = 45 | "cpp gapic proto compiler plugin does not work with generic " 46 | "services. To generate cpp grpc APIs, please set \"" 47 | "cc_generic_service = false\"."; 48 | return false; 49 | } 50 | 51 | for (int i = 0; i < file->service_count(); i++) { 52 | pb::ServiceDescriptor const* service = file->service(i); 53 | 54 | // TODO(michaelbausor): initialize Vars with cross-file-descriptor 55 | // configuration, e.g. metadata annotation. 56 | std::map vars; 57 | internal::DataModel::SetServiceVars(service, vars); 58 | 59 | std::string service_file_path = 60 | internal::ServiceNameToFilePath(service->full_name()); 61 | 62 | std::string header_file_path = absl::StrCat(service_file_path, ".gapic.h"); 63 | internal::Printer header_printer(generator_context, header_file_path); 64 | if (!internal::GenerateClientHeader(service, vars, header_printer, error)) { 65 | return false; 66 | } 67 | 68 | std::string header_stub_file_path = 69 | absl::StrCat(service_file_path, "_stub", ".gapic.h"); 70 | internal::Printer header_stub_printer(generator_context, 71 | header_stub_file_path); 72 | if (!internal::GenerateClientStubHeader(service, vars, header_stub_printer, 73 | error)) { 74 | return false; 75 | } 76 | 77 | std::string cc_file_path = absl::StrCat(service_file_path, ".gapic.cc"); 78 | internal::Printer cc_printer(generator_context, cc_file_path); 79 | if (!internal::GenerateClientCC(service, vars, cc_printer, error)) { 80 | return false; 81 | } 82 | 83 | std::string cc_stub_file_path = 84 | absl::StrCat(service_file_path, "_stub", ".gapic.cc"); 85 | internal::Printer cc_stub_printer(generator_context, cc_stub_file_path); 86 | if (!internal::GenerateClientStubCC(service, vars, cc_stub_printer, 87 | error)) { 88 | return false; 89 | } 90 | } 91 | return true; 92 | } 93 | 94 | } // namespace codegen 95 | } // namespace api 96 | } // namespace google 97 | -------------------------------------------------------------------------------- /generator/internal/stub_header_generator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "generator/internal/stub_header_generator.h" 16 | #include "generator/internal/data_model.h" 17 | #include "generator/internal/gapic_utils.h" 18 | #include "generator/internal/printer.h" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace pb = google::protobuf; 24 | 25 | namespace google { 26 | namespace api { 27 | namespace codegen { 28 | namespace internal { 29 | 30 | std::vector BuildClientStubHeaderIncludes( 31 | pb::ServiceDescriptor const* service) { 32 | return {LocalInclude(absl::StrCat( 33 | absl::StripSuffix(service->file()->name(), ".proto"), ".pb.h")), 34 | LocalInclude("gax/call_context.h"), LocalInclude("gax/status.h"), 35 | LocalInclude("grpcpp/security/credentials.h"), 36 | SystemInclude("memory")}; 37 | } 38 | 39 | std::vector BuildClientStubHeaderNamespaces( 40 | pb::ServiceDescriptor const* service) { 41 | return {}; 42 | } 43 | 44 | bool GenerateClientStubHeader(pb::ServiceDescriptor const* service, 45 | std::map const& vars, 46 | Printer& p, std::string* /* error */) { 47 | auto includes = BuildClientStubHeaderIncludes(service); 48 | auto namespaces = BuildClientStubHeaderNamespaces(service); 49 | 50 | p->Print(vars, 51 | "// Generated by the GAPIC C++ plugin.\n" 52 | "// If you make any local changes, they will be lost.\n" 53 | "// source: $proto_file_name$\n" 54 | "#ifndef $stub_header_include_guard_const$\n" 55 | "#define $stub_header_include_guard_const$\n" 56 | "\n"); 57 | 58 | for (auto const& include : includes) { 59 | p->Print("#include $include$\n", "include", include); 60 | } 61 | 62 | for (auto const& nspace : namespaces) { 63 | p->Print("namespace $namespace$ {\n", "namespace", nspace); 64 | } 65 | 66 | p->Print("\n"); 67 | 68 | // Abstract interface Stub base class 69 | p->Print(vars, 70 | "class $stub_class_name$ {\n" 71 | " public:\n"); 72 | 73 | DataModel::PrintMethods(service, vars, p, 74 | " virtual google::gax::Status $method_name$(" 75 | "google::gax::CallContext& context,\n" 76 | " $request_object$ const& request,\n" 77 | " $response_object$* response);\n" 78 | "\n", 79 | NoStreamingPredicate); 80 | 81 | p->Print(vars, 82 | " virtual ~$stub_class_name$() = 0;\n" 83 | "\n" 84 | "}; // $stub_class_name$\n" 85 | "\n" 86 | "std::unique_ptr<$stub_class_name$>\n" 87 | "Create$stub_class_name$();\n" 88 | "\n" 89 | "std::unique_ptr<$stub_class_name$>\n" 90 | "Create$stub_class_name$(std::shared_ptr " 91 | "creds);\n" 92 | "\n" 93 | "#endif // $stub_header_include_guard_const$\n"); 94 | 95 | return true; 96 | } 97 | 98 | } // namespace internal 99 | } // namespace codegen 100 | } // namespace api 101 | } // namespace google 102 | -------------------------------------------------------------------------------- /generator/internal/client_cc_generator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | #include "generator/internal/client_cc_generator.h" 20 | #include "generator/internal/data_model.h" 21 | #include "generator/internal/gapic_utils.h" 22 | #include "generator/internal/printer.h" 23 | #include 24 | 25 | namespace pb = google::protobuf; 26 | 27 | namespace google { 28 | namespace api { 29 | namespace codegen { 30 | namespace internal { 31 | 32 | std::vector BuildClientCCIncludes( 33 | pb::ServiceDescriptor const* service) { 34 | return { 35 | LocalInclude(absl::StrCat( 36 | internal::ServiceNameToFilePath(service->full_name()), ".gapic.h")), 37 | LocalInclude( 38 | absl::StrCat(internal::ServiceNameToFilePath(service->full_name()), 39 | "_stub.gapic.h")), 40 | LocalInclude("gax/call_context.h"), LocalInclude("gax/status.h"), 41 | LocalInclude("gax/status_or.h"), 42 | }; 43 | } 44 | 45 | std::vector BuildClientCCNamespaces( 46 | pb::ServiceDescriptor const* /* service */) { 47 | return std::vector(); 48 | } 49 | 50 | bool GenerateClientCC(pb::ServiceDescriptor const* service, 51 | std::map const& vars, 52 | Printer& p, std::string* /* error */) { 53 | auto includes = BuildClientCCIncludes(service); 54 | auto namespaces = BuildClientCCNamespaces(service); 55 | 56 | p->Print(vars, 57 | "// Generated by the GAPIC C++ plugin.\n" 58 | "// If you make any local changes, they will be lost.\n" 59 | "// source: $proto_file_name$\n"); 60 | 61 | for (auto include : includes) { 62 | p->Print("#include $include$\n", "include", include); 63 | } 64 | for (auto nspace : namespaces) { 65 | p->Print("namespace $namespace$ {\n", "namespace", nspace); 66 | } 67 | 68 | p->Print("\n"); 69 | 70 | DataModel::PrintMethods( 71 | service, vars, p, 72 | "google::gax::StatusOr<$response_object$>\n" 73 | "$class_name$::$method_name$(\n" 74 | "$request_object$ const& request) {\n" 75 | " google::gax::CallContext context($method_name_snake$_info);\n" 76 | " if (retry_policy_) {\n" 77 | " context.SetRetryPolicy(*retry_policy_);\n" 78 | " }\n" 79 | " if (backoff_policy_) {\n" 80 | " context.SetBackoffPolicy(*backoff_policy_);\n" 81 | " }\n" 82 | " $response_object$ response;\n" 83 | " google::gax::Status status = stub_->$method_name$(context, request, " 84 | "&response);\n" 85 | " if (status.IsOk()) {\n" 86 | " return response;\n" 87 | " } else {\n" 88 | " return status;\n" 89 | " }\n" 90 | "}\n" 91 | "\n", 92 | NoStreamingPredicate); 93 | 94 | DataModel::PrintMethods(service, vars, p, 95 | "constexpr google::gax::MethodInfo " 96 | "$class_name$::$method_name_snake$_info;\n", 97 | NoStreamingPredicate); 98 | 99 | for (auto nspace : namespaces) { 100 | p->Print("\n} // namespace $namespace$", "namespace", nspace); 101 | } 102 | 103 | return true; 104 | } 105 | 106 | } // namespace internal 107 | } // namespace codegen 108 | } // namespace api 109 | } // namespace google 110 | -------------------------------------------------------------------------------- /generator/testdata/google/example/library/v1/library_service.gapic.h.baseline: -------------------------------------------------------------------------------- 1 | // Generated by the GAPIC C++ plugin. 2 | // If you make any local changes, they will be lost. 3 | // source: generator/testdata/library.proto 4 | #ifndef LibraryService_H_ 5 | #define LibraryService_H_ 6 | 7 | #include 8 | #include "library_service_stub.gapic.h" 9 | #include "generator/testdata/library.pb.h" 10 | #include "gax/status_or.h" 11 | #include "gax/retry_policy.h" 12 | #include "gax/backoff_policy.h" 13 | 14 | // TODO: pull in comments 15 | class LibraryService final { 16 | public: 17 | LibraryService(std::shared_ptr stub) : 18 | stub_(std::move(stub)) {} 19 | 20 | template 21 | LibraryService(std::shared_ptr stub, 22 | Policies&&... policies) : LibraryService(std::move(stub)) { 23 | ChangePolicies(std::forward...); 24 | } 25 | 26 | LibraryService(LibraryService const&) = delete; 27 | LibraryService& operator=(LibraryService const&) = delete; 28 | 29 | std::shared_ptr Stub() { return stub_; } 30 | 31 | google::gax::StatusOr<::google::example::library::v1::Book> 32 | CreateBook(::google::example::library::v1::CreateBookRequest const& request); 33 | 34 | google::gax::StatusOr<::google::example::library::v1::Book> 35 | GetBook(::google::example::library::v1::GetBookRequest const& request); 36 | 37 | google::gax::StatusOr<::google::example::library::v1::ListBooksResponse> 38 | ListBooks(::google::example::library::v1::ListBooksRequest const& request); 39 | 40 | google::gax::StatusOr<::google::example::library::v1::Empty> 41 | DeleteBook(::google::example::library::v1::DeleteBookRequest const& request); 42 | 43 | google::gax::StatusOr<::google::example::library::v1::Book> 44 | UpdateBook(::google::example::library::v1::UpdateBookRequest const& request); 45 | 46 | google::gax::StatusOr<::google::example::library::v1::Book> 47 | GetBigBook(::google::example::library::v1::GetBookRequest const& request); 48 | 49 | 50 | private: 51 | void ChangePolicy(google::gax::RetryPolicy const& policy) { 52 | retry_policy_ = policy.clone(); 53 | } 54 | void ChangePolicy(google::gax::BackoffPolicy const& policy) { 55 | backoff_policy_ = policy.clone(); 56 | } 57 | void ChangePolicies() {} 58 | 59 | template 60 | void ChangePolicies(Policy&& policy, Policies&&... policies) { 61 | ChangePolicy(policy); 62 | ChangePolicies(std::forward(policies)...); 63 | } 64 | 65 | std::shared_ptr stub_; 66 | std::unique_ptr retry_policy_; 67 | std::unique_ptr backoff_policy_; 68 | 69 | // Note: conservatively assume no methods are idempotent. 70 | // This will eventually be set from annotations. 71 | static constexpr google::gax::MethodInfo create_book_info = { 72 | "CreateBook", google::gax::MethodInfo::RpcType::NORMAL_RPC, 73 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 74 | static constexpr google::gax::MethodInfo get_book_info = { 75 | "GetBook", google::gax::MethodInfo::RpcType::NORMAL_RPC, 76 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 77 | static constexpr google::gax::MethodInfo list_books_info = { 78 | "ListBooks", google::gax::MethodInfo::RpcType::NORMAL_RPC, 79 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 80 | static constexpr google::gax::MethodInfo delete_book_info = { 81 | "DeleteBook", google::gax::MethodInfo::RpcType::NORMAL_RPC, 82 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 83 | static constexpr google::gax::MethodInfo update_book_info = { 84 | "UpdateBook", google::gax::MethodInfo::RpcType::NORMAL_RPC, 85 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 86 | static constexpr google::gax::MethodInfo get_big_book_info = { 87 | "GetBigBook", google::gax::MethodInfo::RpcType::NORMAL_RPC, 88 | google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT}; 89 | }; // LibraryService 90 | 91 | #endif // LibraryService_H_ 92 | -------------------------------------------------------------------------------- /gax/call_context_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/call_context.h" 16 | #include "grpcpp/client_context.h" 17 | #include "gax/backoff_policy.h" 18 | #include "gax/retry_policy.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace google { 26 | namespace gax { 27 | 28 | static_assert(std::is_move_constructible::value, 29 | "CallContext must be move constructable"); 30 | 31 | static_assert(std::is_copy_constructible::value, 32 | "CallContext must be copy constructable"); 33 | 34 | TEST(CallContext, Basic) { 35 | gax::MethodInfo mi{"TestMethod", MethodInfo::RpcType::CLIENT_STREAMING, 36 | MethodInfo::Idempotency::IDEMPOTENT}; 37 | gax::CallContext ctx(mi); 38 | EXPECT_EQ(ctx.Deadline(), std::chrono::system_clock::time_point::max()); 39 | 40 | auto info = ctx.Info(); 41 | EXPECT_EQ(std::string(info.rpc_name), "TestMethod"); 42 | EXPECT_EQ(info.rpc_type, MethodInfo::RpcType::CLIENT_STREAMING); 43 | EXPECT_EQ(info.idempotency, MethodInfo::Idempotency::IDEMPOTENT); 44 | 45 | auto now = std::chrono::system_clock::now(); 46 | ctx.SetDeadline(now); 47 | EXPECT_EQ(ctx.Deadline(), now); 48 | 49 | ctx.AddMetadata("testKey", "testVal"); 50 | auto iter = ctx.Metadata().find("testKey"); 51 | EXPECT_NE(iter, ctx.Metadata().end()); 52 | EXPECT_EQ(iter->second, "testVal"); 53 | 54 | std::set const vals = {"testVal", "testVal2"}; 55 | std::set tmp; 56 | ctx.AddMetadata("testKey", "testVal2"); 57 | EXPECT_EQ(ctx.Metadata().count("testKey"), std::size_t(2)); 58 | auto range = ctx.Metadata().equal_range("testKey"); 59 | for (auto i = range.first; i != range.second; ++i) { 60 | tmp.insert(i->second); 61 | } 62 | EXPECT_EQ(tmp, vals); 63 | 64 | int policy_invoked = 0; 65 | ctx.AddGrpcContextPolicy( 66 | [&policy_invoked](grpc::ClientContext*) { policy_invoked++; }); 67 | 68 | grpc::ClientContext client_ctx; 69 | ctx.PrepareGrpcContext(&client_ctx); 70 | EXPECT_EQ(policy_invoked, 1); 71 | EXPECT_EQ(client_ctx.deadline(), now); 72 | 73 | // There isn't a good way to examine ClientContext metadata without it being 74 | // sent to a server, so take it on faith that it was properly added. 75 | } 76 | 77 | TEST(CallContext, CopyAndMove) { 78 | gax::MethodInfo mi{"TestMethod", MethodInfo::RpcType::CLIENT_STREAMING, 79 | MethodInfo::Idempotency::IDEMPOTENT}; 80 | gax::CallContext base(mi); 81 | 82 | gax::CallContext no_policy_copy(base); 83 | EXPECT_FALSE(no_policy_copy.RetryPolicy()); 84 | EXPECT_FALSE(no_policy_copy.BackoffPolicy()); 85 | gax::CallContext no_policy_move(std::move(no_policy_copy)); 86 | EXPECT_FALSE(no_policy_move.RetryPolicy()); 87 | EXPECT_FALSE(no_policy_move.BackoffPolicy()); 88 | 89 | base.SetRetryPolicy( 90 | gax::LimitedErrorCountRetryPolicy<>(10, std::chrono::milliseconds(2))); 91 | base.SetBackoffPolicy(gax::ExponentialBackoffPolicy( 92 | std::chrono::milliseconds(1), std::chrono::milliseconds(10))); 93 | gax::CallContext policy_copy(base); 94 | EXPECT_TRUE(policy_copy.RetryPolicy()); 95 | EXPECT_TRUE(policy_copy.BackoffPolicy()); 96 | gax::CallContext policy_move(std::move(base)); 97 | EXPECT_TRUE(policy_move.RetryPolicy()); 98 | EXPECT_TRUE(policy_move.BackoffPolicy()); 99 | } 100 | 101 | } // namespace gax 102 | } // namespace google 103 | -------------------------------------------------------------------------------- /rules_gapic/cpp/cc_gapic.bzl: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | load("@com_google_api_codegen//rules_gapic:gapic.bzl", "gapic_srcjar", "unzipped_srcjar") 16 | 17 | def _cc_gapic_postprocessed_srcjar_impl(ctx): 18 | gapic_zip = ctx.file.gapic_zip 19 | output_main = ctx.outputs.main 20 | output_main_h = ctx.outputs.main_h 21 | 22 | output_dir_name = ctx.label.name 23 | output_dir_path = "%s/%s" % (output_main.dirname, output_dir_name) 24 | 25 | script = """ 26 | unzip -q {gapic_zip} -d {output_dir_path} 27 | # TODO: Call formatter here 28 | pushd {output_dir_path} 29 | zip -q -r {output_dir_name}-h.srcjar . -i ./*.gapic.h 30 | find . -name "*.gapic.h" -delete 31 | zip -q -r {output_dir_name}.srcjar . -i ./*.cc -i ./*.h 32 | popd 33 | mv {output_dir_path}/{output_dir_name}-h.srcjar {output_main_h} 34 | mv {output_dir_path}/{output_dir_name}.srcjar {output_main} 35 | rm -rf {output_dir_path} 36 | """.format( 37 | gapic_zip = gapic_zip.path, 38 | output_dir_name = output_dir_name, 39 | output_dir_path = output_dir_path, 40 | output_main = output_main.path, 41 | output_main_h = output_main_h.path, 42 | ) 43 | 44 | ctx.actions.run_shell( 45 | inputs = [gapic_zip], 46 | command = script, 47 | outputs = [output_main, output_main_h], 48 | ) 49 | 50 | _cc_gapic_postprocessed_srcjar = rule( 51 | _cc_gapic_postprocessed_srcjar_impl, 52 | attrs = { 53 | "gapic_zip": attr.label(mandatory = True, allow_single_file = True), 54 | }, 55 | outputs = { 56 | "main": "%{name}.srcjar", 57 | "main_h": "%{name}-h.srcjar", 58 | }, 59 | ) 60 | 61 | def cc_gapic_srcjar(name, src, package, **kwargs): 62 | raw_srcjar_name = "%s_raw" % name 63 | 64 | gapic_srcjar( 65 | name = raw_srcjar_name, 66 | src = src, 67 | package = package, 68 | output_suffix = ".zip", 69 | gapic_generator = Label("//generator:protoc-gen-cpp_gapic"), 70 | **kwargs 71 | ) 72 | 73 | _cc_gapic_postprocessed_srcjar( 74 | name = name, 75 | gapic_zip = ":%s" % raw_srcjar_name, 76 | **kwargs 77 | ) 78 | 79 | def cc_gapic_library(name, src, package, deps = [], **kwargs): 80 | srcjar_name = "%s_srcjar" % name 81 | 82 | cc_gapic_srcjar( 83 | name = srcjar_name, 84 | src = src, 85 | package = package, 86 | **kwargs 87 | ) 88 | 89 | actual_deps = deps + [ 90 | "@com_google_gapic_generator_cpp//gax:gax", 91 | ] 92 | 93 | main_file = ":%s.srcjar" % srcjar_name 94 | main_dir = "%s_main" % srcjar_name 95 | 96 | unzipped_srcjar( 97 | name = main_dir, 98 | srcjar = main_file, 99 | extension = "", 100 | **kwargs 101 | ) 102 | 103 | main_h_file = ":%s-h.srcjar" % srcjar_name 104 | main_h_dir = "%s_h_main" % srcjar_name 105 | 106 | unzipped_srcjar( 107 | name = main_h_dir, 108 | srcjar = main_h_file, 109 | extension = "", 110 | **kwargs 111 | ) 112 | 113 | native.cc_library( 114 | name = name, 115 | srcs = [":%s" % main_dir], 116 | deps = actual_deps, 117 | hdrs = [":%s" % main_h_dir], 118 | includes = [main_h_dir], 119 | # cc_library generates an empty .so file, making dynamic linking 120 | # impossible. This may be caused by us using a directory (instead of 121 | # exact files) as srcs input. 122 | linkstatic = True, 123 | **kwargs 124 | ) 125 | -------------------------------------------------------------------------------- /gax/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # ~~~ 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ~~~ 16 | 17 | set(GAX_VERSION_MAJOR 0) 18 | set(GAX_VERSION_MINOR 1) 19 | set(GAX_VERSION_PATCH 0) 20 | 21 | string(CONCAT GAX_VERSION 22 | "${GAX_VERSION_MAJOR}" 23 | "." 24 | "${GAX_VERSION_MINOR}" 25 | "." 26 | "${GAX_VERSION_PATCH}") 27 | 28 | include(GapicGeneratorCommon) 29 | 30 | find_package(googleapis REQUIRED) 31 | find_package(gRPC REQUIRED) 32 | 33 | 34 | add_library(gax 35 | # cmake-format: sortable 36 | backoff_policy.cc 37 | backoff_policy.h 38 | call_context.cc 39 | call_context.h 40 | internal/gtest_prod.h 41 | internal/invoke_result.h 42 | operation.h 43 | operations_client.cc 44 | operations_client.h 45 | operations_stub.cc 46 | operations_stub.h 47 | pagination.h 48 | retry_loop.h 49 | retry_policy.h 50 | status.cc 51 | status.h 52 | status_or.h) 53 | 54 | target_include_directories( 55 | gax 56 | PUBLIC $ 57 | $) 58 | 59 | set_target_properties( 60 | gax 61 | PROPERTIES VERSION ${GAX_VERSION} SOVERSION 62 | ${GAX_VERSION_MAJOR}) 63 | 64 | target_link_libraries(gax PUBLIC googleapis-c++::longrunning_operations_protos) 65 | 66 | # Export the CMake targets to make it easy to create configuration files. 67 | install(EXPORT gax-targets 68 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/gax") 69 | 70 | install( 71 | TARGETS gax 72 | EXPORT gax-targets 73 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} 74 | COMPONENT gax_runtime 75 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 76 | COMPONENT gax_runtime 77 | NAMELINK_SKIP 78 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 79 | COMPONENT gax_development) 80 | # With CMake-3.12 and higher we could avoid this separate command (and the 81 | # duplication). 82 | install( 83 | TARGETS gax 84 | LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 85 | COMPONENT gax_development 86 | NAMELINK_ONLY 87 | ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} 88 | COMPONENT gax_development) 89 | 90 | gax_install_headers(gax include/gax) 91 | 92 | if (BUILD_TESTING) 93 | set(gax_unit_tests 94 | # cmake-format: sortable 95 | backoff_policy_test.cc 96 | operations_stub_test.cc 97 | operation_test.cc 98 | pagination_test.cc 99 | retry_loop_test.cc 100 | retry_policy_test.cc 101 | status_or_test.cc 102 | status_test.cc 103 | ) 104 | foreach (fname ${gax_unit_tests}) 105 | string(REPLACE "/" "_" target ${fname}) 106 | string(REPLACE ".cc" "" target ${target}) 107 | add_executable(${target} ${fname}) 108 | target_link_libraries( 109 | ${target} 110 | PRIVATE gax 111 | GTest::gmock_main GTest::gmock GTest::gtest) 112 | if (MSVC) 113 | target_compile_options(${target} PRIVATE "/bigobj") 114 | endif () 115 | add_test(NAME ${target} COMMAND ${target}) 116 | endforeach () 117 | endif() 118 | 119 | # Create and install the CMake configuration files. 120 | configure_file("config.cmake.in" "gax-config.cmake" @ONLY) 121 | configure_file("config-version.cmake.in" 122 | "gax-config-version.cmake" @ONLY) 123 | install( 124 | FILES 125 | "${CMAKE_CURRENT_BINARY_DIR}/gax-config.cmake" 126 | "${CMAKE_CURRENT_BINARY_DIR}/gax-config-version.cmake" 127 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/gax") 128 | -------------------------------------------------------------------------------- /gax/backoff_policy_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/backoff_policy.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace google { 22 | namespace gax { 23 | 24 | TEST(ExponentialBackoffPolicy, Basic) { 25 | ExponentialBackoffPolicy tested(std::chrono::milliseconds(1), 26 | std::chrono::milliseconds(32)); 27 | 28 | for (int i = 0; i < 5; ++i) { 29 | auto base_delay = tested.current_delay_range_; 30 | EXPECT_EQ(base_delay, std::chrono::milliseconds(1 << i)); 31 | auto delay = tested.OnCompletion(); 32 | EXPECT_GE(delay, base_delay / 2.0); 33 | EXPECT_LE(delay, base_delay); 34 | } 35 | 36 | EXPECT_EQ(tested.current_delay_range_, tested.maximum_delay_); 37 | // current_delay_range_ saturates to max delay. 38 | tested.OnCompletion(); 39 | EXPECT_EQ(tested.current_delay_range_, tested.maximum_delay_); 40 | } 41 | 42 | TEST(ExponentialBackoffPolicy, CopyConstruct) { 43 | ExponentialBackoffPolicy tested(std::chrono::milliseconds(10), 44 | std::chrono::milliseconds(320)); 45 | tested.OnCompletion(); 46 | ExponentialBackoffPolicy copy( 47 | tested); // Copy starts with fresh backoff delays 48 | 49 | EXPECT_EQ(copy.current_delay_range_, std::chrono::milliseconds(10)); 50 | EXPECT_EQ(copy.maximum_delay_, std::chrono::milliseconds(320)); 51 | } 52 | 53 | TEST(ExponentialBackoffPolicy, MoveConstruct) { 54 | ExponentialBackoffPolicy tested(std::chrono::milliseconds(10), 55 | std::chrono::milliseconds(320)); 56 | tested.OnCompletion(); 57 | ExponentialBackoffPolicy moved( 58 | std::move(tested)); // Starts with fresh backoff delays 59 | 60 | EXPECT_EQ(moved.current_delay_range_, std::chrono::milliseconds(10)); 61 | EXPECT_EQ(moved.maximum_delay_, std::chrono::milliseconds(320)); 62 | } 63 | 64 | TEST(ExponentialBackoffPolicy, Clone) { 65 | ExponentialBackoffPolicy tested(std::chrono::milliseconds(10), 66 | std::chrono::milliseconds(320)); 67 | tested.OnCompletion(); 68 | std::unique_ptr clone = tested.clone(); 69 | 70 | // We need to check that the clone method has the right signature, but we also 71 | // need to check that the clone attributes have the right initial values. 72 | auto cast_clone = std::unique_ptr( 73 | static_cast(clone.release())); 74 | 75 | EXPECT_EQ(cast_clone->current_delay_range_, std::chrono::milliseconds(10)); 76 | EXPECT_EQ(cast_clone->maximum_delay_, std::chrono::milliseconds(320)); 77 | } 78 | 79 | TEST(ExponentialBackoffPolicy, LazyGenerator) { 80 | ExponentialBackoffPolicy tested(std::chrono::milliseconds(10), 81 | std::chrono::milliseconds(320)); 82 | EXPECT_EQ(tested.generator_, nullptr); 83 | tested.OnCompletion(); 84 | EXPECT_NE(tested.generator_, nullptr); 85 | 86 | // Copies and clones use their own lazily constructed generators 87 | ExponentialBackoffPolicy copy(tested); 88 | EXPECT_EQ(copy.generator_, nullptr); 89 | copy.OnCompletion(); 90 | EXPECT_NE(copy.generator_, nullptr); 91 | 92 | auto clone = std::unique_ptr( 93 | static_cast(copy.clone().release())); 94 | EXPECT_EQ(clone->generator_, nullptr); 95 | clone->OnCompletion(); 96 | EXPECT_NE(clone->generator_, nullptr); 97 | 98 | // Moves reuse the existing generator 99 | ExponentialBackoffPolicy move(std::move(tested)); 100 | EXPECT_NE(move.generator_, nullptr); 101 | } 102 | 103 | } // namespace gax 104 | } // namespace google 105 | -------------------------------------------------------------------------------- /gax/operations_client.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef GAPIC_GENERATOR_CPP_GAX_OPERATIONS_CLIENT_H_ 15 | #define GAPIC_GENERATOR_CPP_GAX_OPERATIONS_CLIENT_H_ 16 | 17 | #include "gax/operation.h" 18 | #include "gax/operations_stub.h" 19 | #include "gax/status.h" 20 | #include 21 | #include 22 | 23 | namespace google { 24 | namespace gax { 25 | 26 | /** 27 | * A client used to interact with long running operation objects. 28 | * 29 | * If a GAPIC client method returns a gax::Operation as a result, further 30 | * interactions with that result use the corresponding OperationsClient. 31 | * Users can poll, cancel, or delete operations. 32 | */ 33 | class OperationsClient final { 34 | public: 35 | // Note: the intended generation of an OperationsClient is via a GAPIC client 36 | // factory method, NOT by manual construction by the user. 37 | // Example: 38 | // 39 | // LibraryClient client(CreateLibraryServiceStub()); 40 | // OperationsClient operationsClient = client.OperationsClient(); 41 | OperationsClient(std::shared_ptr stub) 42 | : stub_(std::move(stub)) {} 43 | 44 | /** 45 | * @brief Ping the server and check if the operation has finished. 46 | * 47 | * Updates metadata. 48 | * 49 | * @return a status indicating whether the update was successful. 50 | */ 51 | template 52 | gax::Status Update(gax::Operation& op) { 53 | if (op.Done()) { 54 | return gax::Status{}; 55 | } 56 | 57 | google::longrunning::GetOperationRequest request; 58 | google::longrunning::Operation tmp; 59 | request.set_name(op.Name()); 60 | gax::CallContext context(get_operation_info); 61 | auto status = stub_->GetOperation(context, request, &tmp); 62 | 63 | if (status.IsOk()) { 64 | op = gax::Operation(std::move(tmp)); 65 | } 66 | 67 | return status; 68 | } 69 | 70 | /** 71 | * @brief Inform the service that the client is no longer interested in the 72 | * result. 73 | * 74 | * @return a status indicating whether the rpc was successful. 75 | */ 76 | template 77 | gax::Status Delete(gax::Operation const& op) { 78 | google::longrunning::DeleteOperationRequest request; 79 | google::protobuf::Empty empty; 80 | request.set_name(op.Name()); 81 | gax::CallContext context(delete_operation_info); 82 | return stub_->DeleteOperation(context, request, &empty); 83 | } 84 | 85 | /** 86 | * @brief Best-effort cancellation attempt of the operation. 87 | * 88 | * @return a status indicating whether the rpc was successful. 89 | */ 90 | template 91 | gax::Status Cancel(gax::Operation const& op) { 92 | google::longrunning::CancelOperationRequest request; 93 | google::protobuf::Empty empty; 94 | request.set_name(op.Name()); 95 | gax::CallContext context(cancel_operation_info); 96 | return stub_->CancelOperation(context, request, &empty); 97 | } 98 | 99 | static constexpr MethodInfo get_operation_info = { 100 | "GetOperation", MethodInfo::RpcType::NORMAL_RPC, 101 | MethodInfo::Idempotency::IDEMPOTENT}; 102 | static constexpr MethodInfo delete_operation_info = { 103 | "DeleteOperation", MethodInfo::RpcType::NORMAL_RPC, 104 | MethodInfo::Idempotency::IDEMPOTENT}; 105 | static constexpr MethodInfo cancel_operation_info = { 106 | "CancelOperation", MethodInfo::RpcType::NORMAL_RPC, 107 | MethodInfo::Idempotency::IDEMPOTENT}; 108 | 109 | private: 110 | std::shared_ptr stub_; 111 | }; 112 | 113 | } // namespace gax 114 | } // namespace google 115 | 116 | #endif // GAPIC_GENERATOR_CPP_GAX_OPERATIONS_CLIENT_H_ 117 | -------------------------------------------------------------------------------- /generator/testdata/google/example/library/v1/library_service.gapic.cc.baseline: -------------------------------------------------------------------------------- 1 | // Generated by the GAPIC C++ plugin. 2 | // If you make any local changes, they will be lost. 3 | // source: generator/testdata/library.proto 4 | #include "google/example/library/v1/library_service.gapic.h" 5 | #include "google/example/library/v1/library_service_stub.gapic.h" 6 | #include "gax/call_context.h" 7 | #include "gax/status.h" 8 | #include "gax/status_or.h" 9 | 10 | google::gax::StatusOr<::google::example::library::v1::Book> 11 | LibraryService::CreateBook( 12 | ::google::example::library::v1::CreateBookRequest const& request) { 13 | google::gax::CallContext context(create_book_info); 14 | if (retry_policy_) { 15 | context.SetRetryPolicy(*retry_policy_); 16 | } 17 | if (backoff_policy_) { 18 | context.SetBackoffPolicy(*backoff_policy_); 19 | } 20 | ::google::example::library::v1::Book response; 21 | google::gax::Status status = stub_->CreateBook(context, request, &response); 22 | if (status.IsOk()) { 23 | return response; 24 | } else { 25 | return status; 26 | } 27 | } 28 | 29 | google::gax::StatusOr<::google::example::library::v1::Book> 30 | LibraryService::GetBook( 31 | ::google::example::library::v1::GetBookRequest const& request) { 32 | google::gax::CallContext context(get_book_info); 33 | if (retry_policy_) { 34 | context.SetRetryPolicy(*retry_policy_); 35 | } 36 | if (backoff_policy_) { 37 | context.SetBackoffPolicy(*backoff_policy_); 38 | } 39 | ::google::example::library::v1::Book response; 40 | google::gax::Status status = stub_->GetBook(context, request, &response); 41 | if (status.IsOk()) { 42 | return response; 43 | } else { 44 | return status; 45 | } 46 | } 47 | 48 | google::gax::StatusOr<::google::example::library::v1::ListBooksResponse> 49 | LibraryService::ListBooks( 50 | ::google::example::library::v1::ListBooksRequest const& request) { 51 | google::gax::CallContext context(list_books_info); 52 | if (retry_policy_) { 53 | context.SetRetryPolicy(*retry_policy_); 54 | } 55 | if (backoff_policy_) { 56 | context.SetBackoffPolicy(*backoff_policy_); 57 | } 58 | ::google::example::library::v1::ListBooksResponse response; 59 | google::gax::Status status = stub_->ListBooks(context, request, &response); 60 | if (status.IsOk()) { 61 | return response; 62 | } else { 63 | return status; 64 | } 65 | } 66 | 67 | google::gax::StatusOr<::google::example::library::v1::Empty> 68 | LibraryService::DeleteBook( 69 | ::google::example::library::v1::DeleteBookRequest const& request) { 70 | google::gax::CallContext context(delete_book_info); 71 | if (retry_policy_) { 72 | context.SetRetryPolicy(*retry_policy_); 73 | } 74 | if (backoff_policy_) { 75 | context.SetBackoffPolicy(*backoff_policy_); 76 | } 77 | ::google::example::library::v1::Empty response; 78 | google::gax::Status status = stub_->DeleteBook(context, request, &response); 79 | if (status.IsOk()) { 80 | return response; 81 | } else { 82 | return status; 83 | } 84 | } 85 | 86 | google::gax::StatusOr<::google::example::library::v1::Book> 87 | LibraryService::UpdateBook( 88 | ::google::example::library::v1::UpdateBookRequest const& request) { 89 | google::gax::CallContext context(update_book_info); 90 | if (retry_policy_) { 91 | context.SetRetryPolicy(*retry_policy_); 92 | } 93 | if (backoff_policy_) { 94 | context.SetBackoffPolicy(*backoff_policy_); 95 | } 96 | ::google::example::library::v1::Book response; 97 | google::gax::Status status = stub_->UpdateBook(context, request, &response); 98 | if (status.IsOk()) { 99 | return response; 100 | } else { 101 | return status; 102 | } 103 | } 104 | 105 | google::gax::StatusOr<::google::example::library::v1::Book> 106 | LibraryService::GetBigBook( 107 | ::google::example::library::v1::GetBookRequest const& request) { 108 | google::gax::CallContext context(get_big_book_info); 109 | if (retry_policy_) { 110 | context.SetRetryPolicy(*retry_policy_); 111 | } 112 | if (backoff_policy_) { 113 | context.SetBackoffPolicy(*backoff_policy_); 114 | } 115 | ::google::example::library::v1::Book response; 116 | google::gax::Status status = stub_->GetBigBook(context, request, &response); 117 | if (status.IsOk()) { 118 | return response; 119 | } else { 120 | return status; 121 | } 122 | } 123 | 124 | constexpr google::gax::MethodInfo LibraryService::create_book_info; 125 | constexpr google::gax::MethodInfo LibraryService::get_book_info; 126 | constexpr google::gax::MethodInfo LibraryService::list_books_info; 127 | constexpr google::gax::MethodInfo LibraryService::delete_book_info; 128 | constexpr google::gax::MethodInfo LibraryService::update_book_info; 129 | constexpr google::gax::MethodInfo LibraryService::get_big_book_info; 130 | -------------------------------------------------------------------------------- /gax/operation.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_OPERATION_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_OPERATION_H_ 17 | 18 | #include "google/longrunning/operations.pb.h" 19 | #include "gax/call_context.h" 20 | #include "gax/operations_stub.h" 21 | #include "gax/status.h" 22 | #include "gax/status_or.h" 23 | #include 24 | 25 | namespace google { 26 | namespace gax { 27 | 28 | /** 29 | * Operation is a user-visible primitive used to support Long Running Operations 30 | * (LROs). 31 | * 32 | * LROs are service methods that may take a 'long time' (anywhere from 33 | * seconds to days), and instead of blocking for that long return an Operation 34 | * object or an error status. The Operation may contain a result and always 35 | * contains metadata. 36 | * 37 | * A service method that returns `google.longrunning.Operation` and that has 38 | * the correct annotations for its result and metadata types will cause the 39 | * generator to define a client method that returns 40 | * gax::StatusOr>. 41 | * 42 | * Example usage: 43 | * 44 | * @code 45 | * gax::StatusOr> res = 46 | * client.GetBigFoo(getBigFooRequest); 47 | * if(!res) { 48 | * ... 49 | * } 50 | * 51 | * operationsClient = client.OperationsClient(); 52 | * Operation op = *std::move(res); 53 | * while(!op.Done()) { 54 | * gax::Status stat = operationsClient.Update(op); 55 | * if(isPermanentFailure(stat)) { 56 | * ... 57 | * } 58 | * std::cout << "Foo request " << getBigFooRequest().name() << " is " << 59 | * op.Metadata().percent() << "% done."; 60 | * std::this_thread::sleep(sleep_period()); 61 | * } 62 | * 63 | * gax::StatusOr terminus = op.Result(); 64 | * if(!terminus) { 65 | * ... 66 | * } 67 | * Result r = *std::move(terminus); 68 | * @endcode 69 | */ 70 | template < 71 | typename ResponseT, typename MetadataT, 72 | typename std::enable_if< 73 | std::is_base_of::value, int>::type = 0, 74 | typename std::enable_if< 75 | std::is_base_of::value, int>::type = 0> 76 | class Operation final { 77 | public: 78 | // Note: the constructor is intended to be used by GAPIC generated code, not 79 | // users. 80 | explicit Operation(google::longrunning::Operation op) : op_(std::move(op)) {} 81 | 82 | /** 83 | * @brief Return the service-provided name of the underlying 84 | * google.longrunning.Operation 85 | */ 86 | std::string const& Name() const { return op_.name(); } 87 | 88 | /** 89 | * @brief If Operation::Done(), return the underlying Response, or an error 90 | * code if a problem occurred. Otherwise return an error indicating that the 91 | * Operation has not completed. 92 | */ 93 | gax::StatusOr Result() const { 94 | if (!Done()) { 95 | return gax::Status{gax::StatusCode::kUnknown, 96 | "operation has not completed=" + Name()}; 97 | } else if (op_.has_error()) { 98 | return gax::Status{static_cast(op_.error().code()), 99 | op_.error().message()}; 100 | } else { 101 | auto const& any = op_.response(); 102 | if (!any.Is()) { 103 | return gax::Status{gax::StatusCode::kUnknown, 104 | "invalid result in operation=" + Name()}; 105 | } 106 | 107 | ResponseT result; 108 | any.UnpackTo(&result); 109 | return std::move(result); 110 | } 111 | } 112 | 113 | /** 114 | * @brief Return the most recent metadata received from the service. 115 | * 116 | * The metadata type is application specific. Manipulating it is left to the 117 | * user. 118 | * 119 | * @return the most recent metadata. 120 | */ 121 | MetadataT Metadata() const { 122 | MetadataT m; 123 | op_.metadata().UnpackTo(&m); 124 | return m; 125 | } 126 | 127 | /** 128 | * @brief Indicate whether the operation has completed. If true, the Operation 129 | * now contains a result or an error status. 130 | */ 131 | bool Done() const { return op_.done(); } 132 | 133 | private: 134 | google::longrunning::Operation op_; 135 | }; 136 | 137 | } // namespace gax 138 | } // namespace google 139 | 140 | #endif // GAPIC_GENERATOR_CPP_GAX_OPERATION_H_ 141 | -------------------------------------------------------------------------------- /gax/retry_loop_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/retry_loop.h" 16 | #include "google/longrunning/operations.pb.h" 17 | #include "gax/backoff_policy.h" 18 | #include "gax/call_context.h" 19 | #include "gax/internal/test_clock.h" 20 | #include "gax/retry_policy.h" 21 | #include 22 | #include 23 | 24 | namespace { 25 | using namespace ::google; 26 | 27 | class DummyBackoffPolicy : public gax::BackoffPolicy { 28 | public: 29 | // Hack to count the number of backoff attempts. 30 | int& delay_count_; 31 | DummyBackoffPolicy(int& delay_count) : delay_count_(delay_count) {} 32 | 33 | std::chrono::microseconds OnCompletion() override { 34 | delay_count_++; 35 | return std::chrono::microseconds(0); 36 | } 37 | std::unique_ptr clone() const override { 38 | return std::unique_ptr( 39 | new DummyBackoffPolicy(delay_count_)); 40 | } 41 | }; 42 | 43 | std::unique_ptr DummyBackoffFactory(int& delay_count) { 44 | return std::unique_ptr( 45 | new DummyBackoffPolicy(delay_count)); 46 | } 47 | 48 | std::unique_ptr ErrCountRetryFactory( 49 | int n, std::chrono::system_clock::time_point& now_point) { 50 | return std::unique_ptr< 51 | gax::LimitedErrorCountRetryPolicy>( 52 | new gax::LimitedErrorCountRetryPolicy( 53 | n, std::chrono::milliseconds(2), now_point)); 54 | } 55 | 56 | TEST(RetryLoop, Basic) { 57 | gax::MethodInfo mi{"TestMethod", gax::MethodInfo::RpcType::CLIENT_STREAMING, 58 | gax::MethodInfo::Idempotency::IDEMPOTENT}; 59 | gax::CallContext context(mi); 60 | longrunning::GetOperationRequest req; 61 | longrunning::Operation resp; 62 | std::chrono::system_clock::time_point now_point; 63 | 64 | int attempts_remaining = 3; 65 | auto fail_until = [&attempts_remaining, &context]( 66 | gax::CallContext& ctx, longrunning::GetOperationRequest const& req, 67 | longrunning::Operation* resp) { 68 | // Make sure each retry has a fresh context. 69 | EXPECT_NE(&context, &ctx); 70 | return ((attempts_remaining--) > 1) 71 | ? gax::Status(gax::StatusCode::kAborted, "Aborted") 72 | : gax::Status{}; 73 | }; 74 | 75 | int delay_count = 0; 76 | gax::Status succeed = gax::MakeRetryCall( 78 | context, req, &resp, fail_until, ErrCountRetryFactory(10, now_point), 79 | DummyBackoffFactory(delay_count)); 80 | EXPECT_EQ(attempts_remaining, 0); 81 | EXPECT_EQ(succeed, gax::Status()); 82 | EXPECT_EQ(delay_count, 2); 83 | 84 | delay_count = 0; 85 | attempts_remaining = 10; 86 | gax::Status retry_timeout = 87 | gax::MakeRetryCall( 89 | context, req, &resp, fail_until, ErrCountRetryFactory(3, now_point), 90 | DummyBackoffFactory(delay_count)); 91 | EXPECT_EQ(retry_timeout, gax::Status(gax::StatusCode::kAborted, "Aborted")); 92 | EXPECT_EQ(attempts_remaining, 6); 93 | EXPECT_EQ(delay_count, 3); 94 | } 95 | 96 | TEST(RetryLoop, OperationDeadline) { 97 | gax::MethodInfo mi{"TestMethod", gax::MethodInfo::RpcType::CLIENT_STREAMING, 98 | gax::MethodInfo::Idempotency::IDEMPOTENT}; 99 | gax::CallContext context(mi); 100 | longrunning::GetOperationRequest req; 101 | longrunning::Operation resp; 102 | int delay_count = 0; 103 | std::chrono::system_clock::time_point now_point; 104 | 105 | auto check_updated_deadline = [&now_point]( 106 | gax::CallContext& ctx, longrunning::GetOperationRequest const& req, 107 | longrunning::Operation* resp) { 108 | grpc::ClientContext test_context; 109 | ctx.PrepareGrpcContext(&test_context); 110 | 111 | EXPECT_EQ(test_context.deadline(), 112 | now_point + std::chrono::milliseconds(2)); 113 | // Double check that we're not setting the deadline from a static 114 | // target. 115 | now_point += std::chrono::milliseconds(30); 116 | // Need to fail in a retryable manner promote retry. 117 | return gax::Status(gax::StatusCode::kAborted, "Aborted"); 118 | }; 119 | 120 | gax::MakeRetryCall( 121 | context, req, &resp, check_updated_deadline, 122 | ErrCountRetryFactory(3, now_point), DummyBackoffFactory(delay_count)); 123 | } 124 | 125 | } // namespace 126 | -------------------------------------------------------------------------------- /gax/pagination_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/pagination.h" 16 | #include "google/longrunning/operations.pb.h" 17 | #include "gax/status.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace { 26 | 27 | using namespace ::google; 28 | 29 | class OperationsAccessor { 30 | public: 31 | protobuf::RepeatedPtrField* operator()( 32 | longrunning::ListOperationsResponse& lor) const { 33 | return lor.mutable_operations(); 34 | } 35 | }; 36 | 37 | class PageRetriever { 38 | public: 39 | // Start at 1 to count number of pages seen total, including the first. 40 | PageRetriever(int max_pages) : i_(1), max_pages_(max_pages) {} 41 | gax::Status operator()(longrunning::ListOperationsResponse* lor) { 42 | if (i_ < max_pages_) { 43 | std::stringstream ss; 44 | ss << "NextPage" << i_; 45 | lor->set_next_page_token(ss.str()); 46 | i_++; 47 | } else { 48 | lor->clear_next_page_token(); 49 | } 50 | 51 | return gax::Status{}; 52 | } 53 | 54 | private: 55 | int i_; 56 | const int max_pages_; 57 | }; 58 | 59 | using TestPages = 60 | gax::Pages; 62 | 63 | using TestedPageResult = 64 | gax::PageResult; 66 | 67 | TestedPageResult MakeTestedPageResult(int num_pages = 10) { 68 | longrunning::ListOperationsResponse response; 69 | response.set_next_page_token("NextPage"); 70 | 71 | for (int i = 0; i < num_pages; i++) { 72 | std::stringstream ss; 73 | ss << "TestOperation" << i; 74 | auto operation = response.add_operations(); 75 | operation->set_name(ss.str()); 76 | } 77 | 78 | return TestedPageResult(std::move(response)); 79 | } 80 | 81 | TEST(PageResult, RawPage) { 82 | TestedPageResult page_result = MakeTestedPageResult(); 83 | 84 | EXPECT_EQ(page_result.NextPageToken(), "NextPage"); 85 | EXPECT_EQ(page_result.NextPageToken(), 86 | page_result.RawPage().next_page_token()); 87 | EXPECT_EQ(page_result.RawPage().operations_size(), 10); 88 | } 89 | 90 | TEST(PageResult, Accessors) { 91 | TestedPageResult page_result = MakeTestedPageResult(); 92 | EXPECT_EQ((*page_result.begin()).name(), "TestOperation0"); 93 | EXPECT_EQ(page_result.begin()->name(), "TestOperation0"); 94 | } 95 | 96 | TEST(PageResult, BasicIteration) { 97 | TestedPageResult page_result = MakeTestedPageResult(); 98 | auto prIt = page_result.begin(); 99 | auto reIt = page_result.RawPage().operations().begin(); 100 | for (; prIt != page_result.end() && 101 | reIt != page_result.RawPage().operations().end(); 102 | ++prIt, ++reIt) { 103 | // Note: cannot use EXPECT_EQ for the elements or on vectors constructed 104 | // from the respective iterators because messages do not define operator== 105 | // as a member function. 106 | EXPECT_TRUE(protobuf::util::MessageDifferencer::Equals(*prIt, *reIt)); 107 | } 108 | EXPECT_EQ(prIt, page_result.end()); 109 | EXPECT_EQ(reIt, page_result.RawPage().operations().end()); 110 | } 111 | 112 | TEST(PageResult, MoveIteration) { 113 | TestedPageResult page_result = MakeTestedPageResult(); 114 | std::vector ops{ 115 | std::move_iterator(page_result.begin()), 116 | std::move_iterator(page_result.end())}; 117 | EXPECT_EQ(page_result.begin()->name(), ""); 118 | } 119 | 120 | TEST(Pages, Basic) { 121 | TestPages terminal( 122 | // The output param is pristine, which means its next_page_token 123 | // is empty. 124 | PageRetriever(0)); 125 | 126 | EXPECT_EQ(terminal.begin(), terminal.end()); 127 | EXPECT_EQ(terminal.end()->NextPageToken(), ""); 128 | } 129 | 130 | TEST(Pages, Iteration) { 131 | int i = 1; 132 | TestPages pages(PageRetriever(10)); 133 | for (auto const& p : pages) { 134 | std::stringstream ss; 135 | ss << "NextPage" << i; 136 | 137 | EXPECT_EQ(p.NextPageToken(), ss.str()); 138 | i++; 139 | } 140 | EXPECT_EQ(i, 10); 141 | } 142 | 143 | TEST(Pages, PageCap) { 144 | int i = 1; 145 | TestPages pages(PageRetriever(10), 5); 146 | auto iter = pages.begin(); 147 | for (; iter != pages.end(); ++iter) { 148 | std::stringstream ss; 149 | ss << "NextPage" << i; 150 | 151 | EXPECT_EQ(iter->NextPageToken(), ss.str()); 152 | i++; 153 | } 154 | EXPECT_EQ(i, 5); 155 | EXPECT_EQ(iter->NextPageToken(), "NextPage5"); 156 | } 157 | 158 | } // namespace 159 | -------------------------------------------------------------------------------- /ci/kokoro/docker/e2e/Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | FROM ubuntu:18.04 16 | ARG NCPU=4 17 | 18 | # Dependencies 19 | RUN \ 20 | apt-get update && \ 21 | apt-get -y install \ 22 | autoconf \ 23 | build-essential \ 24 | clang-tidy \ 25 | cmake \ 26 | curl \ 27 | gcc \ 28 | git-core \ 29 | golang \ 30 | g++ \ 31 | libtool \ 32 | libssl-dev \ 33 | make \ 34 | pkg-config \ 35 | wget \ 36 | vim \ 37 | zip \ 38 | zlib1g-dev 39 | 40 | WORKDIR /build 41 | 42 | # Install c-ares 43 | RUN \ 44 | wget -q https://github.com/c-ares/c-ares/archive/cares-1_15_0.tar.gz && \ 45 | tar -xf cares-1_15_0.tar.gz && \ 46 | cd c-ares-cares-1_15_0 && \ 47 | cmake \ 48 | -DCMAKE_BUILD_TYPE=Release \ 49 | -DBUILD_SHARED_LIBS=yes \ 50 | -DCMAKE_INSTALL_PREFIX=/usr/local \ 51 | -H. -Bcmake-out && \ 52 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 53 | cmake --build cmake-out --target install && \ 54 | ldconfig 55 | 56 | # Install protobuf 57 | RUN \ 58 | wget -q https://github.com/google/protobuf/archive/v3.11.2.tar.gz && \ 59 | tar -xf v3.11.2.tar.gz && \ 60 | cd protobuf-3.11.2/cmake && \ 61 | cmake \ 62 | -DCMAKE_BUILD_TYPE=Release \ 63 | -DBUILD_SHARED_LIBS=yes \ 64 | -Dprotobuf_BUILD_TESTS=OFF \ 65 | -H. -Bcmake-out && \ 66 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 67 | cmake --build cmake-out --target install -- && \ 68 | ldconfig 69 | 70 | # Install gRPC 71 | RUN \ 72 | wget -q https://github.com/grpc/grpc/archive/v1.26.0.tar.gz && \ 73 | tar -xf v1.26.0.tar.gz && \ 74 | cd grpc-1.26.0 && \ 75 | cmake \ 76 | -DgRPC_CARES_PROVIDER=package \ 77 | -DgRPC_PROTOBUF_PROVIDER=package \ 78 | -DgRPC_SSL_PROVIDER=package \ 79 | -DgRPC_ZLIB_PROVIDER=package \ 80 | -DgRPC_INSTALL=on \ 81 | -H. -Bcmake-out && \ 82 | cd cmake-out && \ 83 | CONFIG=dbg make -j ${NCPU:-4} && \ 84 | CONFIG=dbg make install 85 | 86 | # Install abseil 87 | RUN \ 88 | wget -q https://github.com/abseil/abseil-cpp/archive/20190808.tar.gz && \ 89 | tar -xf 20190808.tar.gz && \ 90 | cd abseil-cpp-20190808 && \ 91 | cmake \ 92 | -DBUILD_SHARED_LIBS=yes \ 93 | -H. -Bcmake-out && \ 94 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 95 | cmake --build cmake-out --target install && \ 96 | ldconfig 97 | 98 | # Install cpp-cmakefiles 99 | RUN \ 100 | wget -q \ 101 | https://github.com/googleapis/cpp-cmakefiles/archive/v0.2.1.tar.gz && \ 102 | tar zxvf v0.2.1.tar.gz && \ 103 | cd cpp-cmakefiles-0.2.1 && \ 104 | cmake \ 105 | -DBUILD_SHARED_LIBS=yes \ 106 | -H. -Bcmake-out && \ 107 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 108 | cmake --build cmake-out --target install && \ 109 | ldconfig 110 | 111 | # Install GTest 112 | RUN \ 113 | wget -q \ 114 | https://github.com/google/googletest/archive/release-1.10.0.tar.gz && \ 115 | tar -xf release-1.10.0.tar.gz && \ 116 | cd googletest-release-1.10.0 && \ 117 | cmake \ 118 | -DCMAKE_BUILD_TYPE="Release" \ 119 | -DBUILD_SHARED_LIBS=yes \ 120 | -H. -Bcmake-out && \ 121 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 122 | cmake --build cmake-out --target install -- -j ${NCPU:-4} && \ 123 | ldconfig 124 | 125 | # Install gax 126 | COPY . /build/gapic-generator-cpp/ 127 | RUN \ 128 | cd /build/gapic-generator-cpp && \ 129 | cmake \ 130 | -DBUILD_SHARED_LIBS=on \ 131 | -H. -Bcmake-out && \ 132 | cmake --build cmake-out -- -j ${NCPU:-4} && \ 133 | (cd cmake-out; ctest) && \ 134 | cmake --build cmake-out --target install && \ 135 | ldconfig 136 | 137 | # Install bazel 138 | RUN /build/gapic-generator-cpp/ci/install-bazel.sh linux 139 | 140 | # Build gapic plugin 141 | RUN \ 142 | cd /build/gapic-generator-cpp && \ 143 | /root/bin/bazel build //... 144 | 145 | # Use the newer googleapis repo for default_host option 146 | RUN \ 147 | git clone https://github.com/googleapis/googleapis 148 | 149 | # Run protoc with all the plugin 150 | ENV GOOGLEAPIS_PATH=/build/googleapis 151 | RUN \ 152 | protoc --proto_path=${GOOGLEAPIS_PATH} \ 153 | --cpp_out=/build/gapic-generator-cpp/ci/kokoro/docker/e2e \ 154 | --grpc_out=/build/gapic-generator-cpp/ci/kokoro/docker/e2e \ 155 | --cpp_gapic_out=/build/gapic-generator-cpp/ci/kokoro/docker/e2e \ 156 | --plugin=protoc-gen-grpc=/usr/local/bin/grpc_cpp_plugin \ 157 | --plugin=protoc-gen-cpp_gapic=/build/gapic-generator-cpp/bazel-bin/generator/protoc-gen-cpp_gapic \ 158 | ${GOOGLEAPIS_PATH}/google/spanner/admin/instance/v1/spanner_instance_admin.proto 159 | 160 | # Compile the generated files 161 | RUN \ 162 | cd /build/gapic-generator-cpp/ci/kokoro/docker/e2e && \ 163 | cmake -H. -Bcmake-out && \ 164 | cmake --build cmake-out -- -j ${NCPU:-4} 165 | -------------------------------------------------------------------------------- /generator/internal/client_header_generator.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "generator/internal/client_header_generator.h" 16 | #include "generator/internal/data_model.h" 17 | #include "generator/internal/gapic_utils.h" 18 | #include "generator/internal/printer.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | namespace pb = google::protobuf; 25 | 26 | namespace google { 27 | namespace api { 28 | namespace codegen { 29 | namespace internal { 30 | 31 | std::vector BuildClientHeaderIncludes( 32 | pb::ServiceDescriptor const* service) { 33 | return { 34 | SystemInclude("memory"), 35 | LocalInclude(absl::StrCat( 36 | internal::ServiceNameToFilePath(service->name()), "_stub.gapic.h")), 37 | LocalInclude(absl::StrCat( 38 | absl::StripSuffix(service->file()->name(), ".proto"), ".pb.h")), 39 | 40 | LocalInclude("gax/status_or.h"), LocalInclude("gax/retry_policy.h"), 41 | LocalInclude("gax/backoff_policy.h"), 42 | }; 43 | } 44 | 45 | std::vector BuildClientHeaderNamespaces( 46 | pb::ServiceDescriptor const* /* service */) { 47 | return std::vector(); 48 | } 49 | 50 | bool GenerateClientHeader(pb::ServiceDescriptor const* service, 51 | std::map const& vars, 52 | Printer& p, std::string* /* error */) { 53 | auto includes = BuildClientHeaderIncludes(service); 54 | auto namespaces = BuildClientHeaderNamespaces(service); 55 | 56 | p->Print(vars, 57 | "// Generated by the GAPIC C++ plugin.\n" 58 | "// If you make any local changes, they will be lost.\n" 59 | "// source: $proto_file_name$\n" 60 | "#ifndef $header_include_guard_const$\n" 61 | "#define $header_include_guard_const$\n" 62 | "\n"); 63 | 64 | for (auto include : includes) { 65 | p->Print("#include $include$\n", "include", include); 66 | } 67 | 68 | for (auto nspace : namespaces) { 69 | p->Print("namespace $namespace$ {\n", "namespace", nspace); 70 | } 71 | 72 | p->Print(vars, 73 | "\n" 74 | "$class_comment_block$\n" 75 | "class $class_name$ final {\n" 76 | " public:\n" 77 | " $class_name$(std::shared_ptr<$stub_class_name$> stub) : \n" 78 | " stub_(std::move(stub)) {}\n" 79 | "\n" 80 | " template\n" 81 | " $class_name$(std::shared_ptr<$stub_class_name$> stub, \n" 82 | " Policies&&... policies) : $class_name$(std::move(stub)) {\n" 83 | " ChangePolicies(std::forward...);\n" 84 | " }\n" 85 | "\n" 86 | " $class_name$($class_name$ const&) = delete;\n" 87 | " $class_name$& operator=($class_name$ const&) = delete;\n" 88 | "\n" 89 | " std::shared_ptr<$stub_class_name$> Stub() { return stub_; }\n" 90 | "\n"); 91 | 92 | DataModel::PrintMethods(service, vars, p, 93 | " google::gax::StatusOr<$response_object$> \n" 94 | " $method_name$($request_object$ const& request);\n" 95 | "\n", 96 | NoStreamingPredicate); 97 | 98 | p->Print(vars, 99 | "\n" 100 | " private:\n" 101 | " void ChangePolicy(google::gax::RetryPolicy const& policy) {\n" 102 | " retry_policy_ = policy.clone();\n" 103 | " }\n" 104 | " void ChangePolicy(google::gax::BackoffPolicy const& policy) {\n" 105 | " backoff_policy_ = policy.clone();\n" 106 | " }\n" 107 | " void ChangePolicies() {}\n" 108 | "\n" 109 | " template \n" 110 | " void ChangePolicies(Policy&& policy, Policies&&... policies) {\n" 111 | " ChangePolicy(policy);\n" 112 | " ChangePolicies(std::forward(policies)...);\n" 113 | " }\n" 114 | "\n" 115 | " std::shared_ptr<$stub_class_name$> stub_;\n" 116 | " std::unique_ptr retry_policy_;\n" 117 | " std::unique_ptr backoff_policy_;\n" 118 | "\n" 119 | " // Note: conservatively assume no methods are idempotent.\n" 120 | " // This will eventually be set from annotations.\n"); 121 | 122 | DataModel::PrintMethods( 123 | service, vars, p, 124 | " static constexpr google::gax::MethodInfo $method_name_snake$_info = {" 125 | "\n" 126 | " \"$method_name$\", google::gax::MethodInfo::RpcType::NORMAL_RPC,\n" 127 | " google::gax::MethodInfo::Idempotency::NON_IDEMPOTENT};\n", 128 | NoStreamingPredicate); 129 | 130 | p->Print(vars, 131 | "}; // $class_name$\n" 132 | "\n"); 133 | 134 | for (auto nspace : namespaces) { 135 | p->Print("} // namespace $namespace$\n", "namespace", nspace); 136 | } 137 | 138 | p->Print(vars, "#endif // $header_include_guard_const$\n"); 139 | 140 | return true; 141 | } 142 | 143 | } // namespace internal 144 | } // namespace codegen 145 | } // namespace api 146 | } // namespace google 147 | -------------------------------------------------------------------------------- /gax/retry_policy.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_RETRY_POLICY_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_RETRY_POLICY_H_ 17 | 18 | #include "gax/status.h" 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | namespace google { 26 | namespace gax { 27 | 28 | /** 29 | * Define the interface for controlling how clients retry RPC operations. 30 | * 31 | * Idempotent (and certain non-idempotent) operations can be retried 32 | * transparently to the user. However, we need to give the users enough 33 | * flexiblity to control when to stop retrying. 34 | * 35 | * The application provides an instance of this class when the client is 36 | * created. 37 | */ 38 | class RetryPolicy { 39 | public: 40 | virtual ~RetryPolicy() = default; 41 | 42 | /** 43 | * Return a new copy of this object with the same retry criteria and fresh 44 | * state. 45 | */ 46 | virtual std::unique_ptr clone() const = 0; 47 | 48 | /** 49 | * Handle an RPC failure 50 | * 51 | * @return true if the RPC operation should be retried. 52 | */ 53 | virtual bool OnFailure(Status const& status) = 0; 54 | 55 | /** 56 | * Calculate the deadline for the next RPC operation. 57 | * 58 | * Any internal state modification, if neccessary, should occur in OnFailure. 59 | * 60 | * Note: this is different from the deadline in LimitedDurationRetryPolicy, 61 | * which is the deadline after which retry attempts should be abandoned. 62 | * 63 | * @return the _deadline_ for the next RPC, NOT its maximum _duration_. 64 | */ 65 | virtual std::chrono::system_clock::time_point OperationDeadline() const = 0; 66 | }; 67 | 68 | class DefaultClock { 69 | public: 70 | std::chrono::system_clock::time_point now() const { 71 | return std::chrono::system_clock::now(); 72 | } 73 | }; 74 | 75 | /** 76 | * Implement a simple "count errors and then stop" retry policy. 77 | */ 78 | template 79 | class LimitedErrorCountRetryPolicy : public RetryPolicy { 80 | public: 81 | template 82 | LimitedErrorCountRetryPolicy(int max_failures, 83 | std::chrono::duration rpc_duration, 84 | Clock c = Clock{}) 85 | : c_(std::move(c)), 86 | rpc_duration_(std::chrono::duration_cast( 87 | rpc_duration)), 88 | failure_count_(0), 89 | max_failures_(max_failures) {} 90 | 91 | LimitedErrorCountRetryPolicy(LimitedErrorCountRetryPolicy const& rhs) noexcept 92 | : LimitedErrorCountRetryPolicy(rhs.max_failures_, rhs.rpc_duration_, 93 | rhs.c_) {} 94 | 95 | LimitedErrorCountRetryPolicy(LimitedErrorCountRetryPolicy&& rhs) noexcept 96 | : LimitedErrorCountRetryPolicy(rhs.max_failures_, rhs.rpc_duration_, 97 | std::move(rhs.c_)) {} 98 | 99 | std::unique_ptr clone() const override { 100 | return std::unique_ptr( 101 | new LimitedErrorCountRetryPolicy(*this)); 102 | } 103 | 104 | bool OnFailure(Status const& status) override { 105 | return !status.IsPermanentFailure() && failure_count_++ < max_failures_; 106 | } 107 | 108 | std::chrono::system_clock::time_point OperationDeadline() const override { 109 | return c_.now() + rpc_duration_; 110 | } 111 | 112 | private: 113 | Clock c_; 114 | std::chrono::milliseconds const rpc_duration_; 115 | int failure_count_; 116 | int const max_failures_; 117 | }; 118 | 119 | /** 120 | * Implement a simple "keep trying for this time" retry policy. 121 | */ 122 | template 123 | class LimitedDurationRetryPolicy : public RetryPolicy { 124 | public: 125 | template 126 | LimitedDurationRetryPolicy(std::chrono::duration max_duration, 127 | std::chrono::duration rpc_duration, 128 | Clock c = Clock{}) 129 | : c_(std::move(c)), 130 | rpc_duration_(std::chrono::duration_cast( 131 | rpc_duration)), 132 | max_duration_(std::chrono::duration_cast( 133 | max_duration)), 134 | deadline_(max_duration_ + c_.now()) {} 135 | 136 | LimitedDurationRetryPolicy(LimitedDurationRetryPolicy const& rhs) noexcept 137 | : LimitedDurationRetryPolicy(rhs.max_duration_, rhs.rpc_duration_, 138 | rhs.c_) {} 139 | 140 | LimitedDurationRetryPolicy(LimitedDurationRetryPolicy&& rhs) noexcept 141 | : LimitedDurationRetryPolicy(rhs.max_duration_, rhs.rpc_duration_, 142 | std::move(rhs.c_)) {} 143 | 144 | std::unique_ptr clone() const override { 145 | return std::unique_ptr( 146 | new LimitedDurationRetryPolicy(*this)); 147 | } 148 | 149 | bool OnFailure(Status const& status) override { 150 | return !status.IsPermanentFailure() && c_.now() < deadline_; 151 | } 152 | 153 | std::chrono::system_clock::time_point OperationDeadline() const override { 154 | return std::min(deadline_, c_.now() + rpc_duration_); 155 | } 156 | 157 | private: 158 | Clock c_; 159 | std::chrono::milliseconds const rpc_duration_; 160 | std::chrono::milliseconds const max_duration_; 161 | std::chrono::system_clock::time_point const deadline_; 162 | }; 163 | 164 | } // namespace gax 165 | } // namespace google 166 | 167 | #endif // GAPIC_GENERATOR_CPP_GAX_RETRY_POLICY_H_ 168 | -------------------------------------------------------------------------------- /gax/backoff_policy.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_BACKOFF_POLICY_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_BACKOFF_POLICY_H_ 17 | 18 | #include "gax/internal/gtest_prod.h" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace google { 24 | namespace gax { 25 | 26 | /** 27 | * Define the interface for backoff policies. 28 | * 29 | * The client libraries need to hide partial and temporary failures from the 30 | * application. Exponential backoff is generally considered a best practice when 31 | * retrying operations. However, the details of how exponetial backoff is 32 | * implemented and tuned varies widely. We need to give the users enough 33 | * flexibility, and also provide sensible default implementations. 34 | * 35 | * The client library receives an object of this type and clones a new instance 36 | * for each operation. That is, the application provides the library with a 37 | * [Prototype](https://en.wikipedia.org/wiki/Prototype_pattern) of the policy 38 | * that will be applied to each operation. 39 | * 40 | * [Truncated Exponential 41 | * Backoff](https://cloud.google.com/storage/docs/exponential-backoff) in the 42 | * Google Cloud Storage documentation. 43 | * 44 | */ 45 | class BackoffPolicy { 46 | public: 47 | virtual ~BackoffPolicy() = default; 48 | 49 | /** 50 | * Handle an operation completion. 51 | * 52 | * This function is called when an operation has failed and needs to be 53 | * retried. The decision to retry or not is handled by other policies. 54 | * 55 | * @return the delay to wait before the next retry attempt. 56 | */ 57 | virtual std::chrono::microseconds OnCompletion() = 0; 58 | 59 | /** 60 | * Return a new copy of this object. 61 | */ 62 | virtual std::unique_ptr clone() const = 0; 63 | }; 64 | 65 | /** 66 | * Implements a truncated exponential backoff with randomization policy. 67 | * 68 | * This policy implements the truncated exponential backoff policy for 69 | * retrying operations. After a request fails, and subject to a separate 70 | * retry policy, the client library will wait for an initial delay before 71 | * trying again. If the second attempt fails the delay time is increased by a 72 | * factor of 2. The delay time growth stops at a maximum delay wait time. The 73 | * policy also randomizes the delay each time, to avoid [thundering herd 74 | * problem](https://en.wikipedia.org/wiki/Thundering_herd_problem). 75 | * 76 | * Note: The random number generator used when calculating backoff time in 77 | * OnCompletion is lazily created. 78 | */ 79 | class ExponentialBackoffPolicy : public BackoffPolicy { 80 | public: 81 | /** 82 | * Constructor for an exponential backoff policy. 83 | * 84 | * Define the initial delay and maximum delay for an instance 85 | * of the policy. While the constructor accepts `std::chrono::duration` 86 | * objects at any resolution, the data is kept internally in microseconds. 87 | * Sub-microsecond delays seem unnecessarily precise for this application. 88 | * 89 | * @code 90 | * using namespace std::chrono_literals; // C++14 91 | * auto r1 = ExponentialBackoffPolicy(10ms, 500ms); 92 | * @endcode 93 | * 94 | * @param initial_delay how long to wait after the first (unsuccessful) 95 | * operation. 96 | * @param maximum_delay the maximum value for the delay between operations. 97 | * 98 | * @tparam duration1_t a placeholder to match the Rep tparam for @p 99 | * initial_delay's type, the semantics of this template parameter are 100 | * documented in `std::chrono::duration<>` (in brief, the underlying 101 | * arithmetic type used to store the number of ticks), for our purposes it is 102 | * simply a formal parameter. 103 | * @tparam d1 a placeholder to match the Period tparam for 104 | * @p initial_delay's type, the semantics of this template parameter are 105 | * documented in `std::chrono::duration<>` (in brief, the length of the 106 | * tick in seconds, expressed as a `std::ratio<>`), for our purposes it 107 | * is simply a formal parameter. 108 | * @tparam duration2_t similar formal parameter for the type of @p 109 | * maximum_delay. 110 | * @tparam d2 similar formal parameter for the type of @p maximum_delay. 111 | * 112 | * @see 113 | * [std::chrono::duration<>](http://en.cppreference.com/w/cpp/chrono/duration) 114 | * for more details. 115 | */ 116 | template 117 | ExponentialBackoffPolicy(duration1_t d1, duration2_t d2) 118 | : initial_delay_( 119 | std::chrono::duration_cast(d1)), 120 | current_delay_range_(initial_delay_), 121 | maximum_delay_( 122 | std::chrono::duration_cast(d2)) {} 123 | 124 | ExponentialBackoffPolicy(ExponentialBackoffPolicy const& rhs) noexcept 125 | : ExponentialBackoffPolicy(rhs.initial_delay_, rhs.maximum_delay_) {} 126 | 127 | ExponentialBackoffPolicy(ExponentialBackoffPolicy&& rhs) noexcept 128 | : initial_delay_(std::move(rhs.initial_delay_)), 129 | current_delay_range_(initial_delay_), 130 | maximum_delay_(std::move(rhs.maximum_delay_)), 131 | generator_(std::move(rhs.generator_)) {} 132 | 133 | std::chrono::microseconds OnCompletion() override; 134 | 135 | std::unique_ptr clone() const override; 136 | 137 | private: 138 | FRIEND_TEST(ExponentialBackoffPolicy, Basic); 139 | FRIEND_TEST(ExponentialBackoffPolicy, CopyConstruct); 140 | FRIEND_TEST(ExponentialBackoffPolicy, MoveConstruct); 141 | FRIEND_TEST(ExponentialBackoffPolicy, Clone); 142 | FRIEND_TEST(ExponentialBackoffPolicy, LazyGenerator); 143 | 144 | std::chrono::microseconds const initial_delay_; 145 | std::chrono::microseconds current_delay_range_; 146 | std::chrono::microseconds const maximum_delay_; 147 | 148 | // Store via pointer and do not initialize until OnCompletion is called. 149 | // The 19937 refers to bits of state: as a result, generator_ is very large, 150 | // is expensive to create, and in any case most rpcs succeed on the first 151 | // call. 152 | std::unique_ptr generator_; 153 | }; 154 | 155 | } // namespace gax 156 | } // namespace google 157 | 158 | #endif // GAPIC_GENERATOR_CPP_GAX_BACKOFF_POLICY_H_ 159 | -------------------------------------------------------------------------------- /cmake/FindGMockWithTargets.cmake: -------------------------------------------------------------------------------- 1 | # ~~~ 2 | # Copyright 2020 Google LLC 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # ~~~ 16 | 17 | # GTest always requires thread support. 18 | find_package(Threads REQUIRED) 19 | 20 | # When GTest is compiled with CMake, it exports GTest::gtest, GTest::gmock, 21 | # GTest::gtest_main and GTest::gmock_main as link targets. On the other hand, 22 | # the standard CMake module to discover GTest, it exports GTest::GTest, and does 23 | # not export GTest::gmock. 24 | # 25 | # In this file we try to normalize the situation to the packages defined in the 26 | # source. Not perfect, but better than the mess we have otherwise. 27 | 28 | function (gapic_generator_create_googletest_aliases) 29 | # FindGTest() is a standard CMake module. It, unfortunately, *only* creates 30 | # targets for the googletest libraries (not gmock), and with a name that is 31 | # not the same names used by googletest: GTest::GTest vs. GTest::gtest and 32 | # GTest::Main vs. GTest::gtest_main. We create aliases for them: 33 | add_library(GTest_gtest INTERFACE) 34 | target_link_libraries(GTest_gtest INTERFACE GTest::GTest) 35 | add_library(GTest_gtest_main INTERFACE) 36 | target_link_libraries(GTest_gtest_main INTERFACE GTest::Main) 37 | add_library(GTest::gtest ALIAS GTest_gtest) 38 | add_library(GTest::gtest_main ALIAS GTest_gtest_main) 39 | endfunction () 40 | 41 | function (gapic_generator_gmock_library_import_location target lib) 42 | find_library(_library_release ${lib}) 43 | find_library(_library_debug ${lib}d) 44 | 45 | if ("${_library_debug}" MATCHES "-NOTFOUND" AND "${_library_release}" 46 | MATCHES "-NOTFOUND") 47 | message(FATAL_ERROR "Cannot find library ${lib} for ${target}.") 48 | elseif ("${_library_debug}" MATCHES "-NOTFOUND") 49 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION 50 | "${_library_release}") 51 | elseif ("${_library_release}" MATCHES "-NOTFOUND") 52 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION 53 | "${_library_debug}") 54 | else () 55 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION_DEBUG 56 | "${_library_debug}") 57 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION_RELEASE 58 | "${_library_release}") 59 | endif () 60 | endfunction () 61 | 62 | function (gapic_generator_transfer_library_properties target source) 63 | 64 | add_library(${target} IMPORTED UNKNOWN) 65 | get_target_property(value ${source} IMPORTED_LOCATION) 66 | if (NOT value) 67 | get_target_property(value ${source} IMPORTED_LOCATION_DEBUG) 68 | if (EXISTS "${value}") 69 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION 70 | ${value}) 71 | endif () 72 | get_target_property(value ${source} IMPORTED_LOCATION_RELEASE) 73 | if (EXISTS "${value}") 74 | set_target_properties(${target} PROPERTIES IMPORTED_LOCATION 75 | ${value}) 76 | endif () 77 | endif () 78 | foreach ( 79 | property 80 | IMPORTED_LOCATION_DEBUG 81 | IMPORTED_LOCATION_RELEASE 82 | IMPORTED_CONFIGURATIONS 83 | INTERFACE_INCLUDE_DIRECTORIES 84 | IMPORTED_LINK_INTERFACE_LIBRARIES 85 | IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG 86 | IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE) 87 | get_target_property(value ${source} ${property}) 88 | message("*** ${source} ${property} ${value}") 89 | if (value) 90 | set_target_properties(${target} PROPERTIES ${property} "${value}") 91 | endif () 92 | endforeach () 93 | endfunction () 94 | 95 | include(CTest) 96 | if (TARGET GTest::gmock) 97 | # GTest::gmock is already defined, do not define it again. 98 | elseif (NOT BUILD_TESTING) 99 | # Tests are turned off via -DBUILD_TESTING, do not load the googletest or 100 | # googlemock dependency. 101 | else () 102 | # Try to find the config package first. 103 | find_package(GTest CONFIG QUIET) 104 | find_package(GMock CONFIG QUIET) 105 | if (NOT GTest_FOUND) 106 | find_package(GTest MODULE REQUIRED) 107 | 108 | gapic_generator_create_googletest_aliases() 109 | 110 | # The FindGTest module finds GTest by default, but does not search for 111 | # GMock, though they are usually installed together. Define the 112 | # GTest::gmock* targets manually. 113 | find_path( 114 | GMOCK_INCLUDE_DIR gmock/gmock.h 115 | HINTS $ENV{GTEST_ROOT}/include ${GTEST_ROOT}/include 116 | DOC "The GoogleTest Mocking Library headers") 117 | if ("${GMOCK_INCLUDE_DIR}" MATCHES "-NOTFOUND") 118 | message( 119 | FATAL_ERROR "Cannot find gmock headers ${GMOCK_INCLUDE_DIR}.") 120 | endif () 121 | mark_as_advanced(GMOCK_INCLUDE_DIR) 122 | 123 | add_library(GTest::gmock IMPORTED UNKNOWN) 124 | gapic_generator_gmock_library_import_location(GTest::gmock gmock) 125 | set_target_properties( 126 | GTest::gmock 127 | PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES 128 | "GTest::GTest;Threads::Threads" 129 | INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIRS}") 130 | 131 | add_library(GTest::gmock_main IMPORTED UNKNOWN) 132 | gapic_generator_gmock_library_import_location(GTest::gmock_main 133 | gmock_main) 134 | set_target_properties( 135 | GTest::gmock_main 136 | PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES 137 | "GTest::gmock;Threads::Threads" 138 | INTERFACE_INCLUDE_DIRECTORIES "${GMOCK_INCLUDE_DIRS}") 139 | endif () 140 | 141 | if (NOT TARGET GTest::gmock AND TARGET GMock::gmock) 142 | gapic_generator_transfer_library_properties(GTest::gmock GMock::gmock) 143 | gapic_generator_transfer_library_properties(GTest::gmock_main 144 | GMock::gmock_main) 145 | endif () 146 | endif () 147 | -------------------------------------------------------------------------------- /generator/standalone.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "generator/standalone.h" 16 | #include "absl/strings/str_split.h" 17 | #include "generator/gapic_generator.h" 18 | #include 19 | #include 20 | #include 21 | 22 | namespace google { 23 | namespace api { 24 | namespace codegen { 25 | 26 | namespace pb = google::protobuf; 27 | 28 | // GAPIC Standalone expects proto package as an argument. It defines the API 29 | // for which the GAPIC code must be generated for (i.e. to distinguish between 30 | // common proto descriptors and the actual API descriptors). Protobuf compiler 31 | // and the corresponding google::protobuf::CommandLineInterface expect the list 32 | // of the API-specific .proto files instead. 33 | // 34 | // This function extracts the relevant file names (those, which match the 35 | // package) from the set of descriptors. 36 | bool ExtractFileNames(std::vector const& desc_sets, 37 | std::vector const& packages, 38 | std::vector* filenames, 39 | std::string* error_msg) { 40 | for (auto const& desc_set : desc_sets) { 41 | if (desc_set.empty()) { 42 | continue; 43 | } 44 | 45 | std::ifstream fstr(desc_set); 46 | if (!fstr) { 47 | *error_msg = "Could not open file " + desc_set; 48 | return false; 49 | } 50 | 51 | pb::FileDescriptorSet bin_desc_set; 52 | bool parse_result = bin_desc_set.ParseFromIstream(&fstr); 53 | 54 | fstr.close(); 55 | if (!parse_result) { 56 | return false; 57 | } 58 | 59 | for (int i = 0; i < bin_desc_set.file_size(); i++) { 60 | auto const& fl = bin_desc_set.file(i); 61 | auto iter = std::find(packages.begin(), packages.end(), fl.package()); 62 | if (iter != packages.end()) { 63 | filenames->emplace_back(fl.name()); 64 | } 65 | } 66 | } 67 | 68 | return true; 69 | } 70 | 71 | // Converts arguments from what is required by GAPIC generator standalone mode 72 | // specification (--descriptor, --package, --output) to what is understood by 73 | // google::protobuf::CommandLineInterface. CommandLineInterface seems like the 74 | // preferred way of writing GAPIC generator in C++: 75 | // - it is what is used by protoc main() itself; 76 | // - it does not spawn a new subprocess if the generator was explicitly 77 | // registered by CommandLineInterface::RegisterGenerator(), so it is 78 | // performance efficient and good for debugging (runs in same process); 79 | // - it handles platform-specific file I/O (including writing into zip archive); 80 | // this is especially useful for folder operations, since standard library 81 | // below C++17 does not have folder I/O abstraction whatsoever. 82 | // 83 | bool ConvertCommandLineArgs(int argc, char const* const argv[], 84 | std::vector* args, 85 | std::string* error_msg) { 86 | // GAPIC Generator Standalone arguments 87 | std::string const desc_arg("--descriptor"); 88 | std::string const output_arg("--output"); 89 | std::string const package_arg("--package"); 90 | 91 | std::string const desc_set_in_arg("--descriptor_set_in="); 92 | 93 | std::vector desc_set_in; 94 | std::vector packages; 95 | 96 | for (int i = 0; i < argc; i++) { 97 | std::vector arg = 98 | absl::StrSplit(argv[i], absl::MaxSplits('=', 1)); 99 | if (arg.size() <= 1) { 100 | args->emplace_back(argv[i]); 101 | continue; 102 | } 103 | 104 | std::string const& arg_name = arg[0]; 105 | std::string const& arg_val = arg[1]; 106 | 107 | if (arg_name == desc_arg || arg_name == desc_set_in_arg) { 108 | args->emplace_back(desc_set_in_arg + arg_val); 109 | std::vector const& spl = 110 | absl::StrSplit(arg_val, absl::ByAnyChar(":;")); 111 | std::move(spl.begin(), spl.end(), std::back_inserter(desc_set_in)); 112 | } else if (arg_name == output_arg) { 113 | args->emplace_back("--cpp_gapic_out=" + arg_val); 114 | } else if (arg_name == package_arg) { 115 | std::vector const& spl = 116 | absl::StrSplit(arg_val, absl::ByAnyChar(":;")); 117 | std::move(spl.begin(), spl.end(), std::back_inserter(packages)); 118 | } else { 119 | args->emplace_back(argv[i]); 120 | } 121 | } 122 | 123 | if (!desc_set_in.empty()) { 124 | std::vector file_names; 125 | if (!ExtractFileNames(desc_set_in, packages, &file_names, error_msg)) { 126 | return false; 127 | } 128 | args->insert(args->end(), std::make_move_iterator(file_names.begin()), 129 | std::make_move_iterator(file_names.end())); 130 | } 131 | 132 | return true; 133 | } 134 | 135 | int StandaloneMain(int argc, char const* const argv[], 136 | google::protobuf::compiler::CodeGenerator* generator) { 137 | std::string error_msg; 138 | std::vector args; 139 | if (!ConvertCommandLineArgs(argc, argv, &args, &error_msg)) { 140 | std::cerr << error_msg << std::endl; 141 | return false; 142 | } 143 | 144 | pb::compiler::CommandLineInterface cli; 145 | cli.RegisterGenerator("--cpp_gapic_out", generator, "GAPIC C++ Generator"); 146 | 147 | std::vector c_args; 148 | c_args.reserve(args.size()); 149 | for (auto const& arg : args) { 150 | c_args.push_back(arg.c_str()); 151 | } 152 | 153 | return cli.Run((int)args.size(), c_args.data()); 154 | } 155 | 156 | int StandaloneMain(std::vector const& descriptors, 157 | std::string const& package, std::string const& output, 158 | google::protobuf::compiler::CodeGenerator* generator) { 159 | std::string desc_set_in_arg("--descriptor="); 160 | for (auto const& desc_set : descriptors) { 161 | desc_set_in_arg += desc_set + ":"; 162 | } 163 | std::string package_arg("--package=" + package); 164 | std::string output_arg("--output=" + output); 165 | 166 | std::vector c_args = {"", desc_set_in_arg.c_str(), 167 | package_arg.c_str(), output_arg.c_str()}; 168 | 169 | return StandaloneMain((int)c_args.size(), c_args.data(), generator); 170 | } 171 | 172 | } // namespace codegen 173 | } // namespace api 174 | } // namespace google 175 | -------------------------------------------------------------------------------- /docs/GENERATOR.md: -------------------------------------------------------------------------------- 1 | # C++ GAPIC Generator Design Review # 2 | 3 | *Authors: michaelbausor@google.com, vam@google.com, dovs@google.com* 4 | 5 | Objective 6 | ========= 7 | 8 | Describe the design of a C++ client library generator. This document covers the design of the **generator**; the [generated surface](SURFACE.md) and GAX-owned primitives are discussed in other docs. 9 | 10 | 11 | Compatibility 12 | ------------- 13 | 14 | We will support the google-cloud-cpp repository as our first and primary customer. Because we intend to support users building and running the 15 | GAPIC generator themselves (possibly as part of compiling a project that consumes the generated surface), we will aim to support the [*same set*](https://github.com/googleapis/google-cloud-cpp/tree/master#requirements) of compilers, build tools, dependency versions, and platforms with our generator as are supported by google-cloud-cpp (and by our generated code). 16 | 17 | The generator will **\*not\* throw exceptions**, making it compatible with code that is compiled without exception support. 18 | 19 | Dependencies 20 | ------------ 21 | 22 | We will attempt to minimize the number of external dependencies taken by the generator. Because the generator will implement the protobuf [*CodeGenerator*](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/code_generator.h#L66) interface, we have a dependency on protobuf. We will also take an \*internal only\* dependency on the [*abseil*](https://abseil.io/) library. 23 | 24 | Versioning and Publishing 25 | ------------------------- 26 | 27 | The GAPIC generator will follow semantic versioning. Once the generator is declared GA, we are committing to not breaking users of the generator, **and** not making any breaking changes in the generated surface. We will use Github releases to tag and publish generator versions. Initially we will not support any C++ package managers. However, we will facilitate community contributions so that package manager support is possible in future. 28 | 29 | Building the Generator 30 | ---------------------- 31 | 32 | The generator will be buildable via bazel and cmake, similar to the existing google-cloud-cpp repository. We will use bazel as the source of truth, and generate cmake files from bazel. Example of building using bazel: 33 | 34 | ```bash 35 | $ git clone https://github.com/googleapis/gapic-generator-cpp 36 | $ cd gapic-generator-cpp 37 | $ bazel build ... 38 | $ bazel test ... 39 | ``` 40 | 41 | Consuming the Generator 42 | ----------------------- 43 | 44 | ### Via bazel 45 | 46 | We will provide a `cpp_gapic_library` build rule that will depend on the annotated proto files and output a generated gapic library. This will be similar to the rule that exists for gapic-generator in Java [*here*](https://github.com/googleapis/gapic-generator/blob/master/rules_gapic/java/java_gapic.bzl#L139) or Go [*here*](https://github.com/googleapis/gapic-generator/blob/master/rules_gapic/go/go_gapic.bzl#L98). 47 | See [*go/gapic-bazel-extensions*](https://goto.google.com/gapic-bazel-extensions) for more detail about exposing generation (as well as testing generated libraries and generating packaging) as bazel rules. 48 | 49 | ### Via protoc plugin 50 | 51 | Users can call protoc directly and specify a built gapic-generator-cpp plugin binary. We will defer publishing built binaries that users can download until the generator reaches a post-alpha state, at which time we will re-review. 52 | 53 | Implementation 54 | -------------- 55 | 56 | The GAPIC generator will implement the protobuf [*CodeGenerator*](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/code_generator.h#L66) interface. Where possible, all logic will be implemented as part of the [*Generate*](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/code_generator.h#L82) method. 57 | 58 | The only exception to this is processing metadata annotation information, which may be stored in another protobuf file from the one currently being generated. This will be preprocessed in the [*GenerateAll*](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/compiler/code_generator.h#L98) method, and made available to the Generate method. If metadata annotation information is inconsistent across files, the generator will exit with an error. 59 | 60 | ### Generate Method 61 | 62 | The generator will make use of the protobuf [*io::Printer*](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/io/printer.h#L181) object to write files. The printer provides simple templating functionality by accepting a `std::string` template and a set of variables, performs variable substitution on the template, and outputs the result. Unlike more advanced templating languages such as Jinja2, it does not support complex [*control structures*](http://jinja.pocoo.org/docs/2.10/templates/#list-of-control-structures) such as looping. Where loops are necessary (such as over the RPCs in a service) they must be implemented in code. This makes separating the templates from the data model much more difficult than in (for example) gapic-generator-python. 63 | 64 | We extract information from the file descriptor and store it in a `std::map` object suitable for use with `io::Printer`. This map is mutable and is passed to methods that iterate over elements of the descriptor, update the map with data from the descriptor, and render templates. 65 | 66 | Sample Generation 67 | ----------------- 68 | 69 | The generator will support in-code method samples as a GA requirement, but we will delay their implementation until post-alpha. The generator will also support standalone samples, implementation timeline TBD but likely prioritized after in-code samples. We will work with the Samplegen team to ensure we can support both use cases, and cover the full range of sample specification. 70 | 71 | The google-cloud-cpp repository contains [*standalone samples*](https://github.com/googleapis/google-cloud-cpp/tree/master/google/cloud/bigtable/examples) that are compilable and testable, and that also contain annotations that allow them to be [*linked in to documentation*](https://googleapis.github.io/google-cloud-cpp/0.6.0/bigtable/bigtable-hello-world.html). We can follow this model to support documentation and testing of samples. 72 | 73 | Testing and CI 74 | -------------- 75 | 76 | We will use Kokoro as our CI system. We will integrate with [*GAPIC Showcase*](https://github.com/googleapis/gapic-showcase) to test feature coverage. For example, to use GAPIC Showcase to test paginated methods, we can generate a Showcase API Echo service client and call the [*PagedExpand*](https://github.com/googleapis/gapic-showcase/blob/master/schema/echo.proto#L82) method to verify that our pagination code works as expected. Calls will be made against a local in-memory Showcase API server. 77 | 78 | Documentation 79 | ------------- 80 | 81 | We will use doxygen, [*similar to google-cloud-cpp*](https://googleapis.github.io/google-cloud-cpp/0.6.0/bigtable/index.html), hosted at https://googleapis.github.io/gapic-generator-cpp. 82 | 83 | References 84 | ========== 85 | - [*https://github.com/googleapis/google-cloud-cpp*](https://github.com/googleapis/google-cloud-cpp) 86 | -------------------------------------------------------------------------------- /docs/STATUS.md: -------------------------------------------------------------------------------- 1 | # C++ GAPIC State of the World # 2 | dovs@google.com 3 | 4 | The C++ GAPIC project is being shelved/handed off as of 2019-05-28. This document is intended to be an infodump describing the current status of the project, intended design decisions and philosophies, lacunae, next steps, and anything else that may be relevant to those resurrecting the project at some point in the future. 5 | 6 | **NOTE:** the design docs listed here are maintained on a best effort status. They are meant to illuminate design goals, tradeoffs, and plans, but are NOT maintained as live user or developer documentation. If a design in the code and the docs diverge, the code is authoritative. 7 | 8 | ## Current Capabilities ## 9 | 10 | ### Generator ### 11 | 12 | The generator can read in a correctly formatted service proto file and emit a compilable surface. It can be invoked in a standalone manner or as a proto plugin. 13 | There is a bazel rule that builds the generator. 14 | There is a bazel rule that uses the generator to create and compile client library code. It must be passed the label for the service's proto library 'with info' and the labels for the service's `cc_grpc` and `cc_proto targets` as dependencies. 15 | E.g.: 16 | ```protobuf 17 | load("//rules_gapic/cpp:cc_gapic.bzl", "cc_gapic_srcjar", "cc_gapic_library") 18 | load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") 19 | load("@com_google_api_codegen//rules_gapic:gapic.bzl", "proto_library_with_info") 20 | 21 | proto_library( 22 | name = "library_proto", 23 | srcs = ["library.proto"], 24 | visibility = ["//visibility:public"], 25 | deps = ["@com_google_googleapis//google/api:client_proto"], 26 | ) 27 | 28 | proto_library_with_info( 29 | name = "library_proto_with_info", 30 | deps = [":library_proto"], 31 | ) 32 | 33 | cc_proto_library( 34 | name = "library_cc_proto", 35 | visibility = ["//visibility:public"], 36 | deps = [":library_proto"], 37 | ) 38 | 39 | cc_grpc_library( 40 | name = "library_cc_grpc", 41 | srcs = [":library_proto"], 42 | grpc_only = True, 43 | deps = [":library_cc_proto"], 44 | ) 45 | 46 | cc_gapic_library( 47 | name = "library_cc_gapic", 48 | src = ":library_proto_with_info", 49 | package = "google.example.library.v1", 50 | visibility = ["//visibility:public"], 51 | deps = [ 52 | ":library_cc_grpc", 53 | ":library_cc_proto", 54 | ], 55 | ) 56 | ``` 57 | The two headers for the generated surface, `\*.gapic.h` and `\*_stub.gapic.h`, are exported by the target and are visible at sane include paths in dependent code. 58 | 59 | ### Generated Client ### 60 | 61 | There are two factory functions that return a GAPIC stub; both return a retry stub decorating a 'direct' gRPC invoking stub. 62 | Assuming the service proto is annotated correctly and credentials have been properly set in the environment, synchronous client methods for unary API calls are generated and can be invoked. 63 | 64 | ### Gax ### 65 | 66 | Helper types and library code exist that support the following features: 67 | * Paginated methods 68 | * Long running operations 69 | * Idempotent method retry 70 | * Custom retry and backoff policies 71 | * Setting custom per-call gRPC metadata 72 | 73 | ## Current Limitations ## 74 | 75 | ### Generator ### 76 | 77 | * The generator does not validate the service proto file and does not generate the errors expected by the config validator. 78 | * The generator does not detect long running operations. 79 | * The generator does not detect paginated methods. 80 | * The generator does not create self-contained, compilable samples. 81 | * The generator does not create tests for any part of the generated client. 82 | * The generator does not create standalone Bazel or CMake build files for compiling the client. 83 | * The generator does not annotate the generated client with doxygen comments. 84 | * The generator currently assumes no methods are idempotent. 85 | 86 | ### Generated Client ### 87 | 88 | * There is no mechanism for configuring the service endpoint via the generated GAPIC stub factory functions. 89 | * Long running operations: 90 | * Clients with long running methods do not have `gax::OperationsClient` returning factory methods. 91 | * Client methods that correspond to long running API methods do not return `gax::Operation` instances. 92 | * There is no `gax::future>` returning method variant. 93 | * No code is generated to support streaming API methods. 94 | * No asynchronous method variants are generated. 95 | * Both the client class and the abstract GAPIC stub (and the hidden, concrete, default GAPIC stub classes) live in the global namespace. 96 | * Minimal support for non-gRPC transports. 97 | * Support for anything besides default credentials and authentication is non-existent. 98 | 99 | ### Gax ### 100 | 101 | * No supporting types or library routines exist supporting asynchronous method variants. 102 | * The intended asynchronous primitives are intended to come from Abseil or to be stolen from the Cloud C++ repository. 103 | * The LRO retry loop is not implemented as it relies on asynchronous primitives not yet in the repository. 104 | * No supporting types or library routines exist supporting streaming methods. 105 | * The PaginatedResponse template class, tying together Pages and PageResult, is unimplemented. 106 | 107 | ## In progress designs ## 108 | 109 | The generator and generated client surface are expected to follow the strictures of Google's [API Improvement Proposals](https://aip.dev/) (AIPs). 110 | Requirements for client library generators are available [here](https://aip.dev/client-libraries/4210). 111 | 112 | The limitations of the generator require little to no design or discussion: they are straightforward feature implementations and conformance to the standard set by the other microgenerators. The serious design decisions relate to the generated surface and gax-owned helper types and library code. 113 | 114 | A tentative, verbal decision was made to support asynchronous method variants by providing client methods that return `gax::future>`. 115 | The transition of idiomatic asynchronous gRPC from completion-queues to callbacks may adjust this decision, but this is unlikely. 116 | 117 | No decision was made on this front, but the idea was raised that, since abstracting gRPC away from the implementation of asynchronous method variants and streaming methods may be non-trivial, these methods may only be supported in a child class of the 'vanilla' generated client. The vanilla client therefore remains transport agnostic without forcing an onerous abstraction. 118 | No design work has been done to support streaming methods. 119 | No design work has been made to explicitly support any transport besides gRPC. 120 | 121 | ## Misc ## 122 | No benchmarks or leak check tests have been implemented for either gax code or generated client code. 123 | 124 | ## Feature specific docs ## 125 | [High level generated surface view](SURFACE.md) 126 | [High level generator view](GENERATOR.md) 127 | [Long running operations](LRO_DESIGN.md) 128 | [Paginated methods](PAGINATION.md) 129 | 130 | ## References ## 131 | [Google Cloud Cpp repository](https://github.com/googleapis/google-cloud-cpp/) 132 | -------------------------------------------------------------------------------- /gax/status_or.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef GAPIC_GENERATOR_CPP_GAX_STATUS_OR_H_ 16 | #define GAPIC_GENERATOR_CPP_GAX_STATUS_OR_H_ 17 | 18 | #include "gax/status.h" 19 | #include 20 | #include 21 | #include 22 | 23 | namespace google { 24 | namespace gax { 25 | 26 | /** 27 | * Holds a value or a `Status` indicating why there is no value. 28 | * 29 | * `StatusOr` represents either a usable `T` value or a `Status` object 30 | * explaining why a `T` value is not present. Typical usage of `StatusOr` 31 | * looks like usage of a smart pointer, or even a std::optional, in that you 32 | * first check its validity using a conversion to bool (or by calling 33 | * `StatusOr::ok()`), then you may dereference the object to access the 34 | * contained value. It is undefined behavior (UB) to dereference a 35 | * `StatusOr` that is not "ok". For example: 36 | * 37 | * @code 38 | * StatusOr foo = FetchFoo(); 39 | * if (!foo) { // Same as !foo.ok() 40 | * // handle error and probably look at foo.status() 41 | * } else { 42 | * foo->DoSomethingFooey(); // UB if !foo 43 | * } 44 | * @endcode 45 | * 46 | * Alternatively, you may call the `StatusOr::value()` member function, 47 | * which will invoke `std::abort()` if `!StatusOr::ok()`. 48 | * 49 | * @code 50 | * StatusOr foo = FetchFoo(); 51 | * foo.value().DoSomethingFooey(); // May throw/crash if there is no value 52 | * @endcode 53 | * 54 | * Functions that can fail will often return a `StatusOr` instead of 55 | * returning an error code and taking a `T` out-param, or rather than directly 56 | * returning the `T` and throwing an exception on error. StatusOr is used so 57 | * that callers can choose whether they want to explicitly check for errors, 58 | * crash the program, or throw exceptions. Since constructors do not have a 59 | * return value, they should be designed in such a way that they cannot fail by 60 | * moving the object's complex initialization logic into a separate factory 61 | * function that itself can return a `StatusOr`. For example: 62 | * 63 | * @code 64 | * class Bar { 65 | * public: 66 | * Bar(Arg arg); 67 | * ... 68 | * }; 69 | * StatusOr MakeBar() { 70 | * ... complicated logic that might fail 71 | * return Bar(std::move(arg)); 72 | * } 73 | * @endcode 74 | * 75 | * TODO(...) - the current implementation is fairly naive with respect to `T`, 76 | * it is unlikely to work correctly for reference types, arrays, and so forth. 77 | * 78 | * @tparam T the type of the value. 79 | */ 80 | template 81 | class StatusOr final { 82 | public: 83 | /** 84 | * StatusOr is not default constructible. 85 | * 86 | * There is no good definition of a default StatusOr: 87 | * it can't default construct T because T may not have a default constructor, 88 | * and using an unknown error code and generic message is not helpful. 89 | */ 90 | StatusOr() = delete; 91 | 92 | /** 93 | * Creates a new `StatusOr` holding the error condition @p rhs. 94 | * Creating a StatusOr from an OK status is not permitted 95 | * and invokes `std::abort()`. 96 | * 97 | * @par Post-conditions 98 | * `ok() == false` and `status() == rhs`. 99 | * 100 | * @param rhs the status to initialize the object. 101 | */ 102 | StatusOr(Status rhs) : status_(std::move(rhs)) { 103 | if (status_.IsOk()) { 104 | std::cerr << "Constructing StatusOr from OK status is not allowed" 105 | << std::endl; 106 | std::abort(); 107 | } 108 | } 109 | 110 | /** 111 | * Creates a new `StatusOr` holding the value @p rhs. 112 | * 113 | * @par Post-conditions 114 | * `ok() == true` and `value() == rhs`. 115 | * 116 | * @param rhs the value used to initialize the object. 117 | */ 118 | StatusOr(T const& rhs) : status_() { new (&value_) T(rhs); } 119 | 120 | StatusOr(T&& rhs) : status_() { new (&value_) T(std::move(rhs)); } 121 | 122 | StatusOr(StatusOr const& rhs) : status_(rhs.status_) { 123 | if (ok()) { 124 | new (&value_) T(rhs.value_); 125 | } 126 | } 127 | 128 | StatusOr(StatusOr&& rhs) : status_(std::move(rhs.status_)) { 129 | if (ok()) { 130 | new (&value_) T(std::move(rhs.value_)); 131 | } 132 | } 133 | 134 | ~StatusOr() { 135 | if (ok()) { 136 | value_.~T(); 137 | } 138 | } 139 | 140 | /** 141 | * @brief Status accessors. 142 | * 143 | * @return All these member functions return the (properly ref and 144 | * const-qualified) status. Iff the object contains a value then 145 | * `status().ok() == true`. 146 | */ 147 | Status const& status() const { return status_; } 148 | 149 | inline bool ok() const { return status_.IsOk(); } 150 | explicit inline operator bool() const { return ok(); } 151 | 152 | /** 153 | * @brief Deference operators. 154 | * 155 | * @warning Using these operators when `ok() == false` results in undefined 156 | * behavior. 157 | * 158 | * @return All these return a (properly ref and const-qualified) reference to 159 | * the underlying value. 160 | */ 161 | T& operator*() & { return value_; } 162 | T const& operator*() const& { return value_; } 163 | T&& operator*() && { return std::move(value_); } 164 | 165 | /** 166 | * @brief Member access operators. 167 | * 168 | * @warning Using these operators when `ok() == false` results in undefined 169 | * behavior. 170 | * 171 | * @return All these return a (properly ref and const-qualified) pointer to 172 | * the underlying value. 173 | */ 174 | T* operator->() & { return &value_; } 175 | T const* operator->() const& { return &value_; } 176 | 177 | /** 178 | * @brief Value accessors. 179 | * 180 | * @return All these member functions return a (properly ref and 181 | * const-qualified) reference to the underlying value. 182 | * 183 | * Aborts the program if `!ok()` 184 | */ 185 | T& value() & { 186 | check_value(); 187 | return **this; 188 | } 189 | 190 | T const& value() const& { 191 | check_value(); 192 | return **this; 193 | } 194 | 195 | T&& value() && { 196 | check_value(); 197 | return std::move(**this); 198 | } 199 | 200 | private: 201 | void check_value() const { 202 | if (!ok()) { 203 | std::cerr << status_ << std::endl; 204 | std::abort(); 205 | } 206 | } 207 | 208 | Status const status_; 209 | union { 210 | T value_; 211 | }; 212 | }; 213 | 214 | } // namespace gax 215 | } // namespace google 216 | 217 | #endif // GAPIC_GENERATOR_CPP_GAX_STATUS_OR_H_ 218 | -------------------------------------------------------------------------------- /gax/status_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/status.h" 16 | #include 17 | #include 18 | #include 19 | 20 | namespace { 21 | 22 | using namespace ::google; 23 | 24 | TEST(Status, Basic) { 25 | { 26 | gax::Status s; // sanity check for default construction 27 | EXPECT_TRUE(s.IsOk()); 28 | EXPECT_FALSE(s.IsPermanentFailure()); 29 | } 30 | { 31 | gax::Status s(gax::StatusCode::kCancelled, ""); 32 | EXPECT_FALSE(s.IsOk()); 33 | EXPECT_TRUE(s.IsPermanentFailure()); 34 | } 35 | { 36 | gax::Status s(gax::StatusCode::kInvalidArgument, ""); 37 | EXPECT_FALSE(s.IsOk()); 38 | EXPECT_TRUE(s.IsPermanentFailure()); 39 | } 40 | { 41 | gax::Status s(gax::StatusCode::kDeadlineExceeded, ""); 42 | EXPECT_FALSE(s.IsOk()); 43 | EXPECT_FALSE(s.IsPermanentFailure()); 44 | } 45 | { 46 | gax::Status s(gax::StatusCode::kNotFound, ""); 47 | EXPECT_FALSE(s.IsOk()); 48 | EXPECT_TRUE(s.IsPermanentFailure()); 49 | } 50 | { 51 | gax::Status s(gax::StatusCode::kAlreadyExists, ""); 52 | EXPECT_FALSE(s.IsOk()); 53 | EXPECT_TRUE(s.IsPermanentFailure()); 54 | } 55 | { 56 | gax::Status s(gax::StatusCode::kPermissionDenied, ""); 57 | EXPECT_FALSE(s.IsOk()); 58 | EXPECT_TRUE(s.IsPermanentFailure()); 59 | } 60 | { 61 | gax::Status s(gax::StatusCode::kUnauthenticated, ""); 62 | EXPECT_FALSE(s.IsOk()); 63 | EXPECT_TRUE(s.IsPermanentFailure()); 64 | } 65 | { 66 | gax::Status s(gax::StatusCode::kResourceExhausted, ""); 67 | EXPECT_FALSE(s.IsOk()); 68 | EXPECT_TRUE(s.IsPermanentFailure()); 69 | } 70 | { 71 | gax::Status s(gax::StatusCode::kFailedPrecondition, ""); 72 | EXPECT_FALSE(s.IsOk()); 73 | EXPECT_TRUE(s.IsPermanentFailure()); 74 | } 75 | { 76 | gax::Status s(gax::StatusCode::kAborted, ""); 77 | EXPECT_FALSE(s.IsOk()); 78 | EXPECT_FALSE(s.IsPermanentFailure()); 79 | } 80 | { 81 | gax::Status s(gax::StatusCode::kOutOfRange, ""); 82 | EXPECT_FALSE(s.IsOk()); 83 | EXPECT_TRUE(s.IsPermanentFailure()); 84 | } 85 | { 86 | gax::Status s(gax::StatusCode::kUnimplemented, ""); 87 | EXPECT_FALSE(s.IsOk()); 88 | EXPECT_TRUE(s.IsPermanentFailure()); 89 | } 90 | { 91 | gax::Status s(gax::StatusCode::kInternal, ""); 92 | EXPECT_FALSE(s.IsOk()); 93 | EXPECT_TRUE(s.IsPermanentFailure()); 94 | } 95 | { 96 | gax::Status s(gax::StatusCode::kUnavailable, ""); 97 | EXPECT_FALSE(s.IsOk()); 98 | EXPECT_FALSE(s.IsPermanentFailure()); 99 | } 100 | { 101 | gax::Status s(gax::StatusCode::kDataLoss, ""); 102 | EXPECT_FALSE(s.IsOk()); 103 | EXPECT_TRUE(s.IsPermanentFailure()); 104 | } 105 | } 106 | 107 | TEST(Status, CodeOstream) { 108 | { 109 | std::ostringstream output; 110 | output << gax::StatusCode::kOk; 111 | EXPECT_EQ("OK", output.str()); 112 | } 113 | { 114 | std::ostringstream output; 115 | output << gax::StatusCode::kCancelled; 116 | EXPECT_EQ("CANCELLED", output.str()); 117 | } 118 | { 119 | std::ostringstream output; 120 | output << gax::StatusCode::kUnknown; 121 | EXPECT_EQ("UNKNOWN", output.str()); 122 | } 123 | { 124 | std::ostringstream output; 125 | output << gax::StatusCode::kInvalidArgument; 126 | EXPECT_EQ("INVALID_ARGUMENT", output.str()); 127 | } 128 | { 129 | std::ostringstream output; 130 | output << gax::StatusCode::kDeadlineExceeded; 131 | EXPECT_EQ("DEADLINE_EXCEEDED", output.str()); 132 | } 133 | { 134 | std::ostringstream output; 135 | output << gax::StatusCode::kNotFound; 136 | EXPECT_EQ("NOT_FOUND", output.str()); 137 | } 138 | { 139 | std::ostringstream output; 140 | output << gax::StatusCode::kAlreadyExists; 141 | EXPECT_EQ("ALREADY_EXISTS", output.str()); 142 | } 143 | { 144 | std::ostringstream output; 145 | output << gax::StatusCode::kPermissionDenied; 146 | EXPECT_EQ("PERMISSION_DENIED", output.str()); 147 | } 148 | { 149 | std::ostringstream output; 150 | output << gax::StatusCode::kResourceExhausted; 151 | EXPECT_EQ("RESOURCE_EXHAUSTED", output.str()); 152 | } 153 | { 154 | std::ostringstream output; 155 | output << gax::StatusCode::kFailedPrecondition; 156 | EXPECT_EQ("FAILED_PRECONDITION", output.str()); 157 | } 158 | { 159 | std::ostringstream output; 160 | output << gax::StatusCode::kAborted; 161 | EXPECT_EQ("ABORTED", output.str()); 162 | } 163 | { 164 | std::ostringstream output; 165 | output << gax::StatusCode::kOutOfRange; 166 | EXPECT_EQ("OUT_OF_RANGE", output.str()); 167 | } 168 | { 169 | std::ostringstream output; 170 | output << gax::StatusCode::kUnimplemented; 171 | EXPECT_EQ("UNIMPLEMENTED", output.str()); 172 | } 173 | { 174 | std::ostringstream output; 175 | output << gax::StatusCode::kInternal; 176 | EXPECT_EQ("INTERNAL", output.str()); 177 | } 178 | { 179 | std::ostringstream output; 180 | output << gax::StatusCode::kUnavailable; 181 | EXPECT_EQ("UNAVAILABLE", output.str()); 182 | } 183 | { 184 | std::ostringstream output; 185 | output << gax::StatusCode::kDataLoss; 186 | EXPECT_EQ("DATA_LOSS", output.str()); 187 | } 188 | { 189 | std::ostringstream output; 190 | output << gax::StatusCode::kUnauthenticated; 191 | EXPECT_EQ("UNAUTHENTICATED", output.str()); 192 | } 193 | { 194 | std::ostringstream output; 195 | output << static_cast(42); 196 | EXPECT_EQ("UNEXPECTED_STATUS_CODE=42", output.str()); 197 | } 198 | } 199 | 200 | TEST(Status, Ostream) { 201 | { 202 | std::ostringstream output; 203 | gax::Status s; 204 | 205 | output << s; 206 | EXPECT_EQ(" [OK]", output.str()); 207 | } 208 | 209 | { 210 | std::ostringstream output; 211 | gax::Status s(gax::StatusCode::kCancelled, "Because"); 212 | output << s; 213 | EXPECT_EQ("Because [CANCELLED]", output.str()); 214 | } 215 | } 216 | 217 | TEST(Status, Equality) { 218 | gax::Status ok1, ok2; 219 | EXPECT_EQ(ok1, ok2); 220 | 221 | gax::Status ok3(gax::StatusCode::kOk, ""); 222 | EXPECT_EQ(ok1, ok3); 223 | 224 | gax::Status ok4(gax::StatusCode::kOk, "Because"); 225 | EXPECT_NE(ok1, ok4); 226 | 227 | gax::Status cancelled1(gax::StatusCode::kCancelled, ""); 228 | EXPECT_NE(ok1, cancelled1); 229 | 230 | gax::Status cancelled2(gax::StatusCode::kCancelled, "Because"); 231 | EXPECT_NE(ok1, cancelled2); 232 | } 233 | 234 | TEST(Status, CopyCtor) { 235 | gax::Status ok1; 236 | gax::Status ok2(ok1); 237 | EXPECT_EQ(ok1, ok2); 238 | 239 | gax::Status cancelled1(gax::StatusCode::kCancelled, "Because"); 240 | gax::Status cancelled2(cancelled1); 241 | EXPECT_EQ(cancelled1, cancelled2); 242 | } 243 | 244 | } // namespace 245 | -------------------------------------------------------------------------------- /gax/retry_policy_test.cc: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // https://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "gax/retry_policy.h" 16 | #include "gax/internal/test_clock.h" 17 | #include "gax/status.h" 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | namespace { 24 | using namespace ::google; 25 | 26 | TEST(LimitedErrorCountRetryPolicy, Basic) { 27 | gax::LimitedErrorCountRetryPolicy<> tested(3, std::chrono::milliseconds(30)); 28 | gax::Status s; 29 | EXPECT_TRUE(tested.OnFailure(s)); 30 | EXPECT_TRUE(tested.OnFailure(s)); 31 | EXPECT_TRUE(tested.OnFailure(s)); 32 | EXPECT_FALSE(tested.OnFailure(s)); 33 | EXPECT_FALSE(tested.OnFailure(s)); 34 | } 35 | 36 | TEST(LimitedErrorCountRetryPolicy, PermanentFailureCheck) { 37 | gax::LimitedErrorCountRetryPolicy<> tested(3, std::chrono::milliseconds(30)); 38 | gax::Status s{gax::StatusCode::kCancelled, ""}; 39 | EXPECT_FALSE(tested.OnFailure(s)); 40 | } 41 | 42 | TEST(LimitedErrorCountRetryPolicy, CopyConstruct) { 43 | gax::LimitedErrorCountRetryPolicy<> tested(3, std::chrono::milliseconds(30)); 44 | gax::Status s; 45 | EXPECT_TRUE(tested.OnFailure(s)); 46 | EXPECT_TRUE(tested.OnFailure(s)); 47 | EXPECT_TRUE(tested.OnFailure(s)); 48 | EXPECT_FALSE(tested.OnFailure(s)); 49 | 50 | gax::LimitedErrorCountRetryPolicy<> copy(tested); 51 | EXPECT_TRUE(copy.OnFailure(s)); 52 | EXPECT_TRUE(copy.OnFailure(s)); 53 | EXPECT_TRUE(copy.OnFailure(s)); 54 | EXPECT_FALSE(copy.OnFailure(s)); 55 | } 56 | 57 | TEST(LimitedErrorCountRetryPolicy, MoveConstruct) { 58 | gax::LimitedErrorCountRetryPolicy<> tested(3, std::chrono::milliseconds(30)); 59 | gax::Status s; 60 | EXPECT_TRUE(tested.OnFailure(s)); 61 | EXPECT_TRUE(tested.OnFailure(s)); 62 | EXPECT_TRUE(tested.OnFailure(s)); 63 | EXPECT_FALSE(tested.OnFailure(s)); 64 | 65 | gax::LimitedErrorCountRetryPolicy<> copy(std::move(tested)); 66 | EXPECT_TRUE(copy.OnFailure(s)); 67 | EXPECT_TRUE(copy.OnFailure(s)); 68 | EXPECT_TRUE(copy.OnFailure(s)); 69 | EXPECT_FALSE(copy.OnFailure(s)); 70 | } 71 | 72 | TEST(LimitedErrorCountRetryPolicy, Clone) { 73 | gax::LimitedErrorCountRetryPolicy<> tested(3, std::chrono::milliseconds(30)); 74 | gax::Status s; 75 | EXPECT_TRUE(tested.OnFailure(s)); 76 | EXPECT_TRUE(tested.OnFailure(s)); 77 | EXPECT_TRUE(tested.OnFailure(s)); 78 | EXPECT_FALSE(tested.OnFailure(s)); 79 | 80 | std::unique_ptr clone = tested.clone(); 81 | EXPECT_TRUE(clone->OnFailure(s)); 82 | EXPECT_TRUE(clone->OnFailure(s)); 83 | EXPECT_TRUE(clone->OnFailure(s)); 84 | EXPECT_FALSE(clone->OnFailure(s)); 85 | } 86 | 87 | TEST(LimitedErrorCountRetryPolicy, OperationDeadline) { 88 | std::chrono::system_clock::time_point now_point; 89 | gax::LimitedErrorCountRetryPolicy tested( 90 | 3, std::chrono::milliseconds(30), gax::internal::TestClock(now_point)); 91 | 92 | EXPECT_EQ(tested.OperationDeadline(), 93 | now_point + std::chrono::milliseconds(30)); 94 | 95 | auto clone = tested.clone(); 96 | now_point += std::chrono::milliseconds(50); 97 | EXPECT_EQ(tested.OperationDeadline(), clone->OperationDeadline()); 98 | } 99 | 100 | TEST(LimitedDurationRetryPolicy, Basic) { 101 | std::chrono::system_clock::time_point now_point; 102 | gax::LimitedDurationRetryPolicy tested( 103 | std::chrono::milliseconds(5), std::chrono::milliseconds(30), 104 | gax::internal::TestClock(now_point)); 105 | gax::Status s; 106 | EXPECT_TRUE(tested.OnFailure(s)); 107 | 108 | now_point += std::chrono::milliseconds(2); 109 | EXPECT_TRUE(tested.OnFailure(s)); 110 | 111 | now_point += std::chrono::milliseconds(10); 112 | EXPECT_FALSE(tested.OnFailure(s)); 113 | } 114 | 115 | TEST(LimitedDurationRetryPolicy, PermanentFailureCheck) { 116 | std::chrono::system_clock::time_point now_point; 117 | gax::LimitedDurationRetryPolicy tested( 118 | std::chrono::milliseconds(5), std::chrono::milliseconds(30), 119 | gax::internal::TestClock(now_point)); 120 | gax::Status s{gax::StatusCode::kCancelled, ""}; 121 | 122 | EXPECT_FALSE(tested.OnFailure(s)); 123 | } 124 | 125 | TEST(LimitedDurationRetryPolicy, CopyConstruct) { 126 | std::chrono::system_clock::time_point now_point; 127 | gax::LimitedDurationRetryPolicy tested( 128 | std::chrono::milliseconds(5), std::chrono::milliseconds(30), 129 | gax::internal::TestClock(now_point)); 130 | gax::Status s; 131 | 132 | now_point += std::chrono::milliseconds(10); 133 | EXPECT_FALSE(tested.OnFailure(s)); 134 | 135 | gax::LimitedDurationRetryPolicy copy(tested); 136 | EXPECT_TRUE(copy.OnFailure(s)); 137 | } 138 | 139 | TEST(LimitedDurationRetryPolicy, MoveConstruct) { 140 | std::chrono::system_clock::time_point now_point; 141 | gax::LimitedDurationRetryPolicy tested( 142 | std::chrono::milliseconds(5), std::chrono::milliseconds(30), 143 | gax::internal::TestClock(now_point)); 144 | gax::Status s; 145 | 146 | now_point += std::chrono::milliseconds(10); 147 | EXPECT_FALSE(tested.OnFailure(s)); 148 | 149 | gax::LimitedDurationRetryPolicy copy( 150 | std::move(tested)); 151 | EXPECT_TRUE(copy.OnFailure(s)); 152 | } 153 | 154 | TEST(LimitedDurationRetryPolicy, Clone) { 155 | std::chrono::system_clock::time_point now_point; 156 | gax::LimitedDurationRetryPolicy tested( 157 | std::chrono::milliseconds(5), std::chrono::milliseconds(30), 158 | gax::internal::TestClock(now_point)); 159 | gax::Status s; 160 | 161 | now_point += std::chrono::milliseconds(10); 162 | EXPECT_FALSE(tested.OnFailure(s)); 163 | 164 | std::unique_ptr clone = tested.clone(); 165 | EXPECT_TRUE(clone->OnFailure(s)); 166 | } 167 | 168 | TEST(LimitedDurationRetryPolicy, OperationDeadline) { 169 | std::chrono::system_clock::time_point now_point; 170 | gax::LimitedDurationRetryPolicy tested( 171 | std::chrono::milliseconds(500), std::chrono::milliseconds(30), 172 | gax::internal::TestClock(now_point)); 173 | 174 | EXPECT_EQ(tested.OperationDeadline(), 175 | now_point + std::chrono::milliseconds(30)); 176 | 177 | auto clone = tested.clone(); 178 | now_point += std::chrono::milliseconds(50); 179 | EXPECT_EQ(tested.OperationDeadline(), clone->OperationDeadline()); 180 | } 181 | 182 | TEST(LimitedDurationRetryPolicy, OperationDeadlineCap) { 183 | std::chrono::system_clock::time_point now_point; 184 | gax::LimitedDurationRetryPolicy tested( 185 | std::chrono::milliseconds(500), std::chrono::milliseconds(30), 186 | gax::internal::TestClock(now_point)); 187 | 188 | // Don't exceed the overarching timeout 189 | now_point += std::chrono::milliseconds(490); 190 | EXPECT_EQ(tested.OperationDeadline(), 191 | now_point + std::chrono::milliseconds(10)); 192 | } 193 | 194 | } // namespace 195 | --------------------------------------------------------------------------------