├── .bazelrc ├── .bazelversion ├── .github ├── dependabot.yml └── workflows │ ├── bazel.yml │ ├── gradle.yml │ └── release.yml ├── .gitignore ├── BUILD.bazel ├── BUILDING.md ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── MAINTAINERS.md ├── OWNERS ├── README.md ├── SECURITY.md ├── WORKSPACE ├── build.gradle.kts ├── compiler ├── README.md ├── build.gradle.kts └── src │ ├── main │ └── java │ │ └── io │ │ └── grpc │ │ └── kotlin │ │ └── generator │ │ ├── BUILD.bazel │ │ ├── GeneratorRunner.kt │ │ ├── GrpcClientStubGenerator.kt │ │ ├── GrpcCoroutineServerGenerator.kt │ │ ├── ProtoFileCodeGenerator.kt │ │ ├── ServiceCodeGenerator.kt │ │ ├── ServiceNameGenerator.kt │ │ ├── TopLevelConstantsGenerator.kt │ │ └── protoc │ │ ├── AbstractGeneratorRunner.kt │ │ ├── BUILD.bazel │ │ ├── ClassSimpleName.kt │ │ ├── CodeGenerators.kt │ │ ├── ConstantName.kt │ │ ├── Declarations.kt │ │ ├── DescriptorUtil.kt │ │ ├── GeneratorConfig.kt │ │ ├── JavaPackagePolicy.kt │ │ ├── KtPoetUtil.kt │ │ ├── MemberSimpleName.kt │ │ ├── ProtoEnumValueName.kt │ │ ├── ProtoFieldName.kt │ │ ├── ProtoFileName.kt │ │ ├── ProtoMethodName.kt │ │ ├── ProtoServiceName.kt │ │ ├── ProtoTypeSimpleName.kt │ │ ├── Scope.kt │ │ ├── TypeNames.kt │ │ ├── testing │ │ ├── BUILD.bazel │ │ ├── DeclarationsSubject.kt │ │ ├── FileSpecSubject.kt │ │ ├── FunSpecSubject.kt │ │ └── TypeSpecSubject.kt │ │ └── util │ │ ├── graph │ │ ├── BUILD.bazel │ │ └── TopologicalSortGraph.kt │ │ └── sort │ │ ├── BUILD.bazel │ │ ├── PartialOrdering.kt │ │ └── TopologicalSort.kt │ └── test │ ├── java │ └── io │ │ └── grpc │ │ └── kotlin │ │ └── generator │ │ └── protoc │ │ ├── BUILD.bazel │ │ ├── ClassSimpleNameTest.kt │ │ ├── ConstantNameTest.kt │ │ ├── DeclarationsTest.kt │ │ ├── DescriptorUtilTest.kt │ │ ├── GeneratorConfigTest.kt │ │ ├── JavaPackagePolicyTest.kt │ │ ├── MemberSimpleNameTest.kt │ │ ├── OptionalProto3FieldTest.kt │ │ ├── ProtoEnumValueNameTest.kt │ │ ├── ProtoFieldNameTest.kt │ │ ├── ProtoFileNameTest.kt │ │ ├── ProtoMethodNameTest.kt │ │ ├── ProtoTypeSimpleNameTest.kt │ │ ├── ScopeTest.kt │ │ └── testing │ │ ├── BUILD.bazel │ │ ├── DeclarationsSubjectTest.kt │ │ ├── FileSpecSubjectTest.kt │ │ ├── FunSpecSubjectTest.kt │ │ └── TypeSpecSubjectTest.kt │ └── proto │ ├── helloworld │ ├── BUILD.bazel │ └── helloworld.proto │ └── testing │ ├── BUILD.bazel │ ├── example3.proto │ ├── has_explicit_outer_class_name.proto │ ├── has_nested_class_name_conflict.proto │ ├── has_outer_class_name_conflict.proto │ ├── implicit_java_package.proto │ ├── proto-file-with-hyphen.proto │ ├── rpc_name_contains_underscore.proto │ ├── serviceT.proto │ ├── service_name_conflicts_with_file.proto │ └── test_proto3_optional.proto ├── examples ├── .gitignore ├── Procfile ├── README.md ├── android │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── kotlin │ │ └── io │ │ │ └── grpc │ │ │ └── examples │ │ │ └── helloworld │ │ │ └── MainActivity.kt │ │ └── res │ │ └── values │ │ └── strings.xml ├── build.gradle.kts ├── client │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── io │ │ └── grpc │ │ └── examples │ │ ├── animals │ │ ├── AnimalsClient.kt │ │ └── BUILD.bazel │ │ ├── helloworld │ │ ├── BUILD.bazel │ │ └── HelloWorldClient.kt │ │ └── routeguide │ │ ├── BUILD.bazel │ │ └── RouteGuideClient.kt ├── gradle.properties ├── gradle │ ├── libs.versions.toml │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── native-client │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── io │ │ │ └── grpc │ │ │ └── examples │ │ │ └── helloworld │ │ │ ├── BUILD.bazel │ │ │ └── HelloWorldClient.kt │ │ └── resources │ │ └── META-INF │ │ └── native-image │ │ └── reflect-config.json ├── protos │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── proto │ │ └── io │ │ └── grpc │ │ └── examples │ │ ├── animals │ │ ├── BUILD.bazel │ │ ├── dog.proto │ │ ├── pig.proto │ │ └── sheep.proto │ │ ├── helloworld │ │ ├── BUILD.bazel │ │ └── hello_world.proto │ │ └── routeguide │ │ ├── BUILD.bazel │ │ └── route_guide.proto ├── server │ ├── build.gradle.kts │ └── src │ │ ├── main │ │ └── kotlin │ │ │ └── io │ │ │ └── grpc │ │ │ └── examples │ │ │ ├── animals │ │ │ ├── AnimalsServer.kt │ │ │ └── BUILD.bazel │ │ │ ├── helloworld │ │ │ ├── BUILD.bazel │ │ │ └── HelloWorldServer.kt │ │ │ └── routeguide │ │ │ ├── BUILD.bazel │ │ │ └── RouteGuideServer.kt │ │ └── test │ │ └── kotlin │ │ └── io │ │ └── grpc │ │ └── examples │ │ ├── animals │ │ └── AnimalsServerTest.kt │ │ ├── helloworld │ │ └── HelloWorldServerTest.kt │ │ └── routeguide │ │ └── RouteGuideServerTest.kt ├── settings.gradle.kts ├── stub-android │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── AndroidManifest.xml ├── stub-lite │ └── build.gradle.kts └── stub │ ├── build.gradle.kts │ └── src │ └── main │ ├── kotlin │ └── io │ │ └── grpc │ │ └── examples │ │ └── routeguide │ │ ├── BUILD.bazel │ │ ├── Database.kt │ │ └── Points.kt │ └── resources │ └── io │ └── grpc │ └── examples │ └── routeguide │ ├── BUILD.bazel │ └── route_guide_db.json ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── integration_testing ├── build.gradle.kts └── src │ └── test │ └── kotlin │ └── io │ └── grpc │ └── kotlin │ └── ExamplesTest.kt ├── interop_testing ├── build.gradle.kts └── src │ ├── main │ ├── java │ │ └── io │ │ │ └── grpc │ │ │ └── testing │ │ │ └── integration │ │ │ ├── AbstractInteropTest.kt │ │ │ ├── Http2TestCases.java │ │ │ ├── TestCases.java │ │ │ ├── TestServiceClient.kt │ │ │ ├── TestServiceImpl.kt │ │ │ ├── TestServiceServer.java │ │ │ └── Util.java │ └── proto │ │ └── grpc │ │ └── testing │ │ ├── empty.proto │ │ ├── messages.proto │ │ ├── metrics.proto │ │ └── test.proto │ └── test │ └── java │ └── io │ └── grpc │ ├── stub │ └── StubConfigTest.java │ └── testing │ └── integration │ ├── Http2OkHttpTest.java │ ├── TestCasesTest.java │ └── TestServiceClientTest.java ├── kt_jvm_grpc.bzl ├── repositories.bzl ├── run-test-client.sh ├── run-test-server.sh ├── settings.gradle.kts └── stub ├── build.gradle.kts └── src ├── main └── java │ └── io │ └── grpc │ └── kotlin │ ├── AbstractCoroutineServerImpl.kt │ ├── AbstractCoroutineStub.kt │ ├── BUILD.bazel │ ├── ClientCalls.kt │ ├── CoroutineContextServerInterceptor.kt │ ├── GrpcContextElement.kt │ ├── Helpers.kt │ ├── Readiness.kt │ ├── ServerCalls.kt │ └── StubFor.kt └── test ├── java └── io │ └── grpc │ └── kotlin │ ├── AbstractCallsTest.kt │ ├── BUILD.bazel │ ├── ClientCallsTest.kt │ ├── CoroutineContextServerInterceptorTest.kt │ ├── FlowControlTest.kt │ ├── GeneratedCodeTest.kt │ ├── GrpcContextElementTest.kt │ └── ServerCallsTest.kt └── proto └── helloworld ├── BUILD.bazel └── helloworld.proto /.bazelrc: -------------------------------------------------------------------------------- 1 | build --cxxopt=-std=c++14 --host_cxxopt=-std=c++14 2 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 6.3.2 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | 8 | - package-ecosystem: "gradle" 9 | directory: "/examples" 10 | schedule: 11 | interval: "daily" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "weekly" 17 | -------------------------------------------------------------------------------- /.github/workflows/bazel.yml: -------------------------------------------------------------------------------- 1 | name: Bazel Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | jobs: 8 | bazel: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - name: Mount bazel cache 13 | uses: actions/cache@v4 14 | with: 15 | path: "/home/runner/.cache/bazel" 16 | key: bazel 17 | - name: Install bazelisk 18 | run: | 19 | curl -LO "https://github.com/bazelbuild/bazelisk/releases/download/v1.1.0/bazelisk-linux-amd64" 20 | mkdir -p "${GITHUB_WORKSPACE}/bin/" 21 | mv bazelisk-linux-amd64 "${GITHUB_WORKSPACE}/bin/bazel" 22 | chmod +x "${GITHUB_WORKSPACE}/bin/bazel" 23 | - name: Test 24 | uses: nick-invision/retry@v3 25 | with: 26 | timeout_minutes: 10 27 | max_attempts: 3 28 | command: | 29 | "${GITHUB_WORKSPACE}/bin/bazel" test //... 30 | - name: Build 31 | uses: nick-invision/retry@v3 32 | with: 33 | timeout_minutes: 10 34 | max_attempts: 3 35 | command: | 36 | "${GITHUB_WORKSPACE}/bin/bazel" build //... 37 | -------------------------------------------------------------------------------- /.github/workflows/gradle.yml: -------------------------------------------------------------------------------- 1 | name: Gradle Build 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | jobs: 9 | gradle: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, macos-12] 13 | runs-on: ${{ matrix.os }} 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | - uses: actions/setup-java@v4 18 | with: 19 | distribution: 'temurin' 20 | java-version: '11' 21 | cache: 'gradle' 22 | 23 | - uses: gradle/gradle-build-action@v3 24 | 25 | - name: Test on Mac 26 | if: matrix.os == 'macos-12' 27 | run: | 28 | brew install docker 29 | colima start --network-address 30 | export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE=/var/run/docker.sock 31 | export TESTCONTAINERS_HOST_OVERRIDE=$(colima ls -j | jq -r '.address') 32 | export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock" 33 | ./gradlew test 34 | 35 | - name: Test on Ubuntu 36 | if: matrix.os == 'ubuntu-latest' 37 | run: | 38 | ./gradlew test 39 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | tags: 5 | - v** 6 | workflow_dispatch: 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - uses: actions/setup-java@v4 15 | with: 16 | distribution: 'adopt' 17 | java-version: '11' 18 | cache: 'gradle' 19 | 20 | - name: Setup Gradle 21 | uses: gradle/gradle-build-action@v3 22 | 23 | - name: release 24 | env: 25 | SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} 26 | SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} 27 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 28 | GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} 29 | run: | 30 | # todo: verify version is same as tag 31 | 32 | ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle 2 | build 3 | .gradle 4 | .idea 5 | local.properties 6 | *.iml 7 | /bazel-* 8 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | # Deliberately empty 2 | -------------------------------------------------------------------------------- /BUILDING.md: -------------------------------------------------------------------------------- 1 | # Building gRPC-Kotlin 2 | 3 | Building should only be necessary if you are making changes to gRPC-Kotlin, or if 4 | you'd like to use or test a version of gRPC-Kotlin that hasn't been released 5 | yet. 6 | 7 | Use the following gradle command to build gRPC-Kotlin: 8 | 9 | ```console 10 | $ ./gradlew build 11 | ``` 12 | 13 | Install the built artifacts into your local Maven repository so that you can use 14 | them in your projects: 15 | 16 | ```console 17 | $ ./gradlew publishToMavenLocal 18 | ``` 19 | 20 | Ensure that you configure your project build to use the local version of 21 | gRPC-Kotlin. 22 | 23 | 24 | ## Releasing 25 | 26 | 1. [Generate a changelog](https://github.com/grpc/grpc-kotlin/releases/new) and prepend it to [CHANGELOG.md](CHANGELOG.md) 27 | 2. Create a Pull Request with updated versions in: [build.gradle.kts](build.gradle.kts) and [examples/build.gradle.kts](examples/build.gradle.kts) 28 | 3. Once merged, tag the release with `vX.Y.Z` and push the tag. This will kick off a GitHub Action that does the actual release. -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | # Active maintainers 2 | 3 | The active maintainers of this repository (in alphabetical order) are: 4 | 5 | - [bshaffer](https://github.com/bshaffer), Google LLC 6 | - [jamesward](https://github.com/jamesward), Google LLC 7 | - [lowasser](https://github.com/lowasser), Google LLC 8 | 9 | # Emeritus maintainers 10 | 11 | The emeritus maintainers of this repository (in alphabetical order) are: 12 | 13 | - None currently listed. 14 | 15 | # Notes 16 | 17 | - For governance guidelines, and how to become a maintainer, see 18 | [grpc/grpc-community/governance.md][]. 19 | - For general contribution guidelines, see 20 | [grpc/grpc-community/CONTRIBUTING.md][]. 21 | - If you were a maintainer and would like to add your name to the emeritus list, 22 | submit a PR. 23 | 24 | [grpc/grpc-community/governance.md]: https://github.com/grpc/grpc-community/blob/master/governance.md 25 | [grpc/grpc-community/CONTRIBUTING.md]: https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md 26 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | # Top level ownership 2 | @lowasser **/OWNERS 3 | @jbolinger **/OWNERS 4 | @kevin1e100 **/OWNERS 5 | @bshaffer **/OWNERS 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gRPC-Kotlin/JVM - An RPC library and framework 2 | 3 | [![Gradle Build Status][]](https://github.com/grpc/grpc-kotlin/actions?query=workflow%3A%22Gradle+Build%22) 4 | [![Bazel Build Status][]](https://github.com/grpc/grpc-kotlin/actions?query=workflow%3A%22Bazel+Build%22) 5 | 6 | [![grpc-kotlin-stub][label:stub]][maven:stub] 7 | [![protoc-gen-grpc-kotlin][label:plugin]][maven:plugin] 8 | 9 | A Kotlin/JVM implementation of [gRPC](https://grpc.io): A high performance, open 10 | source, general RPC framework that puts mobile and HTTP/2 first. 11 | 12 | This repo includes the sources for the following: 13 | 14 | - [protoc-gen-grpc-kotlin](compiler): A [protoc][] plugin for generating Kotlin 15 | gRPC client-stub and server plumbing code. 16 | 17 | > **Note:** The Kotlin protoc plugin uses the [Java protoc plugin][gen-java] 18 | > behind the scenes to **generate _message types_ as _Java classes_**. 19 | > Generation of Kotlin sources for proto messages is being discussed in 20 | > [protocolbuffers/protobuf#3742][]. 21 | 22 | - [grpc-kotlin-stub](stub): A Kotlin implementation of gRPC, providing runtime 23 | support for client-stubs and server-side code. 24 | 25 | For more information, see the following [Kotlin/JVM pages from grpc.io][]: 26 | 27 | - [Quick start][] 28 | - [Maven / Gradle Plugin instructions] 29 | - [Basics tutorial][] 30 | - [API reference][] 31 | 32 | How-to pages from this repo: 33 | 34 | - [Contributing](CONTRIBUTING.md) 35 | - [Building gRPC-Kotlin](BUILDING.md) 36 | 37 | Note that [official releases][] are [published to Maven Central][]. 38 | 39 | [API Reference]: https://grpc.io/docs/languages/kotlin/api/ 40 | [Basics tutorial]: https://grpc.io/docs/languages/kotlin/basics/ 41 | [Bazel Build Status]: https://github.com/grpc/grpc-kotlin/workflows/Bazel%20Build/badge.svg 42 | [gen-java]: https://github.com/grpc/grpc-java/tree/master/compiler 43 | [Gradle Build Status]: https://github.com/grpc/grpc-kotlin/workflows/Gradle%20Build/badge.svg 44 | [Kotlin/JVM pages from grpc.io]: https://grpc.io/docs/languages/kotlin/ 45 | [label:plugin]: https://img.shields.io/maven-central/v/io.grpc/protoc-gen-grpc-kotlin.svg?label=protoc-gen-grpc-kotlin 46 | [label:stub]: https://img.shields.io/maven-central/v/io.grpc/grpc-kotlin-stub.svg?label=grpc-kotlin-stub 47 | [maven:plugin]: https://search.maven.org/search?q=g:%22io.grpc%22%20AND%20a:%22protoc-gen-grpc-kotlin%22 48 | [maven:stub]: https://search.maven.org/search?q=g:%22io.grpc%22%20AND%20a:%22grpc-kotlin-stub%22 49 | [official releases]: https://github.com/grpc/grpc-kotlin/releases 50 | [protoc]: https://github.com/protocolbuffers/protobuf#protocol-compiler-installation 51 | [protocolbuffers/protobuf#3742]: https://github.com/protocolbuffers/protobuf/issues/3742 52 | [published to Maven Central]: https://search.maven.org/search?q=g:io.grpc%20AND%20grpc-kotlin 53 | [Quick start]: https://grpc.io/docs/languages/kotlin/quickstart/ 54 | [Maven / Gradle Plugin instructions]: compiler/README.md 55 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md). 4 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace(name = "com_github_grpc_grpc_kotlin") 2 | 3 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 4 | 5 | http_archive( 6 | name = "rules_jvm_external", 7 | sha256 = "cd1a77b7b02e8e008439ca76fd34f5b07aecb8c752961f9640dea15e9e5ba1ca", 8 | strip_prefix = "rules_jvm_external-4.2", 9 | url = "https://github.com/bazelbuild/rules_jvm_external/archive/4.2.zip", 10 | ) 11 | 12 | load("@rules_jvm_external//:defs.bzl", "maven_install") 13 | 14 | # Repositories 15 | load( 16 | "//:repositories.bzl", 17 | "IO_GRPC_GRPC_KOTLIN_ARTIFACTS", 18 | "IO_GRPC_GRPC_KOTLIN_OVERRIDE_TARGETS", 19 | "grpc_kt_repositories", 20 | "io_grpc_grpc_java", 21 | ) 22 | 23 | io_grpc_grpc_java() 24 | 25 | load( 26 | "@io_grpc_grpc_java//:repositories.bzl", 27 | "IO_GRPC_GRPC_JAVA_ARTIFACTS", 28 | "IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS", 29 | "grpc_java_repositories", 30 | ) 31 | 32 | # Maven 33 | maven_install( 34 | artifacts = [ 35 | "com.google.jimfs:jimfs:1.3.0", 36 | "com.google.truth.extensions:truth-proto-extension:1.1.3", 37 | "com.google.protobuf:protobuf-kotlin:3.24.1", 38 | ] + IO_GRPC_GRPC_KOTLIN_ARTIFACTS + IO_GRPC_GRPC_JAVA_ARTIFACTS, 39 | override_targets = dict( 40 | IO_GRPC_GRPC_KOTLIN_OVERRIDE_TARGETS.items() + 41 | IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS.items(), 42 | ), 43 | repositories = [ 44 | "https://repo.maven.apache.org/maven2/", 45 | ], 46 | generate_compat_repositories = True, 47 | ) 48 | 49 | load("@maven//:compat.bzl", "compat_repositories") 50 | 51 | compat_repositories() 52 | 53 | # gRPC 54 | grpc_kt_repositories() 55 | 56 | grpc_java_repositories() 57 | 58 | # Protocol Buffers 59 | load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") 60 | 61 | protobuf_deps() 62 | 63 | # Kotlin 64 | load("@io_bazel_rules_kotlin//kotlin:repositories.bzl", "kotlin_repositories") 65 | 66 | kotlin_repositories() 67 | 68 | load("@io_bazel_rules_kotlin//kotlin:core.bzl", "kt_register_toolchains") 69 | 70 | kt_register_toolchains() 71 | -------------------------------------------------------------------------------- /compiler/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.google.protobuf.gradle.* 2 | 3 | plugins { 4 | application 5 | } 6 | 7 | application { 8 | mainClass.set("io.grpc.kotlin.generator.GeneratorRunner") 9 | } 10 | 11 | java { 12 | withSourcesJar() 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(8) 15 | } 16 | } 17 | 18 | dependencies { 19 | // Kotlin and Java 20 | implementation(libs.kotlinx.coroutines.core) 21 | 22 | // Grpc and Protobuf 23 | implementation(project(":stub")) 24 | implementation(libs.grpc.protobuf) 25 | 26 | // Misc 27 | implementation(kotlin("reflect")) 28 | implementation(libs.kotlinpoet) 29 | implementation(libs.truth) 30 | 31 | // Testing 32 | testImplementation(libs.junit) 33 | testImplementation(libs.guava) 34 | testImplementation(libs.jimfs) 35 | testImplementation(libs.protobuf.gradle.plugin) 36 | testImplementation(libs.protobuf.java) 37 | testImplementation(libs.mockito.kotlin) 38 | testImplementation(libs.junit.jupiter.engine) 39 | testImplementation(libs.mockito.core) 40 | } 41 | 42 | tasks.jar { 43 | manifest { 44 | attributes["Main-Class"] = application.mainClass.get() 45 | } 46 | 47 | from(sourceSets.main.get().output) 48 | 49 | dependsOn(configurations.runtimeClasspath) 50 | 51 | from({ 52 | configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) } 53 | }) 54 | 55 | duplicatesStrategy = DuplicatesStrategy.INCLUDE 56 | } 57 | 58 | publishing { 59 | publications { 60 | named("maven") { 61 | pom { 62 | name.set("gRPC Kotlin Compiler") 63 | artifactId = "protoc-gen-grpc-kotlin" 64 | description.set("gRPC Kotlin protoc compiler plugin") 65 | } 66 | 67 | artifact(tasks.jar) { 68 | classifier = "jdk8" 69 | } 70 | } 71 | } 72 | } 73 | 74 | protobuf { 75 | protoc { 76 | artifact = libs.protoc.asProvider().get().toString() 77 | } 78 | plugins { 79 | id("grpc") { 80 | artifact = libs.protoc.gen.grpc.java.get().toString() 81 | } 82 | id("grpckt") { 83 | path = tasks.jar.get().archiveFile.get().asFile.absolutePath 84 | } 85 | } 86 | generateProtoTasks { 87 | all().forEach { 88 | if (it.name.startsWith("generateTestProto")) { 89 | it.dependsOn("jar") 90 | } 91 | 92 | it.plugins { 93 | id("grpc") 94 | id("grpckt") 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//visibility:public"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "generator", 11 | srcs = glob(["*.kt"]), 12 | deps = [ 13 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc", 14 | "//stub/src/main/java/io/grpc/kotlin:context", 15 | "//stub/src/main/java/io/grpc/kotlin:stub", 16 | "@com_google_guava_guava", 17 | "@com_google_protobuf//:protobuf_java", 18 | "@io_grpc_grpc_java//core", 19 | "@maven//:com_squareup_kotlinpoet", 20 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", 21 | ], 22 | ) 23 | 24 | java_binary( 25 | name = "GeneratorRunner", 26 | main_class = "io.grpc.kotlin.generator.GeneratorRunner", 27 | runtime_deps = [":generator"], 28 | ) 29 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/GeneratorRunner.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin.generator 18 | 19 | import com.google.protobuf.Descriptors.FileDescriptor 20 | import com.squareup.kotlinpoet.FileSpec 21 | import io.grpc.kotlin.generator.protoc.AbstractGeneratorRunner 22 | import io.grpc.kotlin.generator.protoc.GeneratorConfig 23 | import io.grpc.kotlin.generator.protoc.JavaPackagePolicy 24 | 25 | /** Main runner for code generation for Kotlin gRPC APIs. */ 26 | object GeneratorRunner: AbstractGeneratorRunner() { 27 | @JvmStatic 28 | fun main(args: Array) = super.doMain(args) 29 | 30 | private val config = GeneratorConfig(JavaPackagePolicy.OPEN_SOURCE, false) 31 | 32 | val generator = ProtoFileCodeGenerator( 33 | generators = listOf( 34 | ::ServiceNameGenerator, 35 | ::GrpcClientStubGenerator, 36 | ::GrpcCoroutineServerGenerator, 37 | ::TopLevelConstantsGenerator 38 | ), 39 | config = config, 40 | topLevelSuffix = "GrpcKt" 41 | ) 42 | 43 | override fun generateCodeForFile(file: FileDescriptor): List = 44 | listOfNotNull(generator.generateCodeForFile(file)) 45 | } 46 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/ProtoFileCodeGenerator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin.generator 18 | 19 | import com.google.protobuf.Descriptors.FileDescriptor 20 | import com.squareup.kotlinpoet.FileSpec 21 | import com.squareup.kotlinpoet.TypeSpec 22 | import io.grpc.kotlin.generator.protoc.GeneratorConfig 23 | import io.grpc.kotlin.generator.protoc.builder 24 | import io.grpc.kotlin.generator.protoc.declarations 25 | import io.grpc.kotlin.generator.protoc.objectBuilder 26 | import io.grpc.kotlin.generator.protoc.outerClassSimpleName 27 | import io.grpc.kotlin.generator.protoc.serviceName 28 | 29 | /** 30 | * Given a list of [ServiceCodeGenerator] factories, generates (optionally) a [FileSpec] of the 31 | * generated code. 32 | */ 33 | class ProtoFileCodeGenerator( 34 | generators: List<(GeneratorConfig) -> ServiceCodeGenerator>, 35 | private val config: GeneratorConfig, 36 | private val topLevelSuffix: String 37 | ) { 38 | 39 | private val generators = generators.map { it(config) } 40 | 41 | fun generateCodeForFile(fileDescriptor: FileDescriptor): FileSpec? = with(config) { 42 | val outerTypeName = fileDescriptor.outerClassSimpleName.withSuffix(topLevelSuffix) 43 | 44 | var wroteAnything = false 45 | val fileBuilder = FileSpec.builder(javaPackage(fileDescriptor), outerTypeName) 46 | 47 | for (service in fileDescriptor.services) { 48 | val serviceDecls = declarations { 49 | for (generator in generators) { 50 | merge(generator.generate(service)) 51 | } 52 | } 53 | 54 | if (serviceDecls.hasEnclosingScopeDeclarations) { 55 | wroteAnything = true 56 | val serviceObjectBuilder = 57 | TypeSpec 58 | .objectBuilder(service.serviceName.toClassSimpleName().withSuffix(topLevelSuffix)) 59 | .addKdoc( 60 | """ 61 | Holder for Kotlin coroutine-based client and server APIs for %L. 62 | """.trimIndent(), 63 | service.fullName 64 | ) 65 | serviceDecls.writeToEnclosingType(serviceObjectBuilder) 66 | fileBuilder.addType(serviceObjectBuilder.build()) 67 | } 68 | 69 | if (serviceDecls.hasTopLevelDeclarations) { 70 | wroteAnything = true 71 | serviceDecls.writeOnlyTopLevel(fileBuilder) 72 | } 73 | } 74 | 75 | return if (wroteAnything) fileBuilder.build() else null 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/ServiceCodeGenerator.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin.generator 18 | 19 | import com.google.protobuf.Descriptors.MethodDescriptor 20 | import com.google.protobuf.Descriptors.ServiceDescriptor 21 | import com.squareup.kotlinpoet.ClassName 22 | import com.squareup.kotlinpoet.CodeBlock 23 | import com.squareup.kotlinpoet.MemberName 24 | import io.grpc.kotlin.generator.protoc.Declarations 25 | import io.grpc.kotlin.generator.protoc.GeneratorConfig 26 | import io.grpc.kotlin.generator.protoc.declarations 27 | import io.grpc.kotlin.generator.protoc.member 28 | import io.grpc.kotlin.generator.protoc.methodName 29 | import io.grpc.kotlin.generator.protoc.serviceName 30 | 31 | /** Generates code based on a [ServiceDescriptor]. */ 32 | abstract class ServiceCodeGenerator(protected val config: GeneratorConfig) { 33 | companion object { 34 | private const val GRPC_CLASS_NAME_SUFFIX = "Grpc" 35 | } 36 | 37 | /** Function for subclasses to implement. */ 38 | abstract fun generate(service: ServiceDescriptor): Declarations 39 | 40 | operator fun plus(other: ServiceCodeGenerator): ServiceCodeGenerator { 41 | val me = this 42 | return object: ServiceCodeGenerator(config) { 43 | override fun generate(service: ServiceDescriptor): Declarations = declarations { 44 | merge(me.generate(service)) 45 | merge(other.generate(service)) 46 | } 47 | } 48 | } 49 | 50 | /** Gets the fully qualified name of the Java class generated by gRPC. */ 51 | protected val ServiceDescriptor.grpcClass: ClassName 52 | get() = with(config) { 53 | javaPackage(file).nestedClass( 54 | serviceName.toClassSimpleName().withSuffix(GRPC_CLASS_NAME_SUFFIX) 55 | ) 56 | } 57 | 58 | /** Gets the name of the function that gets the [io.grpc.ServiceDescriptor]. */ 59 | protected val ServiceDescriptor.grpcDescriptor: MemberName 60 | get() = grpcClass.member("getServiceDescriptor") 61 | 62 | /** Gets the name of the function that gets the [io.grpc.MethodDescriptor]. */ 63 | protected val MethodDescriptor.descriptorCode: CodeBlock 64 | get() = CodeBlock.of( 65 | "%T.%L()", 66 | service.grpcClass, 67 | methodName.toMemberSimpleName().withPrefix("get").withSuffix("Method") 68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/ServiceNameGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin.generator 2 | 3 | import com.google.protobuf.Descriptors 4 | import com.squareup.kotlinpoet.KModifier 5 | import com.squareup.kotlinpoet.PropertySpec 6 | import io.grpc.kotlin.generator.protoc.Declarations 7 | import io.grpc.kotlin.generator.protoc.GeneratorConfig 8 | import io.grpc.kotlin.generator.protoc.declarations 9 | 10 | class ServiceNameGenerator(config: GeneratorConfig) : ServiceCodeGenerator(config) { 11 | override fun generate(service: Descriptors.ServiceDescriptor): Declarations { 12 | return declarations { 13 | addProperty( 14 | PropertySpec.builder("SERVICE_NAME", String::class, KModifier.CONST) 15 | .initializer("%T.SERVICE_NAME", service.grpcClass) 16 | .build() 17 | ) 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/TopLevelConstantsGenerator.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin.generator 2 | 3 | import com.google.protobuf.Descriptors 4 | import com.squareup.kotlinpoet.FunSpec 5 | import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy 6 | import com.squareup.kotlinpoet.PropertySpec 7 | import com.squareup.kotlinpoet.asTypeName 8 | import io.grpc.MethodDescriptor 9 | import io.grpc.ServiceDescriptor 10 | import io.grpc.kotlin.generator.protoc.Declarations 11 | import io.grpc.kotlin.generator.protoc.GeneratorConfig 12 | import io.grpc.kotlin.generator.protoc.builder 13 | import io.grpc.kotlin.generator.protoc.declarations 14 | import io.grpc.kotlin.generator.protoc.methodName 15 | 16 | /** 17 | * Generates top-level properties for the service descriptor and method descriptors. 18 | */ 19 | class TopLevelConstantsGenerator(config: GeneratorConfig): ServiceCodeGenerator(config) { 20 | override fun generate(service: Descriptors.ServiceDescriptor): Declarations = declarations { 21 | addProperty( 22 | PropertySpec.builder("serviceDescriptor", ServiceDescriptor::class) 23 | .addAnnotation(JvmStatic::class) 24 | .getter( 25 | FunSpec.getterBuilder() 26 | .addStatement("return %T.getServiceDescriptor()", service.grpcClass) 27 | .build() 28 | ) 29 | .build() 30 | ) 31 | 32 | with(config) { 33 | for (method in service.methods) { 34 | addProperty( 35 | PropertySpec 36 | .builder( 37 | method.methodName.toMemberSimpleName().withSuffix("Method"), 38 | MethodDescriptor::class.asTypeName().parameterizedBy( 39 | method.inputType.messageClass(), 40 | method.outputType.messageClass() 41 | ) 42 | ) 43 | .getter( 44 | FunSpec.getterBuilder() 45 | .addAnnotation(JvmStatic::class) 46 | .addStatement("return %T.%L()", 47 | service.grpcClass, 48 | method.methodName 49 | .toMemberSimpleName() 50 | .withPrefix("get") 51 | .withSuffix("Method") 52 | ) 53 | .build() 54 | ) 55 | .build() 56 | ) 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//:__subpackages__"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "protoc", 11 | srcs = glob(["*.kt"]), 12 | deps = [ 13 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/graph", 14 | "@com_google_guava_guava", 15 | "@com_google_protobuf//:protobuf_java", 16 | "@maven//:com_squareup_kotlinpoet", 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ClassSimpleName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.base.CaseFormat 20 | import com.squareup.kotlinpoet.ClassName 21 | import com.squareup.kotlinpoet.TypeSpec 22 | 23 | /** 24 | * Represents a simple (unqualified, unnested) name of a Kotlin/Java class, interface, or enum, 25 | * in UpperCamelCase. 26 | */ 27 | data class ClassSimpleName(val name: String) : CharSequence by name { 28 | /** Returns this class name with a suffix. */ 29 | fun withSuffix(suffix: String): ClassSimpleName = ClassSimpleName(name + suffix) 30 | 31 | /** 32 | * Returns a fully qualified class name as a peer of the specified class, with this simple name. 33 | */ 34 | fun asPeer(className: ClassName): ClassName = className.peerClass(name) 35 | 36 | /** Returns a name of a member based on this class name with a prefix. */ 37 | fun asMemberWithPrefix(prefix: String): MemberSimpleName { 38 | return if (prefix.isEmpty()) { 39 | MemberSimpleName(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name)) 40 | } else { 41 | MemberSimpleName(prefix + name) 42 | } 43 | } 44 | 45 | override fun toString() = name 46 | } 47 | 48 | /** Create a builder for a class with the specified simple name. */ 49 | fun TypeSpec.Companion.classBuilder( 50 | simpleName: ClassSimpleName 51 | ): TypeSpec.Builder = classBuilder(simpleName.name) 52 | 53 | /** Create a builder for an object with the specified simple name. */ 54 | fun TypeSpec.Companion.objectBuilder( 55 | simpleName: ClassSimpleName 56 | ): TypeSpec.Builder = objectBuilder(simpleName.name) 57 | 58 | /** Given a fully qualified class name, get the fully qualified name of a nested class inside it. */ 59 | fun ClassName.nestedClass(classSimpleName: ClassSimpleName): ClassName = 60 | nestedClass(classSimpleName.name) 61 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/CodeGenerators.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.base.Throwables 20 | import com.google.common.graph.GraphBuilder 21 | import com.google.protobuf.DescriptorProtos.FileDescriptorProto 22 | import com.google.protobuf.Descriptors.FileDescriptor 23 | import com.google.protobuf.compiler.PluginProtos 24 | import com.squareup.kotlinpoet.FileSpec 25 | import io.grpc.kotlin.generator.protoc.util.graph.TopologicalSortGraph 26 | 27 | internal object CodeGenerators { 28 | fun descriptorMap( 29 | topologicalSortedProtoFileList: List 30 | ): Map { 31 | val descriptorsByName = mutableMapOf() 32 | for (protoFile in topologicalSortedProtoFileList) { 33 | // we should have visited all the dependencies, so they should be present in the map 34 | val dependencies = protoFile.dependencyNames.map(descriptorsByName::getValue) 35 | 36 | // build and link the descriptor for this file to its dependencies 37 | val fileDescriptor = FileDescriptor.buildFrom(protoFile, dependencies.toTypedArray()) 38 | 39 | descriptorsByName[protoFile.fileName] = fileDescriptor 40 | } 41 | return descriptorsByName 42 | } 43 | 44 | fun descriptorMapFromUnsorted( 45 | protoFileList: List 46 | ): Map { 47 | val byFileName = protoFileList.associateBy { it.fileName } 48 | 49 | val depGraph = 50 | GraphBuilder 51 | .directed() 52 | .expectedNodeCount(protoFileList.size) 53 | .build() 54 | 55 | byFileName.keys.forEach { depGraph.addNode(it) } 56 | 57 | for ((fileName, fileDescriptorProto) in byFileName) { 58 | for (dep in fileDescriptorProto.dependencyNames) { 59 | depGraph.putEdge(dep, fileName) 60 | } 61 | } 62 | 63 | return descriptorMap( 64 | TopologicalSortGraph.topologicalOrdering(depGraph) 65 | .map { byFileName.getValue(it) } 66 | ) 67 | } 68 | 69 | fun toCodeGeneratorResponseFile(fileSpec: FileSpec): PluginProtos.CodeGeneratorResponse.File = 70 | PluginProtos.CodeGeneratorResponse.File.newBuilder().also { 71 | it.name = fileSpec.path.toString() 72 | it.content = fileSpec.toString() 73 | }.build() 74 | 75 | inline fun codeGeneratorResponse(build: () -> List): PluginProtos.CodeGeneratorResponse { 76 | val builder = PluginProtos.CodeGeneratorResponse.newBuilder() 77 | try { 78 | builder.setSupportedFeatures(PluginProtos.CodeGeneratorResponse.Feature.FEATURE_PROTO3_OPTIONAL_VALUE.toLong()) 79 | .addAllFile(build().map { toCodeGeneratorResponseFile(it) }) 80 | } catch (failure: Exception) { 81 | builder.error = Throwables.getStackTraceAsString(failure) 82 | } 83 | return builder.build() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ConstantName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.squareup.kotlinpoet.ClassName 20 | import com.squareup.kotlinpoet.MemberName 21 | 22 | /** Represents a name of an constant, in UPPER_UNDERSCORE. */ 23 | data class ConstantName(val name: String) : CharSequence by name { 24 | override fun toString() = name 25 | } 26 | 27 | /** Returns the fully qualified name of this constant, as a member of the specified class. */ 28 | fun ClassName.member(constantName: ConstantName): MemberName = 29 | MemberName(this, constantName.name) 30 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/GeneratorConfig.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.Descriptors.Descriptor 20 | import com.google.protobuf.Descriptors.EnumDescriptor 21 | import com.google.protobuf.Descriptors.FileDescriptor 22 | import com.squareup.kotlinpoet.ClassName 23 | import com.squareup.kotlinpoet.FunSpec 24 | import com.squareup.kotlinpoet.KModifier 25 | 26 | /** 27 | * Configuration for proto code generation, including settings on inlining and on the mapping 28 | * between protos and Java packages. 29 | */ 30 | data class GeneratorConfig( 31 | val javaPackagePolicy: JavaPackagePolicy, 32 | val aggressiveInlining: Boolean 33 | ) { 34 | 35 | private val inlineModifiers: Array = 36 | if (aggressiveInlining) arrayOf(KModifier.INLINE) else arrayOf() 37 | 38 | /** Generates a [FunSpec.Builder] with appropriate modifiers. */ 39 | fun funSpecBuilder(name: MemberSimpleName): FunSpec.Builder = 40 | FunSpec.builder(name).addModifiers(*inlineModifiers) 41 | 42 | /** Generates a [FunSpec.Builder] for a getter with appropriate modifiers. */ 43 | fun getterBuilder(): FunSpec.Builder = 44 | FunSpec.getterBuilder().addModifiers(*inlineModifiers) 45 | 46 | /** Generates a [FunSpec.Builder] for a setter with appropriate modifiers. */ 47 | fun setterBuilder(): FunSpec.Builder = 48 | FunSpec.setterBuilder().addModifiers(*inlineModifiers) 49 | 50 | /** Returns the package associated with Java APIs for protos in the specified file. */ 51 | fun javaPackage(fileDescriptor: FileDescriptor): PackageScope = 52 | javaPackagePolicy.javaPackage(fileDescriptor.toProto()) 53 | 54 | // Helpers on FileDescriptor. 55 | 56 | /** Returns the fully qualified name of the outer class generated for this proto file. */ 57 | fun FileDescriptor.outerClass(): ClassName = javaPackage(this).nestedClass(outerClassSimpleName) 58 | 59 | // Helpers on EnumDescriptor. 60 | 61 | /** Returns the fully qualified name of the JVM enum type generated for this proto enum. */ 62 | fun EnumDescriptor.enumClass(): ClassName { 63 | val contType: Descriptor? = containingType 64 | return when { 65 | contType != null -> contType.messageClass().nestedClass(enumClassSimpleName) 66 | file.options.javaMultipleFiles -> javaPackage(file).nestedClass(enumClassSimpleName) 67 | else -> file.outerClass().nestedClass(enumClassSimpleName) 68 | } 69 | } 70 | 71 | // Helpers on Descriptor. 72 | 73 | /** Returns the fully qualified name of the JVM class generated for this message type. */ 74 | fun Descriptor.messageClass(): ClassName { 75 | val contType: Descriptor? = containingType 76 | return when { 77 | contType != null -> contType.messageClass().nestedClass(messageClassSimpleName) 78 | file.options.javaMultipleFiles -> javaPackage(file).nestedClass(messageClassSimpleName) 79 | else -> file.outerClass().nestedClass(messageClassSimpleName) 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/JavaPackagePolicy.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.DescriptorProtos.FileDescriptorProto 20 | 21 | /** 22 | * Describes a policy for converting proto message types to Java classes in the correct package. 23 | */ 24 | enum class JavaPackagePolicy { 25 | OPEN_SOURCE { 26 | override fun javaPackage(fileProto: FileDescriptorProto): PackageScope { 27 | return if (fileProto.options.hasJavaPackage()) { 28 | PackageScope(fileProto.options.javaPackage) 29 | } else { 30 | PackageScope(fileProto.`package`) 31 | } 32 | } 33 | }; 34 | 35 | abstract fun javaPackage(fileProto: FileDescriptorProto): PackageScope 36 | } 37 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/KtPoetUtil.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.squareup.kotlinpoet.FileSpec 20 | import com.squareup.kotlinpoet.KModifier 21 | import com.squareup.kotlinpoet.MemberName 22 | import com.squareup.kotlinpoet.ParameterSpec 23 | import com.squareup.kotlinpoet.TypeName 24 | import com.squareup.kotlinpoet.asClassName 25 | import java.nio.file.Path 26 | import java.nio.file.Paths 27 | import kotlin.reflect.KClass 28 | 29 | fun ParameterSpec.Companion.of( 30 | name: String, 31 | type: TypeName, 32 | vararg modifiers: KModifier 33 | ): ParameterSpec = ParameterSpec.builder(name, type, *modifiers).build() 34 | 35 | /** Create a fully qualified [MemberName] in this class with the specified name. */ 36 | fun KClass<*>.member(memberName: String): MemberName = MemberName(asClassName(), memberName) 37 | 38 | private fun path(vararg component: String): Path = 39 | Paths.get(component[0], *component.sliceArray(1 until component.size)) 40 | 41 | val FileSpec.path: Path 42 | get() { 43 | return if (packageName.isEmpty()) { 44 | Paths.get("$name.kt") 45 | } else { 46 | path(*packageName.split('.').toTypedArray(), "$name.kt") 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ProtoEnumValueName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.Descriptors.EnumValueDescriptor 20 | 21 | /** Represents the unqualified name of a proto enum constant, in UPPER_UNDERSCORE. */ 22 | data class ProtoEnumValueName(val name: String) : CharSequence by name { 23 | val asConstantName: ConstantName 24 | get() = ConstantName(name) 25 | 26 | override fun toString() = name 27 | } 28 | 29 | /** Returns the name of a proto enum constant. */ 30 | val EnumValueDescriptor.protoEnumValueName: ProtoEnumValueName 31 | get() = ProtoEnumValueName(name) 32 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ProtoFileName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.DescriptorProtos.FileDescriptorProto 20 | import com.google.protobuf.Descriptors.FileDescriptor 21 | import com.google.protobuf.compiler.PluginProtos 22 | 23 | /** 24 | * Represents the name of a proto file, relative to the root of the source tree, with 25 | * lower_underscore naming. 26 | */ 27 | data class ProtoFileName(private val path: String) : Comparable { 28 | val name: String 29 | get() = path.substringAfterLast('/').removeSuffix(".proto") 30 | 31 | override operator fun compareTo(other: ProtoFileName): Int = path.compareTo(other.path) 32 | } 33 | 34 | /** Returns the filename of the specified file descriptor in proto form. */ 35 | val FileDescriptorProto.fileName: ProtoFileName 36 | get() = ProtoFileName(name) 37 | 38 | /** Returns the filename of the specified file descriptor. */ 39 | val FileDescriptor.fileName: ProtoFileName 40 | get() = toProto().fileName 41 | 42 | val FileDescriptorProto.dependencyNames: List 43 | get() = dependencyList.map(::ProtoFileName) 44 | 45 | val PluginProtos.CodeGeneratorRequest.filesToGenerate: List 46 | get() = fileToGenerateList.map(::ProtoFileName) 47 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ProtoMethodName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.base.CaseFormat 20 | import com.google.protobuf.DescriptorProtos.MethodDescriptorProto 21 | import com.google.protobuf.Descriptors.MethodDescriptor 22 | 23 | /** Represents the unqualified name of an RPC method in a proto file, in UpperCamelCase. */ 24 | data class ProtoMethodName(val name: String) : CharSequence by name { 25 | fun toMemberSimpleName(): MemberSimpleName { 26 | val name = MemberSimpleName(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name)) 27 | if (containsSpecialCharacters(name)) { 28 | return handleSpecialCharacters(name) 29 | } 30 | return name 31 | } 32 | 33 | private fun containsSpecialCharacters(name: MemberSimpleName): Boolean { 34 | return name.contains("_") 35 | } 36 | 37 | private fun handleSpecialCharacters(name: MemberSimpleName): MemberSimpleName { 38 | return name.split("_") 39 | .map(::MemberSimpleName) 40 | .reduce { acc, simpleName -> acc + simpleName } 41 | } 42 | 43 | override fun toString() = name 44 | } 45 | 46 | val MethodDescriptor.methodName: ProtoMethodName 47 | get() = toProto().methodName 48 | 49 | val MethodDescriptorProto.methodName: ProtoMethodName 50 | get() = ProtoMethodName(name) 51 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ProtoServiceName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto 20 | import com.google.protobuf.Descriptors.ServiceDescriptor 21 | 22 | /** Represents the unqualified name of an RPC service in a proto file, in CamelCase. */ 23 | data class ProtoServiceName(val name: String) : CharSequence by name { 24 | fun toClassSimpleName(): ClassSimpleName = ClassSimpleName(name) 25 | 26 | override fun toString() = name 27 | } 28 | 29 | val ServiceDescriptor.serviceName: ProtoServiceName 30 | get() = toProto().serviceName 31 | 32 | val ServiceDescriptorProto.serviceName: ProtoServiceName 33 | get() = ProtoServiceName(name) 34 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/ProtoTypeSimpleName.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.DescriptorProtos.DescriptorProto 20 | import com.google.protobuf.DescriptorProtos.EnumDescriptorProto 21 | import com.google.protobuf.Descriptors.Descriptor 22 | import com.google.protobuf.Descriptors.EnumDescriptor 23 | 24 | /** Represents the unqualified name of a proto message or enum, which is in UpperCamelCase. */ 25 | data class ProtoTypeSimpleName(val name: String) : CharSequence by name { 26 | fun toClassSimpleName(): ClassSimpleName = ClassSimpleName(name) 27 | 28 | override fun toString() = name 29 | } 30 | 31 | /** Returns the name of a message type, given its descriptor. */ 32 | val Descriptor.simpleName: ProtoTypeSimpleName 33 | get() = toProto().simpleName 34 | 35 | /** Returns the name of a message type, given its descriptor in proto form. */ 36 | val DescriptorProto.simpleName: ProtoTypeSimpleName 37 | get() = ProtoTypeSimpleName(name) 38 | 39 | /** Returns the name of a proto enum type, given its descriptor. */ 40 | val EnumDescriptor.simpleName: ProtoTypeSimpleName 41 | get() = toProto().simpleName 42 | 43 | /** Returns the name of a proto enum type, given its descriptor in proto form. */ 44 | val EnumDescriptorProto.simpleName: ProtoTypeSimpleName 45 | get() = ProtoTypeSimpleName(name) 46 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/Scope.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.squareup.kotlinpoet.ClassName 20 | import com.squareup.kotlinpoet.FileSpec 21 | 22 | /** 23 | * Describes a location classes can be nested in, such as a package or another class. This can 24 | * convert a [ClassSimpleName] to a fully qualified [ClassName]. 25 | */ 26 | sealed class Scope { 27 | abstract fun nestedClass(simpleName: ClassSimpleName): ClassName 28 | 29 | fun nestedScope(simpleName: ClassSimpleName): Scope = ClassScope(nestedClass(simpleName)) 30 | } 31 | 32 | /** 33 | * The unqualified, top-level scope. 34 | */ 35 | object UnqualifiedScope : Scope() { 36 | override fun nestedClass(simpleName: ClassSimpleName): ClassName = 37 | ClassName("", simpleName.name) 38 | } 39 | 40 | /** 41 | * The scope of a package. 42 | */ 43 | data class PackageScope(val pkg: String) : Scope() { 44 | override fun nestedClass(simpleName: ClassSimpleName): ClassName = 45 | ClassName(pkg, simpleName.name) 46 | } 47 | 48 | /** 49 | * The scope of a fully qualified class. 50 | */ 51 | class ClassScope(private val className: ClassName) : Scope() { 52 | override fun nestedClass(simpleName: ClassSimpleName): ClassName = 53 | className.nestedClass(simpleName) 54 | } 55 | 56 | /** 57 | * Creates a [FileSpec.Builder] for a class with the specified simple name in the specified package. 58 | */ 59 | fun FileSpec.Companion.builder( 60 | packageName: PackageScope, 61 | simpleName: ClassSimpleName 62 | ): FileSpec.Builder = builder(packageName.pkg, simpleName.name) 63 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/TypeNames.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.protobuf.ByteString 20 | import com.squareup.kotlinpoet.asTypeName 21 | 22 | object TypeNames { 23 | internal val ITERABLE = Iterable::class.asTypeName() 24 | internal val PAIR = Pair::class.asTypeName() 25 | internal val MAP = Map::class.asTypeName() 26 | internal val STRING = String::class.asTypeName() 27 | val BYTE_STRING = ByteString::class.asTypeName() 28 | } 29 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//:__subpackages__"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "testing", 11 | srcs = glob(["*.kt"]), 12 | deps = [ 13 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc", 14 | "@maven//:com_google_truth_truth", 15 | "@maven//:com_squareup_kotlinpoet", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing/DeclarationsSubject.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.FailureMetadata 20 | import com.google.common.truth.Subject 21 | import com.google.common.truth.Truth.assertAbout 22 | import com.squareup.kotlinpoet.FileSpec 23 | import io.grpc.kotlin.generator.protoc.Declarations 24 | 25 | val declarationsSubjectFactory: Subject.Factory = 26 | Subject.Factory(::DeclarationsSubject) 27 | 28 | /** Make Truth assertions about [declarations]. */ 29 | fun assertThat(declarations: Declarations): DeclarationsSubject = 30 | assertAbout(declarationsSubjectFactory).that(declarations) 31 | 32 | /** A Truth subject for [Declarations]. */ 33 | class DeclarationsSubject( 34 | failureMetadata: FailureMetadata, 35 | private val actual: Declarations? 36 | ) : Subject(failureMetadata, actual) { 37 | fun generatesTopLevel(indentedCode: String) { 38 | val actualCode = 39 | FileSpec.builder("", "MyDeclarations.kt") 40 | .apply { actual?.writeOnlyTopLevel(this) } 41 | .build() 42 | check("topLevel").about(fileSpecs).that(actualCode).generates(indentedCode) 43 | } 44 | 45 | fun generatesEnclosed(indentedCode: String) { 46 | val actualCode = 47 | FileSpec.builder("", "MyDeclarations.kt") 48 | .apply { actual?.writeToEnclosingFile(this) } 49 | .build() 50 | check("enclosed").about(fileSpecs).that(actualCode).generates(indentedCode) 51 | } 52 | 53 | fun generatesNoTopLevelMembers() { 54 | val actualCode = 55 | FileSpec.builder("", "MyDeclarations.kt") 56 | .apply { actual?.writeOnlyTopLevel(this) } 57 | .build() 58 | check("topLevel") 59 | .withMessage("top level declarations: %s", actualCode) 60 | .that(actual?.hasTopLevelDeclarations) 61 | .isFalse() 62 | } 63 | 64 | fun generatesNoEnclosedMembers() { 65 | val actualCode = 66 | FileSpec.builder("", "MyDeclarations.kt") 67 | .apply { actual?.writeToEnclosingFile(this) } 68 | .build() 69 | check("enclosed") 70 | .withMessage("enclosed declarations: %s", actualCode) 71 | .that(actual?.hasEnclosingScopeDeclarations) 72 | .isFalse() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing/FileSpecSubject.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.FailureMetadata 20 | import com.google.common.truth.Subject 21 | import com.google.common.truth.Truth.assertAbout 22 | import com.squareup.kotlinpoet.FileSpec 23 | 24 | val fileSpecs: Subject.Factory = Subject.Factory(::FileSpecSubject) 25 | 26 | /** Make Truth assertions about [fileSpec]. */ 27 | fun assertThat(fileSpec: FileSpec): FileSpecSubject = assertAbout(fileSpecs).that(fileSpec) 28 | 29 | /** A Truth subject for [FileSpec]. */ 30 | class FileSpecSubject( 31 | failureMetadata: FailureMetadata, 32 | private val actual: FileSpec? 33 | ) : Subject(failureMetadata, actual) { 34 | fun generates(indentedCode: String) { 35 | val expectedCode = indentedCode.trimIndent() 36 | val actualCode = actual.toString().trim().lines().joinToString("\n") { it.trimEnd() } 37 | check("code").that(actualCode).isEqualTo(expectedCode) 38 | } 39 | 40 | fun hasName(name: String) { 41 | check("name").that(actual?.name).isEqualTo(name) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing/FunSpecSubject.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.FailureMetadata 20 | import com.google.common.truth.Subject 21 | import com.google.common.truth.Truth 22 | import com.squareup.kotlinpoet.FunSpec 23 | 24 | val funSpecs: Subject.Factory = Subject.Factory(::FunSpecSubject) 25 | 26 | /** Make Truth assertions about [funSpec]. */ 27 | fun assertThat(funSpec: FunSpec): FunSpecSubject = Truth.assertAbout(funSpecs).that(funSpec) 28 | 29 | /** A Truth subject for [FunSpec]. */ 30 | class FunSpecSubject( 31 | failureMetadata: FailureMetadata, 32 | private val actual: FunSpec? 33 | ) : Subject(failureMetadata, actual) { 34 | fun generates(indentedCode: String) { 35 | val expectedCode = indentedCode.trimIndent() 36 | val actualCode = actual.toString().trim() 37 | check("code").that(actualCode).isEqualTo(expectedCode) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing/TypeSpecSubject.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.FailureMetadata 20 | import com.google.common.truth.Subject 21 | import com.google.common.truth.Truth.assertAbout 22 | import com.squareup.kotlinpoet.TypeSpec 23 | 24 | val typeSpecs: Subject.Factory = Subject.Factory(::TypeSpecSubject) 25 | 26 | /** Make Truth assertions about [typeSpec]. */ 27 | fun assertThat(typeSpec: TypeSpec): TypeSpecSubject = assertAbout(typeSpecs).that(typeSpec) 28 | 29 | /** A Truth subject for [TypeSpec]. */ 30 | class TypeSpecSubject( 31 | failureMetadata: FailureMetadata, 32 | private val actual: TypeSpec? 33 | ) : Subject(failureMetadata, actual) { 34 | fun generates(indentedCode: String) { 35 | val expectedCode = indentedCode.trimIndent() 36 | val actualCode = actual.toString().trim() 37 | check("code").that(actualCode).isEqualTo(expectedCode) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/graph/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//:__subpackages__"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "graph", 11 | srcs = ["TopologicalSortGraph.kt"], 12 | deps = [ 13 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/sort", 14 | "@com_google_guava_guava//:com_google_guava_guava", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/graph/TopologicalSortGraph.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.util.graph 17 | 18 | import com.google.common.annotations.Beta 19 | import com.google.common.base.Preconditions.checkArgument 20 | import com.google.common.graph.Graph 21 | import io.grpc.kotlin.generator.protoc.util.sort.PartialOrdering 22 | import io.grpc.kotlin.generator.protoc.util.sort.TopologicalSort.sortLexicographicallyLeast 23 | 24 | @Beta 25 | object TopologicalSortGraph { 26 | fun topologicalOrdering(graph: Graph): List { 27 | checkArgument(graph.isDirected, "Cannot get topological ordering of an undirected graph.") 28 | val partialOrdering: PartialOrdering = object : PartialOrdering { 29 | override fun getPredecessors(element: N): Set = element?.let { 30 | graph.predecessors(it) 31 | } ?: emptySet() 32 | } 33 | return sortLexicographicallyLeast(graph.nodes(), partialOrdering) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/sort/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//:__subpackages__"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "sort", 11 | srcs = [ 12 | "PartialOrdering.kt", 13 | "TopologicalSort.kt", 14 | ], 15 | ) -------------------------------------------------------------------------------- /compiler/src/main/java/io/grpc/kotlin/generator/protoc/util/sort/PartialOrdering.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.util.sort 18 | 19 | /** 20 | * The interface that imposes a partial order on elements in a DAG to be topologically sorted. 21 | * 22 | * @author Okhtay Ilghami (okhtay@google.com) 23 | */ 24 | interface PartialOrdering { 25 | /** 26 | * Returns nodes that are considered "less than" `element` for purposes of a [ ]. Transitive predecessors do not need to be included. 27 | * 28 | * 29 | * For example, if `getPredecessors(a)` includes `b` and `getPredecessors(b)` 30 | * includes `c`, it is not necessary to include `c` in `getPredecessors(a)`. 31 | * `c` is not a "direct" predecessor of `a`. 32 | */ 33 | fun getPredecessors(element: T): Set 34 | } 35 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ClassSimpleNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import com.squareup.kotlinpoet.ClassName 21 | import com.squareup.kotlinpoet.TypeSpec 22 | import io.grpc.kotlin.generator.protoc.testing.assertThat 23 | import org.junit.Test 24 | import org.junit.runner.RunWith 25 | import org.junit.runners.JUnit4 26 | 27 | /** Tests for [ClassSimpleName]. */ 28 | @RunWith(JUnit4::class) 29 | class ClassSimpleNameTest { 30 | @Test 31 | fun withSuffix() { 32 | assertThat(ClassSimpleName("FooBar").withSuffix("Baz")) 33 | .isEqualTo(ClassSimpleName("FooBarBaz")) 34 | } 35 | 36 | @Test 37 | fun asPeer() { 38 | val className = ClassName("com.google.protobuf", "ByteString") 39 | val peerName = ClassSimpleName("Peer").asPeer(className) 40 | assertThat(peerName.packageName).isEqualTo("com.google.protobuf") 41 | assertThat(peerName.simpleName).isEqualTo("Peer") 42 | } 43 | 44 | @Test 45 | fun asMemberWithPrefix() { 46 | val simpleName = ClassSimpleName("SimpleName") 47 | 48 | assertThat(simpleName.asMemberWithPrefix("get")) 49 | .isEqualTo(MemberSimpleName("getSimpleName")) 50 | 51 | assertThat(simpleName.asMemberWithPrefix("")) 52 | .isEqualTo(MemberSimpleName("simpleName")) 53 | } 54 | 55 | @Test 56 | fun classBuilder() { 57 | val simpleName = ClassSimpleName("SimpleName") 58 | assertThat(TypeSpec.classBuilder(simpleName).build()).generates("public class SimpleName") 59 | } 60 | 61 | @Test 62 | fun objectBuilder() { 63 | val simpleName = ClassSimpleName("SimpleName") 64 | assertThat(TypeSpec.objectBuilder(simpleName).build()).generates("public object SimpleName") 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ConstantNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import com.squareup.kotlinpoet.ClassName 21 | import com.squareup.kotlinpoet.MemberName 22 | import org.junit.Test 23 | import org.junit.runner.RunWith 24 | import org.junit.runners.JUnit4 25 | 26 | /** Test for [ConstantName]. */ 27 | @RunWith(JUnit4::class) 28 | class ConstantNameTest { 29 | @Test 30 | fun memberConstantName() { 31 | val className = ClassName("com.google.protobuf", "ByteString") 32 | val memberName: MemberName = className.member(ConstantName("EMPTY")) 33 | assertThat(memberName.canonicalName).isEqualTo("com.google.protobuf.ByteString.EMPTY") 34 | assertThat(memberName.packageName).isEqualTo("com.google.protobuf") 35 | assertThat(memberName.enclosingClassName!!.canonicalName) 36 | .isEqualTo("com.google.protobuf.ByteString") 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/JavaPackagePolicyTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import io.grpc.kotlin.generator.protoc.testproto.Example3 21 | import org.junit.Test 22 | import org.junit.runner.RunWith 23 | import org.junit.runners.JUnit4 24 | import testing.ImplicitJavaPackage 25 | 26 | /** Tests for [JavaPackagePolicy]. */ 27 | @RunWith(JUnit4::class) 28 | class JavaPackagePolicyTest { 29 | @Test 30 | fun explicitJavaPackageGoogle() { 31 | with(JavaPackagePolicy.OPEN_SOURCE) { 32 | assertThat(javaPackage(Example3.getDescriptor().toProto())) 33 | .isEqualTo(PackageScope(Example3::class.java.`package`.name)) 34 | } 35 | } 36 | 37 | @Test 38 | fun explicitJavaPackageExternal() { 39 | with(JavaPackagePolicy.OPEN_SOURCE) { 40 | assertThat(javaPackage(Example3.getDescriptor().toProto())) 41 | .isEqualTo(PackageScope(Example3::class.java.`package`.name)) 42 | } 43 | } 44 | 45 | @Test 46 | fun implicitJavaPackageGoogle() { 47 | with(JavaPackagePolicy.OPEN_SOURCE) { 48 | assertThat(javaPackage(ImplicitJavaPackage.getDescriptor().toProto())) 49 | .isEqualTo( 50 | PackageScope("testing") 51 | ) 52 | } 53 | } 54 | 55 | @Test 56 | fun implicitJavaPackageExternal() { 57 | with(JavaPackagePolicy.OPEN_SOURCE) { 58 | assertThat(javaPackage(ImplicitJavaPackage.getDescriptor().toProto())) 59 | .isEqualTo(PackageScope("testing")) 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/MemberSimpleNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import org.junit.Test 21 | import org.junit.runner.RunWith 22 | import org.junit.runners.JUnit4 23 | 24 | /** Tests for [MemberSimpleName]. */ 25 | @RunWith(JUnit4::class) 26 | class MemberSimpleNameTest { 27 | @Test 28 | fun withPrefix() { 29 | assertThat(MemberSimpleName("myField").withPrefix("get")) 30 | .isEqualTo(MemberSimpleName("getMyField")) 31 | assertThat(MemberSimpleName("field").withPrefix("get")) 32 | .isEqualTo(MemberSimpleName("getField")) 33 | } 34 | 35 | @Test 36 | fun withSuffix() { 37 | assertThat(MemberSimpleName("myField").withSuffix("List")) 38 | .isEqualTo(MemberSimpleName("myFieldList")) 39 | assertThat(MemberSimpleName("field").withSuffix("List")) 40 | .isEqualTo(MemberSimpleName("fieldList")) 41 | } 42 | 43 | @Test 44 | fun plus() { 45 | assertThat(MemberSimpleName("putAll") + MemberSimpleName("myField")) 46 | .isEqualTo(MemberSimpleName("putAllMyField")) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/OptionalProto3FieldTest.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin.generator.protoc 2 | 3 | import com.google.common.truth.Truth.assertThat 4 | import io.grpc.testing.TestProto3Optional 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.junit.runners.JUnit4 8 | 9 | /** Tests for supporting proto3 optional fields. */ 10 | @RunWith(JUnit4::class) 11 | class OptionalProto3FieldTest { 12 | 13 | @Test 14 | fun compileProto3OptionalField() { 15 | assertThat(TestProto3Optional.OptionalProto3.getDescriptor().findFieldByName("optional_field")) 16 | .isNotNull() 17 | } 18 | 19 | @Test 20 | fun generateHasOptionalFieldMethod() { 21 | assertThat(TestProto3Optional.OptionalProto3::class.java.getMethod("hasOptionalField")) 22 | .isNotNull() 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ProtoEnumValueNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import io.grpc.kotlin.generator.protoc.testproto.Example3 21 | import org.junit.Test 22 | import org.junit.runner.RunWith 23 | import org.junit.runners.JUnit4 24 | 25 | /** Tests for [ProtoEnumValueName]. */ 26 | @RunWith(JUnit4::class) 27 | class ProtoEnumValueNameTest { 28 | @Test 29 | fun asConstantName() { 30 | assertThat(ProtoEnumValueName("FOO_BAR").asConstantName) 31 | .isEqualTo(ConstantName("FOO_BAR")) 32 | } 33 | 34 | @Test 35 | fun protoEnumConstantName() { 36 | assertThat(Example3.ExampleEnum.BAR.valueDescriptor.protoEnumValueName) 37 | .isEqualTo(ProtoEnumValueName("BAR")) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ProtoFileNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import io.grpc.kotlin.generator.protoc.testproto.Example3 21 | import org.junit.Test 22 | import org.junit.runner.RunWith 23 | import org.junit.runners.JUnit4 24 | 25 | /** Tests for [ProtoFileName]. */ 26 | @RunWith(JUnit4::class) 27 | class ProtoFileNameTest { 28 | @Test 29 | fun fileName() { 30 | assertThat(Example3.getDescriptor().fileName) 31 | .isEqualTo( 32 | ProtoFileName( 33 | "testing/example3.proto" 34 | ) 35 | ) 36 | } 37 | 38 | @Test 39 | fun name() { 40 | assertThat(ProtoFileName("foo/bar/baz/quux.proto").name) 41 | .isEqualTo("quux") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ProtoMethodNameTest.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin.generator.protoc 2 | 3 | import com.google.common.truth.Truth.assertThat 4 | import org.junit.Test 5 | import org.junit.runner.RunWith 6 | import org.junit.runners.JUnit4 7 | 8 | /** Tests for [ProtoMethodName]. */ 9 | @RunWith(JUnit4::class) 10 | class ProtoMethodNameTest { 11 | @Test 12 | fun toMemberSimpleNameWithSingleUnderscore(){ 13 | assertThat(ProtoMethodName("say_hello").toMemberSimpleName()) 14 | .isEqualTo(MemberSimpleName("sayHello")) 15 | } 16 | 17 | @Test 18 | fun toMemberSimpleNameWithMultipleUnderscores(){ 19 | assertThat(ProtoMethodName("say_hello_again").toMemberSimpleName()) 20 | .isEqualTo(MemberSimpleName("sayHelloAgain")) 21 | } 22 | 23 | @Test 24 | fun toMemberSimpleNameWithRecommendedNamingStyle(){ 25 | assertThat(ProtoMethodName("SayHello").toMemberSimpleName()) 26 | .isEqualTo(MemberSimpleName("sayHello")) 27 | } 28 | } -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ProtoTypeSimpleNameTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import io.grpc.kotlin.generator.protoc.testproto.Example3 21 | import org.junit.Test 22 | import org.junit.runner.RunWith 23 | import org.junit.runners.JUnit4 24 | 25 | /** Tests for [ProtoTypeSimpleName]. */ 26 | @RunWith(JUnit4::class) 27 | class ProtoTypeSimpleNameTest { 28 | @Test 29 | fun toSimpleClassName() { 30 | assertThat(ProtoTypeSimpleName("FooBarMessage").toClassSimpleName()) 31 | .isEqualTo(ClassSimpleName("FooBarMessage")) 32 | } 33 | 34 | @Test 35 | fun messageName() { 36 | val descriptor = Example3.ExampleMessage.getDescriptor() 37 | assertThat(descriptor.simpleName).isEqualTo(ProtoTypeSimpleName("ExampleMessage")) 38 | } 39 | 40 | @Test 41 | fun enumName() { 42 | val descriptor = Example3.ExampleEnum.getDescriptor() 43 | assertThat(descriptor.simpleName).isEqualTo(ProtoTypeSimpleName("ExampleEnum")) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/ScopeTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import com.squareup.kotlinpoet.ClassName 21 | import org.junit.Test 22 | import org.junit.runner.RunWith 23 | import org.junit.runners.JUnit4 24 | 25 | /** Tests for [Scope]. */ 26 | @RunWith(JUnit4::class) 27 | class ScopeTest { 28 | @Test 29 | fun unqualifiedScope() { 30 | val name = UnqualifiedScope.nestedClass(ClassSimpleName("FooBar")) 31 | assertThat(name).isEqualTo(ClassName("", "FooBar")) 32 | } 33 | 34 | @Test 35 | fun packageScope() { 36 | val name = PackageScope("com.foo.bar").nestedClass(ClassSimpleName("FooBar")) 37 | assertThat(name).isEqualTo(ClassName("com.foo.bar", "FooBar")) 38 | } 39 | 40 | @Test 41 | fun classScope() { 42 | val name = 43 | ClassScope(ClassName("com.foo.bar", "Baz")) 44 | .nestedClass(ClassSimpleName("Quux")) 45 | assertThat(name).isEqualTo( 46 | ClassName("com.foo.bar", "Baz", "Quux") 47 | ) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/testing/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_test") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//compiler/src/test:__subpackages__"]) 6 | 7 | kt_jvm_test( 8 | name = "DeclarationsSubjectTest", 9 | srcs = ["DeclarationsSubjectTest.kt"], 10 | test_class = "io.grpc.kotlin.generator.protoc.testing.DeclarationsSubjectTest", 11 | deps = [ 12 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing", 13 | "@maven//:com_google_truth_truth", 14 | "@maven//:com_squareup_kotlinpoet", 15 | "@maven//:junit_junit", 16 | ], 17 | ) 18 | 19 | kt_jvm_test( 20 | name = "FileSpecSubjectTest", 21 | srcs = ["FileSpecSubjectTest.kt"], 22 | test_class = "io.grpc.kotlin.generator.protoc.testing.FileSpecSubjectTest", 23 | deps = [ 24 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing", 25 | ], 26 | ) 27 | 28 | kt_jvm_test( 29 | name = "FunSpecSubjectTest", 30 | srcs = ["FunSpecSubjectTest.kt"], 31 | test_class = "io.grpc.kotlin.generator.protoc.testing.FunSpecSubjectTest", 32 | deps = [ 33 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing", 34 | ], 35 | ) 36 | 37 | kt_jvm_test( 38 | name = "TypeSpecSubjectTest", 39 | srcs = ["TypeSpecSubjectTest.kt"], 40 | test_class = "io.grpc.kotlin.generator.protoc.testing.TypeSpecSubjectTest", 41 | deps = [ 42 | "//compiler/src/main/java/io/grpc/kotlin/generator/protoc/testing", 43 | ], 44 | ) 45 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/testing/DeclarationsSubjectTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.ExpectFailure.expectFailureAbout 20 | import com.squareup.kotlinpoet.INT 21 | import com.squareup.kotlinpoet.PropertySpec 22 | import io.grpc.kotlin.generator.protoc.declarations 23 | import org.junit.Test 24 | import org.junit.runner.RunWith 25 | import org.junit.runners.JUnit4 26 | 27 | /** Tests for [DeclarationsSubject]. */ 28 | @RunWith(JUnit4::class) 29 | class DeclarationsSubjectTest { 30 | private val topLevelProperty = PropertySpec.builder("topLevel", INT).build() 31 | private val enclosedProperty = PropertySpec.builder("enclosed", INT).build() 32 | private val decls = declarations { 33 | addTopLevelProperty(topLevelProperty) 34 | addProperty(enclosedProperty) 35 | } 36 | 37 | @Test 38 | fun generatesTopLevel() { 39 | assertThat(decls).generatesTopLevel( 40 | """ 41 | import kotlin.Int 42 | 43 | public val topLevel: Int 44 | """ 45 | ) 46 | } 47 | 48 | @Test 49 | fun generatesEnclosed() { 50 | assertThat(decls).generatesEnclosed( 51 | """ 52 | import kotlin.Int 53 | 54 | public val enclosed: Int 55 | """ 56 | ) 57 | } 58 | 59 | @Test 60 | fun generatesTopLevelFailure() { 61 | expectFailureAbout( 62 | declarationsSubjectFactory 63 | ) { it.that(decls).generatesTopLevel("") } 64 | } 65 | 66 | @Test 67 | fun generatesEnclosedFailure() { 68 | expectFailureAbout( 69 | declarationsSubjectFactory 70 | ) { it.that(decls).generatesEnclosed("") } 71 | } 72 | 73 | @Test 74 | fun generatesNoTopLevel() { 75 | assertThat( 76 | declarations { 77 | addProperty(enclosedProperty) 78 | } 79 | ).generatesNoTopLevelMembers() 80 | } 81 | 82 | @Test 83 | fun generatesNoEnclosed() { 84 | assertThat( 85 | declarations { 86 | addTopLevelProperty(topLevelProperty) 87 | } 88 | ).generatesNoEnclosedMembers() 89 | } 90 | 91 | @Test 92 | fun generatesNoTopLevelFailure() { 93 | expectFailureAbout( 94 | declarationsSubjectFactory 95 | ) { it.that(decls).generatesNoTopLevelMembers() } 96 | } 97 | 98 | @Test 99 | fun generatesNoEnclosedFailure() { 100 | expectFailureAbout( 101 | declarationsSubjectFactory 102 | ) { it.that(decls).generatesNoEnclosedMembers() } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/testing/FileSpecSubjectTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.ExpectFailure.expectFailureAbout 20 | import com.squareup.kotlinpoet.FileSpec 21 | import com.squareup.kotlinpoet.INT 22 | import com.squareup.kotlinpoet.PropertySpec 23 | import org.junit.Test 24 | import org.junit.runner.RunWith 25 | import org.junit.runners.JUnit4 26 | 27 | /** Tests for [FileSpecSubject]. */ 28 | @RunWith(JUnit4::class) 29 | class FileSpecSubjectTest { 30 | private val fileSpec = 31 | FileSpec.builder(packageName = "", fileName = "FileSpecContents.kt") 32 | .addProperty(PropertySpec.builder("bar", INT).build()) 33 | .build() 34 | 35 | @Test 36 | fun generates() { 37 | assertThat(fileSpec).generates( 38 | """ 39 | import kotlin.Int 40 | 41 | public val bar: Int 42 | """ 43 | ) 44 | } 45 | 46 | @Test 47 | fun generatesFailure() { 48 | expectFailureAbout( 49 | fileSpecs 50 | ) { it.that(fileSpec).generates("") } 51 | expectFailureAbout( 52 | fileSpecs 53 | ) { it.that(fileSpec).generates("object Foo") } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/testing/FunSpecSubjectTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.ExpectFailure 20 | import com.google.common.truth.ExpectFailure.SimpleSubjectBuilderCallback 21 | import com.squareup.kotlinpoet.FunSpec 22 | import com.squareup.kotlinpoet.INT 23 | import com.squareup.kotlinpoet.ParameterSpec 24 | import com.squareup.kotlinpoet.asTypeName 25 | import org.junit.Test 26 | import org.junit.runner.RunWith 27 | import org.junit.runners.JUnit4 28 | 29 | /** Tests for [TypeSpecSubject]. */ 30 | @RunWith(JUnit4::class) 31 | class FunSpecSubjectTest { 32 | private val funSpec = 33 | FunSpec 34 | .builder("foo") 35 | .addParameter(ParameterSpec.builder("bar", INT).build()) 36 | .returns(String::class.asTypeName()) 37 | .build() 38 | 39 | @Test 40 | fun generates() { 41 | assertThat(funSpec).generates( 42 | """ 43 | public fun foo(bar: kotlin.Int): kotlin.String { 44 | } 45 | """ 46 | ) 47 | } 48 | 49 | @Test 50 | fun generatesFailure() { 51 | ExpectFailure.expectFailureAbout( 52 | funSpecs 53 | ) { it.that(funSpec).generates("") } 54 | ExpectFailure.expectFailureAbout( 55 | funSpecs 56 | ) { it.that(funSpec).generates("fun bar") } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /compiler/src/test/java/io/grpc/kotlin/generator/protoc/testing/TypeSpecSubjectTest.kt: -------------------------------------------------------------------------------- 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 | package io.grpc.kotlin.generator.protoc.testing 18 | 19 | import com.google.common.truth.ExpectFailure.expectFailureAbout 20 | import com.squareup.kotlinpoet.INT 21 | import com.squareup.kotlinpoet.PropertySpec 22 | import com.squareup.kotlinpoet.TypeSpec 23 | import org.junit.Test 24 | import org.junit.runner.RunWith 25 | import org.junit.runners.JUnit4 26 | 27 | /** Tests for [TypeSpecSubject]. */ 28 | @RunWith(JUnit4::class) 29 | class TypeSpecSubjectTest { 30 | private val typeSpec = 31 | TypeSpec 32 | .objectBuilder("Foo") 33 | .addProperty(PropertySpec.builder("bar", INT).build()) 34 | .build() 35 | 36 | @Test 37 | fun generates() { 38 | assertThat(typeSpec).generates( 39 | """ 40 | public object Foo { 41 | public val bar: kotlin.Int 42 | } 43 | """ 44 | ) 45 | } 46 | 47 | @Test 48 | fun generatesFailure() { 49 | expectFailureAbout( 50 | typeSpecs 51 | ) { it.that(typeSpec).generates("") } 52 | expectFailureAbout( 53 | typeSpecs 54 | ) { it.that(typeSpec).generates("public object Foo") } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /compiler/src/test/proto/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//compiler/src/test:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "hello_world_proto", 11 | srcs = ["helloworld.proto"], 12 | strip_import_prefix = "/compiler/src/test/proto", 13 | ) 14 | 15 | java_proto_library( 16 | name = "hello_world_java_proto", 17 | deps = [":hello_world_proto"], 18 | ) 19 | 20 | java_grpc_library( 21 | name = "hello_world_java_grpc", 22 | srcs = [":hello_world_proto"], 23 | deps = [":hello_world_java_proto"], 24 | ) 25 | 26 | kt_jvm_grpc_library( 27 | name = "hello_world_kt_grpc", 28 | srcs = [":hello_world_proto"], 29 | deps = [":hello_world_java_grpc"], 30 | ) 31 | -------------------------------------------------------------------------------- /compiler/src/test/proto/helloworld/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | package helloworld; 17 | 18 | option java_multiple_files = true; 19 | option java_package = "io.grpc.examples.helloworld"; 20 | option java_outer_classname = "HelloWorldProto"; 21 | 22 | // The greeting service definition. 23 | service Greeter { 24 | // Sends a greeting 25 | rpc SayHello(HelloRequest) returns (HelloReply) {} 26 | 27 | // Sends a greeting to a group 28 | rpc ClientStreamSayHello(stream HelloRequest) returns (HelloReply) {} 29 | 30 | // Sends a number of hellos 31 | rpc ServerStreamSayHello(MultiHelloRequest) returns (stream HelloReply) {} 32 | 33 | // Sends interactive hellos 34 | rpc BidiStreamSayHello(stream HelloRequest) returns (stream HelloReply) {} 35 | } 36 | 37 | // The request message containing the user's name. 38 | message HelloRequest { 39 | string name = 1; 40 | } 41 | 42 | message MultiHelloRequest { 43 | repeated string name = 1; 44 | } 45 | 46 | // The response message containing the greetings 47 | message HelloReply { 48 | string message = 1; 49 | } -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//compiler/src/test:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "example3_proto", 11 | srcs = ["example3.proto"], 12 | strip_import_prefix = "/compiler/src/test/proto", 13 | deps = ["@com_google_protobuf//:wrappers_proto"], 14 | ) 15 | 16 | java_proto_library( 17 | name = "example3_java_proto", 18 | deps = [":example3_proto"], 19 | ) 20 | 21 | proto_library( 22 | name = "has_explicit_outer_class_name_proto", 23 | srcs = ["has_explicit_outer_class_name.proto"], 24 | strip_import_prefix = "/compiler/src/test/proto", 25 | ) 26 | 27 | java_proto_library( 28 | name = "has_explicit_outer_class_name_java_proto", 29 | deps = ["has_explicit_outer_class_name_proto"], 30 | ) 31 | 32 | proto_library( 33 | name = "has_nested_class_name_conflict_proto", 34 | srcs = ["has_nested_class_name_conflict.proto"], 35 | strip_import_prefix = "/compiler/src/test/proto", 36 | ) 37 | 38 | java_proto_library( 39 | name = "has_nested_class_name_conflict_java_proto", 40 | deps = ["has_nested_class_name_conflict_proto"], 41 | ) 42 | 43 | proto_library( 44 | name = "has_outer_class_name_conflict_proto", 45 | srcs = ["has_outer_class_name_conflict.proto"], 46 | strip_import_prefix = "/compiler/src/test/proto", 47 | ) 48 | 49 | java_proto_library( 50 | name = "has_outer_class_name_conflict_java_proto", 51 | deps = ["has_outer_class_name_conflict_proto"], 52 | ) 53 | 54 | proto_library( 55 | name = "implicit_java_package_proto", 56 | srcs = ["implicit_java_package.proto"], 57 | strip_import_prefix = "/compiler/src/test/proto", 58 | ) 59 | 60 | java_proto_library( 61 | name = "implicit_java_package_java_proto", 62 | deps = ["implicit_java_package_proto"], 63 | ) 64 | 65 | proto_library( 66 | name = "proto-file-with-hyphen_proto", 67 | srcs = ["proto-file-with-hyphen.proto"], 68 | strip_import_prefix = "/compiler/src/test/proto", 69 | ) 70 | 71 | java_proto_library( 72 | name = "proto-file-with-hyphen_java_proto", 73 | deps = ["proto-file-with-hyphen_proto"], 74 | ) 75 | 76 | proto_library( 77 | name = "service_name_conflicts_with_file_proto", 78 | srcs = ["service_name_conflicts_with_file.proto"], 79 | strip_import_prefix = "/compiler/src/test/proto", 80 | ) 81 | 82 | java_proto_library( 83 | name = "service_name_conflicts_with_file_java_proto", 84 | deps = ["service_name_conflicts_with_file_proto"], 85 | ) 86 | 87 | proto_library( 88 | name = "service_t_proto", 89 | srcs = ["serviceT.proto"], 90 | strip_import_prefix = "/compiler/src/test/proto", 91 | ) 92 | 93 | java_proto_library( 94 | name = "service_t_java_proto", 95 | deps = ["service_t_proto"], 96 | ) 97 | 98 | proto_library( 99 | name = "test_proto3_optional", 100 | srcs = ["test_proto3_optional.proto"], 101 | strip_import_prefix = "/compiler/src/test/proto", 102 | ) 103 | 104 | java_proto_library( 105 | name = "test_proto3_optional_java_proto", 106 | deps = ["test_proto3_optional"], 107 | ) 108 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/example3.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package testing; 4 | 5 | import "google/protobuf/wrappers.proto"; 6 | 7 | option java_package = "io.grpc.kotlin.generator.protoc.testproto"; 8 | 9 | message ExampleMessage { 10 | int32 int32_field = 1; 11 | string string_field = 2; 12 | SubMessage sub_message_field = 3; 13 | 14 | oneof my_oneof { 15 | string string_oneof_option = 4; 16 | SubMessage sub_message_oneof_option = 5; 17 | } 18 | 19 | repeated string repeated_string_field = 6; 20 | map map_field = 7; 21 | 22 | message SubMessage {} 23 | 24 | // TODO(lowasser): why does this need the leading .? Other protos don't seem 25 | // to. 26 | .google.protobuf.Int32Value optional_int32 = 8; 27 | 28 | string class = 9; 29 | repeated string cached_size = 10; 30 | map serialized_size = 11; 31 | } 32 | 33 | enum ExampleEnum { 34 | DEFAULT = 0; 35 | FOO = 1; 36 | BAR = 2; 37 | } 38 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/has_explicit_outer_class_name.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package testing; 4 | 5 | option java_package = "io.grpc.kotlin.generator.protoc.testproto"; 6 | option java_outer_classname = "MyExplicitOuterClassName"; 7 | 8 | message HasExplicitOuterClassName {} 9 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/has_nested_class_name_conflict.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package testing; 4 | 5 | option java_package = "io.grpc.kotlin.generator.protoc.testproto"; 6 | 7 | message NestedMessageConflicts { 8 | message HasNestedClassNameConflict {} 9 | } 10 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/has_outer_class_name_conflict.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package testing; 4 | 5 | option java_package = "io.grpc.kotlin.generator.protoc.testproto"; 6 | 7 | message HasOuterClassNameConflict {} 8 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/implicit_java_package.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package testing; 4 | 5 | message LivesInImplicitJavaPackage {} 6 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/proto-file-with-hyphen.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package io.grpc.testing; 4 | 5 | option java_package = "io.grpc.testing"; 6 | 7 | message ProtoFileWithHypen {} 8 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/rpc_name_contains_underscore.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package io.grpc.testing.underscore; 3 | option java_multiple_files = true; 4 | service NameContainsUnderscore { 5 | rpc say_hello (HelloRequest) returns (HelloReply); 6 | rpc say_hello_again (HelloRequest) returns (HelloReply); 7 | } 8 | message HelloRequest {} 9 | message HelloReply {} -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/serviceT.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package io.grpc.testing; 3 | 4 | service ServiceT { 5 | rpc serviceT(stream reqT) returns (stream resT) {} 6 | } 7 | 8 | message reqT {} 9 | 10 | message resT {} 11 | -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/service_name_conflicts_with_file.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | package io.grpc.testing; 17 | 18 | option java_package = "io.grpc.testing"; 19 | 20 | service ServiceNameConflictsWithFile { 21 | rpc SayHello(HelloRequest) returns (HelloReply) {} 22 | } 23 | 24 | // The request message containing the user's name. 25 | message HelloRequest { 26 | string name = 1; 27 | } 28 | 29 | // The response message containing the greetings 30 | message HelloReply { 31 | string message = 1; 32 | } -------------------------------------------------------------------------------- /compiler/src/test/proto/testing/test_proto3_optional.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | package io.grpc.testing; 3 | 4 | // Currently, java proto compiler supports optional fields only if there is an additional flag 5 | // --experimental_allow_proto3_optional or the filename (or a directory name) of the proto 6 | // file contains the string 'test_proto3_optional' 7 | message OptionalProto3 { 8 | 9 | optional string optional_field = 1; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | .idea/ 3 | build/ 4 | *.iml 5 | /local.properties 6 | -------------------------------------------------------------------------------- /examples/Procfile: -------------------------------------------------------------------------------- 1 | web: server/build/install/server/bin/server 2 | -------------------------------------------------------------------------------- /examples/android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) 3 | alias(libs.plugins.kotlin.android) 4 | } 5 | 6 | dependencies { 7 | implementation(project(":stub-android")) 8 | 9 | implementation(libs.androidx.activity.compose) 10 | implementation(libs.androidx.compose.foundation.layout) 11 | implementation(libs.androidx.compose.material) 12 | implementation(libs.androidx.compose.runtime) 13 | implementation(libs.androidx.compose.ui) 14 | 15 | runtimeOnly(libs.grpc.okhttp) 16 | } 17 | 18 | kotlin { 19 | jvmToolchain(8) 20 | } 21 | 22 | android { 23 | compileSdk = 34 24 | buildToolsVersion = "34.0.0" 25 | namespace = "io.grpc.examples.helloworld" 26 | 27 | defaultConfig { 28 | applicationId = "io.grpc.examples.hello" 29 | minSdk = 26 30 | targetSdk = 34 31 | versionCode = 1 32 | versionName = "1.0" 33 | 34 | val serverUrl: String? by project 35 | if (serverUrl != null) { 36 | resValue("string", "server_url", serverUrl!!) 37 | } else { 38 | resValue("string", "server_url", "http://10.0.2.2:50051/") 39 | } 40 | } 41 | 42 | buildFeatures { 43 | compose = true 44 | } 45 | 46 | composeOptions { 47 | kotlinCompilerExtensionVersion = libs.androidx.compose.compiler.get().version 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/android/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Name: 4 | Send gRPC Request 5 | gRPC Kotlin Android 6 | Server response: 7 | 8 | -------------------------------------------------------------------------------- /examples/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.application) apply false 3 | alias(libs.plugins.android.library) apply false 4 | alias(libs.plugins.protobuf) apply false 5 | alias(libs.plugins.kotlin.jvm) apply false 6 | alias(libs.plugins.kotlin.android) apply false 7 | alias(libs.plugins.ktlint) apply false 8 | } 9 | 10 | subprojects { 11 | apply(plugin = "org.jlleitschuh.gradle.ktlint") 12 | 13 | configure { 14 | filter { 15 | exclude { 16 | it.file.path.startsWith(project.layout.buildDirectory.get().dir("generated").toString()) 17 | } 18 | } 19 | } 20 | } 21 | 22 | tasks.create("assemble").dependsOn(":server:installDist") 23 | 24 | -------------------------------------------------------------------------------- /examples/client/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | alias(libs.plugins.kotlin.jvm) 4 | } 5 | 6 | kotlin { 7 | jvmToolchain(8) 8 | } 9 | 10 | dependencies { 11 | implementation(project(":stub")) 12 | runtimeOnly(libs.grpc.netty) 13 | } 14 | 15 | tasks.register("HelloWorldClient") { 16 | dependsOn("classes") 17 | classpath = sourceSets["main"].runtimeClasspath 18 | mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt") 19 | } 20 | 21 | tasks.register("RouteGuideClient") { 22 | dependsOn("classes") 23 | classpath = sourceSets["main"].runtimeClasspath 24 | mainClass.set("io.grpc.examples.routeguide.RouteGuideClientKt") 25 | } 26 | 27 | tasks.register("AnimalsClient") { 28 | dependsOn("classes") 29 | classpath = sourceSets["main"].runtimeClasspath 30 | mainClass.set("io.grpc.examples.animals.AnimalsClientKt") 31 | } 32 | 33 | val helloWorldClientStartScripts = 34 | tasks.register("helloWorldClientStartScripts") { 35 | mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt") 36 | applicationName = "hello-world-client" 37 | outputDir = tasks.named("startScripts").get().outputDir 38 | classpath = tasks.named("startScripts").get().classpath 39 | } 40 | 41 | val routeGuideClientStartScripts = 42 | tasks.register("routeGuideClientStartScripts") { 43 | mainClass.set("io.grpc.examples.routeguide.RouteGuideClientKt") 44 | applicationName = "route-guide-client" 45 | outputDir = tasks.named("startScripts").get().outputDir 46 | classpath = tasks.named("startScripts").get().classpath 47 | } 48 | 49 | val animalsClientStartScripts = 50 | tasks.register("animalsClientStartScripts") { 51 | mainClass.set("io.grpc.examples.animals.AnimalsClientKt") 52 | applicationName = "animals-client" 53 | outputDir = tasks.named("startScripts").get().outputDir 54 | classpath = tasks.named("startScripts").get().classpath 55 | } 56 | 57 | tasks.named("startScripts") { 58 | dependsOn(helloWorldClientStartScripts) 59 | dependsOn(routeGuideClientStartScripts) 60 | dependsOn(animalsClientStartScripts) 61 | } 62 | -------------------------------------------------------------------------------- /examples/client/src/main/kotlin/io/grpc/examples/animals/AnimalsClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.animals 18 | 19 | import io.grpc.ManagedChannel 20 | import io.grpc.ManagedChannelBuilder 21 | import java.io.Closeable 22 | import java.util.concurrent.TimeUnit 23 | 24 | class AnimalsClient(private val channel: ManagedChannel) : Closeable { 25 | private val dogStub: DogGrpcKt.DogCoroutineStub by lazy { DogGrpcKt.DogCoroutineStub(channel) } 26 | private val pigStub: PigGrpcKt.PigCoroutineStub by lazy { PigGrpcKt.PigCoroutineStub(channel) } 27 | private val sheepStub: SheepGrpcKt.SheepCoroutineStub by lazy { SheepGrpcKt.SheepCoroutineStub(channel) } 28 | 29 | suspend fun bark() { 30 | val request = barkRequest {} 31 | val response = dogStub.bark(request) 32 | println("Received: ${response.message}") 33 | } 34 | 35 | suspend fun oink() { 36 | val request = oinkRequest {} 37 | val response = pigStub.oink(request) 38 | println("Received: ${response.message}") 39 | } 40 | 41 | suspend fun baa() { 42 | val request = baaRequest {} 43 | val response = sheepStub.baa(request) 44 | println("Received: ${response.message}") 45 | } 46 | 47 | override fun close() { 48 | channel.shutdown().awaitTermination(5, TimeUnit.SECONDS) 49 | } 50 | } 51 | 52 | /** 53 | * Talk to the animals. Fluent in dog, pig and sheep. 54 | */ 55 | suspend fun main(args: Array) { 56 | val usage = "usage: animals_client [{dog|pig|sheep} ...]" 57 | 58 | if (args.isEmpty()) { 59 | println("No animals specified.") 60 | println(usage) 61 | } 62 | 63 | val port = 50051 64 | 65 | val channel = ManagedChannelBuilder.forAddress("localhost", port).usePlaintext().build() 66 | 67 | val client = AnimalsClient(channel) 68 | 69 | args.forEach { 70 | when (it) { 71 | "dog" -> client.bark() 72 | "pig" -> client.oink() 73 | "sheep" -> client.baa() 74 | else -> { 75 | println("Unknown animal type: \"$it\". Try \"dog\", \"pig\" or \"sheep\".") 76 | println(usage) 77 | } 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/client/src/main/kotlin/io/grpc/examples/animals/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "animals_client", 9 | srcs = ["AnimalsClient.kt"], 10 | main_class = "io.grpc.examples.animals.AnimalsClientKt", 11 | deps = [ 12 | "//examples/protos/src/main/proto/io/grpc/examples/animals:animals_kt_grpc", 13 | "//examples/protos/src/main/proto/io/grpc/examples/animals:animals_kt_proto", 14 | "@com_google_protobuf//:protobuf_java_util", 15 | "@io_grpc_grpc_java//netty", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /examples/client/src/main/kotlin/io/grpc/examples/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "hello_world_client", 9 | srcs = ["HelloWorldClient.kt"], 10 | main_class = "io.grpc.examples.helloworld.HelloWorldClientKt", 11 | deps = [ 12 | "//examples/protos/src/main/proto/io/grpc/examples/helloworld:hello_world_kt_grpc", 13 | "//examples/protos/src/main/proto/io/grpc/examples/helloworld:hello_world_kt_proto", 14 | "@io_grpc_grpc_java//netty", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /examples/client/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.helloworld 18 | 19 | import io.grpc.ManagedChannel 20 | import io.grpc.ManagedChannelBuilder 21 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub 22 | import java.io.Closeable 23 | import java.util.concurrent.TimeUnit 24 | 25 | class HelloWorldClient(private val channel: ManagedChannel) : Closeable { 26 | private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel) 27 | 28 | suspend fun greet(name: String) { 29 | val request = helloRequest { this.name = name } 30 | val response = stub.sayHello(request) 31 | println("Received: ${response.message}") 32 | } 33 | 34 | override fun close() { 35 | channel.shutdown().awaitTermination(5, TimeUnit.SECONDS) 36 | } 37 | } 38 | 39 | /** 40 | * Greeter, uses first argument as name to greet if present; 41 | * greets "world" otherwise. 42 | */ 43 | suspend fun main(args: Array) { 44 | val port = System.getenv("PORT")?.toInt() ?: 50051 45 | 46 | val channel = ManagedChannelBuilder.forAddress("localhost", port).usePlaintext().build() 47 | 48 | val client = HelloWorldClient(channel) 49 | 50 | val user = args.singleOrNull() ?: "world" 51 | client.greet(user) 52 | } 53 | -------------------------------------------------------------------------------- /examples/client/src/main/kotlin/io/grpc/examples/routeguide/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "route_guide_client", 9 | srcs = ["RouteGuideClient.kt"], 10 | main_class = "io.grpc.examples.routeguide.RouteGuideClientKt", 11 | resources = ["//examples/stub/src/main/resources/io/grpc/examples/routeguide:route_guide_db"], 12 | deps = [ 13 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_kt_grpc", 14 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_kt_proto", 15 | "//examples/stub/src/main/kotlin/io/grpc/examples/routeguide:route_guide_stub", 16 | "@com_google_protobuf//:protobuf_java_util", 17 | "@io_grpc_grpc_java//netty", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /examples/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-XX:MaxMetaspaceSize=512m 2 | android.useAndroidX=true 3 | -------------------------------------------------------------------------------- /examples/gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [plugins] 2 | android-application = { id = "com.android.application", version = "8.3.0" } 3 | android-library = { id = "com.android.library", version = "8.3.0" } 4 | kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version = "1.9.23" } 5 | kotlin-android = { id = "org.jetbrains.kotlin.android", version = "1.9.23" } 6 | protobuf = { id = "com.google.protobuf", version = "0.9.4" } 7 | ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "12.1.0" } 8 | palantir-graal = { id = "com.palantir.graal", version = "0.12.0" } 9 | jib = { id = "com.google.cloud.tools.jib", version = "3.4.1" } 10 | 11 | [libraries] 12 | kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version = "1.8.0" } 13 | grpc-protobuf = { group = "io.grpc", name = "grpc-protobuf", version = "1.62.2" } 14 | grpc-protobuf-lite = { group = "io.grpc", name = "grpc-protobuf-lite", version = "1.62.2" } 15 | grpc-netty = { group = "io.grpc", name = "grpc-netty", version = "1.62.2" } 16 | grpc-okhttp = { group = "io.grpc", name = "grpc-okhttp", version = "1.62.2" } 17 | grpc-testing = { group = "io.grpc", name = "grpc-testing", version = "1.62.2" } 18 | grpc-stub = { group = "io.grpc", name = "grpc-stub", version = "1.62.2" } 19 | grpc-kotlin-stub = { group = "io.grpc", name = "grpc-kotlin-stub", version = "1.4.1" } 20 | 21 | protoc = { group = "com.google.protobuf", name = "protoc", version = "3.25.3" } 22 | protobuf-kotlin = { group = "com.google.protobuf", name = "protobuf-kotlin", version = "3.25.3" } 23 | protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version = "3.25.3" } 24 | protobuf-java-util = { group = "com.google.protobuf", name = "protobuf-java-util", version = "3.25.3" } 25 | protoc-gen-grpc-java = { group = "io.grpc", name = "protoc-gen-grpc-java", version = "1.62.2" } 26 | protoc-gen-grpc-kotlin = { group = "io.grpc", name = "protoc-gen-grpc-kotlin", version = "1.4.1" } 27 | 28 | androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version = "1.8.2" } 29 | androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout", version = "1.6.3" } 30 | androidx-compose-material = { group = "androidx.compose.material", name = "material", version = "1.6.3" } 31 | androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version = "1.6.3" } 32 | androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version = "1.6.3" } 33 | androidx-compose-compiler = { group = "androidx.compose.compiler", name = "compiler", version = "1.5.10" } 34 | 35 | kotlin-test-junit = { group = "org.jetbrains.kotlin", name = "kotlin-test-junit", version = "1.9.23" } 36 | -------------------------------------------------------------------------------- /examples/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grpc/grpc-kotlin/6f774052d1d6923f8af2e0023886d69949b695ee/examples/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /examples/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /examples/native-client/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | alias(libs.plugins.kotlin.jvm) 4 | alias(libs.plugins.palantir.graal) 5 | } 6 | 7 | kotlin { 8 | jvmToolchain(11) 9 | } 10 | 11 | dependencies { 12 | implementation(project(":stub-lite")) 13 | 14 | runtimeOnly(libs.grpc.okhttp) 15 | } 16 | 17 | application { 18 | mainClass.set("io.grpc.examples.helloworld.HelloWorldClientKt") 19 | } 20 | 21 | // todo: add graalvm-config-create task 22 | // ./gradlew :native-client:install 23 | // JAVA_HOME=~/.gradle/caches/com.palantir.graal/22.3.3/11/graalvm-ce-java11-22.3.3 JAVA_OPTS=-agentlib:native-image-agent=config-output-dir=native-client/src/main/resources/META-INF/native-image native-client/build/install/native-client/bin/native-client 24 | 25 | graal { 26 | graalVersion("22.3.3") 27 | javaVersion("11") 28 | mainClass(application.mainClass.get()) 29 | outputName("hello-world") 30 | option("--verbose") 31 | option("--no-fallback") 32 | option("-H:+ReportExceptionStackTraces") 33 | option("-H:+PrintClassInitialization") 34 | } 35 | -------------------------------------------------------------------------------- /examples/native-client/src/main/kotlin/io/grpc/examples/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "hello_world_client", 9 | srcs = ["HelloWorldClient.kt"], 10 | main_class = "io.grpc.examples.helloworld.HelloWorldClientKt", 11 | deps = [ 12 | "//examples/protos/src/main/proto/io/grpc/examples/helloworld:hello_world_kt_grpc", 13 | "@io_grpc_grpc_java//netty", 14 | ], 15 | ) 16 | -------------------------------------------------------------------------------- /examples/native-client/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.helloworld 18 | 19 | import io.grpc.ManagedChannel 20 | import io.grpc.ManagedChannelBuilder 21 | import io.grpc.examples.helloworld.GreeterGrpcKt.GreeterCoroutineStub 22 | import java.io.Closeable 23 | import java.util.concurrent.TimeUnit 24 | 25 | class HelloWorldClient(private val channel: ManagedChannel) : Closeable { 26 | private val stub: GreeterCoroutineStub = GreeterCoroutineStub(channel) 27 | 28 | suspend fun greet(name: String) { 29 | val request = helloRequest { this.name = name } 30 | val response = stub.sayHello(request) 31 | println("Received: ${response.message}") 32 | } 33 | 34 | override fun close() { 35 | channel.shutdown().awaitTermination(5, TimeUnit.SECONDS) 36 | } 37 | } 38 | 39 | /** 40 | * Greeter, uses first argument as name to greet if present; 41 | * greets "world" otherwise. 42 | */ 43 | suspend fun main(args: Array) { 44 | val port = System.getenv("PORT")?.toInt() ?: 50051 45 | 46 | val channel = ManagedChannelBuilder.forAddress("localhost", port).usePlaintext().build() 47 | 48 | val client = HelloWorldClient(channel) 49 | 50 | val user = args.singleOrNull() ?: "world" 51 | client.greet(user) 52 | } 53 | -------------------------------------------------------------------------------- /examples/native-client/src/main/resources/META-INF/native-image/reflect-config.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name":"com.sun.jndi.dns.DnsContextFactory" 4 | }, 5 | { 6 | "name":"io.grpc.examples.helloworld.HelloReply", 7 | "fields":[{"name":"message_"}] 8 | }, 9 | { 10 | "name":"io.grpc.examples.helloworld.HelloRequest", 11 | "fields":[{"name":"name_"}] 12 | }, 13 | { 14 | "name":"io.grpc.internal.DnsNameResolverProvider" 15 | }, 16 | { 17 | "name":"io.grpc.internal.JndiResourceResolverFactory", 18 | "methods":[{"name":"","parameterTypes":[] }] 19 | }, 20 | { 21 | "name":"io.grpc.internal.PickFirstLoadBalancerProvider" 22 | }, 23 | { 24 | "name":"io.grpc.okhttp.OkHttpChannelProvider" 25 | }, 26 | { 27 | "name":"io.grpc.util.SecretRoundRobinLoadBalancerProvider$Provider" 28 | }, 29 | { 30 | "name":"java.net.InetSocketAddress", 31 | "methods":[{"name":"getHostString","parameterTypes":[] }] 32 | }, 33 | { 34 | "name":"java.nio.Buffer", 35 | "fields":[{"name":"address"}] 36 | }, 37 | { 38 | "name":"java.util.concurrent.ScheduledThreadPoolExecutor", 39 | "methods":[{"name":"setRemoveOnCancelPolicy","parameterTypes":["boolean"] }] 40 | }, 41 | { 42 | "name":"java.util.concurrent.atomic.LongAdder", 43 | "queryAllPublicConstructors":true, 44 | "methods":[ 45 | {"name":"","parameterTypes":[] }, 46 | {"name":"add","parameterTypes":["long"] }, 47 | {"name":"sum","parameterTypes":[] } 48 | ] 49 | }, 50 | { 51 | "name":"javax.naming.directory.InitialDirContext" 52 | }, 53 | { 54 | "name":"sun.misc.Unsafe", 55 | "allDeclaredFields":true, 56 | "methods":[ 57 | {"name":"arrayBaseOffset","parameterTypes":["java.lang.Class"] }, 58 | {"name":"arrayIndexScale","parameterTypes":["java.lang.Class"] }, 59 | {"name":"copyMemory","parameterTypes":["long","long","long"] }, 60 | {"name":"copyMemory","parameterTypes":["java.lang.Object","long","java.lang.Object","long","long"] }, 61 | {"name":"getBoolean","parameterTypes":["java.lang.Object","long"] }, 62 | {"name":"getByte","parameterTypes":["long"] }, 63 | {"name":"getByte","parameterTypes":["java.lang.Object","long"] }, 64 | {"name":"getDouble","parameterTypes":["java.lang.Object","long"] }, 65 | {"name":"getFloat","parameterTypes":["java.lang.Object","long"] }, 66 | {"name":"getInt","parameterTypes":["long"] }, 67 | {"name":"getInt","parameterTypes":["java.lang.Object","long"] }, 68 | {"name":"getLong","parameterTypes":["long"] }, 69 | {"name":"getLong","parameterTypes":["java.lang.Object","long"] }, 70 | {"name":"getObject","parameterTypes":["java.lang.Object","long"] }, 71 | {"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, 72 | {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }, 73 | {"name":"putByte","parameterTypes":["long","byte"] }, 74 | {"name":"putByte","parameterTypes":["java.lang.Object","long","byte"] }, 75 | {"name":"putDouble","parameterTypes":["java.lang.Object","long","double"] }, 76 | {"name":"putFloat","parameterTypes":["java.lang.Object","long","float"] }, 77 | {"name":"putInt","parameterTypes":["long","int"] }, 78 | {"name":"putInt","parameterTypes":["java.lang.Object","long","int"] }, 79 | {"name":"putLong","parameterTypes":["long","long"] }, 80 | {"name":"putLong","parameterTypes":["java.lang.Object","long","long"] }, 81 | {"name":"putObject","parameterTypes":["java.lang.Object","long","java.lang.Object"] } 82 | ] 83 | } 84 | ] 85 | -------------------------------------------------------------------------------- /examples/protos/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // todo: maybe use variants / configurations to do both stub & stub-lite here 2 | 3 | // Note: We use the java-library plugin to get the protos into the artifact for this subproject 4 | // because there doesn't seem to be an better way. 5 | plugins { 6 | `java-library` 7 | } 8 | 9 | java { 10 | sourceSets.getByName("main").resources.srcDir("src/main/proto") 11 | } 12 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/animals/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library", "kt_jvm_proto_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//examples:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "animals_proto", 11 | srcs = [ 12 | "dog.proto", 13 | "pig.proto", 14 | "sheep.proto", 15 | ], 16 | ) 17 | 18 | java_proto_library( 19 | name = "animals_java_proto", 20 | deps = [":animals_proto"], 21 | ) 22 | 23 | java_lite_proto_library( 24 | name = "animals_java_proto_lite", 25 | deps = [":animals_proto"], 26 | ) 27 | 28 | kt_jvm_proto_library( 29 | name = "animals_kt_proto", 30 | deps = [":animals_proto"], 31 | ) 32 | 33 | kt_jvm_grpc_library( 34 | name = "animals_kt_grpc", 35 | srcs = [":animals_proto"], 36 | deps = [":animals_java_proto"], 37 | ) 38 | 39 | kt_jvm_grpc_library( 40 | name = "animals_kt_grpc_lite", 41 | srcs = [":animals_proto"], 42 | flavor = "lite", 43 | deps = [":animals_java_proto_lite"], 44 | ) 45 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/animals/dog.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.animals"; 18 | option java_outer_classname = "DogProto"; 19 | 20 | package animals; 21 | 22 | service Dog { 23 | rpc Bark (BarkRequest) returns (BarkReply) {} 24 | } 25 | 26 | message BarkRequest { 27 | } 28 | 29 | message BarkReply { 30 | string message = 1; 31 | } 32 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/animals/pig.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.animals"; 18 | option java_outer_classname = "PigProto"; 19 | 20 | package animals; 21 | 22 | service Pig { 23 | rpc Oink (OinkRequest) returns (OinkReply) {} 24 | } 25 | 26 | message OinkRequest { 27 | } 28 | 29 | message OinkReply { 30 | string message = 1; 31 | } 32 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/animals/sheep.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.animals"; 18 | option java_outer_classname = "SheepProto"; 19 | 20 | package animals; 21 | 22 | service Sheep { 23 | rpc Baa (BaaRequest) returns (BaaReply) {} 24 | } 25 | 26 | message BaaRequest { 27 | } 28 | 29 | message BaaReply { 30 | string message = 1; 31 | } 32 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library", "kt_jvm_proto_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//examples:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "hello_world_proto", 11 | srcs = ["hello_world.proto"], 12 | ) 13 | 14 | java_lite_proto_library( 15 | name = "hello_world_java_proto_lite", 16 | deps = [":hello_world_proto"], 17 | ) 18 | 19 | kt_jvm_proto_library( 20 | name = "hello_world_kt_proto", 21 | deps = [":hello_world_proto"], 22 | ) 23 | 24 | kt_jvm_grpc_library( 25 | name = "hello_world_kt_grpc", 26 | srcs = [":hello_world_proto"], 27 | deps = [":hello_world_kt_proto"], 28 | ) 29 | 30 | kt_jvm_grpc_library( 31 | name = "hello_world_kt_grpc_lite", 32 | srcs = [":hello_world_proto"], 33 | flavor = "lite", 34 | deps = [":hello_world_java_proto_lite"], 35 | ) 36 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/helloworld/hello_world.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | option java_multiple_files = true; 17 | option java_package = "io.grpc.examples.helloworld"; 18 | option java_outer_classname = "HelloWorldProto"; 19 | 20 | package helloworld; 21 | 22 | // The greeting service definition. 23 | service Greeter { 24 | // Sends a greeting 25 | rpc SayHello (HelloRequest) returns (HelloReply) {} 26 | } 27 | 28 | // The request message containing the user's name. 29 | message HelloRequest { 30 | string name = 1; 31 | } 32 | 33 | // The response message containing the greetings 34 | message HelloReply { 35 | string message = 1; 36 | } 37 | -------------------------------------------------------------------------------- /examples/protos/src/main/proto/io/grpc/examples/routeguide/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library", "kt_jvm_proto_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//examples:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "route_guide_proto", 11 | srcs = ["route_guide.proto"], 12 | deps = ["@com_google_protobuf//:duration_proto"], 13 | ) 14 | 15 | java_proto_library( 16 | name = "route_guide_java_proto", 17 | deps = [":route_guide_proto"], 18 | ) 19 | 20 | java_lite_proto_library( 21 | name = "route_guide_java_proto_lite", 22 | deps = [":route_guide_proto"], 23 | ) 24 | 25 | kt_jvm_proto_library( 26 | name = "route_guide_kt_proto", 27 | deps = [":route_guide_proto"], 28 | ) 29 | 30 | kt_jvm_grpc_library( 31 | name = "route_guide_kt_grpc", 32 | srcs = [":route_guide_proto"], 33 | deps = [":route_guide_java_proto"], 34 | ) 35 | 36 | kt_jvm_grpc_library( 37 | name = "route_guide_kt_grpc_lite", 38 | srcs = [":route_guide_proto"], 39 | flavor = "lite", 40 | deps = [":route_guide_java_proto_lite"], 41 | ) 42 | -------------------------------------------------------------------------------- /examples/server/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | application 3 | alias(libs.plugins.kotlin.jvm) 4 | alias(libs.plugins.jib) 5 | } 6 | 7 | kotlin { 8 | jvmToolchain(8) 9 | } 10 | 11 | dependencies { 12 | implementation(project(":stub")) 13 | 14 | runtimeOnly(libs.grpc.netty) 15 | 16 | testImplementation(libs.kotlin.test.junit) 17 | testImplementation(libs.grpc.testing) 18 | } 19 | 20 | tasks.register("HelloWorldServer") { 21 | dependsOn("classes") 22 | classpath = sourceSets["main"].runtimeClasspath 23 | mainClass.set("io.grpc.examples.helloworld.HelloWorldServerKt") 24 | } 25 | 26 | tasks.register("RouteGuideServer") { 27 | dependsOn("classes") 28 | classpath = sourceSets["main"].runtimeClasspath 29 | mainClass.set("io.grpc.examples.routeguide.RouteGuideServerKt") 30 | } 31 | 32 | tasks.register("AnimalsServer") { 33 | dependsOn("classes") 34 | classpath = sourceSets["main"].runtimeClasspath 35 | mainClass.set("io.grpc.examples.animals.AnimalsServerKt") 36 | } 37 | 38 | val helloWorldServerStartScripts = 39 | tasks.register("helloWorldServerStartScripts") { 40 | mainClass.set("io.grpc.examples.helloworld.HelloWorldServerKt") 41 | applicationName = "hello-world-server" 42 | outputDir = tasks.named("startScripts").get().outputDir 43 | classpath = tasks.named("startScripts").get().classpath 44 | } 45 | 46 | val routeGuideServerStartScripts = 47 | tasks.register("routeGuideServerStartScripts") { 48 | mainClass.set("io.grpc.examples.routeguide.RouteGuideServerKt") 49 | applicationName = "route-guide-server" 50 | outputDir = tasks.named("startScripts").get().outputDir 51 | classpath = tasks.named("startScripts").get().classpath 52 | } 53 | 54 | val animalsServerStartScripts = 55 | tasks.register("animalsServerStartScripts") { 56 | mainClass.set("io.grpc.examples.animals.AnimalsServerKt") 57 | applicationName = "animals-server" 58 | outputDir = tasks.named("startScripts").get().outputDir 59 | classpath = tasks.named("startScripts").get().classpath 60 | } 61 | 62 | tasks.named("startScripts") { 63 | dependsOn(helloWorldServerStartScripts) 64 | dependsOn(routeGuideServerStartScripts) 65 | dependsOn(animalsServerStartScripts) 66 | } 67 | 68 | tasks.withType { 69 | useJUnit() 70 | 71 | testLogging { 72 | events = 73 | setOf( 74 | org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED, 75 | org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED, 76 | org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED, 77 | ) 78 | exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL 79 | showStandardStreams = true 80 | } 81 | } 82 | 83 | jib { 84 | container { 85 | mainClass = "io.grpc.examples.helloworld.HelloWorldServerKt" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /examples/server/src/main/kotlin/io/grpc/examples/animals/AnimalsServer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.animals 18 | 19 | import io.grpc.Server 20 | import io.grpc.ServerBuilder 21 | 22 | class AnimalsServer constructor(private val port: Int) { 23 | val server: Server = 24 | ServerBuilder 25 | .forPort(port) 26 | .addService(DogService()) 27 | .addService(PigService()) 28 | .addService(SheepService()) 29 | .build() 30 | 31 | fun start() { 32 | server.start() 33 | println("Server started, listening on $port") 34 | Runtime.getRuntime().addShutdownHook( 35 | Thread { 36 | println("*** shutting down gRPC server since JVM is shutting down") 37 | this@AnimalsServer.stop() 38 | println("*** server shut down") 39 | }, 40 | ) 41 | } 42 | 43 | private fun stop() { 44 | server.shutdown() 45 | } 46 | 47 | fun blockUntilShutdown() { 48 | server.awaitTermination() 49 | } 50 | 51 | internal class DogService : DogGrpcKt.DogCoroutineImplBase() { 52 | override suspend fun bark(request: BarkRequest) = 53 | barkReply { 54 | message = "Bark!" 55 | } 56 | } 57 | 58 | internal class PigService : PigGrpcKt.PigCoroutineImplBase() { 59 | override suspend fun oink(request: OinkRequest) = 60 | oinkReply { 61 | message = "Oink!" 62 | } 63 | } 64 | 65 | internal class SheepService : SheepGrpcKt.SheepCoroutineImplBase() { 66 | override suspend fun baa(request: BaaRequest) = 67 | baaReply { 68 | message = "Baa!" 69 | } 70 | } 71 | } 72 | 73 | fun main() { 74 | val port = 50051 75 | val server = AnimalsServer(port) 76 | server.start() 77 | server.blockUntilShutdown() 78 | } 79 | -------------------------------------------------------------------------------- /examples/server/src/main/kotlin/io/grpc/examples/animals/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "animals_server", 9 | srcs = ["AnimalsServer.kt"], 10 | main_class = "io.grpc.examples.animals.AnimalsServerKt", 11 | deps = [ 12 | "//examples/protos/src/main/proto/io/grpc/examples/animals:animals_kt_grpc", 13 | "//examples/protos/src/main/proto/io/grpc/examples/animals:animals_kt_proto", 14 | "@com_google_protobuf//:protobuf_java_util", 15 | "@io_grpc_grpc_java//netty", 16 | ], 17 | ) 18 | -------------------------------------------------------------------------------- /examples/server/src/main/kotlin/io/grpc/examples/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "hello_world_server", 9 | srcs = ["HelloWorldServer.kt"], 10 | main_class = "io.grpc.examples.helloworld.HelloWorldServerKt", 11 | deps = [ 12 | "//examples/protos/src/main/proto/io/grpc/examples/helloworld:hello_world_kt_grpc", 13 | "//examples/protos/src/main/proto/io/grpc/examples/helloworld:hello_world_kt_proto", 14 | "@io_grpc_grpc_java//netty", 15 | ], 16 | ) 17 | -------------------------------------------------------------------------------- /examples/server/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.helloworld 18 | 19 | import io.grpc.Server 20 | import io.grpc.ServerBuilder 21 | 22 | class HelloWorldServer(private val port: Int) { 23 | val server: Server = 24 | ServerBuilder 25 | .forPort(port) 26 | .addService(HelloWorldService()) 27 | .build() 28 | 29 | fun start() { 30 | server.start() 31 | println("Server started, listening on $port") 32 | Runtime.getRuntime().addShutdownHook( 33 | Thread { 34 | println("*** shutting down gRPC server since JVM is shutting down") 35 | this@HelloWorldServer.stop() 36 | println("*** server shut down") 37 | }, 38 | ) 39 | } 40 | 41 | private fun stop() { 42 | server.shutdown() 43 | } 44 | 45 | fun blockUntilShutdown() { 46 | server.awaitTermination() 47 | } 48 | 49 | internal class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() { 50 | override suspend fun sayHello(request: HelloRequest) = 51 | helloReply { 52 | message = "Hello ${request.name}" 53 | } 54 | } 55 | } 56 | 57 | fun main() { 58 | val port = System.getenv("PORT")?.toInt() ?: 50051 59 | val server = HelloWorldServer(port) 60 | server.start() 61 | server.blockUntilShutdown() 62 | } 63 | -------------------------------------------------------------------------------- /examples/server/src/main/kotlin/io/grpc/examples/routeguide/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_binary") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples/src:__subpackages__"]) 6 | 7 | kt_jvm_binary( 8 | name = "route_guide_server", 9 | srcs = ["RouteGuideServer.kt"], 10 | main_class = "io.grpc.examples.routeguide.RouteGuideServerKt", 11 | resources = ["//examples/stub/src/main/resources/io/grpc/examples/routeguide:route_guide_db"], 12 | deps = [ 13 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_kt_grpc", 14 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_kt_proto", 15 | "//examples/stub/src/main/kotlin/io/grpc/examples/routeguide:route_guide_stub", 16 | "@com_google_protobuf//:protobuf_java_util", 17 | "@io_grpc_grpc_java//netty", 18 | ], 19 | ) 20 | -------------------------------------------------------------------------------- /examples/server/src/test/kotlin/io/grpc/examples/animals/AnimalsServerTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 gRPC authors. 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 | package io.grpc.examples.animals 18 | 19 | import io.grpc.testing.GrpcServerRule 20 | import kotlinx.coroutines.runBlocking 21 | import org.junit.Rule 22 | import kotlin.test.Test 23 | import kotlin.test.assertEquals 24 | 25 | class AnimalsServerTest { 26 | @get:Rule 27 | val grpcServerRule: GrpcServerRule = GrpcServerRule().directExecutor() 28 | 29 | @Test 30 | fun animals() = 31 | runBlocking { 32 | val dogService = AnimalsServer.DogService() 33 | val pigService = AnimalsServer.PigService() 34 | val sheepService = AnimalsServer.SheepService() 35 | grpcServerRule.serviceRegistry.addService(dogService) 36 | grpcServerRule.serviceRegistry.addService(pigService) 37 | grpcServerRule.serviceRegistry.addService(sheepService) 38 | 39 | val dogStub = DogGrpcKt.DogCoroutineStub(grpcServerRule.channel) 40 | val dogBark = dogStub.bark(barkRequest { }) 41 | assertEquals("Bark!", dogBark.message) 42 | 43 | val pigStub = PigGrpcKt.PigCoroutineStub(grpcServerRule.channel) 44 | val pigOink = pigStub.oink(oinkRequest { }) 45 | assertEquals("Oink!", pigOink.message) 46 | 47 | val sheepStub = SheepGrpcKt.SheepCoroutineStub(grpcServerRule.channel) 48 | val sheepBaa = sheepStub.baa(baaRequest { }) 49 | assertEquals("Baa!", sheepBaa.message) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/server/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 gRPC authors. 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 | package io.grpc.examples.helloworld 18 | 19 | import io.grpc.testing.GrpcServerRule 20 | import kotlinx.coroutines.runBlocking 21 | import org.junit.Rule 22 | import kotlin.test.Test 23 | import kotlin.test.assertEquals 24 | 25 | class HelloWorldServerTest { 26 | @get:Rule 27 | val grpcServerRule: GrpcServerRule = GrpcServerRule().directExecutor() 28 | 29 | @Test 30 | fun sayHello() = 31 | runBlocking { 32 | val service = HelloWorldServer.HelloWorldService() 33 | grpcServerRule.serviceRegistry.addService(service) 34 | 35 | val stub = GreeterGrpcKt.GreeterCoroutineStub(grpcServerRule.channel) 36 | val testName = "test name" 37 | 38 | val reply = stub.sayHello(helloRequest { name = testName }) 39 | 40 | assertEquals("Hello $testName", reply.message) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/server/src/test/kotlin/io/grpc/examples/routeguide/RouteGuideServerTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2022 gRPC authors. 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 | package io.grpc.examples.routeguide 18 | 19 | import io.grpc.testing.GrpcServerRule 20 | import kotlinx.coroutines.flow.toList 21 | import kotlinx.coroutines.runBlocking 22 | import org.junit.Rule 23 | import kotlin.test.Test 24 | import kotlin.test.assertEquals 25 | 26 | class RouteGuideServerTest { 27 | @get:Rule 28 | val grpcServerRule: GrpcServerRule = GrpcServerRule().directExecutor() 29 | 30 | @Test 31 | fun listFeatures() = 32 | runBlocking { 33 | val service = RouteGuideServer.RouteGuideService(Database.features()) 34 | grpcServerRule.serviceRegistry.addService(service) 35 | 36 | val stub = RouteGuideGrpcKt.RouteGuideCoroutineStub(grpcServerRule.channel) 37 | 38 | val rectangle = 39 | rectangle { 40 | lo = 41 | point { 42 | latitude = 407838351 43 | longitude = -746143763 44 | } 45 | hi = 46 | point { 47 | latitude = 407838351 48 | longitude = -746143763 49 | } 50 | } 51 | 52 | val features = stub.listFeatures(rectangle).toList() 53 | assertEquals("Patriots Path, Mendham, NJ 07945, USA", features.first().name) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "grpc-kotlin-examples" 2 | 3 | // when running the assemble task, ignore the android & graalvm related subprojects 4 | if (startParameter.taskRequests.find { it.args.contains("assemble") } == null) { 5 | include("protos", "stub", "stub-lite", "client", "native-client", "server", "stub-android", "android") 6 | } else { 7 | include("protos", "stub", "server") 8 | } 9 | 10 | pluginManagement { 11 | repositories { 12 | gradlePluginPortal() 13 | google() 14 | } 15 | } 16 | 17 | dependencyResolutionManagement { 18 | @Suppress("UnstableApiUsage") 19 | repositories { 20 | mavenCentral() 21 | google() 22 | } 23 | } 24 | 25 | plugins { 26 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" 27 | } 28 | -------------------------------------------------------------------------------- /examples/stub-android/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.android.library) 3 | alias(libs.plugins.kotlin.android) 4 | alias(libs.plugins.protobuf) 5 | } 6 | 7 | dependencies { 8 | protobuf(project(":protos")) 9 | 10 | api(libs.kotlinx.coroutines.core) 11 | 12 | api(libs.grpc.stub) 13 | api(libs.grpc.protobuf.lite) 14 | api(libs.grpc.kotlin.stub) 15 | api(libs.protobuf.kotlin.lite) 16 | } 17 | 18 | kotlin { 19 | jvmToolchain(8) 20 | } 21 | 22 | android { 23 | compileSdk = 34 24 | buildToolsVersion = "34.0.0" 25 | namespace = "io.grpc.examples.stublite" 26 | } 27 | 28 | tasks.withType().all { 29 | kotlinOptions { 30 | freeCompilerArgs = listOf("-opt-in=kotlin.RequiresOptIn") 31 | } 32 | } 33 | 34 | protobuf { 35 | protoc { 36 | artifact = libs.protoc.asProvider().get().toString() 37 | } 38 | plugins { 39 | create("java") { 40 | artifact = libs.protoc.gen.grpc.java.get().toString() 41 | } 42 | create("grpc") { 43 | artifact = libs.protoc.gen.grpc.java.get().toString() 44 | } 45 | create("grpckt") { 46 | artifact = libs.protoc.gen.grpc.kotlin.get().toString() + ":jdk8@jar" 47 | } 48 | } 49 | generateProtoTasks { 50 | all().forEach { 51 | it.plugins { 52 | create("java") { 53 | option("lite") 54 | } 55 | create("grpc") { 56 | option("lite") 57 | } 58 | create("grpckt") { 59 | option("lite") 60 | } 61 | } 62 | it.builtins { 63 | create("kotlin") { 64 | option("lite") 65 | } 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /examples/stub-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /examples/stub-lite/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.kotlin.jvm) 3 | alias(libs.plugins.protobuf) 4 | } 5 | 6 | dependencies { 7 | protobuf(project(":protos")) 8 | 9 | api(libs.kotlinx.coroutines.core) 10 | 11 | api(libs.grpc.stub) 12 | api(libs.grpc.protobuf.lite) 13 | api(libs.grpc.kotlin.stub) 14 | api(libs.protobuf.kotlin.lite) 15 | } 16 | 17 | kotlin { 18 | jvmToolchain(8) 19 | } 20 | 21 | tasks.withType().all { 22 | kotlinOptions { 23 | freeCompilerArgs = listOf("-opt-in=kotlin.RequiresOptIn") 24 | } 25 | } 26 | 27 | protobuf { 28 | protoc { 29 | artifact = libs.protoc.asProvider().get().toString() 30 | } 31 | plugins { 32 | create("grpc") { 33 | artifact = libs.protoc.gen.grpc.java.get().toString() 34 | } 35 | create("grpckt") { 36 | artifact = libs.protoc.gen.grpc.kotlin.get().toString() + ":jdk8@jar" 37 | } 38 | } 39 | generateProtoTasks { 40 | all().forEach { 41 | it.builtins { 42 | named("java") { 43 | option("lite") 44 | } 45 | create("kotlin") { 46 | option("lite") 47 | } 48 | } 49 | it.plugins { 50 | create("grpc") { 51 | option("lite") 52 | } 53 | create("grpckt") { 54 | option("lite") 55 | } 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/stub/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.kotlin.jvm) 3 | alias(libs.plugins.protobuf) 4 | } 5 | 6 | dependencies { 7 | protobuf(project(":protos")) 8 | 9 | api(libs.kotlinx.coroutines.core) 10 | 11 | api(libs.grpc.stub) 12 | api(libs.grpc.protobuf) 13 | api(libs.protobuf.java.util) 14 | api(libs.protobuf.kotlin) 15 | api(libs.grpc.kotlin.stub) 16 | } 17 | 18 | kotlin { 19 | jvmToolchain(8) 20 | } 21 | 22 | tasks.withType().all { 23 | kotlinOptions { 24 | freeCompilerArgs = listOf("-opt-in=kotlin.RequiresOptIn") 25 | } 26 | } 27 | 28 | protobuf { 29 | protoc { 30 | artifact = libs.protoc.asProvider().get().toString() 31 | } 32 | plugins { 33 | create("grpc") { 34 | artifact = libs.protoc.gen.grpc.java.get().toString() 35 | } 36 | create("grpckt") { 37 | artifact = libs.protoc.gen.grpc.kotlin.get().toString() + ":jdk8@jar" 38 | } 39 | } 40 | generateProtoTasks { 41 | all().forEach { 42 | it.plugins { 43 | create("grpc") 44 | create("grpckt") 45 | } 46 | it.builtins { 47 | create("kotlin") 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/stub/src/main/kotlin/io/grpc/examples/routeguide/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//examples:__subpackages__"]) 6 | 7 | kt_jvm_library( 8 | name = "route_guide_stub", 9 | srcs = [ 10 | "Database.kt", 11 | "Points.kt" 12 | ], 13 | deps = [ 14 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_java_proto", 15 | "//examples/protos/src/main/proto/io/grpc/examples/routeguide:route_guide_kt_grpc", 16 | "@com_google_protobuf//:protobuf_java_util" 17 | ], 18 | ) 19 | -------------------------------------------------------------------------------- /examples/stub/src/main/kotlin/io/grpc/examples/routeguide/Database.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.routeguide 18 | 19 | import com.google.protobuf.util.JsonFormat 20 | 21 | object Database { 22 | fun features(): List { 23 | return javaClass.getResourceAsStream("route_guide_db.json")?.use { 24 | val featureDatabaseBuilder = FeatureDatabase.newBuilder() 25 | JsonFormat.parser().merge(it.reader(), featureDatabaseBuilder) 26 | featureDatabaseBuilder.build().featureList 27 | } ?: emptyList() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/stub/src/main/kotlin/io/grpc/examples/routeguide/Points.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.examples.routeguide 18 | 19 | import kotlin.math.atan2 20 | import kotlin.math.cos 21 | import kotlin.math.pow 22 | import kotlin.math.roundToInt 23 | import kotlin.math.sin 24 | import kotlin.math.sqrt 25 | 26 | private const val EARTH_RADIUS_IN_M = 6371000 27 | 28 | private fun Int.toRadians() = Math.toRadians(toDouble()) 29 | 30 | infix fun Point.distanceTo(other: Point): Int { 31 | val lat1 = latitude.toRadians() 32 | val long1 = longitude.toRadians() 33 | val lat2 = other.latitude.toRadians() 34 | val long2 = other.latitude.toRadians() 35 | 36 | val dLat = lat2 - lat1 37 | val dLong = long2 - long1 38 | 39 | val a = sin(dLat / 2).pow(2) + cos(lat1) * cos(lat2) * sin(dLong / 2).pow(2) 40 | val c = 2 * atan2(sqrt(a), sqrt(1 - a)) 41 | return (EARTH_RADIUS_IN_M * c).roundToInt() 42 | } 43 | 44 | operator fun Rectangle.contains(p: Point): Boolean { 45 | val lowLong = minOf(lo.longitude, hi.longitude) 46 | val hiLong = maxOf(lo.longitude, hi.longitude) 47 | val lowLat = minOf(lo.latitude, hi.latitude) 48 | val hiLat = maxOf(lo.latitude, hi.latitude) 49 | return p.longitude in lowLong..hiLong && p.latitude in lowLat..hiLat 50 | } 51 | 52 | private fun Int.normalizeCoordinate(): Double = this / 1.0e7 53 | 54 | fun Point.toStr(): String { 55 | val lat = latitude.normalizeCoordinate() 56 | val long = longitude.normalizeCoordinate() 57 | return "$lat, $long" 58 | } 59 | 60 | fun Feature.exists(): Boolean = name.isNotEmpty() 61 | -------------------------------------------------------------------------------- /examples/stub/src/main/resources/io/grpc/examples/routeguide/BUILD.bazel: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) 2 | 3 | package(default_visibility = ["//examples:__subpackages__"]) 4 | 5 | filegroup( 6 | name = "route_guide_db", 7 | srcs = ["route_guide_db.json"], 8 | ) 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grpc/grpc-kotlin/6f774052d1d6923f8af2e0023886d69949b695ee/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /integration_testing/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.gradle.api.tasks.testing.logging.TestExceptionFormat 2 | import org.gradle.api.tasks.testing.logging.TestLogEvent 3 | 4 | plugins { 5 | alias(libs.plugins.kotlin.jvm) 6 | } 7 | 8 | kotlin { 9 | jvmToolchain(17) 10 | } 11 | 12 | dependencies { 13 | testImplementation(libs.testcontainers) 14 | testImplementation(libs.gradle.test.kit) 15 | testImplementation(libs.gradle.tooling.api) 16 | testImplementation(libs.commons.io) 17 | testImplementation(libs.junit.jupiter) 18 | testImplementation(libs.slf4j.simple) 19 | testRuntimeOnly(libs.junit.platform.launcher) 20 | } 21 | 22 | tasks.named("test") { 23 | val examplesDir = File(rootDir, "examples") 24 | inputs.dir(examplesDir) 25 | dependsOn(":compiler:publishAllPublicationsToMavenRepository") 26 | dependsOn(":stub:publishAllPublicationsToMavenRepository") 27 | 28 | useJUnitPlatform() 29 | 30 | testLogging { 31 | showStandardStreams = true 32 | exceptionFormat = TestExceptionFormat.FULL 33 | events(TestLogEvent.STANDARD_OUT, TestLogEvent.STANDARD_ERROR, TestLogEvent.STARTED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED) 34 | } 35 | 36 | retry { 37 | maxRetries = 1 38 | maxFailures = 1 39 | } 40 | 41 | systemProperties["grpc-kotlin-version"] = project.version 42 | systemProperties["examples-dir"] = examplesDir 43 | systemProperties["test-repo"] = (publishing.repositories.getByName("maven") as MavenArtifactRepository).url 44 | 45 | /* 46 | val properties = Properties() 47 | if (rootProject.file("local.properties").exists()) { 48 | properties.load(rootProject.file("local.properties").inputStream()) 49 | environment("ANDROID_HOME", properties.getProperty("sdk.dir")) 50 | } 51 | */ 52 | 53 | // todo: cleanup copyExamples.destinationDir or move copy to tests 54 | } 55 | 56 | tasks.withType { 57 | enabled = false 58 | } 59 | 60 | -------------------------------------------------------------------------------- /interop_testing/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.google.protobuf.gradle.* 2 | 3 | plugins { 4 | application 5 | } 6 | 7 | dependencies { 8 | implementation(kotlin("test")) 9 | implementation(libs.kotlinx.coroutines.core) 10 | 11 | implementation(project(":stub")) 12 | 13 | implementation(libs.grpc.protobuf) 14 | implementation(libs.grpc.protobuf.lite) 15 | implementation(libs.grpc.auth) 16 | implementation(libs.grpc.alts) 17 | implementation(libs.grpc.netty) 18 | implementation(libs.grpc.okhttp) 19 | implementation(libs.grpc.testing) 20 | 21 | implementation(libs.protobuf.java) 22 | 23 | implementation(libs.truth) 24 | 25 | testImplementation(libs.mockito.core) 26 | testImplementation(libs.okhttp) { 27 | because("transitive dep for grpc-okhttp") 28 | } 29 | } 30 | 31 | protobuf { 32 | protoc { 33 | artifact = libs.protoc.asProvider().get().toString() 34 | } 35 | plugins { 36 | id("grpc") { 37 | artifact = libs.protoc.gen.grpc.java.get().toString() 38 | } 39 | id("grpckt") { 40 | path = project(":compiler").tasks.jar.get().archiveFile.get().asFile.absolutePath 41 | } 42 | } 43 | generateProtoTasks { 44 | all().forEach { 45 | if (it.name.startsWith("generateTestProto") || it.name.startsWith("generateProto")) { 46 | it.dependsOn(":compiler:jar") 47 | } 48 | 49 | it.plugins { 50 | id("grpc") 51 | id("grpckt") 52 | } 53 | } 54 | } 55 | } 56 | 57 | val testServiceClientStartScripts = tasks.register("testServiceClientStartScripts") { 58 | mainClass.set("io.grpc.testing.integration.TestServiceClient") 59 | applicationName = "test-service-client" 60 | outputDir = tasks.named("startScripts").get().outputDir 61 | classpath = tasks.named("startScripts").get().classpath 62 | } 63 | 64 | val testServiceServerStartScripts = tasks.register("testServiceServerStartScripts") { 65 | mainClass.set("io.grpc.testing.integration.TestServiceServer") 66 | applicationName = "test-service-server" 67 | outputDir = tasks.named("startScripts").get().outputDir 68 | classpath = tasks.named("startScripts").get().classpath 69 | } 70 | 71 | tasks.named("startScripts") { 72 | dependsOn(testServiceClientStartScripts) 73 | dependsOn(testServiceServerStartScripts) 74 | } 75 | 76 | tasks.withType { 77 | enabled = false 78 | } 79 | -------------------------------------------------------------------------------- /interop_testing/src/main/java/io/grpc/testing/integration/Http2TestCases.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The gRPC Authors 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 | package io.grpc.testing.integration; 18 | 19 | import com.google.common.base.Preconditions; 20 | 21 | /** 22 | * Enum of HTTP/2 interop test cases. 23 | */ 24 | public enum Http2TestCases { 25 | RST_AFTER_HEADER("server resets stream after sending header"), 26 | RST_AFTER_DATA("server resets stream after sending data"), 27 | RST_DURING_DATA("server resets stream in the middle of sending data"), 28 | GOAWAY("server sends goaway after first request and asserts second request uses new connection"), 29 | PING("server sends pings during request and verifies client response"), 30 | MAX_STREAMS("server verifies that the client respects MAX_STREAMS setting"); 31 | 32 | private final String description; 33 | 34 | Http2TestCases(String description) { 35 | this.description = description; 36 | } 37 | 38 | /** 39 | * Returns a description of the test case. 40 | */ 41 | public String description() { 42 | return description; 43 | } 44 | 45 | /** 46 | * Returns the {@link Http2TestCases} matching the string {@code s}. The 47 | * matching is case insensitive. 48 | */ 49 | public static Http2TestCases fromString(String s) { 50 | Preconditions.checkNotNull(s, "s"); 51 | try { 52 | return Http2TestCases.valueOf(s.toUpperCase()); 53 | } catch (IllegalArgumentException ex) { 54 | throw new IllegalArgumentException("Invalid test case: " + s); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /interop_testing/src/main/java/io/grpc/testing/integration/TestCases.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The gRPC Authors 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 | package io.grpc.testing.integration; 18 | 19 | import com.google.common.base.Preconditions; 20 | 21 | /** 22 | * Enum of interop test cases. 23 | */ 24 | public enum TestCases { 25 | EMPTY_UNARY("empty (zero bytes) request and response"), 26 | CACHEABLE_UNARY("cacheable unary rpc sent using GET"), 27 | LARGE_UNARY("single request and (large) response"), 28 | CLIENT_COMPRESSED_UNARY("client compressed unary request"), 29 | CLIENT_COMPRESSED_UNARY_NOPROBE( 30 | "client compressed unary request (skip initial feature-probing request)"), 31 | SERVER_COMPRESSED_UNARY("server compressed unary response"), 32 | CLIENT_STREAMING("request streaming with single response"), 33 | CLIENT_COMPRESSED_STREAMING("client per-message compression on stream"), 34 | CLIENT_COMPRESSED_STREAMING_NOPROBE( 35 | "client per-message compression on stream (skip initial feature-probing request)"), 36 | SERVER_STREAMING("single request with response streaming"), 37 | SERVER_COMPRESSED_STREAMING("server per-message compression on stream"), 38 | PING_PONG("full-duplex ping-pong streaming"), 39 | EMPTY_STREAM("A stream that has zero-messages in both directions"), 40 | COMPUTE_ENGINE_CREDS("large_unary with service_account auth"), 41 | COMPUTE_ENGINE_CHANNEL_CREDENTIALS("large unary with compute engine channel builder"), 42 | SERVICE_ACCOUNT_CREDS("large_unary with compute engine auth"), 43 | JWT_TOKEN_CREDS("JWT-based auth"), 44 | OAUTH2_AUTH_TOKEN("raw oauth2 access token auth"), 45 | PER_RPC_CREDS("per rpc raw oauth2 access token auth"), 46 | GOOGLE_DEFAULT_CREDENTIALS( 47 | "google default credentials, i.e. GoogleManagedChannel based auth"), 48 | CUSTOM_METADATA("unary and full duplex calls with metadata"), 49 | STATUS_CODE_AND_MESSAGE("request error code and message"), 50 | SPECIAL_STATUS_MESSAGE("special characters in status message"), 51 | UNIMPLEMENTED_METHOD("call an unimplemented RPC method"), 52 | UNIMPLEMENTED_SERVICE("call an unimplemented RPC service"), 53 | CANCEL_AFTER_BEGIN("cancel stream after starting it"), 54 | CANCEL_AFTER_FIRST_RESPONSE("cancel on first response"), 55 | TIMEOUT_ON_SLEEPING_SERVER("timeout before receiving a response"), 56 | VERY_LARGE_REQUEST("very large request"), 57 | PICK_FIRST_UNARY("all requests are sent to one server despite multiple servers are resolved"); 58 | 59 | private final String description; 60 | 61 | TestCases(String description) { 62 | this.description = description; 63 | } 64 | 65 | /** 66 | * Returns a description of the test case. 67 | */ 68 | public String description() { 69 | return description; 70 | } 71 | 72 | /** 73 | * Returns the {@link TestCases} matching the string {@code s}. The 74 | * matching is done case insensitive. 75 | */ 76 | public static TestCases fromString(String s) { 77 | Preconditions.checkNotNull(s, "s"); 78 | return TestCases.valueOf(s.toUpperCase()); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /interop_testing/src/main/java/io/grpc/testing/integration/Util.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The gRPC Authors 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 | package io.grpc.testing.integration; 18 | 19 | import com.google.protobuf.MessageLite; 20 | import io.grpc.Metadata; 21 | import io.grpc.protobuf.lite.ProtoLiteUtils; 22 | import java.net.URI; 23 | import java.net.URISyntaxException; 24 | import java.util.List; 25 | import org.junit.Assert; 26 | 27 | /** 28 | * Utility methods to support integration testing. 29 | */ 30 | public class Util { 31 | 32 | public static final Metadata.Key METADATA_KEY = 33 | Metadata.Key.of( 34 | "grpc.testing.SimpleContext" + Metadata.BINARY_HEADER_SUFFIX, 35 | ProtoLiteUtils.metadataMarshaller(Messages.SimpleContext.getDefaultInstance())); 36 | public static final Metadata.Key ECHO_INITIAL_METADATA_KEY 37 | = Metadata.Key.of("x-grpc-test-echo-initial", Metadata.ASCII_STRING_MARSHALLER); 38 | public static final Metadata.Key ECHO_TRAILING_METADATA_KEY 39 | = Metadata.Key.of("x-grpc-test-echo-trailing-bin", Metadata.BINARY_BYTE_MARSHALLER); 40 | 41 | /** 42 | * Combine a host and port into an authority string. 43 | */ 44 | public static String authorityFromHostAndPort(String host, int port) { 45 | try { 46 | return new URI(null, null, host, port, null, null, null).getAuthority(); 47 | } catch (URISyntaxException ex) { 48 | throw new IllegalArgumentException("Invalid host or port: " + host + " " + port, ex); 49 | } 50 | } 51 | 52 | /** Assert that two messages are equal, producing a useful message if not. */ 53 | @SuppressWarnings("LiteProtoToString") 54 | public static void assertEquals(MessageLite expected, MessageLite actual) { 55 | if (expected == null || actual == null) { 56 | Assert.assertEquals(expected, actual); 57 | } else { 58 | if (!expected.equals(actual)) { 59 | // This assertEquals should always complete. 60 | Assert.assertEquals(expected.toString(), actual.toString()); 61 | // But if it doesn't, then this should. 62 | Assert.assertEquals(expected, actual); 63 | Assert.fail("Messages not equal, but assertEquals didn't throw"); 64 | } 65 | } 66 | } 67 | 68 | /** Assert that two lists of messages are equal, producing a useful message if not. */ 69 | public static void assertEquals(List expected, 70 | List actual) { 71 | if (expected == null || actual == null) { 72 | Assert.assertEquals(expected, actual); 73 | } else if (expected.size() != actual.size()) { 74 | Assert.assertEquals(expected, actual); 75 | } else { 76 | for (int i = 0; i < expected.size(); i++) { 77 | assertEquals(expected.get(i), actual.get(i)); 78 | } 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /interop_testing/src/main/proto/grpc/testing/empty.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The gRPC Authors 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 | syntax = "proto2"; 15 | 16 | package grpc.testing; 17 | 18 | option java_package = "io.grpc.testing.integration"; 19 | option java_outer_classname = "EmptyProtos"; 20 | 21 | // An empty message that you can re-use to avoid defining duplicated empty 22 | // messages in your project. A typical example is to use it as argument or the 23 | // return value of a service API. For instance: 24 | // 25 | // service Foo { 26 | // rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; 27 | // }; 28 | // 29 | message Empty {} 30 | -------------------------------------------------------------------------------- /interop_testing/src/main/proto/grpc/testing/metrics.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 The gRPC Authors 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 | // Contains the definitions for a metrics service and the type of metrics 15 | // exposed by the service. 16 | // 17 | // Currently, 'Gauge' (i.e a metric that represents the measured value of 18 | // something at an instant of time) is the only metric type supported by the 19 | // service. 20 | syntax = "proto3"; 21 | 22 | package grpc.testing; 23 | 24 | option java_package = "io.grpc.testing.integration"; 25 | 26 | // Reponse message containing the gauge name and value 27 | message GaugeResponse { 28 | string name = 1; 29 | oneof value { 30 | int64 long_value = 2; 31 | double double_value = 3; 32 | string string_value = 4; 33 | } 34 | } 35 | 36 | // Request message containing the gauge name 37 | message GaugeRequest { 38 | string name = 1; 39 | } 40 | 41 | message EmptyMessage {} 42 | 43 | service MetricsService { 44 | // Returns the values of all the gauges that are currently being maintained by 45 | // the service 46 | rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse); 47 | 48 | // Returns the value of one gauge 49 | rpc GetGauge(GaugeRequest) returns (GaugeResponse); 50 | } 51 | -------------------------------------------------------------------------------- /interop_testing/src/test/java/io/grpc/stub/StubConfigTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The gRPC Authors 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 | package io.grpc.stub; 18 | 19 | import static java.util.concurrent.TimeUnit.NANOSECONDS; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertNotSame; 22 | import static org.junit.Assert.assertNull; 23 | import static org.mockito.ArgumentMatchers.any; 24 | import static org.mockito.ArgumentMatchers.same; 25 | import static org.mockito.Mockito.*; 26 | 27 | import io.grpc.*; 28 | import io.grpc.testing.integration.Messages.SimpleRequest; 29 | import io.grpc.testing.integration.Messages.SimpleResponse; 30 | import io.grpc.testing.integration.TestServiceGrpc; 31 | import org.junit.Before; 32 | import org.junit.Test; 33 | import org.junit.runner.RunWith; 34 | import org.junit.runners.JUnit4; 35 | import org.mockito.ArgumentMatchers; 36 | import org.mockito.Mock; 37 | import org.mockito.MockitoAnnotations; 38 | 39 | /** 40 | * Tests for stub reconfiguration. 41 | */ 42 | @RunWith(JUnit4.class) 43 | public class StubConfigTest { 44 | 45 | @Mock 46 | private Channel channel; 47 | 48 | @Mock 49 | private StreamObserver responseObserver; 50 | 51 | @Mock 52 | private ClientCall call; 53 | 54 | /** 55 | * Sets up mocks. 56 | */ 57 | @Before public void setUp() { 58 | MockitoAnnotations.openMocks(this); 59 | 60 | when(channel.newCall( 61 | ArgumentMatchers.>any(), 62 | any(CallOptions.class))) 63 | .thenReturn(call); 64 | } 65 | 66 | @Test 67 | public void testConfigureDeadline() { 68 | Deadline deadline = Deadline.after(2, NANOSECONDS); 69 | // Create a default stub 70 | TestServiceGrpc.TestServiceBlockingStub stub = TestServiceGrpc.newBlockingStub(channel); 71 | assertNull(stub.getCallOptions().getDeadline()); 72 | // Reconfigure it 73 | TestServiceGrpc.TestServiceBlockingStub reconfiguredStub = stub.withDeadline(deadline); 74 | // New altered config 75 | assertEquals(deadline, reconfiguredStub.getCallOptions().getDeadline()); 76 | // Default config unchanged 77 | assertNull(stub.getCallOptions().getDeadline()); 78 | } 79 | 80 | @Test 81 | public void testStubCallOptionsPopulatedToNewCall() { 82 | TestServiceGrpc.TestServiceStub stub = TestServiceGrpc.newStub(channel); 83 | CallOptions options1 = stub.getCallOptions(); 84 | SimpleRequest request = SimpleRequest.getDefaultInstance(); 85 | stub.unaryCall(request, responseObserver); 86 | verify(channel).newCall(same(TestServiceGrpc.getUnaryCallMethod()), same(options1)); 87 | stub = stub.withDeadlineAfter(2, NANOSECONDS); 88 | CallOptions options2 = stub.getCallOptions(); 89 | assertNotSame(options1, options2); 90 | stub.unaryCall(request, responseObserver); 91 | verify(channel).newCall(same(TestServiceGrpc.getUnaryCallMethod()), same(options2)); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /interop_testing/src/test/java/io/grpc/testing/integration/TestCasesTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The gRPC Authors 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 | package io.grpc.testing.integration; 18 | 19 | import static io.grpc.testing.integration.TestCases.fromString; 20 | import static org.junit.Assert.assertEquals; 21 | 22 | import java.util.HashSet; 23 | import java.util.Set; 24 | import org.junit.Test; 25 | import org.junit.runner.RunWith; 26 | import org.junit.runners.JUnit4; 27 | 28 | /** 29 | * Unit tests for {@link TestCases}. 30 | */ 31 | @RunWith(JUnit4.class) 32 | public class TestCasesTest { 33 | 34 | @Test(expected = IllegalArgumentException.class) 35 | public void unknownStringThrowsException() { 36 | fromString("does_not_exist_1234"); 37 | } 38 | 39 | @Test 40 | public void testCaseNamesShouldMapToEnums() { 41 | // names of testcases as defined in the interop spec 42 | String[] testCases = { 43 | "empty_unary", 44 | "cacheable_unary", 45 | "large_unary", 46 | "client_compressed_unary", 47 | "server_compressed_unary", 48 | "client_streaming", 49 | "client_compressed_streaming", 50 | "compute_engine_channel_credentials", 51 | "server_streaming", 52 | "server_compressed_streaming", 53 | "ping_pong", 54 | "empty_stream", 55 | "compute_engine_creds", 56 | "service_account_creds", 57 | "jwt_token_creds", 58 | "oauth2_auth_token", 59 | "per_rpc_creds", 60 | "google_default_credentials", 61 | "custom_metadata", 62 | "status_code_and_message", 63 | "special_status_message", 64 | "unimplemented_method", 65 | "unimplemented_service", 66 | "cancel_after_begin", 67 | "cancel_after_first_response", 68 | "timeout_on_sleeping_server" 69 | }; 70 | 71 | // additional test cases 72 | String[] additionalTestCases = { 73 | "client_compressed_unary_noprobe", 74 | "client_compressed_streaming_noprobe", 75 | "very_large_request", 76 | "pick_first_unary" 77 | }; 78 | 79 | assertEquals(testCases.length + additionalTestCases.length, TestCases.values().length); 80 | 81 | Set testCaseSet = new HashSet<>(testCases.length); 82 | for (String testCase : testCases) { 83 | testCaseSet.add(TestCases.fromString(testCase)); 84 | } 85 | for (String testCase : additionalTestCases) { 86 | testCaseSet.add(TestCases.fromString(testCase)); 87 | } 88 | 89 | assertEquals(TestCases.values().length, testCaseSet.size()); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /interop_testing/src/test/java/io/grpc/testing/integration/TestServiceClientTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 The gRPC Authors 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 | package io.grpc.testing.integration; 18 | 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | import org.junit.runners.JUnit4; 22 | 23 | /** Unit tests for {@link TestServiceClient}. */ 24 | @RunWith(JUnit4.class) 25 | public class TestServiceClientTest { 26 | 27 | @Test 28 | public void emptyArgumentListShouldNotThrowException() { 29 | TestServiceClient client = new TestServiceClient(); 30 | client.parseArgs(new String[0]); 31 | client.setUp(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /repositories.bzl: -------------------------------------------------------------------------------- 1 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 2 | 3 | # For use with maven_install's artifacts. 4 | # maven_install( 5 | # ... 6 | # artifacts = [ 7 | # # Your own deps 8 | # ] + IO_GRPC_GRPC_KOTLIN_ARTIFACTS + IO_GRPC_GRPC_JAVA_ARTIFACTS, 9 | # ) 10 | IO_GRPC_GRPC_KOTLIN_ARTIFACTS = [ 11 | "com.google.guava:guava:32.0.1-android", 12 | "com.squareup:kotlinpoet:1.14.2", 13 | "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3", 14 | "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3", 15 | "org.jetbrains.kotlinx:kotlinx-coroutines-debug:1.7.3", 16 | ] 17 | 18 | # For use with maven_install's override_targets. 19 | # maven_install( 20 | # ... 21 | # override_targets = dict( 22 | # IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS.items() + 23 | # IO_GRPC_GRPC_KOTLIN_OVERRIDE_TARGETS.items(), 24 | # "your.target:artifact": "@//third_party/artifact", 25 | # ) 26 | IO_GRPC_GRPC_KOTLIN_OVERRIDE_TARGETS = dict() 27 | 28 | # Call this after compat_repositories() to load all dependencies. 29 | def grpc_kt_repositories(): 30 | """Imports dependencies for kt_jvm_grpc.bzl""" 31 | if not native.existing_rule("io_bazel_rules_kotlin"): 32 | io_bazel_rules_kotlin() 33 | if not native.existing_rule("com_google_protobuf"): 34 | com_google_protobuf() 35 | if not native.existing_rule("io_grpc_grpc_java"): 36 | io_grpc_grpc_java() 37 | 38 | def io_bazel_rules_kotlin(): 39 | rules_kotlin_version = "v1.8" 40 | rules_kotlin_sha = "01293740a16e474669aba5b5a1fe3d368de5832442f164e4fbfc566815a8bc3a" 41 | http_archive( 42 | name = "io_bazel_rules_kotlin", 43 | urls = ["https://github.com/bazelbuild/rules_kotlin/releases/download/%s/rules_kotlin_release.tgz" % rules_kotlin_version], 44 | sha256 = rules_kotlin_sha, 45 | ) 46 | 47 | def com_google_protobuf(): 48 | protobuf_version = "24.2" 49 | protobuf_sha = "39b52572da90ad54c883a828cb2ca68e5ac918aa75d36c3e55c9c76b94f0a4f7" 50 | 51 | http_archive( 52 | name = "com_google_protobuf", 53 | sha256 = protobuf_sha, 54 | strip_prefix = "protobuf-%s" % protobuf_version, 55 | urls = ["https://github.com/protocolbuffers/protobuf/releases/download/v%s/protobuf-%s.tar.gz" % (protobuf_version, protobuf_version)], 56 | ) 57 | 58 | def io_grpc_grpc_java(): 59 | http_archive( 60 | name = "io_grpc_grpc_java", 61 | sha256 = "970dcec6c8eb3fc624015f24b98df78f4c857a158fce0617deceafab470b90fc", 62 | strip_prefix = "grpc-java-1.57.2", 63 | url = "https://github.com/grpc/grpc-java/archive/v1.57.2.zip", 64 | ) 65 | -------------------------------------------------------------------------------- /run-test-client.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | cd "$(dirname "$0")" 3 | BIN="./interop_testing/build/install/interop_testing/bin/test-service-client" 4 | if [[ ! -e "$BIN" ]]; then 5 | cat >&2 <&2 <>( 32 | channel: Channel, 33 | callOptions: CallOptions = CallOptions.DEFAULT 34 | ): AbstractStub(channel, callOptions) 35 | -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library") 2 | 3 | licenses(["notice"]) 4 | 5 | package( 6 | default_visibility = ["//visibility:public"], 7 | ) 8 | 9 | kt_jvm_library( 10 | name = "stub", 11 | srcs = glob( 12 | ["*.kt"], 13 | exclude = ["GrpcContextElement.kt"], 14 | ), 15 | deps = [ 16 | ":context", 17 | "@io_grpc_grpc_java//core", 18 | "@io_grpc_grpc_java//stub", 19 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", 20 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", 21 | ], 22 | ) 23 | 24 | kt_jvm_library( 25 | name = "context", 26 | srcs = ["GrpcContextElement.kt"], 27 | deps = [ 28 | "@io_grpc_grpc_java//context", 29 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", 30 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core_jvm", 31 | ], 32 | ) 33 | -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/CoroutineContextServerInterceptor.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin 2 | 3 | import io.grpc.Metadata 4 | import io.grpc.ServerCall 5 | import io.grpc.ServerCallHandler 6 | import io.grpc.ServerInterceptor 7 | import io.grpc.StatusException 8 | import kotlin.coroutines.CoroutineContext 9 | import kotlin.coroutines.EmptyCoroutineContext 10 | import io.grpc.Context as GrpcContext 11 | 12 | /** 13 | * A [ServerInterceptor] subtype that can install elements in the [CoroutineContext] where server 14 | * logic is executed. These elements are applied "after" the 15 | * [AbstractCoroutineServerImpl.context]; that is, the interceptor overrides the server's context. 16 | */ 17 | abstract class CoroutineContextServerInterceptor : ServerInterceptor { 18 | companion object { 19 | // This is deliberately kept visibility-restricted; it's intentional that the only way to affect 20 | // the CoroutineContext is to extend CoroutineContextServerInterceptor. 21 | internal val COROUTINE_CONTEXT_KEY : GrpcContext.Key = 22 | GrpcContext.keyWithDefault("grpc-kotlin-coroutine-context", EmptyCoroutineContext) 23 | 24 | private fun GrpcContext.extendCoroutineContext(coroutineContext: CoroutineContext): GrpcContext { 25 | val oldCoroutineContext: CoroutineContext = COROUTINE_CONTEXT_KEY[this] 26 | val newCoroutineContext = oldCoroutineContext + coroutineContext 27 | return withValue(COROUTINE_CONTEXT_KEY, newCoroutineContext) 28 | } 29 | } 30 | 31 | /** 32 | * Override this function to return a [CoroutineContext] in which to execute [call] and [headers]. 33 | * The returned [CoroutineContext] will override any corresponding context elements in the 34 | * server object. 35 | * 36 | * This function will be called each time a [call] is executed. 37 | * 38 | * @throws StatusException if the call should be closed with the [Status][io.grpc.Status] in the 39 | * exception and further processing suppressed 40 | */ 41 | abstract fun coroutineContext(call: ServerCall<*, *>, headers: Metadata): CoroutineContext 42 | 43 | private inline fun withGrpcContext(context: GrpcContext, action: () -> R): R { 44 | val oldContext: GrpcContext = context.attach() 45 | return try { 46 | action() 47 | } finally { 48 | context.detach(oldContext) 49 | } 50 | } 51 | 52 | final override fun interceptCall( 53 | call: ServerCall, 54 | headers: Metadata, 55 | next: ServerCallHandler 56 | ): ServerCall.Listener { 57 | val coroutineContext = try { 58 | coroutineContext(call, headers) 59 | } catch (e: StatusException) { 60 | call.close(e.status, e.trailers ?: Metadata()) 61 | throw e 62 | } 63 | return withGrpcContext(GrpcContext.current().extendCoroutineContext(coroutineContext)) { 64 | next.startCall(call, headers) 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/GrpcContextElement.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin 18 | 19 | import kotlinx.coroutines.ThreadContextElement 20 | import kotlin.coroutines.CoroutineContext 21 | import io.grpc.Context as GrpcContext 22 | 23 | /** 24 | * A [CoroutineContext] that propagates an associated [io.grpc.Context] to coroutines run using 25 | * that context, regardless of thread. 26 | */ 27 | class GrpcContextElement(private val grpcContext: GrpcContext) : ThreadContextElement { 28 | companion object Key : CoroutineContext.Key { 29 | fun current(): GrpcContextElement = GrpcContextElement(GrpcContext.current()) 30 | } 31 | 32 | override val key: CoroutineContext.Key 33 | get() = Key 34 | 35 | override fun restoreThreadContext(context: CoroutineContext, oldState: GrpcContext) { 36 | grpcContext.detach(oldState) 37 | } 38 | 39 | override fun updateThreadContext(context: CoroutineContext): GrpcContext { 40 | return grpcContext.attach() 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/Helpers.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin 18 | 19 | import io.grpc.Status 20 | import io.grpc.StatusException 21 | import kotlinx.coroutines.Deferred 22 | import kotlinx.coroutines.Dispatchers 23 | import kotlinx.coroutines.Job 24 | import kotlinx.coroutines.cancel 25 | import kotlinx.coroutines.flow.Flow 26 | import kotlinx.coroutines.flow.collect 27 | import kotlinx.coroutines.flow.flow 28 | import kotlinx.coroutines.flow.single 29 | import kotlinx.coroutines.runBlocking 30 | 31 | /** 32 | * Extracts the value of a [Deferred] known to be completed, or throws its exception if it was 33 | * not completed successfully. (Non-experimental variant of `getDone`.) 34 | */ 35 | internal val Deferred.doneValue: T 36 | get() { 37 | check(isCompleted) { "doneValue should only be called on completed Deferred values" } 38 | return runBlocking(Dispatchers.Unconfined) { 39 | await() 40 | } 41 | } 42 | 43 | /** 44 | * Cancels a [Job] with a cause and suspends until the job completes/is finished cancelling. 45 | */ 46 | internal suspend fun Job.cancelAndJoin(message: String, cause: Exception? = null) { 47 | cancel(message, cause) 48 | join() 49 | } 50 | 51 | /** 52 | * Returns this flow, save that if there is not exactly one element, it throws a [StatusException]. 53 | * 54 | * The purpose of this function is to enable the one element to get processed before we have 55 | * confirmation that the input flow is done. 56 | */ 57 | internal fun Flow.singleOrStatusFlow( 58 | expected: String, 59 | descriptor: Any 60 | ): Flow = flow { 61 | var found = false 62 | collect { 63 | if (!found) { 64 | found = true 65 | emit(it) 66 | } else { 67 | throw StatusException( 68 | Status.INTERNAL.withDescription("Expected one $expected for $descriptor but received two") 69 | ) 70 | } 71 | } 72 | if (!found) { 73 | throw StatusException( 74 | Status.INTERNAL.withDescription("Expected one $expected for $descriptor but received none") 75 | ) 76 | } 77 | } 78 | 79 | /** 80 | * Returns the one and only element of this flow, and throws a [StatusException] if there is not 81 | * exactly one element. 82 | */ 83 | internal suspend fun Flow.singleOrStatus( 84 | expected: String, 85 | descriptor: Any 86 | ): T = singleOrStatusFlow(expected, descriptor).single() 87 | -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/Readiness.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin 18 | 19 | import kotlinx.coroutines.channels.Channel 20 | import kotlinx.coroutines.channels.onFailure 21 | 22 | /** 23 | * A simple helper allowing a notification of "ready" to be broadcast, and waited for. 24 | */ 25 | internal class Readiness( 26 | private val isReallyReady: () -> Boolean 27 | ) { 28 | // A CONFLATED channel never suspends to send, and two notifications of readiness are equivalent 29 | // to one 30 | private val channel = Channel(Channel.CONFLATED) 31 | 32 | fun onReady() { 33 | channel.trySend(Unit).onFailure { e -> 34 | throw e ?: AssertionError( 35 | "Should be impossible; a CONFLATED channel should never return false on offer" 36 | ) 37 | } 38 | } 39 | 40 | suspend fun suspendUntilReady() { 41 | while (!isReallyReady()) { 42 | channel.receive() 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /stub/src/main/java/io/grpc/kotlin/StubFor.kt: -------------------------------------------------------------------------------- 1 | package io.grpc.kotlin 2 | 3 | import kotlin.reflect.KClass 4 | 5 | @Target(AnnotationTarget.CLASS) 6 | @Retention(AnnotationRetention.RUNTIME) 7 | annotation class StubFor(val value: KClass<*>) 8 | -------------------------------------------------------------------------------- /stub/src/test/java/io/grpc/kotlin/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library", "kt_jvm_test") 2 | 3 | licenses(["notice"]) 4 | 5 | package(default_visibility = ["//stub/src/test:__subpackages__"]) 6 | 7 | kt_jvm_library( 8 | name = "AbstractCallsTest", 9 | testonly = True, 10 | srcs = [":AbstractCallsTest.kt"], 11 | deps = [ 12 | "//stub/src/test/proto/helloworld:hello_world_kt_grpc", 13 | "@io_grpc_grpc_java//testing", 14 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_debug", 15 | ], 16 | ) 17 | 18 | kt_jvm_test( 19 | name = "ClientCallsTest", 20 | srcs = [":ClientCallsTest.kt"], 21 | test_class = "io.grpc.kotlin.ClientCallsTest", 22 | deps = [ 23 | ":AbstractCallsTest", 24 | "//stub/src/test/proto/helloworld:hello_world_kt_grpc", 25 | "@maven//:com_google_truth_extensions_truth_proto_extension", 26 | ], 27 | ) 28 | 29 | kt_jvm_test( 30 | name = "FlowControlTest", 31 | srcs = [":FlowControlTest.kt"], 32 | test_class = "io.grpc.kotlin.FlowControlTest", 33 | deps = [ 34 | ":AbstractCallsTest", 35 | "//stub/src/test/proto/helloworld:hello_world_kt_grpc", 36 | "@maven//:com_google_truth_truth", 37 | ], 38 | ) 39 | 40 | kt_jvm_test( 41 | name = "GeneratedCodeTest", 42 | srcs = [":GeneratedCodeTest.kt"], 43 | test_class = "io.grpc.kotlin.GeneratedCodeTest", 44 | deps = [ 45 | ":AbstractCallsTest", 46 | "//stub/src/test/proto/helloworld:hello_world_kt_grpc", 47 | "@maven//:com_google_truth_extensions_truth_proto_extension", 48 | ], 49 | ) 50 | 51 | kt_jvm_test( 52 | name = "GrpcContextElementTest", 53 | srcs = [":GrpcContextElementTest.kt"], 54 | test_class = "io.grpc.kotlin.GrpcContextElementTest", 55 | deps = [ 56 | "//stub/src/main/java/io/grpc/kotlin:context", 57 | "@io_grpc_grpc_java//core", 58 | "@maven//:com_google_truth_truth", 59 | "@maven//:org_jetbrains_kotlinx_kotlinx_coroutines_core", 60 | ], 61 | ) 62 | 63 | kt_jvm_test( 64 | name = "ServerCallsTest", 65 | srcs = [":ServerCallsTest.kt"], 66 | test_class = "io.grpc.kotlin.ServerCallsTest", 67 | deps = [ 68 | ":AbstractCallsTest", 69 | "//stub/src/test/proto/helloworld:hello_world_kt_grpc", 70 | "@maven//:com_google_truth_extensions_truth_proto_extension", 71 | ], 72 | ) 73 | -------------------------------------------------------------------------------- /stub/src/test/java/io/grpc/kotlin/GrpcContextElementTest.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 gRPC authors. 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 | package io.grpc.kotlin 18 | 19 | import com.google.common.truth.Truth.assertThat 20 | import io.grpc.Context 21 | import kotlinx.coroutines.asCoroutineDispatcher 22 | import kotlinx.coroutines.runBlocking 23 | import org.junit.Test 24 | import org.junit.runner.RunWith 25 | import org.junit.runners.JUnit4 26 | import java.util.concurrent.Executors 27 | 28 | @RunWith(JUnit4::class) 29 | class GrpcContextElementTest { 30 | val testKey = Context.key("test") 31 | 32 | @Test 33 | fun testContextPropagation() { 34 | val testGrpcContext = Context.ROOT.withValue(testKey, "testValue") 35 | val coroutineContext = 36 | Executors.newSingleThreadExecutor().asCoroutineDispatcher() + GrpcContextElement(testGrpcContext) 37 | runBlocking(coroutineContext) { 38 | val currentTestKey = testKey.get() 39 | // gets from the implicit current gRPC context 40 | assertThat(currentTestKey).isEqualTo("testValue") 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /stub/src/test/proto/helloworld/BUILD.bazel: -------------------------------------------------------------------------------- 1 | load("@rules_proto//proto:defs.bzl", "proto_library") 2 | load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") 3 | load("//:kt_jvm_grpc.bzl", "kt_jvm_grpc_library") 4 | 5 | licenses(["notice"]) 6 | 7 | package(default_visibility = ["//stub/src/test:__subpackages__"]) 8 | 9 | proto_library( 10 | name = "hello_world_proto", 11 | srcs = ["helloworld.proto"], 12 | ) 13 | 14 | java_proto_library( 15 | name = "hello_world_java_proto", 16 | deps = [":hello_world_proto"], 17 | ) 18 | 19 | java_grpc_library( 20 | name = "hello_world_java_grpc", 21 | srcs = [":hello_world_proto"], 22 | deps = [":hello_world_java_proto"], 23 | ) 24 | 25 | kt_jvm_grpc_library( 26 | name = "hello_world_kt_grpc", 27 | srcs = [":hello_world_proto"], 28 | deps = [":hello_world_java_grpc"], 29 | ) 30 | -------------------------------------------------------------------------------- /stub/src/test/proto/helloworld/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2020 The gRPC Authors 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 | syntax = "proto3"; 15 | 16 | package helloworld; 17 | 18 | option java_multiple_files = true; 19 | option java_package = "io.grpc.examples.helloworld"; 20 | option java_outer_classname = "HelloWorldProto"; 21 | 22 | // The greeting service definition. 23 | service Greeter { 24 | // Sends a greeting 25 | rpc SayHello(HelloRequest) returns (HelloReply) {} 26 | 27 | // Sends a greeting to a group 28 | rpc ClientStreamSayHello(stream HelloRequest) returns (HelloReply) {} 29 | 30 | // Sends a number of hellos 31 | rpc ServerStreamSayHello(MultiHelloRequest) returns (stream HelloReply) {} 32 | 33 | // Sends interactive hellos 34 | rpc BidiStreamSayHello(stream HelloRequest) returns (stream HelloReply) {} 35 | } 36 | 37 | // The request message containing the user's name. 38 | message HelloRequest { 39 | string name = 1; 40 | } 41 | 42 | message MultiHelloRequest { 43 | repeated string name = 1; 44 | } 45 | 46 | // The response message containing the greetings 47 | message HelloReply { 48 | string message = 1; 49 | } 50 | --------------------------------------------------------------------------------