diff options
author | zpencer <spencerfang@google.com> | 2018-05-01 14:54:34 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-01 14:54:34 -0700 |
commit | f8424f7b7baba45bacd22622e9a35054a4ce41b6 (patch) | |
tree | b8129527b953c63096e3b9a893710e698f0dea81 /examples | |
parent | 3e43757efc98a177218919304d62114569fec9ea (diff) | |
download | grpc-grpc-java-f8424f7b7baba45bacd22622e9a35054a4ce41b6.tar.gz |
examples: add kotlin and kotlin android examples (#4037)
Add kotlin version of HelloWorldClient and HelloWorldServer.
Add kotlin version of android example.
Diffstat (limited to 'examples')
29 files changed, 1377 insertions, 0 deletions
diff --git a/examples/example-kotlin/README.md b/examples/example-kotlin/README.md new file mode 100644 index 000000000..aec61f7dd --- /dev/null +++ b/examples/example-kotlin/README.md @@ -0,0 +1,59 @@ +grpc Kotlin example +============================================== + +The examples require grpc-java to already be built. You are strongly encouraged +to check out a git release tag, since there will already be a build of grpc +available. Otherwise you must follow COMPILING.md. + +You may want to read through the +[Quick Start Guide](https://grpc.io/docs/quickstart/java.html) +before trying out the examples. + +To build the examples, run in this directory: + +``` +$ ./gradlew installDist +``` + +This creates the scripts `hello-world-server`, `hello-world-client`, +`route-guide-server`, and `route-guide-client` in the +`build/install/examples/bin/` directory that run the examples. Each +example requires the server to be running before starting the client. + +For example, to try the hello world example first run: + +``` +$ ./build/install/examples/bin/hello-world-server +``` + +And in a different terminal window run: + +``` +$ ./build/install/examples/bin/hello-world-client +``` + +That's it! + +Please refer to gRPC Java's [README](../README.md) and +[tutorial](https://grpc.io/docs/tutorials/basic/java.html) for more +information. + +Unit test examples +============================================== + +Examples for unit testing gRPC clients and servers are located in [./src/test](./src/test). + +In general, we DO NOT allow overriding the client stub. +We encourage users to leverage `InProcessTransport` as demonstrated in the examples to +write unit tests. `InProcessTransport` is light-weight and runs the server +and client in the same process without any socket/TCP connection. + +For testing a gRPC client, create the client with a real stub +using an InProcessChannelBuilder.java and test it against an InProcessServer.java +with a mock/fake service implementation. + +For testing a gRPC server, create the server as an InProcessServer, +and test it against a real client stub with an InProcessChannel. + +The gRPC-java library also provides a JUnit rule, GrpcServerRule.java, to do the starting +up and shutting down boilerplate for you. diff --git a/examples/example-kotlin/android/helloworld/app/build.gradle b/examples/example-kotlin/android/helloworld/app/build.gradle new file mode 100644 index 000000000..ba05ae621 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/build.gradle @@ -0,0 +1,91 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' +apply plugin: 'com.google.protobuf' + +android { + compileSdkVersion 27 + + defaultConfig { + applicationId "io.grpc.helloworldexample" + // API level 14+ is required for TLS since Google Play Services v10.2 + minSdkVersion 14 + targetSdkVersion 27 + versionCode 1 + versionName "1.0" + } + buildTypes { + debug { + minifyEnabled false + } + release { + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + disable 'GoogleAppIndexingWarning', 'HardcodedText', 'InvalidPackage' + textReport true + textOutput "stdout" + } + // Android Studio 3.1 does not automatically pick up '<src_set>/kotlin' as source input + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + main.java.srcDirs += 'src/test/kotlin' + androidTest.java.srcDirs += 'src/androidTest/kotlin' + } + + lintOptions { + // Do not complain about outdated deps, so that this can javax.annotation-api can be same + // as other projects in this repo. Your project is not required to do this, and can + // upgrade the dep. + disable 'GradleDependency' + // The Android linter does not correctly detect resources used in Kotlin. + // See: + // - https://youtrack.jetbrains.com/issue/KT-7729 + // - https://youtrack.jetbrains.com/issue/KT-12499 + disable 'UnusedResources' + textReport true + textOutput "stdout" + } +} + +protobuf { + protoc { + artifact = 'com.google.protobuf:protoc:3.5.1-1' + } + plugins { + javalite { + artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" + } + grpc { + artifact = 'io.grpc:protoc-gen-grpc-java:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION + } + } + generateProtoTasks { + all().each { task -> + task.plugins { + javalite {} + grpc { + // Options added to --grpc_out + option 'lite' + } + } + } + } +} + +dependencies { + compile 'com.android.support:appcompat-v7:27.0.2' + compile 'javax.annotation:javax.annotation-api:1.2' + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + + // You need to build grpc-java to obtain these libraries below. + compile 'io.grpc:grpc-okhttp:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION + compile 'io.grpc:grpc-protobuf-lite:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION + compile 'io.grpc:grpc-stub:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION +} + +repositories { + mavenCentral() +} diff --git a/examples/example-kotlin/android/helloworld/app/proguard-rules.pro b/examples/example-kotlin/android/helloworld/app/proguard-rules.pro new file mode 100644 index 000000000..1507a5267 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in $ANDROID_HOME/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +-dontwarn com.google.common.** +# Ignores: can't find referenced class javax.lang.model.element.Modifier +-dontwarn com.google.errorprone.annotations.** +-dontwarn javax.naming.** +-dontwarn okio.** +-dontwarn sun.misc.Unsafe diff --git a/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml b/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..eee4057cd --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="io.grpc.helloworldexample" > + + <uses-permission android:name="android.permission.INTERNET" /> + + <application + android:allowBackup="false" + android:icon="@mipmap/ic_launcher" + android:label="@string/app_name" + android:theme="@style/Base.V7.Theme.AppCompat.Light" > + <activity + android:name=".HelloworldActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt b/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt new file mode 100644 index 000000000..bcc6d0f28 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2015, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.helloworldexample + +import android.app.Activity +import android.content.Context +import android.os.AsyncTask +import android.os.Bundle +import android.support.v7.app.AppCompatActivity +import android.text.TextUtils +import android.text.method.ScrollingMovementMethod +import android.view.View +import android.view.inputmethod.InputMethodManager +import android.widget.Button +import android.widget.TextView +import io.grpc.ManagedChannel +import io.grpc.ManagedChannelBuilder +import io.grpc.examples.helloworld.GreeterGrpc +import io.grpc.examples.helloworld.HelloRequest +import java.io.PrintWriter +import java.io.StringWriter +import java.lang.ref.WeakReference +import java.util.concurrent.TimeUnit +import kotlinx.android.synthetic.main.activity_helloworld.* + +class HelloworldActivity : AppCompatActivity(), View.OnClickListener { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_helloworld) + grpc_response_text!!.movementMethod = ScrollingMovementMethod() + send_button!!.setOnClickListener(this) + } + + override fun onClick(view: View) { + (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager) + .hideSoftInputFromWindow(host_edit_text!!.windowToken, 0) + send_button!!.isEnabled = false + grpc_response_text!!.text = "" + GrpcTask(this) + .execute( + host_edit_text!!.text.toString(), + message_edit_text!!.text.toString(), + port_edit_text!!.text.toString()) + } + + private class GrpcTask constructor(activity: Activity) : AsyncTask<String, Void, String>() { + private val activityReference: WeakReference<Activity> = WeakReference(activity) + private var channel: ManagedChannel? = null + + override fun doInBackground(vararg params: String): String { + val host = params[0] + val message = params[1] + val portStr = params[2] + val port = if (TextUtils.isEmpty(portStr)) 0 else Integer.valueOf(portStr) + return try { + channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build() + val stub = GreeterGrpc.newBlockingStub(channel) + val request = HelloRequest.newBuilder().setName(message).build() + val reply = stub.sayHello(request) + reply.message + } catch (e: Exception) { + val sw = StringWriter() + val pw = PrintWriter(sw) + e.printStackTrace(pw) + pw.flush() + + "Failed... : %s".format(sw) + } + } + + override fun onPostExecute(result: String) { + try { + channel?.shutdown()?.awaitTermination(1, TimeUnit.SECONDS) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + } + + val activity = activityReference.get() ?: return + val resultText: TextView = activity.findViewById(R.id.grpc_response_text) + val sendButton: Button = activity.findViewById(R.id.send_button) + + resultText.text = result + sendButton.isEnabled = true + } + } +} diff --git a/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto b/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto new file mode 100644 index 000000000..78441b2d5 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto @@ -0,0 +1,38 @@ +// Copyright 2015, gRPC Authors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml b/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml new file mode 100644 index 000000000..e9f41f466 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml @@ -0,0 +1,54 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" + android:layout_height="match_parent" + tools:context=".MainActivity" + android:orientation="vertical" > + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <EditText + android:id="@+id/host_edit_text" + android:layout_weight="2" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:hint="Enter Host" /> + <EditText + android:id="@+id/port_edit_text" + android:layout_weight="1" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:inputType="numberDecimal" + android:hint="Enter Port" /> + </LinearLayout> + + + <EditText + android:id="@+id/message_edit_text" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:hint="Enter message to send" /> + + <Button + android:id="@+id/send_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Send Grpc Request" /> + + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="12dp" + android:paddingBottom="12dp" + android:textSize="16sp" + android:text="Response:" /> + + <TextView + android:id="@+id/grpc_response_text" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:scrollbars = "vertical" + android:textSize="16sp" /> + +</LinearLayout> diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..cde69bccc --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..c133a0cbd --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..bfa42f0e7 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 000000000..324e72cdd --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml b/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..64cb312d5 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ +<resources> + <string name="app_name">GrpcHelloworldExample</string> +</resources> diff --git a/examples/example-kotlin/android/helloworld/build.gradle b/examples/example-kotlin/android/helloworld/build.gradle new file mode 100644 index 000000000..ef4b2a199 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.kotlin_version = '1.2.21' + + repositories { + google() + jcenter() + mavenLocal() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.0.1' + classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + jcenter() + mavenLocal() + } +} diff --git a/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 000000000..27768f1bb --- /dev/null +++ b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..92165eede --- /dev/null +++ b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip diff --git a/examples/example-kotlin/android/helloworld/gradlew b/examples/example-kotlin/android/helloworld/gradlew new file mode 100755 index 000000000..cccdd3d51 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/examples/example-kotlin/android/helloworld/gradlew.bat b/examples/example-kotlin/android/helloworld/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/examples/example-kotlin/android/helloworld/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/example-kotlin/android/helloworld/settings.gradle b/examples/example-kotlin/android/helloworld/settings.gradle new file mode 100644 index 000000000..e7b4def49 --- /dev/null +++ b/examples/example-kotlin/android/helloworld/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/examples/example-kotlin/build.gradle b/examples/example-kotlin/build.gradle new file mode 100644 index 000000000..150ea179b --- /dev/null +++ b/examples/example-kotlin/build.gradle @@ -0,0 +1,88 @@ +apply plugin: 'kotlin' +apply plugin: 'com.google.protobuf' + +// Generate IntelliJ IDEA's .idea & .iml project files +// Starting with 0.8.4 of protobuf-gradle-plugin, *.proto and the gen output files are added +// to IntelliJ as sources. It is no longer necessary to add them manually to the idea {} block +// to jump to definitions from Java and Kotlin files. +// For best results, install the Protobuf and Kotlin plugins for IntelliJ. +apply plugin: 'idea' + +// Provide convenience executables for trying out the examples. +apply plugin: 'application' + + +buildscript { + ext.kotlin_version = '1.2.21' + + repositories { + mavenCentral() + mavenLocal() + } + dependencies { + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +repositories { + mavenCentral() + mavenLocal() +} + +// IMPORTANT: You probably want the non-SNAPSHOT version of gRPC. Make sure you +// are looking at a tagged version of the example and not "master"! + +// Feel free to delete the comment at the next line. It is just for safely +// updating the version in our release process. +def grpcVersion = '1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + compile "com.google.api.grpc:proto-google-common-protos:1.0.0" + compile "io.grpc:grpc-netty:${grpcVersion}" + compile "io.grpc:grpc-protobuf:${grpcVersion}" + compile "io.grpc:grpc-stub:${grpcVersion}" + + testCompile "io.grpc:grpc-testing:${grpcVersion}" // gRCP testing utilities + testCompile "junit:junit:4.12" + testCompile "org.mockito:mockito-core:1.9.5" +} + +protobuf { + protoc { + artifact = 'com.google.protobuf:protoc:3.5.1-1' + } + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" + } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } +} + +startScripts.enabled = false + +task helloWorldServer(type: CreateStartScripts) { + mainClassName = 'io.grpc.examples.helloworld.HelloWorldServer' + applicationName = 'hello-world-server' + outputDir = new File(project.buildDir, 'tmp') + classpath = jar.outputs.files + project.configurations.runtime +} + +task helloWorldClient(type: CreateStartScripts) { + mainClassName = 'io.grpc.examples.helloworld.HelloWorldClient' + applicationName = 'hello-world-client' + outputDir = new File(project.buildDir, 'tmp') + classpath = jar.outputs.files + project.configurations.runtime +} + +applicationDistribution.into('bin') { + from(helloWorldServer) + from(helloWorldClient) + fileMode = 0755 +} diff --git a/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar Binary files differnew file mode 100644 index 000000000..27768f1bb --- /dev/null +++ b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar diff --git a/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..92165eede --- /dev/null +++ b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip diff --git a/examples/example-kotlin/gradlew b/examples/example-kotlin/gradlew new file mode 100755 index 000000000..cccdd3d51 --- /dev/null +++ b/examples/example-kotlin/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/examples/example-kotlin/gradlew.bat b/examples/example-kotlin/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/examples/example-kotlin/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/examples/example-kotlin/settings.gradle b/examples/example-kotlin/settings.gradle new file mode 100644 index 000000000..9512a19f3 --- /dev/null +++ b/examples/example-kotlin/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'examples' diff --git a/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt new file mode 100644 index 000000000..74fe7c993 --- /dev/null +++ b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2015, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.examples.helloworld + +import io.grpc.ManagedChannel +import io.grpc.ManagedChannelBuilder +import io.grpc.StatusRuntimeException +import java.util.concurrent.TimeUnit +import java.util.logging.Level +import java.util.logging.Logger + +/** + * A simple client that requests a greeting from the [HelloWorldServer]. + */ +class HelloWorldClient +/** Construct client for accessing RouteGuide server using the existing channel. */ +internal constructor(private val channel: ManagedChannel) { + private val blockingStub: GreeterGrpc.GreeterBlockingStub + = GreeterGrpc.newBlockingStub(channel) + + /** Construct client connecting to HelloWorld server at `host:port`. */ + constructor(host: String, port: Int) : this(ManagedChannelBuilder.forAddress(host, port) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. + .usePlaintext() + .build()) { + } + + + @Throws(InterruptedException::class) + fun shutdown() { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS) + } + + /** Say hello to server. */ + fun greet(name: String) { + logger.log(Level.INFO, "Will try to greet {0}...", name) + val request = HelloRequest.newBuilder().setName(name).build() + val response: HelloReply = try { + blockingStub.sayHello(request) + } catch (e: StatusRuntimeException) { + logger.log(Level.WARNING, "RPC failed: {0}", e.status) + return + } + + logger.info("Greeting: ${response.message}") + } + + companion object { + private val logger = Logger.getLogger(HelloWorldClient::class.java.name) + + /** + * Greet server. If provided, the first element of `args` is the name to use in the + * greeting. + */ + @Throws(Exception::class) + @JvmStatic + fun main(args: Array<String>) { + val client = HelloWorldClient("localhost", 50051) + try { + /* Access a service running on the local machine on port 50051 */ + val user = if (args.size > 0) "world" else "world" + client.greet(user) + } finally { + client.shutdown() + } + } + } +} diff --git a/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt new file mode 100644 index 000000000..ae0d8de82 --- /dev/null +++ b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2015, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.examples.helloworld + +import io.grpc.Server +import io.grpc.ServerBuilder +import io.grpc.stub.StreamObserver +import java.io.IOException +import java.util.logging.Level +import java.util.logging.Logger + +/** + * Server that manages startup/shutdown of a `Greeter` server. + * + * Note: this file was automatically converted from Java + */ +class HelloWorldServer { + + private var server: Server? = null + + @Throws(IOException::class) + private fun start() { + /* The port on which the server should run */ + val port = 50051 + server = ServerBuilder.forPort(port) + .addService(GreeterImpl()) + .build() + .start() + logger.log(Level.INFO, "Server started, listening on {0}", port) + Runtime.getRuntime().addShutdownHook(object : Thread() { + override fun run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down") + this@HelloWorldServer.stop() + System.err.println("*** server shut down") + } + }) + } + + private fun stop() { + server?.shutdown() + } + + /** + * Await termination on the main thread since the grpc library uses daemon threads. + */ + @Throws(InterruptedException::class) + private fun blockUntilShutdown() { + server?.awaitTermination() + } + + internal class GreeterImpl : GreeterGrpc.GreeterImplBase() { + + override fun sayHello(req: HelloRequest, responseObserver: StreamObserver<HelloReply>) { + val reply = HelloReply.newBuilder().setMessage("Hello ${req.name}").build() + responseObserver.onNext(reply) + responseObserver.onCompleted() + } + } + + companion object { + private val logger = Logger.getLogger(HelloWorldServer::class.java.name) + + /** + * Main launches the server from the command line. + */ + @Throws(IOException::class, InterruptedException::class) + @JvmStatic + fun main(args: Array<String>) { + val server = HelloWorldServer() + server.start() + server.blockUntilShutdown() + } + } +} diff --git a/examples/example-kotlin/src/main/proto/helloworld.proto b/examples/example-kotlin/src/main/proto/helloworld.proto new file mode 100644 index 000000000..78441b2d5 --- /dev/null +++ b/examples/example-kotlin/src/main/proto/helloworld.proto @@ -0,0 +1,38 @@ +// Copyright 2015, gRPC Authors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.helloworld"; +option java_outer_classname = "HelloWorldProto"; +option objc_class_prefix = "HLW"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt new file mode 100644 index 000000000..3d096c920 --- /dev/null +++ b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2015, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.examples.helloworld + +import org.junit.Assert.assertEquals +import org.mockito.AdditionalAnswers.delegatesTo +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify + +import io.grpc.stub.StreamObserver +import io.grpc.testing.GrpcServerRule +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.mockito.ArgumentCaptor +import org.mockito.Matchers + +/** + * Unit tests for [HelloWorldClient]. + * For demonstrating how to write gRPC unit test only. + * Not intended to provide a high code coverage or to test every major usecase. + * + * + * For more unit test examples see [io.grpc.examples.routeguide.RouteGuideClientTest] and + * [io.grpc.examples.routeguide.RouteGuideServerTest]. + */ +@RunWith(JUnit4::class) +class HelloWorldClientTest { + /** + * This creates and starts an in-process server, and creates a client with an in-process channel. + * When the test is done, it also shuts down the in-process client and server. + */ + @get:Rule + val grpcServerRule = GrpcServerRule().directExecutor() + + private val serviceImpl = mock(GreeterGrpc.GreeterImplBase::class.java, delegatesTo<Any>(object : GreeterGrpc.GreeterImplBase() { + + })) + private var client: HelloWorldClient? = null + + @Before + @Throws(Exception::class) + fun setUp() { + // Add service. + grpcServerRule.serviceRegistry.addService(serviceImpl) + // Create a HelloWorldClient using the in-process channel; + client = HelloWorldClient(grpcServerRule.channel) + } + + /** + * To test the client, call from the client against the fake server, and verify behaviors or state + * changes from the server side. + */ + @Test + fun greet_messageDeliveredToServer() { + val requestCaptor = ArgumentCaptor.forClass(HelloRequest::class.java) + val testName = "test name" + + client!!.greet(testName) + + verify<GreeterGrpc.GreeterImplBase>(serviceImpl) + .sayHello(requestCaptor.capture(), Matchers.any<StreamObserver<HelloReply>>()) + assertEquals(testName, requestCaptor.value.name) + } +} diff --git a/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt new file mode 100644 index 000000000..4512b34ac --- /dev/null +++ b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2016, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.examples.helloworld + +import org.junit.Assert.assertEquals + +import io.grpc.examples.helloworld.HelloWorldServer.GreeterImpl +import io.grpc.testing.GrpcServerRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +/** + * Unit tests for [HelloWorldServer]. + * For demonstrating how to write gRPC unit test only. + * Not intended to provide a high code coverage or to test every major usecase. + * + * + * For more unit test examples see [io.grpc.examples.routeguide.RouteGuideClientTest] and + * [io.grpc.examples.routeguide.RouteGuideServerTest]. + */ +@RunWith(JUnit4::class) +class HelloWorldServerTest { + /** + * This creates and starts an in-process server, and creates a client with an in-process channel. + * When the test is done, it also shuts down the in-process client and server. + */ + @get:Rule + val grpcServerRule = GrpcServerRule().directExecutor() + + /** + * To test the server, make calls with a real stub using the in-process channel, and verify + * behaviors or state changes from the client side. + */ + @Test + @Throws(Exception::class) + fun greeterImpl_replyMessage() { + // Add the service to the in-process server. + grpcServerRule.serviceRegistry.addService(GreeterImpl()) + + val blockingStub = GreeterGrpc.newBlockingStub(grpcServerRule.channel) + val testName = "test name" + + val reply = blockingStub.sayHello(HelloRequest.newBuilder().setName(testName).build()) + + assertEquals("Hello $testName", reply.message) + } +} |